diff --git a/zigbee-philipshue/integrationpluginzigbeephilipshue.cpp b/zigbee-philipshue/integrationpluginzigbeephilipshue.cpp index 68223354..8c71c0c1 100644 --- a/zigbee-philipshue/integrationpluginzigbeephilipshue.cpp +++ b/zigbee-philipshue/integrationpluginzigbeephilipshue.cpp @@ -339,6 +339,8 @@ void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node) connect(reply, &ZigbeeReply::finished, node, [=](){ if (reply->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 @@ -352,11 +354,10 @@ void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node) connect(readAttributeReply, &ZigbeeClusterReply::finished, node, [=](){ if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) { qCWarning(dcZigbeePhilipsHue()) << "Failed to read power cluster attributes" << readAttributeReply->error(); - //emit nodeInitialized(node); - return; + } else { + qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes finished successfully"; } - qCDebug(dcZigbeePhilipsHue()) << "Read power configuration cluster attributes finished successfully"; // Bind the cluster to the coordinator qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator IEEE address"; @@ -365,9 +366,9 @@ void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node) connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { qCWarning(dcZigbeePhilipsHue()) << "Failed to bind power cluster to coordinator" << zdoReply->error(); - return; + } else { + qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator finished successfully"; } - qCDebug(dcZigbeePhilipsHue()) << "Bind power configuration cluster to coordinator finished successfully"; // Configure attribute rporting for battery remaining (0.5 % changes = 1) ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; @@ -382,28 +383,27 @@ void IntegrationPluginZigbeePhilipsHue::initDimmerSwitch(ZigbeeNode *node) connect(reportingReply, &ZigbeeClusterReply::finished, this, [=](){ if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { qCWarning(dcZigbeePhilipsHue()) << "Failed to configure power cluster attribute reporting" << reportingReply->error(); - return; + } else { + qCDebug(dcZigbeePhilipsHue()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); } - 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()->requestBindShortAddress(endpointZll->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(); - return; + } else { + qCDebug(dcZigbeePhilipsHue()) << "Bind on/off cluster to coordinator finished successfully"; } - qCDebug(dcZigbeePhilipsHue()) << "Bind on/off cluster to coordinator finished successfully"; qCDebug(dcZigbeePhilipsHue()) << "Bind power level cluster to coordinator"; ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpointZll->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(); - return; + } else { + qCDebug(dcZigbeePhilipsHue()) << "Bind level cluster to coordinator finished successfully"; } - qCDebug(dcZigbeePhilipsHue()) << "Bind level cluster to coordinator finished successfully"; qCDebug(dcZigbeePhilipsHue()) << "Read binding table from node" << node; ZigbeeReply *reply = node->readBindingTableEntries(); @@ -433,6 +433,8 @@ void IntegrationPluginZigbeePhilipsHue::initOutdoorSensor(ZigbeeNode *node) connect(reply, &ZigbeeReply::finished, node, [=](){ if (reply->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 diff --git a/zigbee-tradfri/integrationpluginzigbee-tradfri.json b/zigbee-tradfri/integrationpluginzigbee-tradfri.json index 35ef6e06..cb113115 100644 --- a/zigbee-tradfri/integrationpluginzigbee-tradfri.json +++ b/zigbee-tradfri/integrationpluginzigbee-tradfri.json @@ -236,6 +236,120 @@ } ] }, + { + "name": "soundRemote", + "displayName": "TRÅDFRI Symfonsik", + "id": "a18e398d-c14b-4bcd-8e6d-b64737436814", + "setupMethod": "JustAdd", + "createMethods": [ "Auto" ], + "interfaces": [ "longpressmultibutton", "batterylevel", "wirelessconnectable" ], + "paramTypes": [ + { + "id": "fa6544fd-9023-4c01-8600-7cc2f93aa4ca", + "name": "ieeeAddress", + "displayName": "IEEE adress", + "type": "QString", + "defaultValue": "00:00:00:00:00:00:00:00" + }, + { + "id": "268c557d-09e9-4cbb-9b0b-910c338c0dfb", + "name": "networkUuid", + "displayName": "Zigbee network UUID", + "type": "QString", + "defaultValue": "" + }, + { + "id": "194f1d90-fcdc-4489-b4d3-2448200b21d0", + "name": "endpointId", + "displayName": "Endpoint ID", + "type": "uint", + "defaultValue": 1 + } + ], + "stateTypes": [ + { + "id": "41ca0f43-998e-4a5e-ad6b-ae7deab38461", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "cached": false, + "defaultValue": false + }, + { + "id": "9485fea7-adfc-47aa-a7c4-76f38eff49ca", + "name": "signalStrength", + "displayName": "Signal strength", + "displayNameEvent": "Signal strength changed", + "defaultValue": 0, + "maxValue": 100, + "minValue": 0, + "type": "uint", + "unit": "Percentage" + }, + { + "id": "36c0a07a-7e20-4303-b6c7-7711c8ae36ad", + "name": "version", + "displayName": "Version", + "displayNameEvent": "Version changed", + "type": "QString", + "cached": true, + "defaultValue": "" + }, + { + "id": "1a0e2e7b-1b2a-461c-a24f-1323c2aea4a1", + "name": "batteryLevel", + "displayName": "Battery", + "displayNameEvent": "Battery changed", + "type": "int", + "unit": "Percentage", + "defaultValue": 0, + "minValue": 0, + "maxValue": 100 + }, + { + "id": "59312570-9cab-4e64-ac2f-2eda1c5ac314", + "name": "batteryCritical", + "displayName": "Battery critical", + "displayNameEvent": "Battery critical changed", + "type": "bool", + "defaultValue": false + } + ], + "actionTypes": [ + + ], + "eventTypes": [ + { + "id": "46a8c0c7-2bc7-4eb7-a7fe-c0d7263c2e39", + "name": "pressed", + "displayName": "Button pressed", + "paramTypes": [ + { + "id": "e728e820-13e5-4ea8-ad93-a9a1d3f8742c", + "name": "buttonName", + "displayName": "Button name", + "type": "QString", + "allowedValues": ["Power"] + } + ] + }, + { + "id": "18ece32b-e0a0-4544-a00c-7e70b25a2398", + "name": "longPressed", + "displayName": "Button longpressed", + "paramTypes": [ + { + "id": "f8a72cd6-1b78-4595-a941-377d7e9a2edf", + "name": "buttonName", + "displayName": "Button name", + "type": "QString", + "allowedValues": ["Power"] + } + ] + } + ] + }, { "name": "motionSensor", "displayName": "TRÅDFRI motion sensor", diff --git a/zigbee-tradfri/integrationpluginzigbeetradfri.cpp b/zigbee-tradfri/integrationpluginzigbeetradfri.cpp index b0680e4a..574c8744 100644 --- a/zigbee-tradfri/integrationpluginzigbeetradfri.cpp +++ b/zigbee-tradfri/integrationpluginzigbeetradfri.cpp @@ -38,31 +38,37 @@ IntegrationPluginZigbeeTradfri::IntegrationPluginZigbeeTradfri() { m_ieeeAddressParamTypeIds[onOffSwitchThingClassId] = onOffSwitchThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[remoteThingClassId] = remoteThingIeeeAddressParamTypeId; + m_ieeeAddressParamTypeIds[soundRemoteThingClassId] = soundRemoteThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[motionSensorThingClassId] = motionSensorThingIeeeAddressParamTypeId; m_ieeeAddressParamTypeIds[signalRepeaterThingClassId] = signalRepeaterThingIeeeAddressParamTypeId; m_networkUuidParamTypeIds[onOffSwitchThingClassId] = onOffSwitchThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[remoteThingClassId] = remoteThingNetworkUuidParamTypeId; + m_networkUuidParamTypeIds[soundRemoteThingClassId] = soundRemoteThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[motionSensorThingClassId] = motionSensorThingNetworkUuidParamTypeId; m_networkUuidParamTypeIds[signalRepeaterThingClassId] = signalRepeaterThingNetworkUuidParamTypeId; m_endpointIdParamTypeIds[onOffSwitchThingClassId] = onOffSwitchThingEndpointIdParamTypeId; m_endpointIdParamTypeIds[remoteThingClassId] = remoteThingEndpointIdParamTypeId; + m_endpointIdParamTypeIds[soundRemoteThingClassId] = soundRemoteThingEndpointIdParamTypeId; m_endpointIdParamTypeIds[motionSensorThingClassId] = motionSensorThingEndpointIdParamTypeId; m_endpointIdParamTypeIds[signalRepeaterThingClassId] = signalRepeaterThingEndpointIdParamTypeId; m_connectedStateTypeIds[onOffSwitchThingClassId] = onOffSwitchConnectedStateTypeId; m_connectedStateTypeIds[remoteThingClassId] = remoteConnectedStateTypeId; + m_connectedStateTypeIds[soundRemoteThingClassId] = soundRemoteConnectedStateTypeId; m_connectedStateTypeIds[motionSensorThingClassId] = motionSensorConnectedStateTypeId; m_connectedStateTypeIds[signalRepeaterThingClassId] = signalRepeaterConnectedStateTypeId; m_signalStrengthStateTypeIds[onOffSwitchThingClassId] = onOffSwitchSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[remoteThingClassId] = remoteSignalStrengthStateTypeId; + m_signalStrengthStateTypeIds[soundRemoteThingClassId] = soundRemoteSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[motionSensorThingClassId] = motionSensorSignalStrengthStateTypeId; m_signalStrengthStateTypeIds[signalRepeaterThingClassId] = signalRepeaterSignalStrengthStateTypeId; m_versionStateTypeIds[onOffSwitchThingClassId] = onOffSwitchVersionStateTypeId; m_versionStateTypeIds[remoteThingClassId] = remoteVersionStateTypeId; + m_versionStateTypeIds[soundRemoteThingClassId] = soundRemoteVersionStateTypeId; m_versionStateTypeIds[motionSensorThingClassId] = motionSensorVersionStateTypeId; m_versionStateTypeIds[signalRepeaterThingClassId] = signalRepeaterVersionStateTypeId; } @@ -101,6 +107,13 @@ bool IntegrationPluginZigbeeTradfri::handleNode(ZigbeeNode *node, const QUuid &n handled = true; } + if (endpoint->profile() == Zigbee::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceRemoteControl) { + qCDebug(dcZigbeeTradfri()) << "Handeling TRADFRI Symfonsik sound remote" << node << endpoint; + createThing(soundRemoteThingClassId, networkUuid, node, endpoint); + initRemote(node, endpoint); + handled = true; + } + if (endpoint->profile() == Zigbee::ZigbeeProfileHomeAutomation && endpoint->deviceId() == Zigbee::HomeAutomationDeviceRangeExtender) { qCDebug(dcZigbeeTradfri()) << "Handeling TRADFRI signal repeater" << node << endpoint; createThing(signalRepeaterThingClassId, networkUuid, node, endpoint); @@ -306,6 +319,63 @@ void IntegrationPluginZigbeeTradfri::setupThing(ThingSetupInfo *info) } } + if (thing->thingClassId() == soundRemoteThingClassId) { + // Get battery level changes + ZigbeeClusterPowerConfiguration *powerCluster = endpoint->inputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration); + if (!powerCluster) { + qCWarning(dcZigbeeTradfri()) << "Could not find power configuration cluster on" << thing << endpoint; + } else { + // Only set the initial state if the attribute already exists + if (powerCluster->hasAttribute(ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining)) { + thing->setStateValue(soundRemoteBatteryLevelStateTypeId, powerCluster->batteryPercentage()); + thing->setStateValue(soundRemoteBatteryCriticalStateTypeId, (powerCluster->batteryPercentage() < 10.0)); + } + + connect(powerCluster, &ZigbeeClusterPowerConfiguration::batteryPercentageChanged, thing, [=](double percentage){ + qCDebug(dcZigbeeTradfri()) << "Battery percentage changed" << percentage << "%" << thing; + thing->setStateValue(soundRemoteBatteryLevelStateTypeId, percentage); + thing->setStateValue(soundRemoteBatteryCriticalStateTypeId, (percentage < 10.0)); + }); + } + + // Receive on/off commands + ZigbeeClusterOnOff *onOffCluster = endpoint->outputCluster(ZigbeeClusterLibrary::ClusterIdOnOff); + if (!onOffCluster) { + qCWarning(dcZigbeeTradfri()) << "Could not find on/off client cluster on" << thing << endpoint; + } else { + connect(onOffCluster, &ZigbeeClusterOnOff::commandSent, thing, [=](ZigbeeClusterOnOff::Command command){ + qCDebug(dcZigbeeTradfri()) << thing << "button pressed" << command; + if (command == ZigbeeClusterOnOff::CommandToggle) { + qCDebug(dcZigbeeTradfri()) << thing << "pressed power"; + emit emitEvent(Event(soundRemotePressedEventTypeId, thing->id(), ParamList() << Param(soundRemotePressedEventButtonNameParamTypeId, "Power"))); + } + }); + } + + // Receive level control commands + ZigbeeClusterLevelControl *levelCluster = endpoint->outputCluster(ZigbeeClusterLibrary::ClusterIdLevelControl); + if (!levelCluster) { + qCWarning(dcZigbeeTradfri()) << "Could not find level client cluster on" << thing << endpoint; + } else { + connect(levelCluster, &ZigbeeClusterLevelControl::commandSent, thing, [=](ZigbeeClusterLevelControl::Command command, const QByteArray &payload){ + qCDebug(dcZigbeeTradfri()) << thing << "level cluster command sent" << command << payload.toHex(); +// switch (command) { +// case ZigbeeClusterLevelControl::CommandMoveWithOnOff: +// qCDebug(dcZigbeeTradfri()) << thing << "long pressed ON"; +// emit emitEvent(Event(onOffSwitchLongPressedEventTypeId, thing->id(), ParamList() << Param(onOffSwitchLongPressedEventButtonNameParamTypeId, "ON"))); +// break; +// case ZigbeeClusterLevelControl::CommandMove: +// qCDebug(dcZigbeeTradfri()) << thing << "long pressed OFF"; +// emit emitEvent(Event(onOffSwitchLongPressedEventTypeId, thing->id(), ParamList() << Param(onOffSwitchLongPressedEventButtonNameParamTypeId, "OFF"))); +// break; +// default: +// break; +// } + }); + } + } + + info->finish(Thing::ThingErrorNoError); } @@ -454,7 +524,6 @@ void IntegrationPluginZigbeeTradfri::initRemote(ZigbeeNode *node, ZigbeeNodeEndp } // Read battery, bind and configure attribute reporting for battery - if (!endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { qCWarning(dcZigbeeTradfri()) << "Failed to initialize the power configuration cluster because the cluster could not be found" << node << endpoint; return; @@ -481,7 +550,7 @@ void IntegrationPluginZigbeeTradfri::initRemote(ZigbeeNode *node, ZigbeeNodeEndp qCDebug(dcZigbeeTradfri()) << "Bind power configuration cluster to coordinator finished successfully"; } - // Configure attribute rporting for battery remaining (0.5 % changes = 1) + // Configure attribute reporting for battery remaining (0.5 % changes = 1) ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; reportingConfig.dataType = Zigbee::Uint8; @@ -498,8 +567,8 @@ void IntegrationPluginZigbeeTradfri::initRemote(ZigbeeNode *node, ZigbeeNodeEndp qCDebug(dcZigbeeTradfri()) << "Attribute reporting configuration finished for power cluster" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); } - - qCDebug(dcZigbeeTradfri()) << "Bind power configuration cluster to coordinator"; + // Init OnOff cluster + qCDebug(dcZigbeeTradfri()) << "Bind on/off cluster to coordinator"; ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, 0x0000); connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { @@ -508,6 +577,8 @@ void IntegrationPluginZigbeeTradfri::initRemote(ZigbeeNode *node, ZigbeeNodeEndp qCDebug(dcZigbeeTradfri()) << "Bind on/off cluster to coordinator finished successfully"; } + + // Init Level cluster qCDebug(dcZigbeeTradfri()) << "Bind power level cluster to coordinator"; ZigbeeDeviceObjectReply * zdoReply = node->deviceObject()->requestBindShortAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, 0x0000); connect(zdoReply, &ZigbeeDeviceObjectReply::finished, node, [=](){ @@ -517,6 +588,7 @@ void IntegrationPluginZigbeeTradfri::initRemote(ZigbeeNode *node, ZigbeeNodeEndp qCDebug(dcZigbeeTradfri()) << "Bind level cluster to coordinator finished successfully"; } + // Read final bindings qCDebug(dcZigbeeTradfri()) << "Read binding table from node" << node; ZigbeeReply *reply = node->readBindingTableEntries(); connect(reply, &ZigbeeReply::finished, node, [=](){