diff --git a/CellframeNodeDiagtool/AbstractDiagnostic.cpp b/CellframeNodeDiagtool/AbstractDiagnostic.cpp
index 3f0c8fb932a67c75c8c3b8c98fe0039ecfb5614a..65f412858140cfbe9a944b96b48b74a02a7c62ee 100644
--- a/CellframeNodeDiagtool/AbstractDiagnostic.cpp
+++ b/CellframeNodeDiagtool/AbstractDiagnostic.cpp
@@ -234,6 +234,7 @@ QJsonObject AbstractDiagnostic::get_net_info(QString net)
     
     QString result = proc.readAll();
     
+    // ---------- Status ----------------
     QRegularExpression rx_state(R"(.*current: ([A-Z,_]+).*)");
     QRegularExpression rx_addr(R"(.*current_addr: (.+))");
     
@@ -263,7 +264,35 @@ QJsonObject AbstractDiagnostic::get_net_info(QString net)
         resultObj.insert("links_count", match_req.captured(1));
     }
     
-    
+    // ---------- Sync statuses ----------------
+    QRegularExpression rxZeroChainSync(R"(zerochain: \s+status: (\S+|.+)\s+current: (\S+)\s+in network: (\S+)\s+percent: (\S+|.+))");
+    QJsonObject objZeroChain;
+
+    QRegularExpressionMatch match_zeroChain = rxZeroChainSync.match(result);
+    if (match_zeroChain.hasMatch()) {
+        objZeroChain.insert("status",  match_zeroChain.captured(1));
+        objZeroChain.insert("current", match_zeroChain.captured(2));
+        objZeroChain.insert("network", match_zeroChain.captured(3));
+        objZeroChain.insert("percent", match_zeroChain.captured(4));
+    }
+
+    QRegularExpression rxMainChainSync(R"(main: \s+status: (\S+|.+)\s+current: (\S+)\s+in network: (\S+)\s+percent: (\S+|.+))");
+    QJsonObject objMainChain;
+
+    QRegularExpressionMatch match_mainChain = rxMainChainSync.match(result);
+    if (match_mainChain.hasMatch()) {
+       objMainChain.insert("status",  match_mainChain.captured(1));
+       objMainChain.insert("current", match_mainChain.captured(2));
+       objMainChain.insert("network", match_mainChain.captured(3));
+       objMainChain.insert("percent", match_mainChain.captured(4));
+    }
+
+    QJsonObject syncObj{
+       {"main", objMainChain},
+       {"zero", objZeroChain}
+    };
+
+    resultObj.insert("sync_status", syncObj);
     resultObj.insert("balancer", get_balancer_links(net));
 
     return resultObj;
diff --git a/CellframeNodeDiagtool/DiagnosticWorker.cpp b/CellframeNodeDiagtool/DiagnosticWorker.cpp
index 72ca0b0f0ead8ad9eba054d7c8e54d2548bd3ec1..a4b5bec3b8487134319fac5653d803d5ac5d8432 100644
--- a/CellframeNodeDiagtool/DiagnosticWorker.cpp
+++ b/CellframeNodeDiagtool/DiagnosticWorker.cpp
@@ -3,6 +3,7 @@
 #include <QHttpPart>
 #include <QHttpMultiPart>
 #include <QNetworkReply>
+
 static QString group = "global.users.statistic";
 
 DiagnosticWorker::DiagnosticWorker(QObject * parent)
@@ -37,6 +38,10 @@ void DiagnosticWorker::init()
     m_diagnostic = new MacDiagnostic();
 #endif
 
+    m_notifyWorker = new NotifyWorker();
+    m_notifyWorker->rcvNetObj(m_diagnostic->roles_processing());
+
+
     connect(m_diagnostic, &AbstractDiagnostic::data_updated,
             this, &DiagnosticWorker::slot_diagnostic_data,
             Qt::QueuedConnection);
