diff --git a/zigbeephilipshue/README.md b/zigbeephilipshue/README.md index 5c45c43c..1413257f 100644 --- a/zigbeephilipshue/README.md +++ b/zigbeephilipshue/README.md @@ -30,6 +30,12 @@ The [Hue Smart button](https://www.philips-hue.com/en-us/p/hue-smart-button/0466 **Pairing instructions**: Open the ZigBee network for joining. Press the setup button behind the back cap for 5 seconds until the LED start blinking in different colors. +### Hue wall switch module + +The [Hue Smart button](https://www.philips-hue.com/en-us/p/hue-philips-hue-wall-switch-module/046677571160) is fully supported. + +**Pairing instructions**: Open the ZigBee network for joining. Press the setup button on the back for 5 seconds until the LED start blinking in different colors. + ### Hue lights Most of the lights and lamps from Philips Hue should be handled in a generic way by the `nymea-plugin-zigbee-generic-lights` plugin. There are 2 methods for bringing a Hue light / bulb into the nymea ZigBee network. diff --git a/zigbeephilipshue/integrationpluginzigbeephilipshue.cpp b/zigbeephilipshue/integrationpluginzigbeephilipshue.cpp index c826023e..f6c412b3 100644 --- a/zigbeephilipshue/integrationpluginzigbeephilipshue.cpp +++ b/zigbeephilipshue/integrationpluginzigbeephilipshue.cpp @@ -40,22 +40,27 @@ IntegrationPluginZigbeePhilipsHue::IntegrationPluginZigbeePhilipsHue() m_ieeeAddressParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[smartButtonThingClassId] = smartButtonThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[motionSensorThingClassId] = motionSensorThingIeeeAddressParamTypeId; + m_ieeeAddressParamTypeIds[wallSwitchModuleThingClassId] = wallSwitchModuleThingIeeeAddressParamTypeId; m_networkUuidParamTypeIds[dimmerSwitchThingClassId] = dimmerSwitchThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[smartButtonThingClassId] = smartButtonThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[motionSensorThingClassId] = motionSensorThingNetworkUuidParamTypeId; + m_networkUuidParamTypeIds[wallSwitchModuleThingClassId] = wallSwitchModuleThingNetworkUuidParamTypeId; m_connectedStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchConnectedStateTypeId; m_connectedStateTypeIds[smartButtonThingClassId] = smartButtonConnectedStateTypeId; m_connectedStateTypeIds[motionSensorThingClassId] = motionSensorConnectedStateTypeId; + m_connectedStateTypeIds[wallSwitchModuleThingClassId] = wallSwitchModuleConnectedStateTypeId; m_signalStrengthStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[smartButtonThingClassId] = smartButtonSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[motionSensorThingClassId] = motionSensorSignalStrengthStateTypeId; + m_signalStrengthStateTypeIds[wallSwitchModuleThingClassId] = wallSwitchModuleSignalStrengthStateTypeId; m_versionStateTypeIds[dimmerSwitchThingClassId] = dimmerSwitchVersionStateTypeId; m_versionStateTypeIds[smartButtonThingClassId] = smartButtonVersionStateTypeId; m_versionStateTypeIds[motionSensorThingClassId] = motionSensorVersionStateTypeId; + m_versionStateTypeIds[wallSwitchModuleThingClassId] = wallSwitchModuleVersionStateTypeId; } QString IntegrationPluginZigbeePhilipsHue::name() const @@ -66,8 +71,10 @@ QString IntegrationPluginZigbeePhilipsHue::name() const bool IntegrationPluginZigbeePhilipsHue::handleNode(ZigbeeNode *node, const QUuid &networkUuid) { // Make sure this is from Philips 0x100b - if (node->nodeDescriptor().manufacturerCode != Zigbee::Philips) + if (node->nodeDescriptor().manufacturerCode != Zigbee::Philips) { + qCDebug(dcZigbeePhilipsHue()) << "Manufacturer code not matching. Ignoring node." << node->nodeDescriptor().manufacturerCode; return false; + } if (node->endpoints().count() == 2 && node->hasEndpoint(0x01) && node->hasEndpoint(0x02)) { ZigbeeNodeEndpoint *endpointOne = node->getEndpoint(0x01); @@ -98,8 +105,8 @@ bool IntegrationPluginZigbeePhilipsHue::handleNode(ZigbeeNode *node, const QUuid } } - if (node->endpoints().count() == 1 && node->hasEndpoint(0x01)) { - ZigbeeNodeEndpoint *endpointOne = node->getEndpoint(0x01); + ZigbeeNodeEndpoint *endpointOne = node->getEndpoint(0x01); + if (endpointOne) { // Smart buttton if (endpointOne->profile() == Zigbee::ZigbeeProfileHomeAutomation && @@ -109,7 +116,18 @@ bool IntegrationPluginZigbeePhilipsHue::handleNode(ZigbeeNode *node, const QUuid initSmartButton(node); return true; } + + // Wall switch module + if (endpointOne->profile() == Zigbee::ZigbeeProfileHomeAutomation && + endpointOne->deviceId() == Zigbee::HomeAutomationDeviceNonColourController) { + createThing(wallSwitchModuleThingClassId, networkUuid, node); + initWallSwitchModule(node); + return true; + } } + + qCWarning(dcZigbeePhilipsHue()) << "Device manufacturer code matches Philips/Signify, but node not handled by plugin:" << node->modelName(); + return false; } @@ -267,8 +285,8 @@ void IntegrationPluginZigbeePhilipsHue::setupThing(ThingSetupInfo *info) } else { // Only set the initial state if the attribute already exists if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) { - thing->setStateValue(dimmerSwitchBatteryLevelStateTypeId, powerCluster->batteryPercentage()); - thing->setStateValue(dimmerSwitchBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0)); + thing->setStateValue(smartButtonBatteryLevelStateTypeId, powerCluster->batteryPercentage()); + thing->setStateValue(smartButtonBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0)); } connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){ @@ -279,6 +297,82 @@ void IntegrationPluginZigbeePhilipsHue::setupThing(ThingSetupInfo *info) } } + if (thing->thingClassId() == wallSwitchModuleThingClassId) { + ZigbeeNodeEndpoint *endpointHa = node->getEndpoint(0x01); + + // Set the version + thing->setStateValue(m_versionStateTypeIds.value(thing->thingClassId()), endpointHa->softwareBuildId()); + + // Connect to the manufactuer specific cluster + ZigbeeClusterManufacturerSpecificPhilips *philipsCluster = endpointHa->inputCluster(ZigbeeClusterLibrary::ClusterIdManufacturerSpecificPhilips); + if (!philipsCluster) { + qCWarning(dcZigbeePhilipsHue()) << "Could not find Manufacturer Specific (Philips) cluster on" << thing << endpointHa; + } else { + qCDebug(dcZigbeePhilipsHue()) << "Connecting to manufacturer specific cluster"; + connect(philipsCluster, &ZigbeeClusterManufacturerSpecificPhilips::buttonPressed, thing, [=](quint8 button, ZigbeeClusterManufacturerSpecificPhilips::Operation operation) { + qCDebug(dcZigbeePhilipsHue()) << "Button" << button << operation; + switch (operation) { + case ZigbeeClusterManufacturerSpecificPhilips::OperationButtonPress: + // Unused (could be used for a bool "pressed" state type) + break; + case ZigbeeClusterManufacturerSpecificPhilips::OperationButtonShortRelease: + thing->emitEvent(wallSwitchModulePressedEventTypeId, ParamList() << Param(wallSwitchModulePressedEventButtonNameParamTypeId, QString::number(button))); + break; + case ZigbeeClusterManufacturerSpecificPhilips::OperationButtonHold: + thing->emitEvent(wallSwitchModuleLongPressedEventTypeId, ParamList() << Param(wallSwitchModuleLongPressedEventButtonNameParamTypeId, QString::number(button))); + break; + case ZigbeeClusterManufacturerSpecificPhilips::OperationButtonLongRelease: + // Release after a longpress. But for longpresses we always seem to get the Hold before, so we'll use that. + break; + } + }); + } + + // Get battery level changes + ZigbeeClusterPowerConfiguration *powerCluster = endpointHa->inputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration); + if (!powerCluster) { + qCWarning(dcZigbeePhilipsHue()) << "Could not find power configuration cluster on" << thing << endpointHa; + } else { + // Only set the initial state if the attribute already exists + if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) { + thing->setStateValue(wallSwitchModuleBatteryLevelStateTypeId, powerCluster->batteryPercentage()); + thing->setStateValue(wallSwitchModuleBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0)); + } + + connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){ + qCDebug(dcZigbeePhilipsHue()) << "Battery percentage changed" << percentage << "%" << thing; + thing->setStateValue(wallSwitchModuleBatteryLevelStateTypeId, percentage); + thing->setStateValue(wallSwitchModuleBatteryCriticalStateTypeId, (percentage < 10.0)); + }); + } + + // Button mode settings + connect(thing, &Thing::settingChanged, this, [=](const ParamTypeId &settingTypeId, const QVariant &value){ + if (settingTypeId == wallSwitchModuleSettingsButtonModeParamTypeId) { + QHash modeMap = { + {0x00, "Single rocker"}, + {0x01, "Single push button"}, + {0x02, "Dual rocker"}, + {0x03, "Dual push button"} + }; + quint8 buttonMode = modeMap.key(value.toString()); + QList attributes; + ZigbeeClusterLibrary::WriteAttributeRecord deviceModeAttribute; + deviceModeAttribute.attributeId = 0x0034; + deviceModeAttribute.dataType = Zigbee::Enum8; + deviceModeAttribute.data = ZigbeeDataType(buttonMode).data(); + attributes.append(deviceModeAttribute); + + qCDebug(dcZigbeePhilipsHue()) << "Setting device mode config to" << value.toString(); + ZigbeeClusterBasic *basicCluster = endpointHa->inputCluster(ZigbeeClusterLibrary::ClusterIdBasic); + ZigbeeClusterReply *deviceModeConfigReply = basicCluster->writeAttributes(attributes, Zigbee::Philips); + connect(deviceModeConfigReply, &ZigbeeClusterReply::finished, node, [deviceModeConfigReply](){ + qCDebug(dcZigbeePhilipsHue()) << "Writing device mode configuration finished:" << deviceModeConfigReply->error(); + }); + } + }); + } + if (thing->thingClassId() == motionSensorThingClassId) { ZigbeeNodeEndpoint *endpointHa = node->getEndpoint(0x02); @@ -403,66 +497,19 @@ void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node) { ZigbeeNodeEndpoint *endpointHa = node->getEndpoint(0x02); - // Get the current configured bindings for this node - ZigbeeReply *reply = node->removeAllBindings(); - connect(reply, &ZigbeeReply::finished, node, [=](){ - if (reply->error() != ZigbeeReply::ErrorNoError) { + qCDebug(dcZigbeePhilipsHue()) << "Clearing binding table on node" << node; + ZigbeeReply *removeBindingsReply = node->removeAllBindings(); + connect(removeBindingsReply, &ZigbeeReply::finished, node, [=](){ + if (removeBindingsReply->error() != ZigbeeReply::ErrorNoError) { qCWarning(dcZigbeePhilipsHue()) << "Failed to remove all bindings for initialization of" << node; } else { qCDebug(dcZigbeePhilipsHue()) << "Removed all bindings successfully from" << node; } - // Read battery, bind and configure attribute reporting for battery - if (!endpointHa->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to initialize the power configuration cluster because the cluster could not be found" << node << endpointHa; - return; - } - - qCDebug(dcZigbeePhilipsHue()) << "Reading power configuration cluster attributes" << node; - ZigbeeClusterReply *readAttributeReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining}); - connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){ - if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to read power cluster attributes" << readAttributeReply->error(); - } else { - qCDebug(dcZigbeePhilipsHue()) << "Reading power configuration cluster attributes finished successfully"; - } - }); - - - // Bind the cluster to the coordinator - qCDebug(dcZigbeePhilipsHue()) << "Binding power configuration cluster to coordinator IEEE address"; - ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, - hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01); - connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ - if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to bind power cluster to coordinator" << zdoReply->error(); - } else { - qCDebug(dcZigbeePhilipsHue()) << "Binding power configuration cluster to coordinator finished successfully"; - } - - // Configure attribute rporting for battery remaining (0.5 % changes = 1) - ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; - reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; - reportingConfig.dataType = Zigbee::Uint8; - reportingConfig.minReportingInterval = 300; - reportingConfig.maxReportingInterval = 2700; - reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); - - qCDebug(dcZigbeePhilipsHue()) << "Configure attribute reporting for power configuration cluster to coordinator"; - ZigbeeClusterReply *reportingReply = endpointHa->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); - connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){ - if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to configure power cluster attribute reporting" << reportingReply->error(); - } else { - qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); - } - }); - }); - - + bindBatteryCluster(node, endpointHa); qCDebug(dcZigbeePhilipsHue()) << "Binding Manufacturer specific cluster to coordinator"; - zdoReply = node->deviceObject()->requestBindGroupAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdManufacturerSpecificPhilips, 0x0000); + ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindGroupAddress(endpointHa->endpointId(), ZigbeeClusterLibrary::ClusterIdManufacturerSpecificPhilips, 0x0000); connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { qCWarning(dcZigbeePhilipsHue()) << "Failed to bind manufacturer specific cluster to coordinator" << zdoReply->error(); @@ -489,93 +536,151 @@ void IntegrationPluginZigbeePhilipsHue::initSmartButton(ZigbeeNode *node) { ZigbeeNodeEndpoint *endpoint = node->getEndpoint(0x01); - // Get the current configured bindings for this node - ZigbeeReply *reply = node->removeAllBindings(); - connect(reply, &ZigbeeReply::finished, node, [=](){ - if (reply->error() != ZigbeeReply::ErrorNoError) { + qCDebug(dcZigbeePhilipsHue()) << "Clearing binding table on node" << node; + ZigbeeReply *removeBindingsReply = node->removeAllBindings(); + connect(removeBindingsReply, &ZigbeeReply::finished, node, [=](){ + if (removeBindingsReply->error() != ZigbeeReply::ErrorNoError) { qCWarning(dcZigbeePhilipsHue()) << "Failed to remove all bindings for initialization of" << node; } else { qCDebug(dcZigbeePhilipsHue()) << "Removed all bindings successfully from" << node; } - // Read battery, bind and configure attribute reporting for battery - if (!endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to initialize the power configuration cluster because the cluster could not be found" << node << endpoint; - return; + bindBatteryCluster(node, endpoint); + bindOnOffCluster(node, endpoint); + bindLevelControlCluster(node, endpoint); + dumpBindingTable(node); + }); +} + +void IntegrationPluginZigbeePhilipsHue::initWallSwitchModule(ZigbeeNode *node) +{ + ZigbeeNodeEndpoint *endpoint = node->getEndpoint(0x01); + + qCDebug(dcZigbeePhilipsHue()) << "Clearing binding table on node" << node; + ZigbeeReply *removeBindingsReply = node->removeAllBindings(); + connect(removeBindingsReply, &ZigbeeReply::finished, node, [=](){ + if (removeBindingsReply->error() != ZigbeeReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to remove all bindings for initialization of" << node; + } else { + qCDebug(dcZigbeePhilipsHue()) << "Removed all bindings successfully from" << node; } - qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes" << node; - ZigbeeClusterReply *readAttributeReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining}); - connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){ - if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to read power cluster attributes" << readAttributeReply->error(); + qCDebug(dcZigbeePhilipsHue()) << "Binding Manufacturer specific cluster from node" << node; + ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdManufacturerSpecificPhilips, hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to bind manufacturer specific cluster:" << zdoReply->error(); } else { - qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes finished successfully"; + qCDebug(dcZigbeePhilipsHue()) << "Successfully bound manufacturer specific cluster."; } - - - // Bind the cluster to the coordinator - qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator IEEE address"; - ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, - hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01); - connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ - if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to bind power cluster to coordinator" << zdoReply->error(); - } else { - qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator finished successfully"; - } - - // Configure attribute rporting for battery remaining (0.5 % changes = 1) - ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; - reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; - reportingConfig.dataType = Zigbee::Uint8; - reportingConfig.minReportingInterval = 300; - reportingConfig.maxReportingInterval = 2700; - reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); - - qCDebug(dcZigbeePhilipsHue()) << "Configure attribute reporting for power configuration cluster to coordinator"; - ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); - connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){ - if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to configure power cluster attribute reporting" << reportingReply->error(); - } else { - qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); - } - - qCDebug(dcZigbeePhilipsHue()) << "Bind on/off cluster to coordinator"; - ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindGroupAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000); - connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ - if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to bind on/off cluster to coordinator" << zdoReply->error(); - } else { - qCDebug(dcZigbeePhilipsHue()) << "Bind on/off cluster to coordinator finished successfully"; - } - - qCDebug(dcZigbeePhilipsHue()) << "Bind power level cluster to coordinator"; - ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindGroupAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, 0x0000); - connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ - if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to bind level cluster to coordinator" << zdoReply->error(); - } else { - qCDebug(dcZigbeePhilipsHue()) << "Bind level cluster to coordinator finished successfully"; - } - - qCDebug(dcZigbeePhilipsHue()) << "Read binding table from node" << node; - ZigbeeReply *reply = node->readBindingTableEntries(); - connect(reply, &ZigbeeReply::finished, node, [=](){ - if (reply->error() != ZigbeeReply::ErrorNoError) { - qCWarning(dcZigbeePhilipsHue()) << "Failed to read binding table from" << node; - } else { - foreach (const ZigbeeDeviceProfile::BindingTableListRecord &binding, node->bindingTableRecords()) { - qCDebug(dcZigbeePhilipsHue()) << node << binding; - } - } - }); - }); - }); - }); - }); }); + + + qCDebug(dcZigbeePhilipsHue()) << "Configuring device for single rocker mode (default)"; + // singlerocker 0x00 + // singlepushbutton 0x01 + // dualrocker 0x02 + // dualpushbutton 0x03 + + QList attributes; + ZigbeeClusterLibrary::WriteAttributeRecord deviceModeAttribute; + deviceModeAttribute.attributeId = 0x0034; + deviceModeAttribute.dataType = Zigbee::Enum8; + deviceModeAttribute.data = ZigbeeDataType(static_cast(0x00)).data(); + attributes.append(deviceModeAttribute); + + ZigbeeClusterReply *deviceModeConfigReply = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdBasic)->writeAttributes(attributes, Zigbee::Philips); + connect(deviceModeConfigReply, &ZigbeeClusterReply::finished, node, [deviceModeConfigReply](){ + qCDebug(dcZigbeePhilipsHue()) << "Writing device mode configuration finished:" << deviceModeConfigReply->error(); + }); + + + bindBatteryCluster(node, endpoint); + bindOnOffCluster(node, endpoint); + bindLevelControlCluster(node, endpoint); + + dumpBindingTable(node); + }); +} + +void IntegrationPluginZigbeePhilipsHue::bindBatteryCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint) +{ + // Read battery, bind and configure attribute reporting for battery + if (!endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to initialize the power configuration cluster because the cluster could not be found" << node << endpoint; + return; + } + + // Bind the cluster to the coordinator + qCDebug(dcZigbeePhilipsHue()) << "Binding power configuration cluster from node" << node; + ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdPowerConfiguration, + hardwareManager()->zigbeeResource()->coordinatorAddress(node->networkUuid()), 0x01); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to bind power cluster" << zdoReply->error(); + } else { + qCDebug(dcZigbeePhilipsHue()) << "Successfully bound power configuration cluster."; + } + + // Configure attribute reporting for battery remaining (0.5 % changes = 1) + ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; + reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; + reportingConfig.dataType = Zigbee::Uint8; + reportingConfig.minReportingInterval = 300; + reportingConfig.maxReportingInterval = 2700; + reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); + + qCDebug(dcZigbeePhilipsHue()) << "Configuring attribute reporting for power configuration cluster on node:" << node; + ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); + connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){ + if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to configure power cluster attribute reporting" << reportingReply->error(); + } else { + qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); + } + }); + }); +} + +void IntegrationPluginZigbeePhilipsHue::bindOnOffCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint) +{ + qCDebug(dcZigbeePhilipsHue()) << "Binding on/off cluster from node" << node; + ZigbeeDeviceObjectReply * bindOnOffReply = node->deviceObject()->requestBindGroupAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000); + connect(bindOnOffReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ + if (bindOnOffReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to bind on/off cluster:" << bindOnOffReply->error(); + } else { + qCDebug(dcZigbeePhilipsHue()) << "Successfully bound on/off cluster."; + } + }); +} + +void IntegrationPluginZigbeePhilipsHue::bindLevelControlCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint) +{ + qCDebug(dcZigbeePhilipsHue()) << "Binding level control cluster from node" << node; + ZigbeeDeviceObjectReply * bindLevelControlReply = node->deviceObject()->requestBindGroupAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, 0x0000); + connect(bindLevelControlReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ + if (bindLevelControlReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to bind level control cluster:" << bindLevelControlReply->error(); + } else { + qCDebug(dcZigbeePhilipsHue()) << "Successfully bound level control cluster."; + } + }); +} + +void IntegrationPluginZigbeePhilipsHue::dumpBindingTable(ZigbeeNode *node) +{ + qCDebug(dcZigbeePhilipsHue()) << "Reading binding table from node" << node; + ZigbeeReply *reply = node->readBindingTableEntries(); + connect(reply, &ZigbeeReply::finished, node, [=](){ + if (reply->error() != ZigbeeReply::ErrorNoError) { + qCWarning(dcZigbeePhilipsHue()) << "Failed to read binding table from" << node; + } else { + qCDebug(dcZigbeePhilipsHue()) << "Binding table:"; + foreach (const ZigbeeDeviceProfile::BindingTableListRecord &binding, node->bindingTableRecords()) { + qCDebug(dcZigbeePhilipsHue()) << node << binding; + } + } }); } diff --git a/zigbeephilipshue/integrationpluginzigbeephilipshue.h b/zigbeephilipshue/integrationpluginzigbeephilipshue.h index 38ee2fe2..fbebf0b2 100644 --- a/zigbeephilipshue/integrationpluginzigbeephilipshue.h +++ b/zigbeephilipshue/integrationpluginzigbeephilipshue.h @@ -72,7 +72,13 @@ private: void initDimmerSwitch(ZigbeeNode *node); void initMotionSensor(ZigbeeNode *node); void initSmartButton(ZigbeeNode *node); + void initWallSwitchModule(ZigbeeNode *node); + void bindBatteryCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); + void bindOnOffCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); + void bindLevelControlCluster(ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint); + + void dumpBindingTable(ZigbeeNode *node); }; #endif // INTEGRATIONPLUGINZIGBEEPHILIPSHUE_H diff --git a/zigbeephilipshue/integrationpluginzigbeephilipshue.json b/zigbeephilipshue/integrationpluginzigbeephilipshue.json index cd2e5088..8c43f3b1 100644 --- a/zigbeephilipshue/integrationpluginzigbeephilipshue.json +++ b/zigbeephilipshue/integrationpluginzigbeephilipshue.json @@ -326,6 +326,119 @@ "eventTypes": [ ] + }, + { + "id": "1a81dffb-42e9-48f4-8fc5-b5917a7548b4", + "name": "wallSwitchModule", + "displayName": "Hue Wall Switch Module", + "createMethods": ["auto"], + "interfaces": [ "longpressmultibutton", "battery", "wirelessconnectable" ], + "paramTypes": [ + { + "id": "96f7e24c-7c24-449b-8df8-decbc00ccc5b", + "name": "ieeeAddress", + "displayName": "IEEE adress", + "type": "QString", + "defaultValue": "00:00:00:00:00:00:00:00" + }, + { + "id": "2450cdd2-6192-45fd-8374-583d12f45b68", + "name": "networkUuid", + "displayName": "Zigbee network UUID", + "type": "QString", + "defaultValue": "" + } + ], + "settingsTypes": [ + { + "id": "6c5c3ae0-2efc-41a7-ac75-092fbdfd244d", + "name": "buttonMode", + "displayName": "Button mode", + "type": "QString", + "allowedValues": [ "Single rocker", "Single push button", "Dual rocker", "Dual push button" ], + "defaultValue": "Single rocker" + } + ], + "stateTypes": [ + { + "id": "d36454c9-a90e-415a-870a-5488ba981006", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "ce55dd06-6d27-49f4-ad40-4a85bc126c2d", + "name": "signalStrength", + "displayName": "Signal strength", + "displayNameEvent": "Signal strength changed", + "defaultValue": 0, + "maxValue": 100, + "minValue": 0, + "type": "uint", + "unit": "Percentage" + }, + { + "id": "df6ce2f3-b09f-4fdd-b923-f8dca4e7a054", + "name": "version", + "displayName": "Version", + "displayNameEvent": "Version changed", + "type": "QString", + "cached": true, + "defaultValue": "" + }, + { + "id": "6a5f652c-5fa1-4477-a68c-ec1f2a3c1f91", + "name": "batteryLevel", + "displayName": "Battery", + "displayNameEvent": "Battery changed", + "type": "int", + "unit": "Percentage", + "defaultValue": 0, + "minValue": 0, + "maxValue": 100 + }, + { + "id": "2e4453a3-b8de-4494-b49e-f09ca855ff77", + "name": "batteryCritical", + "displayName": "Battery critical", + "displayNameEvent": "Battery critical changed", + "type": "bool", + "defaultValue": false + } + ], + "eventTypes": [ + { + "id": "19acc530-0c21-4582-9c82-17ccf5901476", + "name": "pressed", + "displayName": "Pressed", + "paramTypes": [ + { + "id": "564bb644-40b4-46ec-bb26-63ca0b704102", + "name": "buttonName", + "displayName": "Button", + "type": "QString", + "allowedValues": ["1", "2"] + } + ] + }, + { + "id": "20a9a579-3560-4260-878d-153b8d59d8ec", + "name": "longPressed", + "displayName": "Long pressed", + "paramTypes": [ + { + "id": "b8babc97-06f8-4413-8a94-2e90d0b52014", + "name": "buttonName", + "displayName": "Button", + "type": "QString", + "allowedValues": ["1", "2"] + } + ] + } + ] } ] } diff --git a/zigbeephilipshue/translations/0ca340b7-061a-42e6-ab7d-d7b4fd235d02-en_US.ts b/zigbeephilipshue/translations/0ca340b7-061a-42e6-ab7d-d7b4fd235d02-en_US.ts index bb23b20a..0a0cbe5e 100644 --- a/zigbeephilipshue/translations/0ca340b7-061a-42e6-ab7d-d7b4fd235d02-en_US.ts +++ b/zigbeephilipshue/translations/0ca340b7-061a-42e6-ab7d-d7b4fd235d02-en_US.ts @@ -4,12 +4,18 @@ ZigbeePhilipsHue - - - - + + + + + + Battery - The name of the ParamType (ThingClass: motionSensor, EventType: batteryLevel, ID: {00a4450b-d2fe-4e2b-92c8-1ab3a98d1628}) + The name of the ParamType (ThingClass: wallSwitchModule, EventType: batteryLevel, ID: {6a5f652c-5fa1-4477-a68c-ec1f2a3c1f91}) +---------- +The name of the StateType ({6a5f652c-5fa1-4477-a68c-ec1f2a3c1f91}) of ThingClass wallSwitchModule +---------- +The name of the ParamType (ThingClass: motionSensor, EventType: batteryLevel, ID: {00a4450b-d2fe-4e2b-92c8-1ab3a98d1628}) ---------- The name of the StateType ({00a4450b-d2fe-4e2b-92c8-1ab3a98d1628}) of ThingClass motionSensor ---------- @@ -19,23 +25,32 @@ The name of the StateType ({3e28e0b3-fe23-4293-8876-8384def6c4fb}) of ThingClass - - + + + Battery changed - The name of the EventType ({00a4450b-d2fe-4e2b-92c8-1ab3a98d1628}) of ThingClass motionSensor + The name of the EventType ({6a5f652c-5fa1-4477-a68c-ec1f2a3c1f91}) of ThingClass wallSwitchModule +---------- +The name of the EventType ({00a4450b-d2fe-4e2b-92c8-1ab3a98d1628}) of ThingClass motionSensor ---------- The name of the EventType ({3e28e0b3-fe23-4293-8876-8384def6c4fb}) of ThingClass dimmerSwitch - - - - - - + + + + + + + + Battery critical - The name of the ParamType (ThingClass: motionSensor, EventType: batteryCritical, ID: {9341f65a-b0aa-4648-82eb-e8400779f817}) + The name of the ParamType (ThingClass: wallSwitchModule, EventType: batteryCritical, ID: {2e4453a3-b8de-4494-b49e-f09ca855ff77}) +---------- +The name of the StateType ({2e4453a3-b8de-4494-b49e-f09ca855ff77}) of ThingClass wallSwitchModule +---------- +The name of the ParamType (ThingClass: motionSensor, EventType: batteryCritical, ID: {9341f65a-b0aa-4648-82eb-e8400779f817}) ---------- The name of the StateType ({9341f65a-b0aa-4648-82eb-e8400779f817}) of ThingClass motionSensor ---------- @@ -49,11 +64,14 @@ The name of the StateType ({4223a3bc-9616-4ed2-ae50-704b9df62d0e}) of ThingClass - - - + + + + Battery critical changed - The name of the EventType ({9341f65a-b0aa-4648-82eb-e8400779f817}) of ThingClass motionSensor + The name of the EventType ({2e4453a3-b8de-4494-b49e-f09ca855ff77}) of ThingClass wallSwitchModule +---------- +The name of the EventType ({9341f65a-b0aa-4648-82eb-e8400779f817}) of ThingClass motionSensor ---------- The name of the EventType ({3d79d36e-008e-41c8-9bb5-28db235b93ce}) of ThingClass smartButton ---------- @@ -61,8 +79,8 @@ The name of the EventType ({4223a3bc-9616-4ed2-ae50-704b9df62d0e}) of ThingClass - - + + Battery level The name of the ParamType (ThingClass: smartButton, EventType: batteryLevel, ID: {2837540f-a97b-4a92-9e17-900db38577e4}) ---------- @@ -70,32 +88,50 @@ The name of the StateType ({2837540f-a97b-4a92-9e17-900db38577e4}) of ThingClass - + Battery level changed The name of the EventType ({2837540f-a97b-4a92-9e17-900db38577e4}) of ThingClass smartButton - + + + Button + The name of the ParamType (ThingClass: wallSwitchModule, EventType: longPressed, ID: {b8babc97-06f8-4413-8a94-2e90d0b52014}) +---------- +The name of the ParamType (ThingClass: wallSwitchModule, EventType: pressed, ID: {564bb644-40b4-46ec-bb26-63ca0b704102}) + + + + + Button mode + The name of the ParamType (ThingClass: wallSwitchModule, Type: settings, ID: {6c5c3ae0-2efc-41a7-ac75-092fbdfd244d}) + + + + + Button name - The name of the ParamType (ThingClass: dimmerSwitch, EventType: pressed, ID: {c086a247-838f-49c0-b1e4-2ae1ed181b55}) + The name of the ParamType (ThingClass: dimmerSwitch, EventType: longPressed, ID: {046877e7-8e1c-489b-ac5f-8f0242c27b68}) +---------- +The name of the ParamType (ThingClass: dimmerSwitch, EventType: pressed, ID: {c086a247-838f-49c0-b1e4-2ae1ed181b55}) - - Button pressed - The name of the EventType ({33bb5816-8479-4995-99e2-cb0443886003}) of ThingClass dimmerSwitch - - - - - - - - - + + + + + + + + Connected - The name of the ParamType (ThingClass: motionSensor, EventType: connected, ID: {0d0a5ee1-41f2-4b5a-a3c0-7c8cca1c064d}) + The name of the ParamType (ThingClass: wallSwitchModule, EventType: connected, ID: {d36454c9-a90e-415a-870a-5488ba981006}) +---------- +The name of the StateType ({d36454c9-a90e-415a-870a-5488ba981006}) of ThingClass wallSwitchModule +---------- +The name of the ParamType (ThingClass: motionSensor, EventType: connected, ID: {0d0a5ee1-41f2-4b5a-a3c0-7c8cca1c064d}) ---------- The name of the StateType ({0d0a5ee1-41f2-4b5a-a3c0-7c8cca1c064d}) of ThingClass motionSensor ---------- @@ -109,11 +145,14 @@ The name of the StateType ({5ac101b2-4bb7-4b5c-8493-08b1ae7ca0c1}) of ThingClass - - - + + + + Connected changed - The name of the EventType ({0d0a5ee1-41f2-4b5a-a3c0-7c8cca1c064d}) of ThingClass motionSensor + The name of the EventType ({d36454c9-a90e-415a-870a-5488ba981006}) of ThingClass wallSwitchModule +---------- +The name of the EventType ({0d0a5ee1-41f2-4b5a-a3c0-7c8cca1c064d}) of ThingClass motionSensor ---------- The name of the EventType ({4748fc45-5ffd-4472-97a2-9fef256937db}) of ThingClass smartButton ---------- @@ -121,29 +160,38 @@ The name of the EventType ({5ac101b2-4bb7-4b5c-8493-08b1ae7ca0c1}) of ThingClass - + Hue Dimmer switch The name of the ThingClass ({b2711164-a848-4715-8ddf-33ca86f9f4cf}) - + Hue Motion sensor The name of the ThingClass ({031c45d1-e782-4f91-9f05-259d6b81c7ef}) - + Hue Smart button The name of the ThingClass ({edfa223b-aade-4369-a4e2-77b99989f49d}) - - - + + Hue Wall Switch Module + The name of the ThingClass ({1a81dffb-42e9-48f4-8fc5-b5917a7548b4}) + + + + + + + IEEE adress - The name of the ParamType (ThingClass: motionSensor, Type: thing, ID: {a866df99-7e2a-40e1-b82e-529c03846d5e}) + The name of the ParamType (ThingClass: wallSwitchModule, Type: thing, ID: {96f7e24c-7c24-449b-8df8-decbc00ccc5b}) +---------- +The name of the ParamType (ThingClass: motionSensor, Type: thing, ID: {a866df99-7e2a-40e1-b82e-529c03846d5e}) ---------- The name of the ParamType (ThingClass: smartButton, Type: thing, ID: {2c2bd259-b1cd-47f4-825f-03c3806a346f}) ---------- @@ -151,8 +199,8 @@ The name of the ParamType (ThingClass: dimmerSwitch, Type: thing, ID: {b221cad1- - - + + Last seen time The name of the ParamType (ThingClass: motionSensor, EventType: lastSeenTime, ID: {128777a9-75e7-4cc6-b196-691d2ffddbc9}) ---------- @@ -160,14 +208,14 @@ The name of the StateType ({128777a9-75e7-4cc6-b196-691d2ffddbc9}) of ThingClass - + Last seen time changed The name of the EventType ({128777a9-75e7-4cc6-b196-691d2ffddbc9}) of ThingClass motionSensor - - + + Light intensity The name of the ParamType (ThingClass: motionSensor, EventType: lightIntensity, ID: {8077e335-1d18-4e3f-9b5e-6f71af4a33b1}) ---------- @@ -175,26 +223,32 @@ The name of the StateType ({8077e335-1d18-4e3f-9b5e-6f71af4a33b1}) of ThingClass - + Light intensity changed The name of the EventType ({8077e335-1d18-4e3f-9b5e-6f71af4a33b1}) of ThingClass motionSensor - + + + Long pressed - The name of the EventType ({c7e6b02a-2700-4dbb-b012-cb641655ce2b}) of ThingClass smartButton + The name of the EventType ({20a9a579-3560-4260-878d-153b8d59d8ec}) of ThingClass wallSwitchModule +---------- +The name of the EventType ({c7e6b02a-2700-4dbb-b012-cb641655ce2b}) of ThingClass smartButton +---------- +The name of the EventType ({1a0be168-c9cb-44be-bca3-14c389f18e9f}) of ThingClass dimmerSwitch - + Philips The name of the vendor ({0ae1e001-2aa6-47ed-b8c0-334c3728a68f}) - - + + Present The name of the ParamType (ThingClass: motionSensor, EventType: isPresent, ID: {66e3b840-4f4c-4f4a-a71a-69fb751f2a3b}) ---------- @@ -202,26 +256,38 @@ The name of the StateType ({66e3b840-4f4c-4f4a-a71a-69fb751f2a3b}) of ThingClass - + Present changed The name of the EventType ({66e3b840-4f4c-4f4a-a71a-69fb751f2a3b}) of ThingClass motionSensor - + + + Pressed - The name of the EventType ({b2c94c5a-0076-4231-b455-1ca1567d1b43}) of ThingClass smartButton + The name of the EventType ({19acc530-0c21-4582-9c82-17ccf5901476}) of ThingClass wallSwitchModule +---------- +The name of the EventType ({b2c94c5a-0076-4231-b455-1ca1567d1b43}) of ThingClass smartButton +---------- +The name of the EventType ({33bb5816-8479-4995-99e2-cb0443886003}) of ThingClass dimmerSwitch - - - - - - + + + + + + + + Signal strength - The name of the ParamType (ThingClass: motionSensor, EventType: signalStrength, ID: {d4f85c34-896a-4bab-af71-8b80d9889815}) + The name of the ParamType (ThingClass: wallSwitchModule, EventType: signalStrength, ID: {ce55dd06-6d27-49f4-ad40-4a85bc126c2d}) +---------- +The name of the StateType ({ce55dd06-6d27-49f4-ad40-4a85bc126c2d}) of ThingClass wallSwitchModule +---------- +The name of the ParamType (ThingClass: motionSensor, EventType: signalStrength, ID: {d4f85c34-896a-4bab-af71-8b80d9889815}) ---------- The name of the StateType ({d4f85c34-896a-4bab-af71-8b80d9889815}) of ThingClass motionSensor ---------- @@ -235,11 +301,14 @@ The name of the StateType ({5a6e325e-a6ee-4a36-b429-f5d8c8adb80b}) of ThingClass - - - + + + + Signal strength changed - The name of the EventType ({d4f85c34-896a-4bab-af71-8b80d9889815}) of ThingClass motionSensor + The name of the EventType ({ce55dd06-6d27-49f4-ad40-4a85bc126c2d}) of ThingClass wallSwitchModule +---------- +The name of the EventType ({d4f85c34-896a-4bab-af71-8b80d9889815}) of ThingClass motionSensor ---------- The name of the EventType ({0eb19a1e-04d1-44ce-9554-f70c47a4f48a}) of ThingClass smartButton ---------- @@ -247,8 +316,8 @@ The name of the EventType ({5a6e325e-a6ee-4a36-b429-f5d8c8adb80b}) of ThingClass - - + + Temperature The name of the ParamType (ThingClass: motionSensor, EventType: temperature, ID: {978f069c-57c0-4e73-a81b-c593bc2e7624}) ---------- @@ -256,26 +325,32 @@ The name of the StateType ({978f069c-57c0-4e73-a81b-c593bc2e7624}) of ThingClass - + Temperature changed The name of the EventType ({978f069c-57c0-4e73-a81b-c593bc2e7624}) of ThingClass motionSensor - + Time period The name of the ParamType (ThingClass: motionSensor, Type: settings, ID: {4576f68f-7856-48f8-a3fd-2c9e7f968537}) - - - - - - + + + + + + + + Version - The name of the ParamType (ThingClass: motionSensor, EventType: version, ID: {18cb67e1-220f-41d7-9145-1816fc5d38d0}) + The name of the ParamType (ThingClass: wallSwitchModule, EventType: version, ID: {df6ce2f3-b09f-4fdd-b923-f8dca4e7a054}) +---------- +The name of the StateType ({df6ce2f3-b09f-4fdd-b923-f8dca4e7a054}) of ThingClass wallSwitchModule +---------- +The name of the ParamType (ThingClass: motionSensor, EventType: version, ID: {18cb67e1-220f-41d7-9145-1816fc5d38d0}) ---------- The name of the StateType ({18cb67e1-220f-41d7-9145-1816fc5d38d0}) of ThingClass motionSensor ---------- @@ -289,11 +364,14 @@ The name of the StateType ({12139630-668a-4ad8-96fa-781028e9eced}) of ThingClass - - - + + + + Version changed - The name of the EventType ({18cb67e1-220f-41d7-9145-1816fc5d38d0}) of ThingClass motionSensor + The name of the EventType ({df6ce2f3-b09f-4fdd-b923-f8dca4e7a054}) of ThingClass wallSwitchModule +---------- +The name of the EventType ({18cb67e1-220f-41d7-9145-1816fc5d38d0}) of ThingClass motionSensor ---------- The name of the EventType ({06268fbd-08d1-4f6c-bf81-ee44d8628ebc}) of ThingClass smartButton ---------- @@ -301,17 +379,20 @@ The name of the EventType ({12139630-668a-4ad8-96fa-781028e9eced}) of ThingClass - + Zigbee Philips Hue The name of the plugin ZigbeePhilipsHue ({0ca340b7-061a-42e6-ab7d-d7b4fd235d02}) - - - + + + + Zigbee network UUID - The name of the ParamType (ThingClass: motionSensor, Type: thing, ID: {99f4ff28-6d61-4e96-bfc4-c32aa05bb256}) + The name of the ParamType (ThingClass: wallSwitchModule, Type: thing, ID: {2450cdd2-6192-45fd-8374-583d12f45b68}) +---------- +The name of the ParamType (ThingClass: motionSensor, Type: thing, ID: {99f4ff28-6d61-4e96-bfc4-c32aa05bb256}) ---------- The name of the ParamType (ThingClass: smartButton, Type: thing, ID: {cee19fae-eac7-4cad-ab4f-b5fe68710115}) ----------