diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0d7c51ca6c53b4abd999c0a5615c36c5606aca08..40437fd5c280e0eb399106ffb6d97192dec27c75 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -343,6 +343,7 @@ SET( libringclient_LIB_SRCS
   src/authority/databasehelper.cpp
   src/lrc.cpp
   src/newaccountmodel.cpp
+  src/peerdiscoverymodel.cpp
   src/callbackshandler.cpp
   src/behaviorcontroller.cpp
   src/datatransfermodel.cpp
@@ -483,6 +484,7 @@ SET(libringclient_api_LIB_HDRS
   src/api/lrc.h
   src/api/avmodel.h
   src/api/newaccountmodel.h
+  src/api/peerdiscoverymodel.h
   src/api/newcallmodel.h
   src/api/newcodecmodel.h
   src/api/newdevicemodel.h
diff --git a/src/api/account.h b/src/api/account.h
index 8d353d19349a38cf2688bc82dd2641553dd63264..6f9ecfe36b588b5dc6c4bee5957dd1ad7b49094d 100644
--- a/src/api/account.h
+++ b/src/api/account.h
@@ -40,6 +40,7 @@ class NewCallModel;
 class NewAccountModel;
 class NewDeviceModel;
 class NewCodecModel;
+class PeerDiscoveryModel;
 
 namespace account
 {
@@ -225,6 +226,7 @@ struct Info
     std::unique_ptr<lrc::api::NewCallModel> callModel;
     std::unique_ptr<lrc::api::NewDeviceModel> deviceModel;
     std::unique_ptr<lrc::api::NewCodecModel> codecModel;
+    std::unique_ptr<lrc::api::PeerDiscoveryModel> peerDiscoveryModel;
     NewAccountModel* accountModel {nullptr};
 
     // daemon config
diff --git a/src/api/peerdiscoverymodel.h b/src/api/peerdiscoverymodel.h
new file mode 100644
index 0000000000000000000000000000000000000000..5112629e942e061de5360e7f1081e45a8c52eca8
--- /dev/null
+++ b/src/api/peerdiscoverymodel.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+ *    Copyright (C) 2019 Savoir-faire Linux Inc.                            *
+ *   Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>             *
+ *                                                                          *
+ *   This library is free software; you can redistribute it and/or          *
+ *   modify it under the terms of the GNU Lesser General Public             *
+ *   License as published by the Free Software Foundation; either           *
+ *   version 2.1 of the License, or (at your option) any later version.     *
+ *                                                                          *
+ *   This library is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
+ *   Lesser General Public License for more details.                        *
+ *                                                                          *
+ *   You should have received a copy of the GNU General Public License      *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#pragma once
+
+// std
+#include <vector>
+#include <map>
+#include <memory>
+#include <string>
+
+// Qt
+#include <qobject.h>
+
+// Lrc
+#include "typedefs.h"
+
+namespace lrc
+{
+
+class CallbacksHandler;
+class PeerDiscoveryModelPimpl;
+
+namespace api
+{
+
+struct PeerContact
+{
+    std::string uri;
+    std::string displayName;
+};
+
+enum class PeerModelChanged
+{
+    INSERT,
+    REMOVE
+};
+
+
+/**
+  *  @brief Class that manages local peer discovery info
+  */
+class LIB_EXPORT PeerDiscoveryModel : public QObject {
+    Q_OBJECT
+public:
+
+    PeerDiscoveryModel(const CallbacksHandler& callbackHandler, const std::string& accountID);
+    ~PeerDiscoveryModel();
+    /**
+     * get a map of discovered peers account
+     * @return a std::vector<PeerContact>
+     */
+    std::vector<PeerContact> getNearbyPeers() const;
+
+Q_SIGNALS:
+    /**
+     * Connect this signal to know when the status of local peer discovery map changed.
+     */
+    void modelChanged(const std::string& contactUri, PeerModelChanged state, const std::string& displayname);
+
+private:
+    std::unique_ptr<PeerDiscoveryModelPimpl> pimpl_;
+};
+
+} // namespace api
+} // namespace lrc
diff --git a/src/callbackshandler.cpp b/src/callbackshandler.cpp
index dad2607e865669fb4f384e9855c4bbd6d8cd99e0..283d54e33804afd14d2b36ac402053e2d9c97258 100644
--- a/src/callbackshandler.cpp
+++ b/src/callbackshandler.cpp
@@ -64,6 +64,12 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent)
             &CallbacksHandler::slotNewBuddySubscription,
             Qt::QueuedConnection);
 
+    connect(&PresenceManager::instance(),
+            &PresenceManagerInterface::nearbyPeerNotification,
+            this,
+            &CallbacksHandler::slotNearbyPeerSubscription,
+            Qt::QueuedConnection);
+
     connect(&ConfigurationManager::instance(),
             &ConfigurationManagerInterface::contactAdded,
             this,
@@ -248,6 +254,15 @@ CallbacksHandler::slotNewBuddySubscription(const QString& accountId,
     emit newBuddySubscription(uri.toStdString(), status);
 }
 
+void
+CallbacksHandler::slotNearbyPeerSubscription(const QString& accountId,
+                                             const QString& contactUri,
+                                             int state,
+                                             const QString& displayname)
+{
+    emit newPeerSubscription(accountId.toStdString(), contactUri.toStdString(), state, displayname.toStdString());
+}
+
 void
 CallbacksHandler::slotContactAdded(const QString& accountId,
                                    const QString& contactUri,
diff --git a/src/callbackshandler.h b/src/callbackshandler.h
index 098e7b9af70f9fc479ff9b4b0b932d2da1d40a96..31409cf187f9f078d2fd31113843781861a66852 100644
--- a/src/callbackshandler.h
+++ b/src/callbackshandler.h
@@ -68,6 +68,12 @@ Q_SIGNALS:
      * @param present if the peer is online.
      */
     void newBuddySubscription(const std::string& contactUri, bool present);
+    /**
+     * Connect this signal to get information when peer discovery changes.
+     * @param contactUri the peer.
+     * @param state is 0 if the peer is added.
+     */
+    void newPeerSubscription(const std::string& accountId, const std::string& contactUri, int state, const std::string& displayname);
     /**
      * Connect this signal to know when a contact is removed by the daemon.
      * @param accountId the one who lost a contact.
@@ -467,6 +473,18 @@ private Q_SLOTS:
      */
     void slotAudioMeterReceived(const QString& id, float level);
 
+    /**
+     * Emit newPeerSubscription
+     * @param accountId
+     * @param contactUri
+     * @param status if the peer is added or removed
+     * @param displayname is the account display name
+     */
+    void slotNearbyPeerSubscription(const QString& accountId,
+                                    const QString& contactUri,
+                                    int state,
+                                    const QString& displayname);
+
 private:
     const api::Lrc& parent;
 };
diff --git a/src/newaccountmodel.cpp b/src/newaccountmodel.cpp
index c12703f56dbcfad1ea621f3060b73a2e4b1f75eb..887d613b9d174d6cc492d25e10987d09b219d9e1 100644
--- a/src/newaccountmodel.cpp
+++ b/src/newaccountmodel.cpp
@@ -31,6 +31,7 @@
 #include "api/lrc.h"
 #include "api/contactmodel.h"
 #include "api/conversationmodel.h"
+#include "api/peerdiscoverymodel.h"
 #include "api/newcallmodel.h"
 #include "api/newcodecmodel.h"
 #include "api/newdevicemodel.h"
@@ -582,6 +583,7 @@ NewAccountModelPimpl::addToAccounts(const std::string& accountId)
     newAcc.callModel = std::make_unique<NewCallModel>(newAcc, callbacksHandler);
     newAcc.contactModel = std::make_unique<ContactModel>(newAcc, database, callbacksHandler, behaviorController);
     newAcc.conversationModel = std::make_unique<ConversationModel>(newAcc, lrc, database, callbacksHandler, behaviorController);
+    newAcc.peerDiscoveryModel = std::make_unique<PeerDiscoveryModel>(callbacksHandler, accountId);
     newAcc.deviceModel = std::make_unique<NewDeviceModel>(newAcc, callbacksHandler);
     newAcc.codecModel = std::make_unique<NewCodecModel>(newAcc, callbacksHandler);
     newAcc.accountModel = &linked;
diff --git a/src/peerdiscoverymodel.cpp b/src/peerdiscoverymodel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..759edc89e836e0f414976dd7e249fd4f30c2251c
--- /dev/null
+++ b/src/peerdiscoverymodel.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+ *    Copyright (C) 2019 Savoir-faire Linux Inc.                            *
+ *   Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>             *
+ *                                                                          *
+ *   This library is free software; you can redistribute it and/or          *
+ *   modify it under the terms of the GNU Lesser General Public             *
+ *   License as published by the Free Software Foundation; either           *
+ *   version 2.1 of the License, or (at your option) any later version.     *
+ *                                                                          *
+ *   This library is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
+ *   Lesser General Public License for more details.                        *
+ *                                                                          *
+ *   You should have received a copy of the GNU General Public License      *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+#include "api/peerdiscoverymodel.h"
+
+// new LRC
+#include "callbackshandler.h"
+
+// Dbus
+#include "dbus/configurationmanager.h"
+
+namespace lrc
+{
+
+using namespace api;
+
+class PeerDiscoveryModelPimpl: public QObject
+{
+    Q_OBJECT
+public:
+    PeerDiscoveryModelPimpl(PeerDiscoveryModel& linked,
+                            const CallbacksHandler& callbackHandler,
+                            const std::string& accountID);
+    ~PeerDiscoveryModelPimpl();
+
+    PeerDiscoveryModel& linked_;
+    const CallbacksHandler& callbacksHandler_;
+    const std::string accountID_;
+
+public Q_SLOTS:
+
+    /**
+     * Emit peerMapStatusChanged.
+     * @param accountId
+     * @param status
+     */
+    void slotPeerMapStatusChanged(const std::string& accountID, const std::string& contactUri, int state, const std::string& displayname);
+};
+
+PeerDiscoveryModel::PeerDiscoveryModel(const CallbacksHandler& callbacksHandler, const std::string& accountID)
+: QObject()
+, pimpl_(std::make_unique<PeerDiscoveryModelPimpl>(*this, callbacksHandler, accountID))
+{
+}
+
+PeerDiscoveryModel::~PeerDiscoveryModel()
+{
+}
+
+PeerDiscoveryModelPimpl::PeerDiscoveryModelPimpl(PeerDiscoveryModel& linked,
+                                                 const CallbacksHandler& callbacksHandler,
+                                                 const std::string& accountID)
+: linked_(linked)
+, callbacksHandler_(callbacksHandler)
+, accountID_(accountID)
+{
+    connect(&callbacksHandler_, &CallbacksHandler::newPeerSubscription, this, &PeerDiscoveryModelPimpl::slotPeerMapStatusChanged);
+}
+
+PeerDiscoveryModelPimpl::~PeerDiscoveryModelPimpl()
+{
+    disconnect(&callbacksHandler_, &CallbacksHandler::newPeerSubscription, this, &PeerDiscoveryModelPimpl::slotPeerMapStatusChanged);
+}
+
+void
+PeerDiscoveryModelPimpl::slotPeerMapStatusChanged(const std::string& accountID, const std::string& contactUri, int state, const std::string& displayname)
+{
+    if(accountID != accountID_){
+        return;
+    } 
+    emit linked_.modelChanged(contactUri,state == 0 ? PeerModelChanged::INSERT : PeerModelChanged::REMOVE,displayname);
+
+}
+
+std::vector<PeerContact>
+PeerDiscoveryModel::getNearbyPeers() const
+{
+    std::vector<PeerContact> result;
+    const MapStringString nearbyPeers = ConfigurationManager::instance().getNearbyPeers(QString::fromStdString(pimpl_->accountID_));
+    result.reserve(nearbyPeers.size());
+
+    QMap<QString, QString>::const_iterator i = nearbyPeers.constBegin();
+    while (i != nearbyPeers.constEnd()) {
+        result.emplace_back(PeerContact{i.key().toStdString(), i.value().toStdString()});
+        ++i;
+    }
+    return result;
+}
+
+} // namespace lrc
+
+#include "api/moc_peerdiscoverymodel.cpp"
+#include "peerdiscoverymodel.moc"
diff --git a/src/qtwrapper/configurationmanager_wrap.h b/src/qtwrapper/configurationmanager_wrap.h
index 703bc068ebbb6d2323af62943cb67e88447fd372..49bfb04675c9c045541b5779a46a04e6d3bfd4a4 100644
--- a/src/qtwrapper/configurationmanager_wrap.h
+++ b/src/qtwrapper/configurationmanager_wrap.h
@@ -621,6 +621,10 @@ public Q_SLOTS: // METHODS
         return DRing::getMessageStatus(id);
     }
 
+    MapStringString getNearbyPeers(const QString &accountID){
+        return convertMap(DRing::getNearbyPeers(accountID.toStdString()));
+    }
+
     void connectivityChanged() {
         DRing::connectivityChanged();
     }
diff --git a/src/qtwrapper/presencemanager_wrap.h b/src/qtwrapper/presencemanager_wrap.h
index f1019a7478272d4aaa030d6cbdf30245fe002bf2..1ca89e731afd2c5bb3f895cd1b3e43bae8f7561d 100644
--- a/src/qtwrapper/presencemanager_wrap.h
+++ b/src/qtwrapper/presencemanager_wrap.h
@@ -63,6 +63,10 @@ public:
             exportable_callback<PresenceSignal::SubscriptionStateChanged>(
                 [this] (const std::string &accountID, const std::string &buddyUri, bool state) {
                     Q_EMIT this->subscriptionStateChanged(QString(accountID.c_str()), QString(buddyUri.c_str()), state);
+                }),
+            exportable_callback<PresenceSignal::NearbyPeerNotification>(
+                [this] (const std::string &accountID, const std::string &buddyUri, int status, const std::string &displayname) {
+                    Q_EMIT this->nearbyPeerNotification(QString(accountID.c_str()), QString(buddyUri.c_str()), status, QString(displayname.c_str()));
                 })
          };
     }