@@ -112,9 +117,12 @@ void DiagnosticWorker::slot_diagnostic_data(QJsonDocument data)
             result = result.split("version")[1];
             m_node_version = result.split('\n', QString::SkipEmptyParts).first().trimmed();
         }
+
+        m_notifyWorker->nodeIsOnline();
     }
 
     proc.insert("version", m_node_version);
+    proc.insert("node_init", m_notifyWorker->m_docNodeInit.object());
     obj.insert("process",proc);
     data.setObject(obj);
     m_lastSendedPack = data;
diff --git a/CellframeNodeDiagtool/DiagnosticWorker.h b/CellframeNodeDiagtool/DiagnosticWorker.h
index 51c1d3b79a416168152090ef7b36a1387ac2cfcb..b73a853bc805722aaea0478b7121594476c64b78 100644
--- a/CellframeNodeDiagtool/DiagnosticWorker.h
+++ b/CellframeNodeDiagtool/DiagnosticWorker.h
@@ -14,6 +14,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "NotifyWorker.h"
+
 #ifdef Q_OS_LINUX
     #include "LinuxDiagnostic.h"
 #elif defined Q_OS_WIN
@@ -46,6 +48,7 @@ private:
     QString m_node_version{""};
     QSettings m_settings;
     AbstractDiagnostic* m_diagnostic;
+    NotifyWorker* m_notifyWorker;
 
     QTimer *s_uptime_timer;
     QElapsedTimer *s_elapsed_timer;
