Skip to content

Commit

Permalink
Improve multi endpoint ZCL value handling
Browse files Browse the repository at this point in the history
Some devices have the same clusters and attributes on multiple endpoints. This commit lets book keep the data specific for an endpoint.
  • Loading branch information
manup committed Feb 19, 2020
1 parent edf380f commit 0f56415
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 100 deletions.
56 changes: 28 additions & 28 deletions bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ void DeRestPluginPrivate::handleZclConfigureReportingResponseIndication(const de
continue;
}

DBG_Printf(DBG_INFO, "ZCL configure reporting rsp seq: %u 0x%016llX for cluster 0x%04X attr 0x%04X status 0x%02X\n", zclFrame.sequenceNumber(), ind.srcAddress().ext(), ind.clusterId(), val.attributeId, status);
DBG_Printf(DBG_INFO, "ZCL configure reporting rsp seq: %u 0x%016llX for ep: 0x%02X cluster: 0x%04X attr: 0x%04X status: 0x%02X\n", zclFrame.sequenceNumber(), ind.srcAddress().ext(), ind.srcEndpoint(), ind.clusterId(), val.attributeId, status);

// mark as succefully configured
if (status == deCONZ::ZclSuccessStatus)
Expand All @@ -496,10 +496,10 @@ void DeRestPluginPrivate::handleZclConfigureReportingResponseIndication(const de
stream >> direction;
stream >> attrId;

NodeValue &val = restNode->getZclValue(ind.clusterId(), attrId);
NodeValue &val = restNode->getZclValue(ind.clusterId(), attrId, ind.srcEndpoint());
if (val.zclSeqNum == zclFrame.sequenceNumber() && val.clusterId == ind.clusterId())
{
DBG_Printf(DBG_INFO, "ZCL configure reporting rsp seq: %u 0x%016llX for cluster 0x%04X attr 0x%04X status 0x%02X\n", zclFrame.sequenceNumber(), ind.srcAddress().ext(), ind.clusterId(), val.attributeId, status);
DBG_Printf(DBG_INFO, "ZCL configure reporting rsp seq: %u 0x%016llX for ep: 0x%02X cluster: 0x%04X attr: 0x%04X status: 0x%02X\n", zclFrame.sequenceNumber(), ind.srcAddress().ext(), ind.srcEndpoint(), ind.clusterId(), val.attributeId, status);

if (status == deCONZ::ZclSuccessStatus)
{
Expand Down Expand Up @@ -550,7 +550,7 @@ void DeRestPluginPrivate::handleBindAndUnbindRspIndication(const deCONZ::ApsData

if (status == deCONZ::ZdpSuccess)
{
DBG_Printf(DBG_INFO, "%s response success for 0x%016llx cluster 0x%04X\n", what, i->binding.srcAddress, i->binding.clusterId);
DBG_Printf(DBG_INFO, "%s response success for 0x%016llx ep: 0x%02X cluster: 0x%04X\n", what, i->binding.srcAddress, i->binding.srcEndpoint, i->binding.clusterId);
if (ind.clusterId() == ZDP_BIND_RSP_CLID)
{
if (sendConfigureReportingRequest(*i))
Expand All @@ -561,7 +561,7 @@ void DeRestPluginPrivate::handleBindAndUnbindRspIndication(const deCONZ::ApsData
}
else
{
DBG_Printf(DBG_INFO, "%s response failed with status 0x%02X for 0x%016llx cluster 0x%04X\n", what, status, i->binding.srcAddress, i->binding.clusterId);
DBG_Printf(DBG_INFO, "%s response failed with status 0x%02X for 0x%016llx ep: 0x%02X cluster: 0x%04X\n", what, status, i->binding.srcAddress, i->binding.srcEndpoint, i->binding.clusterId);
}

i->state = BindingTask::StateFinished;
Expand Down Expand Up @@ -692,7 +692,7 @@ bool DeRestPluginPrivate::sendConfigureReportingRequest(BindingTask &bt, const s

for (const ConfigureReportingRequest &rq : requests)
{
NodeValue &val = bt.restNode->getZclValue(bt.binding.clusterId, rq.attributeId);
NodeValue &val = bt.restNode->getZclValue(bt.binding.clusterId, rq.attributeId, bt.binding.srcEndpoint);
if (val.clusterId == bt.binding.clusterId)
{
// value exists
Expand Down Expand Up @@ -727,7 +727,7 @@ bool DeRestPluginPrivate::sendConfigureReportingRequest(BindingTask &bt, const s
// values doesn't exist, create
deCONZ::NumericUnion dummy;
dummy.u64 = 0;
bt.restNode->setZclValue(NodeValue::UpdateByZclReport, bt.binding.clusterId, rq.attributeId, dummy);
bt.restNode->setZclValue(NodeValue::UpdateByZclReport, bt.binding.srcEndpoint, bt.binding.clusterId, rq.attributeId, dummy);
val.zclSeqNum = zclSeqNum;
val.minInterval = rq.minInterval;
val.maxInterval = rq.maxInterval;
Expand Down Expand Up @@ -860,9 +860,9 @@ bool DeRestPluginPrivate::sendConfigureReportingRequest(BindingTask &bt)
// add values if not already present
deCONZ::NumericUnion dummy;
dummy.u64 = 0;
if (bt.restNode->getZclValue(bt.binding.clusterId, 0x0000).clusterId != bt.binding.clusterId)
if (bt.restNode->getZclValue(bt.binding.clusterId, 0x0000, bt.binding.srcEndpoint).clusterId != bt.binding.clusterId)
{
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.clusterId, 0x0000, dummy);
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.srcEndpoint, bt.binding.clusterId, 0x0000, dummy);
}

rq.dataType = deCONZ::Zcl8BitBitMap;
Expand All @@ -879,9 +879,9 @@ bool DeRestPluginPrivate::sendConfigureReportingRequest(BindingTask &bt)
const Sensor *sensor = static_cast<Sensor *>(bt.restNode);
if (sensor && sensor->modelId().startsWith(QLatin1String("SML00"))) // Hue motion sensor
{
if (bt.restNode->getZclValue(bt.binding.clusterId, 0x0030).clusterId != bt.binding.clusterId)
if (bt.restNode->getZclValue(bt.binding.clusterId, 0x0030, bt.binding.srcEndpoint).clusterId != bt.binding.clusterId)
{
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.clusterId, 0x0030, dummy);
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.srcEndpoint, bt.binding.clusterId, 0x0030, dummy);
}
ConfigureReportingRequest rq2;
rq2.dataType = deCONZ::Zcl8BitUint;
Expand Down Expand Up @@ -911,9 +911,9 @@ bool DeRestPluginPrivate::sendConfigureReportingRequest(BindingTask &bt)
// add values if not already present
deCONZ::NumericUnion dummy;
dummy.u64 = 0;
if (bt.restNode->getZclValue(bt.binding.clusterId, IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID).clusterId != bt.binding.clusterId)
if (bt.restNode->getZclValue(bt.binding.clusterId, IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID, bt.binding.srcEndpoint).clusterId != bt.binding.clusterId)
{
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.clusterId, IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID, dummy);
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.srcEndpoint, bt.binding.clusterId, IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID, dummy);
}
rq.minInterval = 1;
rq.maxInterval = 300;
Expand Down Expand Up @@ -1166,12 +1166,12 @@ bool DeRestPluginPrivate::sendConfigureReportingRequest(BindingTask &bt)
// add values if not already present
deCONZ::NumericUnion dummy;
dummy.u64 = 0;
if (bt.restNode->getZclValue(POWER_CONFIGURATION_CLUSTER_ID, rq.attributeId).attributeId != rq.attributeId)
if (bt.restNode->getZclValue(POWER_CONFIGURATION_CLUSTER_ID, rq.attributeId, bt.binding.srcEndpoint).attributeId != rq.attributeId)
{
bt.restNode->setZclValue(NodeValue::UpdateInvalid, POWER_CONFIGURATION_CLUSTER_ID, rq.attributeId, dummy);
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.srcEndpoint, POWER_CONFIGURATION_CLUSTER_ID, rq.attributeId, dummy);
}

NodeValue &val = bt.restNode->getZclValue(POWER_CONFIGURATION_CLUSTER_ID, rq.attributeId);
NodeValue &val = bt.restNode->getZclValue(POWER_CONFIGURATION_CLUSTER_ID, rq.attributeId, bt.binding.srcEndpoint);

if (val.timestampLastReport.isValid() && (val.timestampLastReport.secsTo(now) < val.maxInterval * 1.5))
{
Expand Down Expand Up @@ -1441,17 +1441,17 @@ bool DeRestPluginPrivate::sendConfigureReportingRequest(BindingTask &bt)
deCONZ::NumericUnion dummy;
dummy.u64 = 0;
// add usertest value if not already present
if (bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x0032).attributeId != 0x0032)
if (bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x0032, bt.binding.srcEndpoint).attributeId != 0x0032)
{
bt.restNode->setZclValue(NodeValue::UpdateInvalid, BASIC_CLUSTER_ID, 0x0032, dummy);
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.srcEndpoint, BASIC_CLUSTER_ID, 0x0032, dummy);
}
// ledindication value if not already present
if (bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x0033).attributeId != 0x0033)
if (bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x0033, bt.binding.srcEndpoint).attributeId != 0x0033)
{
bt.restNode->setZclValue(NodeValue::UpdateInvalid, BASIC_CLUSTER_ID, 0x0033, dummy);
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.srcEndpoint, BASIC_CLUSTER_ID, 0x0033, dummy);
}

