Merge PR #457: Philips Hue - add support for Friends of Hue switch and Wall switch module
commit
f6c6e421ca
|
|
@ -10,14 +10,16 @@ This plugin allows to interact with the Hue bridge. Each light bulb, sensor and
|
|||
* No internet or cloud connection required
|
||||
* Hue Dimmer switch V1 and V2
|
||||
* Hue Tap Switch
|
||||
* Friends of Hue Switch (e.g. Niko, ...)
|
||||
* Hue Smart Button
|
||||
* Hue Wall Switch Module
|
||||
* Hue Motion Sensor
|
||||
* Hue Outdoor Motion Sensor
|
||||
* Hue Ambient White Bulb
|
||||
* Hue Color Bulb
|
||||
* Hue Smart plug
|
||||
* Any other Bulb that can be connected and controlled by the Hue App
|
||||
* In-wall dimmers/switches that can be connected and controlled by the Hue App.
|
||||
* In-wall dimmers/switches that can be connected and controlled by the Hue App
|
||||
|
||||
## Requirements
|
||||
|
||||
|
|
|
|||
|
|
@ -516,6 +516,21 @@ void IntegrationPluginPhilipsHue::setupThing(ThingSetupInfo *info)
|
|||
return info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
// Friends of Hue switch
|
||||
if (thing->thingClassId() == fohThingClassId) {
|
||||
HueRemote *hueFoh = new HueRemote(bridge, this);
|
||||
hueFoh->setName(thing->name());
|
||||
hueFoh->setId(thing->paramValue(fohThingSensorIdParamTypeId).toInt());
|
||||
hueFoh->setModelId(thing->paramValue(fohThingModelIdParamTypeId).toString());
|
||||
hueFoh->setUuid(thing->paramValue(fohThingUuidParamTypeId).toString());
|
||||
|
||||
connect(hueFoh, &HueRemote::stateChanged, this, &IntegrationPluginPhilipsHue::remoteStateChanged);
|
||||
connect(hueFoh, &HueRemote::buttonPressed, this, &IntegrationPluginPhilipsHue::onRemoteButtonEvent);
|
||||
|
||||
m_remotes.insert(hueFoh, thing);
|
||||
return info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
// Hue smart button
|
||||
if (thing->thingClassId() == smartButtonThingClassId) {
|
||||
HueRemote *smartButton = new HueRemote(bridge, this);
|
||||
|
|
@ -531,6 +546,21 @@ void IntegrationPluginPhilipsHue::setupThing(ThingSetupInfo *info)
|
|||
return info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
// Hue Wall Switch module
|
||||
if (thing->thingClassId() == wallSwitchThingClassId) {
|
||||
HueRemote *wallSwitch = new HueRemote(bridge, this);
|
||||
wallSwitch->setName(thing->name());
|
||||
wallSwitch->setId(thing->paramValue(wallSwitchThingSensorIdParamTypeId).toInt());
|
||||
wallSwitch->setModelId(thing->paramValue(wallSwitchThingModelIdParamTypeId).toString());
|
||||
wallSwitch->setUuid(thing->paramValue(wallSwitchThingUuidParamTypeId).toString());
|
||||
|
||||
connect(wallSwitch, &HueRemote::stateChanged, this, &IntegrationPluginPhilipsHue::remoteStateChanged);
|
||||
connect(wallSwitch, &HueRemote::buttonPressed, this, &IntegrationPluginPhilipsHue::onRemoteButtonEvent);
|
||||
|
||||
m_remotes.insert(wallSwitch, thing);
|
||||
return info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
// Hue Motion sensor
|
||||
if (thing->thingClassId() == motionSensorThingClassId) {
|
||||
qCDebug(dcPhilipsHue) << "Setup Hue motion sensor" << thing->params();
|
||||
|
|
@ -644,7 +674,7 @@ void IntegrationPluginPhilipsHue::thingRemoved(Thing *thing)
|
|||
light->deleteLater();
|
||||
}
|
||||
|
||||
if (thing->thingClassId() == remoteThingClassId || thing->thingClassId() == dimmerSwitch2ThingClassId|| thing->thingClassId() == tapThingClassId || thing->thingClassId() == smartButtonThingClassId) {
|
||||
if (thing->thingClassId() == remoteThingClassId || thing->thingClassId() == dimmerSwitch2ThingClassId|| thing->thingClassId() == tapThingClassId || thing->thingClassId() == fohThingClassId || thing->thingClassId() == smartButtonThingClassId || thing->thingClassId() == wallSwitchThingClassId) {
|
||||
HueRemote *remote = m_remotes.key(thing);
|
||||
m_remotes.remove(remote);
|
||||
remote->deleteLater();
|
||||
|
|
@ -1160,10 +1190,16 @@ void IntegrationPluginPhilipsHue::remoteStateChanged()
|
|||
thing->setStateValue(dimmerSwitch2BatteryCriticalStateTypeId, remote->battery() < 5);
|
||||
} else if (thing->thingClassId() == tapThingClassId) {
|
||||
thing->setStateValue(tapConnectedStateTypeId, remote->reachable());
|
||||
} else if (thing->thingClassId() == fohThingClassId) {
|
||||
thing->setStateValue(fohConnectedStateTypeId, remote->reachable());
|
||||
} else if (thing->thingClassId() == smartButtonThingClassId) {
|
||||
thing->setStateValue(smartButtonConnectedStateTypeId, remote->reachable());
|
||||
thing->setStateValue(smartButtonBatteryLevelStateTypeId, remote->battery());
|
||||
thing->setStateValue(smartButtonBatteryCriticalStateTypeId, remote->battery() < 5);
|
||||
} else if (thing->thingClassId() == wallSwitchThingClassId) {
|
||||
thing->setStateValue(wallSwitchConnectedStateTypeId, remote->reachable());
|
||||
thing->setStateValue(wallSwitchBatteryLevelStateTypeId, remote->battery());
|
||||
thing->setStateValue(wallSwitchBatteryCriticalStateTypeId, remote->battery() < 5);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1223,7 +1259,7 @@ void IntegrationPluginPhilipsHue::onRemoteButtonEvent(int buttonCode)
|
|||
param = Param(dimmerSwitch2PressedEventButtonNameParamTypeId, "POWER");
|
||||
id = dimmerSwitch2PressedEventTypeId;
|
||||
break;
|
||||
case 1000:
|
||||
case 1001:
|
||||
param = Param(dimmerSwitch2LongPressedEventButtonNameParamTypeId, "POWER");
|
||||
id = dimmerSwitch2LongPressedEventTypeId;
|
||||
break;
|
||||
|
|
@ -1231,7 +1267,7 @@ void IntegrationPluginPhilipsHue::onRemoteButtonEvent(int buttonCode)
|
|||
param = Param(dimmerSwitch2PressedEventButtonNameParamTypeId, "DIM UP");
|
||||
id = dimmerSwitch2PressedEventTypeId;
|
||||
break;
|
||||
case 2000:
|
||||
case 2001:
|
||||
param = Param(dimmerSwitch2LongPressedEventButtonNameParamTypeId, "DIM UP");
|
||||
id = dimmerSwitch2LongPressedEventTypeId;
|
||||
break;
|
||||
|
|
@ -1239,7 +1275,7 @@ void IntegrationPluginPhilipsHue::onRemoteButtonEvent(int buttonCode)
|
|||
param = Param(dimmerSwitch2PressedEventButtonNameParamTypeId, "DIM DOWN");
|
||||
id = dimmerSwitch2PressedEventTypeId;
|
||||
break;
|
||||
case 3000:
|
||||
case 3001:
|
||||
param = Param(dimmerSwitch2LongPressedEventButtonNameParamTypeId, "DIM DOWN");
|
||||
id = dimmerSwitch2LongPressedEventTypeId;
|
||||
break;
|
||||
|
|
@ -1247,7 +1283,7 @@ void IntegrationPluginPhilipsHue::onRemoteButtonEvent(int buttonCode)
|
|||
param = Param(dimmerSwitch2PressedEventButtonNameParamTypeId, "HUE");
|
||||
id = dimmerSwitch2PressedEventTypeId;
|
||||
break;
|
||||
case 4000:
|
||||
case 4001:
|
||||
param = Param(dimmerSwitch2LongPressedEventButtonNameParamTypeId, "HUE");
|
||||
id = dimmerSwitch2LongPressedEventTypeId;
|
||||
break;
|
||||
|
|
@ -1256,10 +1292,10 @@ void IntegrationPluginPhilipsHue::onRemoteButtonEvent(int buttonCode)
|
|||
return;
|
||||
}
|
||||
// codes ending in 2 (e.g. 1002) are short presses;
|
||||
// for long presses the Dimmer Switch V2 sends 3 codes:
|
||||
// for long presses the Dimmer Switch V2 sends 3 codes (same behaviour as hue remote and smart button):
|
||||
// * codes ending in 0 (e.g. 1000) indicate start of long press
|
||||
// * codes ending in 3 (e.g. 1003) indicate end of long press --> not yet supported by this plugin, but e.g. LongPressEnded action could be added
|
||||
// * codes ending in 1 (e.g. 1001) are sent during the long press --> probably for backwards compatibility with earlier version, and therefore not added to this plugin
|
||||
// * codes ending in 3 (e.g. 1003) indicate end of long press
|
||||
// * codes ending in 1 (e.g. 1001) are sent during the long press
|
||||
} else if (thing->thingClassId() == tapThingClassId) {
|
||||
switch (buttonCode) {
|
||||
case 34:
|
||||
|
|
@ -1282,6 +1318,28 @@ void IntegrationPluginPhilipsHue::onRemoteButtonEvent(int buttonCode)
|
|||
qCDebug(dcPhilipsHue()) << "Received unhandled button code from Hue Tap:" << buttonCode;
|
||||
return;
|
||||
}
|
||||
} else if (thing->thingClassId() == fohThingClassId) {
|
||||
switch (buttonCode) {
|
||||
case 20:
|
||||
param = Param(fohPressedEventButtonNameParamTypeId, "UPPER LEFT");
|
||||
id = fohPressedEventTypeId;
|
||||
break;
|
||||
case 21:
|
||||
param = Param(fohPressedEventButtonNameParamTypeId, "LOWER LEFT");
|
||||
id = fohPressedEventTypeId;
|
||||
break;
|
||||
case 23:
|
||||
param = Param(fohPressedEventButtonNameParamTypeId, "UPPER RIGHT");
|
||||
id = fohPressedEventTypeId;
|
||||
break;
|
||||
case 22:
|
||||
param = Param(fohPressedEventButtonNameParamTypeId, "LOWER RIGHT");
|
||||
id = fohPressedEventTypeId;
|
||||
break;
|
||||
default:
|
||||
qCDebug(dcPhilipsHue()) << "Received unhandled button code from Friends of Hue switch:" << buttonCode;
|
||||
return;
|
||||
}
|
||||
} else if (thing->thingClassId() == smartButtonThingClassId) {
|
||||
switch (buttonCode) {
|
||||
case 1002:
|
||||
|
|
@ -1294,6 +1352,20 @@ void IntegrationPluginPhilipsHue::onRemoteButtonEvent(int buttonCode)
|
|||
qCDebug(dcPhilipsHue()) << "Received unhandled button code from Hue Smart Button:" << buttonCode;
|
||||
return;
|
||||
}
|
||||
} else if (thing->thingClassId() == wallSwitchThingClassId) {
|
||||
switch (buttonCode) {
|
||||
case 1002: // temporary number, replace with code (codes for on and off?)
|
||||
param = Param(wallSwitchPressedEventButtonNameParamTypeId, "ONE");
|
||||
id = wallSwitchPressedEventTypeId;
|
||||
break;
|
||||
case 2002: // temporary number, replace with code (codes for on and off?)
|
||||
param = Param(wallSwitchPressedEventButtonNameParamTypeId, "TWO");
|
||||
id = wallSwitchPressedEventTypeId;
|
||||
break;
|
||||
default:
|
||||
qCDebug(dcPhilipsHue()) << "Received unhandled button code from Hue Wall Switch Module:" << buttonCode;
|
||||
return;
|
||||
}
|
||||
}
|
||||
emitEvent(Event(id, m_remotes.value(remote)->id(), ParamList() << param));
|
||||
}
|
||||
|
|
@ -1648,6 +1720,30 @@ void IntegrationPluginPhilipsHue::processBridgeSensorDiscoveryResponse(Thing *th
|
|||
emit autoThingsAppeared({descriptor});
|
||||
qCDebug(dcPhilipsHue) << "Found new smart button" << sensorMap.value("name").toString() << model;
|
||||
|
||||
// Wall Switch Module
|
||||
} else if (model == "RDM001") {
|
||||
ThingDescriptor descriptor(wallSwitchThingClassId, sensorMap.value("name").toString(), "Philips Hue Wall Switch Module", thing->id());
|
||||
ParamList params;
|
||||
params.append(Param(wallSwitchThingModelIdParamTypeId, model));
|
||||
params.append(Param(wallSwitchThingTypeParamTypeId, sensorMap.value("type").toString()));
|
||||
params.append(Param(wallSwitchThingUuidParamTypeId, uuid));
|
||||
params.append(Param(wallSwitchThingSensorIdParamTypeId, sensorId));
|
||||
descriptor.setParams(params);
|
||||
emit autoThingsAppeared({descriptor});
|
||||
qCDebug(dcPhilipsHue) << "Found new wall switch module" << sensorMap.value("name").toString() << model;
|
||||
|
||||
// Friends of Hue switch
|
||||
} else if (model == "FOHSWITCH") {
|
||||
ThingDescriptor descriptor(fohThingClassId, sensorMap.value("name").toString(), "Friends of Hue Switch", thing->id());
|
||||
ParamList params;
|
||||
params.append(Param(fohThingModelIdParamTypeId, model));
|
||||
params.append(Param(fohThingTypeParamTypeId, sensorMap.value("type").toString()));
|
||||
params.append(Param(fohThingUuidParamTypeId, uuid));
|
||||
params.append(Param(fohThingSensorIdParamTypeId, sensorId));
|
||||
descriptor.setParams(params);
|
||||
emit autoThingsAppeared({descriptor});
|
||||
qCDebug(dcPhilipsHue) << "Found new friends of hue switch" << sensorMap.value("name").toString() << model;
|
||||
|
||||
// Hue Tap
|
||||
} else if (sensorMap.value("type").toString() == "ZGPSwitch") {
|
||||
ThingDescriptor descriptor(tapThingClassId, sensorMap.value("name").toString(), "Philips Hue Tap", thing->id());
|
||||
|
|
@ -2015,8 +2111,12 @@ void IntegrationPluginPhilipsHue::bridgeReachableChanged(Thing *thing, bool reac
|
|||
m_remotes.value(remote)->setStateValue(dimmerSwitch2ConnectedStateTypeId, false);
|
||||
} else if (m_remotes.value(remote)->thingClassId() == tapThingClassId) {
|
||||
m_remotes.value(remote)->setStateValue(tapConnectedStateTypeId, false);
|
||||
} else if (m_remotes.value(remote)->thingClassId() == fohThingClassId) {
|
||||
m_remotes.value(remote)->setStateValue(fohConnectedStateTypeId, false);
|
||||
} else if (m_remotes.value(remote)->thingClassId() == smartButtonThingClassId) {
|
||||
m_remotes.value(remote)->setStateValue(smartButtonConnectedStateTypeId, false);
|
||||
} else if (m_remotes.value(remote)->thingClassId() == wallSwitchThingClassId) {
|
||||
m_remotes.value(remote)->setStateValue(wallSwitchConnectedStateTypeId, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2097,6 +2197,13 @@ bool IntegrationPluginPhilipsHue::sensorAlreadyAdded(const QString &uuid)
|
|||
}
|
||||
}
|
||||
|
||||
// Friends of Hue
|
||||
if (thing->thingClassId() == fohThingClassId) {
|
||||
if (thing->paramValue(fohThingUuidParamTypeId).toString() == uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Hue smart button
|
||||
if (thing->thingClassId() == smartButtonThingClassId) {
|
||||
if (thing->paramValue(smartButtonThingUuidParamTypeId).toString() == uuid) {
|
||||
|
|
@ -2104,6 +2211,13 @@ bool IntegrationPluginPhilipsHue::sensorAlreadyAdded(const QString &uuid)
|
|||
}
|
||||
}
|
||||
|
||||
// Hue wall switch module
|
||||
if (thing->thingClassId() == wallSwitchThingClassId) {
|
||||
if (thing->paramValue(wallSwitchThingUuidParamTypeId).toString() == uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Outdoor sensor consits out of 3 sensors
|
||||
if (thing->thingClassId() == outdoorSensorThingClassId) {
|
||||
if (thing->paramValue(outdoorSensorThingSensorUuidLightParamTypeId).toString() == uuid) {
|
||||
|
|
|
|||
|
|
@ -751,6 +751,89 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "e967027f-f8fc-410c-8b48-6ac4c42e2777",
|
||||
"name": "wallSwitch",
|
||||
"displayName": "Hue Wall Switch Module",
|
||||
"interfaces": ["multibutton", "wirelessconnectable"],
|
||||
"createMethods": ["auto"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "71c2c485-6a09-4bcd-80e5-24cdc45d323f",
|
||||
"name": "modelId",
|
||||
"displayName": "Model ID",
|
||||
"type": "QString",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "08606780-2251-4c15-bb7d-7506535e14ed",
|
||||
"name": "type",
|
||||
"displayName": "Type",
|
||||
"type" : "QString",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "4cdab881-5d2d-4443-816a-231bbb331f22",
|
||||
"name": "uuid",
|
||||
"displayName": "UUID",
|
||||
"type" : "QString",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "62a9df8c-51b5-434f-9d5d-5fa97144076a",
|
||||
"name": "sensorId",
|
||||
"displayName": "Sensor ID",
|
||||
"type" : "int",
|
||||
"readOnly": true
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "b51071af-1290-41f1-b2eb-e84527342ade",
|
||||
"name": "connected",
|
||||
"displayName": "Reachable",
|
||||
"displayNameEvent": "Reachable changed",
|
||||
"defaultValue": false,
|
||||
"type": "bool",
|
||||
"cached": false
|
||||
},
|
||||
{
|
||||
"id": "b025cab6-d128-43eb-ba63-b16861d6ab10",
|
||||
"name": "batteryLevel",
|
||||
"displayName": "Battery level",
|
||||
"displayNameEvent": "Battery level changed",
|
||||
"type": "int",
|
||||
"unit": "Percentage",
|
||||
"defaultValue": 0,
|
||||
"minValue": 0,
|
||||
"maxValue": 100
|
||||
},
|
||||
{
|
||||
"id": "7fcf84e4-5638-46ce-9a7c-85b8bd466b38",
|
||||
"name": "batteryCritical",
|
||||
"displayName": "Battery critical",
|
||||
"displayNameEvent": "Battery critical changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
}
|
||||
],
|
||||
"eventTypes": [
|
||||
{
|
||||
"id": "4623b5ff-b999-4200-ba38-89435d78fcae",
|
||||
"name": "pressed",
|
||||
"displayName": "Button pressed",
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "adb4ec5e-e48f-4697-a876-e56e8458987a",
|
||||
"name": "buttonName",
|
||||
"displayName": "Button name",
|
||||
"type": "QString",
|
||||
"allowedValues": ["ONE", "TWO"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2b8c1fb8-67ee-42e9-947b-16e0a09f0d4e",
|
||||
"name": "tap",
|
||||
|
|
@ -815,6 +898,70 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "692bc4be-07b8-4b77-ab0b-a36185b17d76",
|
||||
"name": "foh",
|
||||
"displayName": "Friends of Hue Switch",
|
||||
"interfaces": ["multibutton", "wirelessconnectable"],
|
||||
"createMethods": ["auto"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "664c7091-12eb-4402-8239-31da85f73d38",
|
||||
"name": "modelId",
|
||||
"displayName": "Model ID",
|
||||
"type" : "QString",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "16ca2ee1-d738-4f51-8f9a-53547d3d824e",
|
||||
"name": "type",
|
||||
"displayName": "Type",
|
||||
"type" : "QString",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "2ca66286-1caf-4e09-8e18-05bb7d7df314",
|
||||
"name": "uuid",
|
||||
"displayName": "UUID",
|
||||
"type" : "QString",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "7559d16c-b56b-42e2-8347-65582fa276c0",
|
||||
"name": "sensorId",
|
||||
"displayName": "Sensor ID",
|
||||
"type" : "int",
|
||||
"readOnly": true
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "840b220c-656b-4f56-bbaa-ce818cffad64",
|
||||
"name": "connected",
|
||||
"displayName": "Reachable",
|
||||
"displayNameEvent": "Reachable changed",
|
||||
"defaultValue": false,
|
||||
"type": "bool",
|
||||
"cached": false
|
||||
}
|
||||
],
|
||||
"eventTypes": [
|
||||
{
|
||||
"id": "2cc68bd3-ad73-4bf3-9905-639870d071bd",
|
||||
"name": "pressed",
|
||||
"displayName": "Button pressed",
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "f1da229e-fce2-4329-8850-1c92b5bc5925",
|
||||
"name": "buttonName",
|
||||
"displayName": "Button name",
|
||||
"type": "QString",
|
||||
"allowedValues": ["UPPER LEFT", "LOWER LEFT", "UPPER RIGHT", "LOWER RIGHT"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "32dc6390-600f-4eb4-b349-cc2d6796a82a",
|
||||
"name": "outdoorSensor",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue