diff --git a/docs/MQTT.md b/docs/MQTT.md index a683308..85cda8f 100755 --- a/docs/MQTT.md +++ b/docs/MQTT.md @@ -3,14 +3,25 @@ MQTT Client for OpenZWave Docker Repo: https://hub.docker.com/r/openzwave/ozwdaemon -Copy the "config" folder from OZW to `/tmp/ozw/`. +Make sure you have create a local folder where ozwdaemon can store the config files etc for your installation. In this example, /home/ozw/config/ is on your local machine. + +If you are using Secure Communications, setup a Docker Secret: +``` +printf "0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0b,0x0c,0x0d,0x0e,0x0f,0x10" | docker secret create OZW_Network_Key - +``` +* replace the Hex String with 16 Bytes to use as your Network Key. Start a container with the following command line: ``` -docker run -it --security-opt seccomp=unconfined --device=/dev/ttyUSB0 -v /tmp/ozw:/opt/ozw/config -e MQTT_SERVER="10.100.200.102" -e USBPATH=/dev/ttyUSB0 openzwave/ozwdaemon:latest +docker run -it --security-opt seccomp=unconfined --device=/dev/ttyUSB0 -v /home/ozw/config:/opt/ozw/config -e MQTT_SERVER="10.100.200.102" -e USBPATH=/dev/ttyUSB0 --secret OZW_Network_Key openzwave/ozwdaemon:latest ``` -(replace `MQTT_SERVER` with the IP address of the MQTT Server and all `/dev/ttyUSB0` entries with the path to your USB Stick. +* Update `MQTT_SERVER` with the IP address of the MQTT Server and all `/dev/ttyUSB0` entries with the path to your USB Stick. +* If you are not running with a ZWave Network Key, remove the `--secret OZW_Network_Key` command + + +(Alternatively, you can specify the Network Key via a Docker Enviroment, but this is less secure: +`-e OZW_NETWORK_KEY="0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0b,0x0c,0x0d,0x0e,0x0f,0x10"`) ## MQTT Topic Structure The MQTT Client for OZW will send messages to a MQTT Broker with a predifined topic structure. The structure of the messages are detailed in the sections below. @@ -1230,3 +1241,40 @@ This allows a MQTT Client to set a value on a Device. As OZW supports many diffe ​ [addAssociation](#addAssociation) +## enablePoll + +**Params**: + +​ "ValueIDKey" - uint64: The ValueID Key + +​ "Intensity" - uint8: The Intensity we should poll the value at + +**Returns**: + +​"enablePoll" - if OZW accepted the command + +**Notification**: + +The appropriate value key in the MQTT Topic should be updated with a updated IsPolled Value + +**See Also**: + +​ [disablePoll](#disablePoll) + +## disablePoll + +**Params**: + +​ "ValueIDKey" - uint64: The ValueID Key + +**Returns**: + +​"disablePoll" - if OZW accepted the command + +**Notification**: + +The appropriate value key in the MQTT Topic should be updated with a updated IsPolled Value + +**See Also**: + +​ [enablePoll](#enablePoll) diff --git a/qt-openzwave/include/qt-openzwave/qtozwmanager.h b/qt-openzwave/include/qt-openzwave/qtozwmanager.h index 5577c0a..78e2ea0 100644 --- a/qt-openzwave/include/qt-openzwave/qtozwmanager.h +++ b/qt-openzwave/include/qt-openzwave/qtozwmanager.h @@ -144,6 +144,9 @@ public: bool AddAssociation (quint8 const _nodeId, quint8 const _groupIdx, QString const target); bool RemoveAssociation (quint8 const _nodeId, quint8 const _groupIdx, QString const target); + bool enablePoll(quint64 vidKey, quint8 intensity); + bool disablePoll(quint64 vidKey); + /* Property Methods */ QDir OZWDatabasePath() { return this->m_ozwdatabasepath; } QDir OZWUserPath() { return this->m_ozwuserpath; } diff --git a/qt-openzwave/include/qt-openzwave/qtozwmanager.rep b/qt-openzwave/include/qt-openzwave/qtozwmanager.rep index aa063f0..67b28f6 100644 --- a/qt-openzwave/include/qt-openzwave/qtozwmanager.rep +++ b/qt-openzwave/include/qt-openzwave/qtozwmanager.rep @@ -156,7 +156,8 @@ class QTOZWManager { SLOT(qint32 getPollInterval()) SLOT(void setPollInterval(qint32 interval, bool intervalBetweenPolls)) - + SLOT(bool enablePoll(quint64 vidKey, quint8 intensity)) + SLOT(bool disablePoll(quint64 vidKey)) SLOT(void syncroniseNodeNeighbors(quint8 node)) } \ No newline at end of file diff --git a/qt-openzwave/include/qtozwmanager_p.h b/qt-openzwave/include/qtozwmanager_p.h index 5df2819..65f105c 100644 --- a/qt-openzwave/include/qtozwmanager_p.h +++ b/qt-openzwave/include/qtozwmanager_p.h @@ -138,6 +138,8 @@ public Q_SLOTS: bool AddAssociation (quint8 const _nodeId, quint8 const _groupIdx, QString const target); bool RemoveAssociation (quint8 const _nodeId, quint8 const _groupIdx, QString const target); + bool enablePoll(quint64 vidKey, quint8 intensity); + bool disablePoll(quint64 vidKey); /* these slots are called from our OZWNotification Class. Applications should not call them */ void pvt_valueAdded(quint64 vidKey); diff --git a/qt-openzwave/source/qtozwmanager.cpp b/qt-openzwave/source/qtozwmanager.cpp index 4fcb8ce..e1b7c3c 100644 --- a/qt-openzwave/source/qtozwmanager.cpp +++ b/qt-openzwave/source/qtozwmanager.cpp @@ -459,7 +459,12 @@ bool QTOZWManager::AddAssociation (quint8 const _nodeId, quint8 const _groupIdx, bool QTOZWManager::RemoveAssociation (quint8 const _nodeId, quint8 const _groupIdx, QString const target) { CALL_DPTR_RTN(RemoveAssociation(_nodeId, _groupIdx, target), bool); } - +bool QTOZWManager::enablePoll(quint64 vidKey, quint8 intensity) { + CALL_DPTR_RTN(enablePoll(vidKey, intensity), bool); +} +bool QTOZWManager::disablePoll(quint64 vidKey) { + CALL_DPTR_RTN(disablePoll(vidKey), bool); +} void QTOZWManager::setOZWDatabasePath(QDir path) { if (path.exists()) diff --git a/qt-openzwave/source/qtozwmanager_p.cpp b/qt-openzwave/source/qtozwmanager_p.cpp index bd47563..8228a85 100644 --- a/qt-openzwave/source/qtozwmanager_p.cpp +++ b/qt-openzwave/source/qtozwmanager_p.cpp @@ -811,6 +811,36 @@ void QTOZWManager_Internal::setPollInterval(qint32 interval, bool intervalBetwee } return; } + +bool QTOZWManager_Internal::enablePoll(quint64 vidKey, quint8 intensity) { + if (!this->checkValueKey(vidKey)) + return false; + try { + OpenZWave::ValueID vid(this->homeId(), vidKey); + bool ret = this->m_manager->EnablePoll(vid, intensity); + this->m_valueModel->setValueFlags(vidKey, QTOZW_ValueIds::ValueIDFlags::ValuePolled, this->m_manager->IsValuePolled(vid), false); + return ret; + } catch (OpenZWave::OZWException &e) { + emit this->error(QTOZWManagerErrorCodes::OZWException); + this->setErrorString(e.GetMsg().c_str()); + } + return false; +} +bool QTOZWManager_Internal::disablePoll(quint64 vidKey) { + if (!this->checkValueKey(vidKey)) + return false; + try { + OpenZWave::ValueID vid(this->homeId(), vidKey); + bool ret = this->m_manager->DisablePoll(vid); + this->m_valueModel->setValueFlags(vidKey, QTOZW_ValueIds::ValueIDFlags::ValuePolled, this->m_manager->IsValuePolled(vid), false); + return ret; + } catch (OpenZWave::OZWException &e) { + emit this->error(QTOZWManagerErrorCodes::OZWException); + this->setErrorString(e.GetMsg().c_str()); + } + return false; +} + void QTOZWManager_Internal::syncroniseNodeNeighbors(quint8 node) { if (!this->checkHomeId()) return; diff --git a/qt-ozwdaemon/mqttcommands/enablePoll.cpp b/qt-ozwdaemon/mqttcommands/enablePoll.cpp index a6745f7..925bcbb 100644 --- a/qt-ozwdaemon/mqttcommands/enablePoll.cpp +++ b/qt-ozwdaemon/mqttcommands/enablePoll.cpp @@ -3,10 +3,10 @@ MqttCommand_EnablePoll::MqttCommand_EnablePoll(QObject *parent) : MqttCommand(parent) { - this->m_requiredIntFields << "ValueIDKey"; + this->m_requiredIntFields << "ValueIDKey" << "Intensity"; } MqttCommand* MqttCommand_EnablePoll::Create(QObject *parent) { - return new MqttCommand_SyncroniseNodeNeighbors(parent); + return new MqttCommand_EnablePoll(parent); } bool MqttCommand_EnablePoll::processMessage(rapidjson::Document &msg) { @@ -15,6 +15,5 @@ bool MqttCommand_EnablePoll::processMessage(rapidjson::Document &msg) { } QTOZWManager *mgr = getOZWManager(); - //mgr->syncroniseNodeNeighbors(msg["node"].GetInt()); - return this->sendSimpleStatus(true); + return this->sendSimpleStatus(mgr->enablePoll(msg["ValueIdKey"].GetUint64(), msg["Intensity"].GetUint())); } \ No newline at end of file diff --git a/qt-ozwdaemon/mqttcommands/mqttcommands.cpp b/qt-ozwdaemon/mqttcommands/mqttcommands.cpp index 3fc4b53..f7fbc51 100644 --- a/qt-ozwdaemon/mqttcommands/mqttcommands.cpp +++ b/qt-ozwdaemon/mqttcommands/mqttcommands.cpp @@ -37,6 +37,7 @@ #include "mqttcommands/setPollInterval.h" #include "mqttcommands/syncroniseNodeNeighbors.h" #include "mqttcommands/enablePoll.h" +#include "mqttcommands/disablePoll.h" #include "mqttcommands/refreshValue.h" #include "mqttcommands/addAssociation.h" #include "mqttcommands/removeAssociation.h" @@ -251,7 +252,8 @@ void MqttCommands::setupCommands() { this->Register(MqttCommand_GetPollInterval::StaticGetCommand(), &MqttCommand_GetPollInterval::Create); this->Register(MqttCommand_SetPollInterval::StaticGetCommand(), &MqttCommand_SetPollInterval::Create); this->Register(MqttCommand_SyncroniseNodeNeighbors::StaticGetCommand(), &MqttCommand_SyncroniseNodeNeighbors::Create); -// this->Register(MqttCommand_EnablePoll::StaticGetCommand(), &MqttCommand_EnablePoll::Create); + this->Register(MqttCommand_EnablePoll::StaticGetCommand(), &MqttCommand_EnablePoll::Create); + this->Register(MqttCommand_DisablePoll::StaticGetCommand(), &MqttCommand_DisablePoll::Create); this->Register(MqttCommand_RefreshValue::StaticGetCommand(), &MqttCommand_RefreshValue::Create); this->Register(MqttCommand_AddAssociation::StaticGetCommand(), &MqttCommand_AddAssociation::Create); this->Register(MqttCommand_RemoveAssociation::StaticGetCommand(), &MqttCommand_RemoveAssociation::Create); diff --git a/qt-ozwdaemon/qt-ozwdaemon.pro b/qt-ozwdaemon/qt-ozwdaemon.pro index 622d718..8623d28 100644 --- a/qt-ozwdaemon/qt-ozwdaemon.pro +++ b/qt-ozwdaemon/qt-ozwdaemon.pro @@ -61,7 +61,9 @@ qtHaveModule(mqtt) { mqttcommands/syncroniseNodeNeighbors.cpp \ mqttcommands/refreshValue.cpp \ mqttcommands/addAssociation.cpp \ - mqttcommands/removeAssociation.cpp + mqttcommands/removeAssociation.cpp \ + mqttcommands/enablePoll.cpp \ + mqttcommands/disablePoll.cpp HEADERS += mqttpublisher.h \ qtrj.h \ @@ -105,7 +107,9 @@ qtHaveModule(mqtt) { mqttcommands/syncroniseNodeNeighbors.h \ mqttcommands/refreshValue.h \ mqttcommands/addAssociation.h \ - mqttcommands/removeAssociation.h + mqttcommands/removeAssociation.h \ + mqttcommands/enablePoll.h \ + mqttcommands/disablePoll.h } else { diff --git a/qt-ozwdaemon/qtozwdaemon.cpp b/qt-ozwdaemon/qtozwdaemon.cpp index 6272f9e..2396b19 100644 --- a/qt-ozwdaemon/qtozwdaemon.cpp +++ b/qt-ozwdaemon/qtozwdaemon.cpp @@ -4,10 +4,45 @@ qtozwdaemon::qtozwdaemon(QObject *parent) : QObject(parent) { + QRegularExpression re("^(0[xX][a-fA-F0-9]{2}[ ,]*){16}$"); + + QString NetworkKeyTest = qgetenv("OZW_NETWORK_KEY"); + QString NetworkKey; + QRegularExpressionMatch match = re.match(NetworkKeyTest); + if (match.hasMatch()) { + NetworkKey = NetworkKeyTest; + qInfo() << "Network Key Specified in Enviroment is Valid"; + } else { + qWarning() << "Network Key Specified in Enviroment is Invalid"; + } + + QFile nwk_file("/run/secrets/OZW_Network_Key"); + if (nwk_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + NetworkKeyTest = nwk_file.readLine().trimmed(); + nwk_file.close(); + match = re.match(NetworkKeyTest); + if (match.hasMatch()) { + NetworkKey = NetworkKeyTest; + qInfo() << "Network Key From File is Valid - Using File"; + } else { + if (NetworkKey.isEmpty()) { + qWarning() << "Network Key From File in Invalid - No Valid Network Key Found in Enviroment or File"; + } + } + } else { + qInfo() << "Didn't Find Network Key File. Skipping"; + } + if (!NetworkKey.isEmpty()) { + qInfo() << "We Have what appears to be a valid Network Key - Passing to OZW"; + } + this->m_openzwave = new QTOpenZwave(this); this->m_qtozwmanager = this->m_openzwave->GetManager(); QObject::connect(this->m_qtozwmanager, &QTOZWManager::ready, this, &qtozwdaemon::QTOZW_Ready); this->m_qtozwmanager->initilizeSource(true); + if (!NetworkKey.isEmpty()) { + this->m_qtozwmanager->getOptions()->setNetworkKey(NetworkKey); + } } void qtozwdaemon::QTOZW_Ready() {