NodeValue &val = bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x0032);
NodeValue &val = bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x0032, bt.binding.srcEndpoint);

if (val.timestampLastReport.isValid() && (val.timestampLastReport.secsTo(now) < val.maxInterval * 1.5))
{
Expand Down Expand Up @@ -1485,12 +1485,12 @@ bool DeRestPluginPrivate::sendConfigureReportingRequest(BindingTask &bt)
deCONZ::NumericUnion dummy;
dummy.u64 = 0;
// 'sw build id' value if not already present
if (bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x4000).attributeId != 0x4000)
if (bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x4000, bt.binding.srcEndpoint).attributeId != 0x4000)
{
bt.restNode->setZclValue(NodeValue::UpdateInvalid, BASIC_CLUSTER_ID, 0x4000, dummy);
bt.restNode->setZclValue(NodeValue::UpdateInvalid, bt.binding.srcEndpoint, BASIC_CLUSTER_ID, 0x4000, dummy);
}

NodeValue &val = bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x4000);
NodeValue &val = bt.restNode->getZclValue(BASIC_CLUSTER_ID, 0x4000, bt.binding.srcEndpoint);

if (val.timestampLastReport.isValid() && (val.timestampLastReport.secsTo(now) < val.maxInterval * 1.5))
{
Expand Down Expand Up @@ -1521,8 +1521,8 @@ bool DeRestPluginPrivate::sendConfigureReportingRequest(BindingTask &bt)
val.u64 = 0;

// mark button event binding as resolved
sensor->setZclValue(NodeValue::UpdateByZclReport, VENDOR_CLUSTER_ID, 0x0000, val);
NodeValue &val2 = bt.restNode->getZclValue(VENDOR_CLUSTER_ID, 0x0000);
sensor->setZclValue(NodeValue::UpdateByZclReport, bt.binding.srcEndpoint, VENDOR_CLUSTER_ID, 0x0000, val);
NodeValue &val2 = bt.restNode->getZclValue(VENDOR_CLUSTER_ID, 0x0000, bt.binding.srcEndpoint);
if (val2.maxInterval == 0)
{
val2.maxInterval = 60 * 60 * 8; // prevent further check for 8 hours
Expand Down Expand Up @@ -2111,13 +2111,13 @@ bool DeRestPluginPrivate::checkSensorBindingsForAttributeReporting(Sensor *senso
if (val.timestampLastReport.isValid() &&
val.timestampLastReport.secsTo(now) < maxInterval) // got update in timely manner
{
DBG_Printf(DBG_INFO_L2, "binding for attribute reporting of cluster 0x%04X seems to be active\n", (*i));
DBG_Printf(DBG_INFO_L2, "binding for attribute reporting of ep: 0x%02X cluster 0x%04X seems to be active\n", val.endpoint, *i);
continue;
}

if (!sensor->node()->nodeDescriptor().receiverOnWhenIdle() && sensor->lastRx().secsTo(now) > 3)
{
DBG_Printf(DBG_INFO, "skip binding for attribute reporting of cluster 0x%04X (end-device might sleep)\n", (*i));
DBG_Printf(DBG_INFO, "skip binding for attribute reporting of ep: 0x%02X cluster 0x%04X (end-device might sleep)\n", val.endpoint, *i);
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2997,7 +2997,7 @@ static int sqliteLoadAllSensorsCallback(void *user, int ncols, char **colval , c
// TODO write and recover min/max to db
deCONZ::NumericUnion dummy;
dummy.u64 = 0;
sensor.setZclValue(NodeValue::UpdateInvalid, clusterId, 0x0000, dummy);
sensor.setZclValue(NodeValue::UpdateInvalid, sensor.fingerPrint().endpoint, clusterId, 0x0000, dummy);
NodeValue &val = sensor.getZclValue(clusterId, 0x0000);
val.minInterval = 1; // value used by Hue bridge
val.maxInterval = 300; // value used by Hue bridge
Expand Down
2 changes: 1 addition & 1 deletion de_otau.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ void DeRestPluginPrivate::otauDataIndication(const deCONZ::ApsDataIndication &in
deCONZ::NumericUnion val = {0};
val.u32 = swVersion;

lightNode->setZclValue(NodeValue::UpdateByZclRead, OTAU_CLUSTER_ID, OTAU_SWVERSION_ID, val);
lightNode->setZclValue(NodeValue::UpdateByZclRead, ind.srcEndpoint(), OTAU_CLUSTER_ID, OTAU_SWVERSION_ID, val);

if (lightNode->swBuildId().isEmpty())
{
Expand Down
Loading

0 comments on commit 0f56415

Please sign in to comment.