@@ -100,6 +104,7 @@ public Q_SLOTS: // METHODS
     }
 
 Q_SIGNALS: // SIGNALS
+    void nearbyPeerNotification(const QString &accountID, const QString &buddyUri, int status, const QString &displayname);
     void newServerSubscriptionRequest(const QString &buddyUri);
     void serverError(const QString &accountID, const QString &error, const QString &msg);
     void newBuddyNotification(const QString &accountID, const QString &buddyUri, bool status, const QString &lineStatus);
diff --git a/test/mocks/presencemanager_mock.h b/test/mocks/presencemanager_mock.h
index facd091943eace61e7b892a20dcb186ff04116bf..4d6e2c98419bb3e38966dcdc0e60e8ca5685171f 100644
--- a/test/mocks/presencemanager_mock.h
+++ b/test/mocks/presencemanager_mock.h
@@ -52,6 +52,10 @@ public:
     {
         emit newBuddyNotification(accountID, buddyUri, status, lineStatus);
     }
+    void emitNearbyPeerNotification(const QString &accountID, const QString &buddyUri, int status, const QString &displayname)
+    {
+        emit nearbyPeerNotification(accountID, buddyUri, status, displayname);
+    }
 
 public Q_SLOTS: // METHODS
     void answerServerRequest(const QString &uri, bool flag)
@@ -91,6 +95,7 @@ Q_SIGNALS: // SIGNALS
     void newServerSubscriptionRequest(const QString &buddyUri);
     void serverError(const QString &accountID, const QString &error, const QString &msg);
     void newBuddyNotification(const QString &accountID, const QString &buddyUri, bool status, const QString &lineStatus);
+    void nearbyPeerNotification(const QString &accountID, const QString &buddyUri, int status, const QString &displayname);
     void subscriptionStateChanged(const QString &accountID, const QString &buddyUri, bool state);
 };