diff --git a/CellframeNodeDiagtool/NotifyWorker.cpp b/CellframeNodeDiagtool/NotifyWorker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..625ab913c7ee6731a7da0f9e7b2cfa2663d777d2
--- /dev/null
+++ b/CellframeNodeDiagtool/NotifyWorker.cpp
@@ -0,0 +1,287 @@
+#include "NotifyWorker.h"
+#include "NodeTrayCommandController.h"
+
+QByteArrayList NotifyWorker::jsonListFromData(QByteArray data)
+{
+    return data.split('\x00');
+}
+
+NotifyWorker::NotifyWorker(QObject *parent)
+    :QObject(parent)
+{
+    NodeTrayCommandController *m_trayCtrl = &NodeTrayCommandController::getInstance();
+
+    if(m_trayCtrl->initConfTool())
+    {
+        m_configWorkerPath = m_trayCtrl->m_confToolPath;
+        m_initTimer = new QTimer(this);
+        m_reconnectTimer = new QTimer(this);
+
+        if(initWatcher())
+            return;
+        else
+        {
+            m_initTimer->start(5000);
+            connect(m_initTimer, &QTimer::timeout, [=] {
+                qDebug()<<"Reinit timer tick";
+                if(initWatcher())
+                    m_initTimer->stop();
+            });
+        }
+    }
+    m_statusInitWatcher = false;
+}
+
+NotifyWorker::~NotifyWorker()
+{
+    delete m_initTimer;
+    delete m_reconnectTimer;
+}
+
+QVariant NotifyWorker::readConfig(QString filename, QString section, QString param, QVariant defaultValue)
+{
+    QProcess proc;
+    proc.setProgram(m_configWorkerPath);
+    proc.setArguments(QStringList()<<"-e"<<"config"<<filename<<section<<param<<"get");
+
+    proc.start();
+
+    if(proc.waitForFinished())
+    {
+        QByteArray res = proc.readAllStandardOutput();
+
+        QString strRes = QString(res).remove("\n").remove("\r").remove("\t");
+        return strRes.split("=")[1];
+    }
+
+    qDebug()<<proc.readAllStandardError();
+    return defaultValue;
+}
+
+bool NotifyWorker::initWatcher()
+{
+    m_listenPath = readConfig("cellframe-node", "notify_server", "listen_path", "").toString();
+    m_listenAddr = readConfig("cellframe-node", "notify_server", "listen_address", "").toString();
+    m_listenPort = readConfig("cellframe-node", "notify_server", "listen_port", 0).toUInt();
+
+    if(m_listenAddr.contains(":"))
+    {
+        m_listenAddr = m_listenAddr.contains("[") ? m_listenAddr.remove("[") : m_listenAddr;
+        m_listenAddr = m_listenAddr.contains("]") ? m_listenAddr.remove("]") : m_listenAddr;
+
+        m_listenPort = QString(m_listenAddr.split(":")[1]).toUInt();
+        m_listenAddr = m_listenAddr.split(":")[0];
+    }
+
+    qDebug() << "Tcp config: " << m_listenAddr << m_listenPort;
+    connect(m_reconnectTimer, SIGNAL(timeout()), this, SLOT(slotReconnect()));
+
+    if (!m_listenPath.isEmpty())
+    {
+        m_socket = new QLocalSocket(this);
+        connect((QLocalSocket*)m_socket, QOverload<QLocalSocket::LocalSocketError>::of(&QLocalSocket::error),
+                this, &NotifyWorker::slotError);
+
+        connect((QLocalSocket*)m_socket, &QLocalSocket::connected,
+                this, &NotifyWorker::socketConnected);
+
+        connect((QLocalSocket*)m_socket, &QLocalSocket::disconnected,
+                this, &NotifyWorker::socketDisconnected);
+
+        connect((QAbstractSocket*)m_socket, &QAbstractSocket::stateChanged,
+                this, &NotifyWorker::socketStateChanged);
+
+        connect(m_socket, &QLocalSocket::readyRead, this, &NotifyWorker::socketReadyRead);
+
+        ((QLocalSocket*)m_socket)->connectToServer(m_listenPath);
+        ((QLocalSocket*)m_socket)->waitForConnected();
+    }
+    else
+    {
+        m_socket = new QTcpSocket(this);
+        connect((QTcpSocket*)m_socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
+                this, &NotifyWorker::slotError);
+
+        connect((QTcpSocket*)m_socket, &QTcpSocket::connected,
+                this, &NotifyWorker::socketConnected);
+
+        connect((QTcpSocket*)m_socket, &QTcpSocket::disconnected,
+                this, &NotifyWorker::socketDisconnected);
+
+        connect((QTcpSocket*)m_socket, &QTcpSocket::stateChanged,
+                this, &NotifyWorker::socketStateChanged);
+
+        connect(m_socket, &QTcpSocket::readyRead, this, &NotifyWorker::socketReadyRead);
+
+        ((QTcpSocket*)m_socket)->connectToHost(m_listenAddr, m_listenPort);
+        ((QTcpSocket*)m_socket)->waitForConnected();
+    }
+    m_statusInitWatcher = true;
+    return true;
+}
+
+
+void NotifyWorker::slotError()
+{
+    qWarning() << "Notify socket error" << m_socket->errorString();
+    reconnectFunc();
+}
+
+void NotifyWorker::slotReconnect()
+{
+    qInfo()<<"NotifyWorker::slotReconnect()" << m_listenAddr << m_listenPort << "Socket state" << m_socketState;
+
+    ((QTcpSocket*)m_socket)->connectToHost(m_listenAddr, m_listenPort);
+    ((QTcpSocket*)m_socket)->waitForConnected(5000);
+}
+
+void NotifyWorker::socketConnected()
+{
+    qInfo() << "Notify socket connected";
+    m_reconnectTimer->stop();
+    m_socket->waitForReadyRead(4000);
+}
+
+void NotifyWorker::socketDisconnected()
+{
+    qWarning() << "Notify socket disconnected";
+    reconnectFunc();
+}
+
+void NotifyWorker::socketStateChanged(QAbstractSocket::SocketState socketState)
+{
+    qDebug() << "Socket state changed" << socketState;
+    m_socketState = socketState;
+}
+
+void NotifyWorker::socketReadyRead()
+{
+    //    qDebug() << "Ready Read";
+    QByteArray data = m_socket->readLine();
+    //    QByteArray data = socket->readAll();
+    if (data[data.length() - 1] != '}')
+        data = data.left(data.length() - 1);
+
+    if (data[0] != '{')
+        data = data.right(data.length() - 1);
+
+    QByteArrayList list = jsonListFromData(data);
+
+    for (int i = 0; i < list.length(); ++i)
+    {
+        QJsonParseError error;
+        QJsonDocument reply = QJsonDocument::fromJson(list[i], &error);
+        if (error.error != QJsonParseError::NoError) {
+            //            qWarning()<<"Notify parse error. " << error.errorString(); // more logs
+            return;
+        }
+
+        if(reply.object()["class"].toString() == "chain_init")
+            procNotifyData(reply.object());
+    }
+}
+
+void NotifyWorker::procNotifyData(const QJsonObject &rcvObj)
+{
+    m_rcvInitProgress = true;
+
+    bool isContains{false};
+    int itr{0};
+
+    for (const auto &net: qAsConst(m_arrNodeInit)) {
+        const auto findNet = net.toObject();
+
+        if (findNet["name"] == rcvObj["net"]) {
+            isContains = true;
+
+            QJsonObject objChains = m_arrNodeInit[itr].toObject()["chains"].toObject();
+
+            if(rcvObj["chain_id"].toInt() == 1)
+            {
+                objChains["main"] = rcvObj["load_progress"];
+                objChains["zero"] = 100;
+            }
+            else
+                objChains["zero"] = rcvObj["load_progress"];
+
+            QJsonObject object
+            {
+                {"name", rcvObj["net"].toString()},
+                {"chains", objChains}
+            };
+
+            m_arrNodeInit[itr] = object;
+            break;
+        }
+        itr++;
+    }
+
+    QJsonObject result{
+        {"init_progress", m_arrNodeInit},
+        {"notify_status", m_socketState == QAbstractSocket::SocketState::ConnectedState?
+                                           "connected" : "disconnected"}
+    };
+
+    m_docNodeInit.setObject(result);
+
+//    qDebug()<<m_docNodeInit.toJson();
+}
+
+void NotifyWorker::nodeIsOnline()
+{
+    if(!m_rcvInitProgress)
+    {
+        m_arrNodeInit = QJsonArray();
+        for(const auto &net: qAsConst(m_netList))
+        {
+            QJsonObject chains;
+            chains.insert("main", 100);
+            chains.insert("zero", 100);
+
+            QJsonObject obj;
+            obj.insert("name", net);
+            obj.insert("chains", chains);
+
+            m_arrNodeInit.append(obj);
+        }
+
+        QJsonObject result{
+            {"init_progress", m_arrNodeInit},
+            {"notify_status", m_socketState == QAbstractSocket::SocketState::ConnectedState?
+                                  "connected" : "disconnected"}
+        };
+
+        m_docNodeInit.setObject(result);
+    }
+}
+
+void NotifyWorker::rcvNetObj(QJsonObject objNet)
+{
+    m_netList = objNet.keys();
+
+    for(const auto &net: qAsConst(m_netList))
+    {
+        QJsonObject chains;
+        chains.insert("zero", 0);
+        chains.insert("main", 0);
+
+
+        QJsonObject obj;
+        obj.insert("name", net);
+        obj.insert("chains", chains);
+
+        m_arrNodeInit.append(obj);
+    }
+}
+
+void NotifyWorker::reconnectFunc()
+{
+    m_reconnectTimer->stop();
+
+    if(m_socketState != QAbstractSocket::SocketState::ConnectedState &&
+        m_socketState != QAbstractSocket::SocketState::ConnectingState)
+    {
+        m_reconnectTimer->start(10000);
+        qWarning()<< "Notify socket reconnecting...";
+    }
+}
diff --git a/CellframeNodeDiagtool/NotifyWorker.h b/CellframeNodeDiagtool/NotifyWorker.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc780cfa18ea8d7ccf54c7990386d9c4d7ffa4b2
--- /dev/null
+++ b/CellframeNodeDiagtool/NotifyWorker.h
@@ -0,0 +1,70 @@
+#ifndef NOTIFYWORKER_H
+#define NOTIFYWORKER_H
+
+#include <QThread>
+#include <QIODevice>
+#include <QLocalSocket>
+#include <QTcpSocket>
+#include <QTimer>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QDebug>
+#include <QProcess>
+#include <QVariant>
+
+
+class NotifyWorker : public QObject
+{
+    Q_OBJECT
+public:
+    explicit NotifyWorker(QObject *parent = nullptr);
+    ~NotifyWorker();
+
+    bool initWatcher();
+
+    const QString& getSocketState() const {return m_socketState;}
+
+    QVariant readConfig(QString filename, QString section, QString param, QVariant defaultValue);
+
+    bool m_statusInitWatcher{false};
+    QJsonDocument m_docNodeInit;
+    QJsonArray m_arrNodeInit;
+    QStringList m_netList;
+
+    void nodeIsOnline();
+    void rcvNetObj(QJsonObject objNet);
+
+public slots:
+    void slotError();
+    void socketConnected();
+    void slotReconnect();
+    void socketDisconnected();
+
+    void socketReadyRead();
+
+    void socketStateChanged(QAbstractSocket::SocketState socketState);
+
+signals:
+    void changeConnectState(QString);
+
+private:
+    void reconnectFunc();
+    QByteArrayList jsonListFromData(QByteArray data);
+
+    void procNotifyData(const QJsonObject &rcvObj);
+private:
+    QString m_configWorkerPath;
+    QIODevice *m_socket;
+    QString m_listenPath;
+    QString m_listenAddr;
+    uint16_t m_listenPort;
+    QTimer * m_reconnectTimer;
+    QTimer * m_initTimer;
+
+    bool m_rcvInitProgress{false};
+
+    QString m_socketState{""};
+};
+
+#endif // NOTIFYWORKER_H
diff --git a/CellframeNodeTray/NodeTrayCommandController.cpp b/CellframeNodeTray/NodeTrayCommandController.cpp
index 66fa952955f2fbe517a54592f4ec1f5b5d869797..912bd81cbb40dd23916a9c55b46fa849425a2bdc 100644
--- a/CellframeNodeTray/NodeTrayCommandController.cpp
+++ b/CellframeNodeTray/NodeTrayCommandController.cpp
@@ -1,7 +1,18 @@
 #include "NodeTrayCommandController.h"
 
 NodeTrayCommandController::NodeTrayCommandController(QObject *parent)
