Polling Commands and Network Key Support (#21)

* Add Methods to enable/disable Polling on a ValueID

* add enablePoll/disablePoll MQTT comamnds

* Read Network Key from either Environment or docker secrets file

* Update Docs
This commit is contained in:
Justin Hammond 2020-01-21 23:50:01 +08:00 committed by GitHub
parent 72a55e5b38
commit 14453f555e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 141 additions and 12 deletions

View file

@ -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)

View file

@ -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; }

View file

@ -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))
}

View file

@ -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);

View file

@ -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())

View file

@ -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;

View file

@ -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()));
}

View file

@ -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);

View file

@ -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 {

View file

@ -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() {