-    : QObject(parent)
+    : QObject{parent}
+{
+
+}
+
+NodeTrayCommandController &NodeTrayCommandController::getInstance()
+{
+    static NodeTrayCommandController instance;
+    return instance;
+}
+
+void NodeTrayCommandController::init()
 {
     m_configDir = getConfigPath();
     m_statusInitConftool = initConfTool();
@@ -11,9 +22,20 @@ NodeTrayCommandController::NodeTrayCommandController(QObject *parent)
 
 void NodeTrayCommandController::initEngine()
 {
+#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
+    QString os = "linux";
+#elif defined Q_OS_WIN
+    QString os = "win";
+#elif defined Q_OS_MAC
+    QString os = "macos";
+#else
+    QString os = "unknown";
+#endif
+
     QQmlContext * context = m_engine.rootContext();
     context->setContextProperty("trayCommandController", this);
     context->setContextProperty("diagnosticWorker", &diagnosticWorker);
+    context->setContextProperty("CURRENT_OS", QVariant::fromValue(os));
 
     const QUrl url(QStringLiteral("qrc:/main.qml"));
     QObject::connect(&m_engine, &QQmlApplicationEngine::objectCreated,
@@ -25,10 +47,6 @@ void NodeTrayCommandController::initEngine()
     m_engine.load(url);
 }
 
-NodeTrayCommandController::~NodeTrayCommandController()
-{
-
-}
 
 QQmlApplicationEngine *NodeTrayCommandController::qmlEngine()
 {
@@ -249,3 +267,51 @@ void NodeTrayCommandController::showMessage(const QString msg, const QMessageBox
 
     emit sigShowMessage("Celflrame Node Tray",msg);
 }
+
+#ifdef WIN32
+LONG NodeTrayCommandController::GetDWORDRegKey(HKEY hKey, const std::wstring &strValueName, DWORD &nValue, DWORD nDefaultValue)
+{
+    nValue = nDefaultValue;
+    DWORD dwBufferSize(sizeof(DWORD));
+    DWORD nResult(0);
+    LONG nError = ::RegQueryValueExW(hKey,
+                                     strValueName.c_str(),
+                                     0,
+                                     NULL,
+                                     reinterpret_cast<LPBYTE>(&nResult),
+                                     &dwBufferSize);
+    if (ERROR_SUCCESS == nError)
+    {
+        nValue = nResult;
+    }
+    return nError;
+}
+
+
+LONG NodeTrayCommandController::GetBoolRegKey(HKEY hKey, const std::wstring &strValueName, bool &bValue, bool bDefaultValue)
+{
+    DWORD nDefValue((bDefaultValue) ? 1 : 0);
+    DWORD nResult(nDefValue);
+    LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult, nDefValue);
+    if (ERROR_SUCCESS == nError)
+    {
+        bValue = (nResult != 0) ? true : false;
+    }
+    return nError;
+}
+
+
+LONG NodeTrayCommandController::GetStringRegKey(HKEY hKey, const std::wstring &strValueName, std::wstring &strValue, const std::wstring &strDefaultValue)
+{
+    strValue = strDefaultValue;
+    WCHAR szBuffer[512];
+    DWORD dwBufferSize = sizeof(szBuffer);
+    ULONG nError;
+    nError = RegQueryValueExW(hKey, strValueName.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
+    if (ERROR_SUCCESS == nError)
+    {
+        strValue = szBuffer;
+    }
+    return nError;
+}
+#endif
diff --git a/CellframeNodeTray/NodeTrayCommandController.h b/CellframeNodeTray/NodeTrayCommandController.h
index e50f46adde4821530b22da1ea9181e75d94bb7d9..482a63a97be7685101403b0dff92aaae9dc78823 100644
--- a/CellframeNodeTray/NodeTrayCommandController.h
+++ b/CellframeNodeTray/NodeTrayCommandController.h
@@ -14,7 +14,6 @@
 
 #include <QQmlEngine>
 
-
 #include "DiagnosticWorker.h"
 
 #ifdef WIN32
@@ -24,9 +23,13 @@
 class NodeTrayCommandController : public QObject
 {
     Q_OBJECT
-public:
     explicit NodeTrayCommandController(QObject *parent = nullptr);
-    ~NodeTrayCommandController();
+
+public:
+    static NodeTrayCommandController &getInstance();
+
+    void init();
+    bool initConfTool();
 
     QQmlApplicationEngine *qmlEngine();
 
@@ -49,7 +52,7 @@ public:
 
     DiagnosticWorker &diagnosticWorker = DiagnosticWorker::getInstance();
 
-private:
+public:
     bool m_statusInitConftool{false};
     QString m_confToolPath{""};
     QString m_configDir{""};
@@ -57,7 +60,6 @@ private:
     QQmlApplicationEngine m_engine;
 
 private:
-    bool initConfTool();
     QString getConfigPath();
     QString sendRequest(QString req);
 
@@ -65,6 +67,12 @@ private:
 
     QString getResult(QString find, QStringList list);
 
+#ifdef WIN32
+    LONG GetDWORDRegKey(HKEY hKey, const std::wstring &strValueName, DWORD &nValue, DWORD nDefaultValue);
+    LONG GetBoolRegKey(HKEY hKey, const std::wstring &strValueName, bool &bValue, bool bDefaultValue);
+    LONG GetStringRegKey(HKEY hKey, const std::wstring &strValueName, std::wstring &strValue, const std::wstring &strDefaultValue);
+#endif
+
 signals:
     Q_INVOKABLE void sigResultStatus(bool status);
     Q_INVOKABLE void sigShowMessage(QString title, QString message);
diff --git a/CellframeNodeTray/main.qml b/CellframeNodeTray/main.qml
index f379feac47b7bc6f67a1c1f321af7aea34767bdf..3e02d5ed888275e82c9e34057eb51f7819f2e2d0 100644
--- a/CellframeNodeTray/main.qml
+++ b/CellframeNodeTray/main.qml
@@ -57,17 +57,17 @@ ApplicationWindow {
                 }
             }
             MenuItem {
-                visible: autostartItemMenu.status
+                visible: CURRENT_OS === "macos" ? false : autostartItemMenu.status
                 text: qsTr("Stop cellframe-node")
                 onTriggered: trayCommandController.serviceCommand(3)
             }
             MenuItem {
-                visible: autostartItemMenu.status
+                visible: CURRENT_OS === "macos" ? false : autostartItemMenu.status
                 text: qsTr("Start cellframe-node")
                 onTriggered: trayCommandController.serviceCommand(4)
             }
             MenuItem {
-                visible: autostartItemMenu.status
+                visible: CURRENT_OS === "macos" ? false : autostartItemMenu.status
                 text: qsTr("Restart cellframe-node")
                 onTriggered: trayCommandController.serviceCommand(5)
             }
diff --git a/cellfram-node-diagtool.pro b/cellfram-node-diagtool.pro
index 34b3fbfbe35607fc80d1c2277b6e0153e2cd0251..50cd47c3852fec4360caa239cfaf0bdc5cab8ff9 100644
--- a/cellfram-node-diagtool.pro
+++ b/cellfram-node-diagtool.pro
@@ -10,12 +10,14 @@ INCLUDEPATH += CellframeNodeTray \
                CellframeNodeDiagtool
 
 SOURCES += \
+        CellframeNodeDiagtool/NotifyWorker.cpp \
         CellframeNodeTray/NodeTrayCommandController.cpp \
         main.cpp \
         CellframeNodeDiagtool/AbstractDiagnostic.cpp \
         CellframeNodeDiagtool/DiagnosticWorker.cpp
 
 HEADERS += \
+    CellframeNodeDiagtool/NotifyWorker.h \
     CellframeNodeTray/NodeTrayCommandController.h \
     CellframeNodeDiagtool/AbstractDiagnostic.h \
     CellframeNodeDiagtool/DiagnosticWorker.h
diff --git a/main.cpp b/main.cpp
index d283575a5b739ac03b1b00e178175a1fd946ba9a..d7e25ee9093e2af691915926312302dee9a09397 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,13 +1,7 @@
 #include <QApplication>
 #include <QQmlApplicationEngine>
-#include <QIcon>
-#include <QQuickWidget>
-#include <QSystemTrayIcon>
-#include <QQmlContext>
 #include <QDebug>
 
-#include <QProcess>
-
 #include <QSystemSemaphore>
 #include <QSharedMemory>
 #include <QScreen>
@@ -18,7 +12,6 @@
 #include "DiagnosticWorker.h"
 
 
-
 bool SingleApplicationTest(const QString &appName)
 {
     static QSystemSemaphore semaphore("<"+appName+" uniq semaphore id>", 1);
@@ -58,7 +51,6 @@ bool SingleApplicationTest(const QString &appName)
     return true;
 }
 
-
 bool findArg(char** begin, char** end, const std::string& option)
 {
     return std::find(begin, end, option) != end;
@@ -91,7 +83,7 @@ qSetMessagePattern("%{type} %{if-category}%{category}: %{endif}%{function}: %{me
 
         QCoreApplication::setApplicationName(appName);
 
-        NodeTrayCommandController *trayCommandController = new NodeTrayCommandController();
+        NodeTrayCommandController::getInstance().init();
     }
 
     qDebug() << "Desctop session" << getDesctopSession();