add remote events and prevent double adding of bridges

pull/135/head
Simon Stürz 2015-12-18 17:22:32 +01:00 committed by Michael Zanetti
parent cf6c79ec2e
commit b44d5aa9b7
5 changed files with 175 additions and 75 deletions

View File

@ -76,7 +76,7 @@ DevicePluginPhilipsHue::DevicePluginPhilipsHue()
{
m_timer = new QTimer(this);
m_timer->setSingleShot(false);
m_timer->setInterval(1000);
m_timer->setInterval(1500);
connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
}
@ -120,6 +120,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
// loaded bridge
qCDebug(dcPhilipsHue) << "Setup Hue Bridge" << device->params();
HueBridge *bridge = new HueBridge(this);
bridge->setId(device->paramValue("id").toString());
bridge->setApiKey(device->paramValue("api key").toString());
@ -136,6 +137,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
// hue color light
if (device->deviceClassId() == hueLightDeviceClassId) {
qCDebug(dcPhilipsHue) << "Setup Hue color light" << device->params();
HueLight *hueLight = new HueLight(this);
hueLight->setId(device->paramValue("light id").toInt());
hueLight->setHostAddress(QHostAddress(device->paramValue("host address").toString()));
@ -145,14 +147,14 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
hueLight->setUuid(device->paramValue("uuid").toString());
hueLight->setType(device->paramValue("type").toString());
hueLight->setBridgeId(DeviceId(device->paramValue("bridge").toString()));
device->setParentId(hueLight->bridgeId());
connect(hueLight, &HueLight::stateChanged, this, &DevicePluginPhilipsHue::lightStateChanged);
device->setParentId(device->paramValue("bridge").toString());
m_lights.insert(hueLight, device);
refreshLight(device);
setLightName(device, device->paramValue("name").toString());
return DeviceManager::DeviceSetupStatusSuccess;
}
@ -169,12 +171,11 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
hueLight->setType(device->paramValue("type").toString());
hueLight->setUuid(device->paramValue("uuid").toString());
hueLight->setBridgeId(DeviceId(device->paramValue("bridge").toString()));
device->setParentId(hueLight->bridgeId());
connect(hueLight, &HueLight::stateChanged, this, &DevicePluginPhilipsHue::lightStateChanged);
device->setParentId(device->paramValue("bridge").toString());
m_lights.insert(hueLight, device);
refreshLight(device);
setLightName(device, device->paramValue("name").toString());
@ -186,7 +187,7 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
qCDebug(dcPhilipsHue) << "Setup Hue remote" << device->params();
HueRemote *hueRemote = new HueRemote(this);
hueRemote->setId(device->paramValue("light id").toInt());
hueRemote->setId(device->paramValue("sensor id").toInt());
hueRemote->setHostAddress(QHostAddress(device->paramValue("host address").toString()));
hueRemote->setName(device->paramValue("name").toString());
hueRemote->setApiKey(device->paramValue("api key").toString());
@ -194,10 +195,11 @@ DeviceManager::DeviceSetupStatus DevicePluginPhilipsHue::setupDevice(Device *dev
hueRemote->setType(device->paramValue("type").toString());
hueRemote->setUuid(device->paramValue("uuid").toString());
hueRemote->setBridgeId(DeviceId(device->paramValue("bridge").toString()));
device->setParentId(hueRemote->bridgeId());
connect(hueRemote, &HueRemote::stateChanged, this, &DevicePluginPhilipsHue::remoteStateChanged);
connect(hueRemote, &HueRemote::buttonPressed, this, &DevicePluginPhilipsHue::onRemoteButtonEvent);
device->setParentId(device->paramValue("bridge").toString());
m_remotes.insert(hueRemote, device);
return DeviceManager::DeviceSetupStatusSuccess;
}
@ -219,6 +221,12 @@ void DevicePluginPhilipsHue::deviceRemoved(Device *device)
light->deleteLater();
}
if (device->deviceClassId() == hueRemoteDeviceClassId) {
HueRemote *remote = m_remotes.key(device);
m_remotes.remove(remote);
remote->deleteLater();
}
if (myDevices().isEmpty())
m_timer->stop();
}
@ -323,7 +331,7 @@ void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
// check HTTP status code
if (status != 200) {
qCWarning(dcPhilipsHue) << "Bridge light discovery error:" << status << reply->errorString();
onBridgeError(device);
bridgeReachableChanged(device, false);
reply->deleteLater();
return;
}
@ -335,7 +343,7 @@ void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
// check HTTP status code
if (status != 200) {
qCWarning(dcPhilipsHue) << "Bridge sensor discovery error:" << status << reply->errorString();
onBridgeError(device);
bridgeReachableChanged(device, false);
reply->deleteLater();
return;
}
@ -347,11 +355,10 @@ void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
// check HTTP status code
if (status != 200) {
qCWarning(dcPhilipsHue) << "Bridge search new devices error:" << status << reply->errorString();
onBridgeError(device);
bridgeReachableChanged(device, false);
reply->deleteLater();
return;
}
discoverBridgeDevices(m_bridges.key(device));
} else if (m_lightRefreshRequests.keys().contains(reply)) {
@ -360,7 +367,7 @@ void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
// check HTTP status code
if (status != 200) {
qCWarning(dcPhilipsHue) << "Refresh Hue Light request error:" << status << reply->errorString();
onBridgeError(device);
bridgeReachableChanged(device, false);
reply->deleteLater();
return;
}
@ -372,8 +379,8 @@ void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
// check HTTP status code
if (status != 200) {
if (device->stateValue(bridgeReachableStateTypeId).toBool()) {
qCWarning(dcPhilipsHue) << "Refresh Hue Bridge request error:" << status << reply->errorString();
onBridgeError(device);
qCWarning(dcPhilipsHue) << "Refresh Hue lights request error:" << status << reply->errorString();
bridgeReachableChanged(device, false);
}
reply->deleteLater();
return;
@ -381,13 +388,13 @@ void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
processLightsRefreshResponse(device, reply->readAll());
} else if (m_sensorsRefreshRequests.keys().contains(reply)) {
Device *device = m_lightsRefreshRequests.take(reply);
Device *device = m_sensorsRefreshRequests.take(reply);
// check HTTP status code
if (status != 200) {
if (device->stateValue(bridgeReachableStateTypeId).toBool()) {
qCWarning(dcPhilipsHue) << "Refresh Hue Bridge request error:" << status << reply->errorString();
onBridgeError(device);
qCWarning(dcPhilipsHue) << "Refresh Hue sensors request error:" << status << reply->errorString();
bridgeReachableChanged(device, false);
}
reply->deleteLater();
return;
@ -401,7 +408,7 @@ void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
if (status != 200) {
if (device->stateValue(bridgeReachableStateTypeId).toBool()) {
qCWarning(dcPhilipsHue) << "Refresh Hue Bridge request error:" << status << reply->errorString();
onBridgeError(device);
bridgeReachableChanged(device, false);
}
reply->deleteLater();
return;
@ -414,13 +421,12 @@ void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
// check HTTP status code
if (status != 200) {
qCWarning(dcPhilipsHue) << "Execute Hue Light action request error:" << status << reply->errorString();
onBridgeError(actionInfo.first);
bridgeReachableChanged(actionInfo.first, false);
emit actionExecutionFinished(actionInfo.second, DeviceManager::DeviceErrorHardwareNotAvailable);
reply->deleteLater();
return;
}
QByteArray data = reply->readAll();
processActionResponse(actionInfo.first, actionInfo.second, data);
processActionResponse(actionInfo.first, actionInfo.second, reply->readAll());
} else if (m_lightSetNameRequests.keys().contains(reply)) {
Device *device = m_lightSetNameRequests.take(reply);
@ -428,7 +434,7 @@ void DevicePluginPhilipsHue::networkManagerReplyReady(QNetworkReply *reply)
// check HTTP status code
if (status != 200) {
qCWarning(dcPhilipsHue) << "Set name of Hue Light request error:" << status << reply->errorString();
onBridgeError(device);
bridgeReachableChanged(device, false);
reply->deleteLater();
return;
}
@ -442,12 +448,13 @@ DeviceManager::DeviceError DevicePluginPhilipsHue::executeAction(Device *device,
{
qCDebug(dcPhilipsHue) << "Execute action" << action.actionTypeId() << action.params();
// color light
if (device->deviceClassId() == hueLightDeviceClassId) {
HueLight *light = m_lights.key(device);
if (!light->reachable()) {
return DeviceManager::DeviceErrorHardwareNotAvailable;
qCWarning(dcPhilipsHue) << "Light not reachable";
qCWarning(dcPhilipsHue) << "Light" << light->name() << "not reachable";
}
if (action.actionTypeId() == huePowerActionTypeId) {
@ -478,12 +485,13 @@ DeviceManager::DeviceError DevicePluginPhilipsHue::executeAction(Device *device,
return DeviceManager::DeviceErrorActionTypeNotFound;
}
// white light
if (device->deviceClassId() == hueWhiteLightDeviceClassId) {
HueLight *light = m_lights.key(device);
if (!light->reachable()) {
return DeviceManager::DeviceErrorHardwareNotAvailable;
qCWarning(dcPhilipsHue) << "Light not reachable";
qCWarning(dcPhilipsHue) << "Light" << light->name() << "not reachable";
}
if (action.actionTypeId() == huePowerActionTypeId) {
@ -503,13 +511,12 @@ DeviceManager::DeviceError DevicePluginPhilipsHue::executeAction(Device *device,
}
if (device->deviceClassId() == hueBridgeDeviceClassId) {
HueBridge *bridge = m_bridges.key(device);
if (!device->stateValue(bridgeReachableStateTypeId).toBool()) {
qCWarning(dcPhilipsHue) << "Bridge not reachable";
qCWarning(dcPhilipsHue) << "Bridge" << bridge->hostAddress().toString() << "not reachable";
return DeviceManager::DeviceErrorHardwareNotAvailable;
}
HueBridge *bridge = m_bridges.key(device);
if (action.actionTypeId() == searchNewDevicesActionTypeId) {
searchNewDevices(bridge);
return DeviceManager::DeviceErrorNoError;
@ -532,6 +539,7 @@ void DevicePluginPhilipsHue::lightStateChanged()
qCWarning(dcPhilipsHue) << "Could not find device for light" << light->name();
return;
}
if (device->deviceClassId() == hueLightDeviceClassId) {
device->setStateValue(hueReachableStateTypeId, light->reachable());
device->setStateValue(hueColorStateTypeId, QVariant::fromValue(light->color()));
@ -560,18 +568,44 @@ void DevicePluginPhilipsHue::remoteStateChanged()
device->setStateValue(batteryStateTypeId, remote->battery());
}
void DevicePluginPhilipsHue::onRemoteButtonEvent(const int &buttonCode)
{
HueRemote *remote = static_cast<HueRemote *>(sender());
switch (buttonCode) {
case HueRemote::OnPressed:
emitEvent(Event(onPressedEventTypeId, m_remotes.value(remote)->id()));
break;
case HueRemote::OnLongPressed:
emitEvent(Event(onLongPressedEventTypeId, m_remotes.value(remote)->id()));
break;
case HueRemote::DimUpPressed:
emitEvent(Event(dimUpPressedEventTypeId, m_remotes.value(remote)->id()));
break;
case HueRemote::DimUpLongPressed:
emitEvent(Event(dimUpLongPressedEventTypeId, m_remotes.value(remote)->id()));
break;
case HueRemote::DimDownPressed:
emitEvent(Event(dimDownPressedEventTypeId, m_remotes.value(remote)->id()));
break;
case HueRemote::DimDownLongPressed:
emitEvent(Event(dimDownLongPressedEventTypeId, m_remotes.value(remote)->id()));
break;
case HueRemote::OffPressed:
emitEvent(Event(offPressedEventTypeId, m_remotes.value(remote)->id()));
break;
case HueRemote::OffLongPressed:
emitEvent(Event(offLongPressedEventTypeId, m_remotes.value(remote)->id()));
break;
default:
break;
}
}
void DevicePluginPhilipsHue::onTimeout()
{
foreach (Device *device, m_bridges.values()) {
HueBridge *bridge = m_bridges.key(device);
// if (!device->stateValue(hueReachableStateTypeId).toBool()) {
// if (!m_bridgeRefreshRequests.values().contains(device))
// refreshBridge(device);
// } else {
refreshBridge(device);
refreshLights(bridge);
//refreshSensors(bridge);
// }
refreshBridge(device);
}
}
@ -678,7 +712,7 @@ void DevicePluginPhilipsHue::processNUpnpResponse(const QByteArray &data)
params.append(Param("host address", bridgeMap.value("internalipaddress").toString()));
params.append(Param("api key", QString()));
params.append(Param("mac address", QString()));
params.append(Param("id", bridgeMap.value("id").toString().toLower()));
params.append(Param("id", bridgeMap.value("internalipaddress").toString().toLower()));
params.append(Param("zigbee channel", -1));
descriptor.setParams(params);
deviceDescriptors.append(descriptor);
@ -784,9 +818,8 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
return;
}
// create Lights if not already added
// create sensors if not already added
QList<DeviceDescriptor> sensorDescriptors;
QVariantMap sensorsMap = jsonDoc.toVariant().toMap();
foreach (QString sensorId, sensorsMap.keys()) {
QVariantMap sensorMap = sensorsMap.value(sensorId).toMap();
@ -798,7 +831,7 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
continue;
// check if this is a white light
if (model == "RWL021") {
if (model == "RWL021" || model == "RWL020") {
DeviceDescriptor descriptor(hueRemoteDeviceClassId, "Philips Hue Remote", sensorMap.value("name").toString());
ParamList params;
params.append(Param("name", sensorMap.value("name").toString()));
@ -814,7 +847,10 @@ void DevicePluginPhilipsHue::processBridgeSensorDiscoveryResponse(Device *device
qCDebug(dcPhilipsHue) << "Found new remote" << sensorMap.value("name").toString() << model;
}
}
emit autoDevicesAppeared(hueRemoteDeviceClassId, sensorDescriptors);
if (!sensorDescriptors.isEmpty())
emit autoDevicesAppeared(hueRemoteDeviceClassId, sensorDescriptors);
}
void DevicePluginPhilipsHue::processLightRefreshResponse(Device *device, const QByteArray &data)
@ -855,14 +891,14 @@ void DevicePluginPhilipsHue::processBridgeRefreshResponse(Device *device, const
if (!jsonDoc.toVariant().toList().isEmpty()) {
qCWarning(dcPhilipsHue) << "Failed to refresh Hue Bridge:" << jsonDoc.toVariant().toList().first().toMap().value("error").toMap().value("description").toString();
onBridgeError(device);
bridgeReachableChanged(device, false);
return;
}
QVariantMap configMap = jsonDoc.toVariant().toMap();
// mark bridge as reachable
device->setStateValue(bridgeReachableStateTypeId, true);
bridgeReachableChanged(device, true);
device->setStateValue(apiVersionStateTypeId, configMap.value("apiversion").toString());
device->setStateValue(softwareVersionStateTypeId, configMap.value("swversion").toString());
@ -883,6 +919,15 @@ void DevicePluginPhilipsHue::processBridgeRefreshResponse(Device *device, const
default:
break;
}
// do lights/sensor update right after successfull bridge update
HueBridge *bridge = m_bridges.key(device);
refreshLights(bridge);
if (!m_remotes.isEmpty())
refreshSensors(bridge);
}
void DevicePluginPhilipsHue::processLightsRefreshResponse(Device *device, const QByteArray &data)
@ -939,15 +984,12 @@ void DevicePluginPhilipsHue::processSensorsRefreshResponse(Device *device, const
// Update sensor states
QVariantMap sensorsMap = jsonDoc.toVariant().toMap();
qCDebug(dcPhilipsHue) << sensorsMap;
foreach (const QString &sensorId, sensorsMap.keys()) {
QVariantMap sensorMap = sensorsMap.value(sensorId).toMap();
foreach (HueRemote *remote, m_remotes.keys()) {
if (remote->id() == sensorId.toInt() && remote->bridgeId() == device->id()) {
qCDebug(dcPhilipsHue) << "update remote" << remote->id() << remote->name();
remote->updateStates(sensorMap.value("state").toMap());
//qCDebug(dcPhilipsHue) << "update remote" << remote->id() << remote->name();
remote->updateStates(sensorMap.value("state").toMap(), sensorMap.value("config").toMap());
}
}
}
@ -1061,6 +1103,13 @@ void DevicePluginPhilipsHue::processInformationResponse(PairingInfo *pairingInfo
bridge->setName(response.value("name").toString());
bridge->setZigbeeChannel(response.value("zigbeechannel").toInt());
if (bridgeAlreadyAdded(bridge->id())) {
qCWarning(dcPhilipsHue) << "Bridge with id" << bridge->id() << "already added.";
emit pairingFinished(pairingInfo->pairingTransactionId(), DeviceManager::DeviceSetupStatusFailure);
bridge->deleteLater();
pairingInfo->deleteLater();
}
m_unconfiguredBridges.append(bridge);
emit pairingFinished(pairingInfo->pairingTransactionId(), DeviceManager::DeviceSetupStatusSuccess);
@ -1096,18 +1145,31 @@ void DevicePluginPhilipsHue::processActionResponse(Device *device, const ActionI
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorNoError);
}
void DevicePluginPhilipsHue::onBridgeError(Device *device)
void DevicePluginPhilipsHue::bridgeReachableChanged(Device *device, const bool &reachable)
{
// mark bridge and lamps unreachable
if (device->deviceClassId() == hueBridgeDeviceClassId) {
device->setStateValue(bridgeReachableStateTypeId, false);
foreach (HueLight *light, m_lights.keys()) {
if (light->bridgeId() == device->id()) {
light->setReachable(false);
device->setStateValue(hueReachableStateTypeId, false);
if (reachable) {
device->setStateValue(bridgeReachableStateTypeId, true);
} else {
// mark bridge and corresponding hue devices unreachable
if (device->deviceClassId() == hueBridgeDeviceClassId) {
device->setStateValue(bridgeReachableStateTypeId, false);
foreach (HueLight *light, m_lights.keys()) {
if (light->bridgeId() == device->id()) {
light->setReachable(false);
m_lights.value(light)->setStateValue(hueReachableStateTypeId, false);
}
}
foreach (HueRemote *remote, m_remotes.keys()) {
if (remote->bridgeId() == device->id()) {
remote->setReachable(false);
m_remotes.value(remote)->setStateValue(hueReachableStateTypeId, false);
}
}
}
}
}
bool DevicePluginPhilipsHue::bridgeAlreadyAdded(const QString &id)

View File

@ -58,6 +58,7 @@ public slots:
private slots:
void lightStateChanged();
void remoteStateChanged();
void onRemoteButtonEvent(const int &buttonCode);
void onTimeout();
private:
@ -108,7 +109,7 @@ private:
void processInformationResponse(PairingInfo *pairingInfo, const QByteArray &data);
void processActionResponse(Device *device, const ActionId actionId, const QByteArray &data);
void onBridgeError(Device *device);
void bridgeReachableChanged(Device *device, const bool &reachable);
bool bridgeAlreadyAdded(const QString &id);
bool lightAlreadyAdded(const QString &uuid);

View File

@ -399,23 +399,43 @@
"eventTypes": [
{
"id": "de769db0-4c31-46cf-9760-dbc6f9209c26",
"idName": "onButton",
"name": "on"
"idName": "onPressed",
"name": "on pressed"
},
{
"id": "6c5e596b-7c15-40bb-af9d-c778a6b0f30e",
"idName": "onLongPressed",
"name": "on long pressed"
},
{
"id": "8e3d6a62-6a19-4e9a-a25b-e1da2e56ede9",
"idName": "brightnessUpButton",
"name": "brightness up"
"idName": "dimUpPressed",
"name": "dim up pressed"
},
{
"id": "53d3c9af-3e25-4116-b22b-38d897bc20aa",
"idName": "dimUpLongPressed",
"name": "dim up long pressed"
},
{
"id": "efd8b972-9a37-43f2-b9bc-f9dfe144a96d",
"idName": "brightnessDownButton",
"name": "brightness down"
"idName": "dimDownPressed",
"name": "dim down pressed"
},
{
"id": "1986d4c6-4c9f-4e43-ba70-0ff06c6f177b",
"idName": "dimDownLongPressed",
"name": "dim down long pressed"
},
{
"id": "7c2a58f1-137c-4bf3-8f9e-453dff020487",
"idName": "offButton",
"name": "off"
"idName": "offPressed",
"name": "off pressed"
},
{
"id": "d69306eb-ea52-4841-9e26-89c69e9cf6fc",
"idName": "offLongPressed",
"name": "off long pressed"
}
]
}

View File

@ -36,12 +36,21 @@ void HueRemote::setBattery(const int &battery)
m_battery = battery;
}
void HueRemote::updateStates(const QVariantMap &statesMap)
void HueRemote::updateStates(const QVariantMap &statesMap, const QVariantMap &configMap)
{
qCDebug(dcPhilipsHue) << statesMap;
setReachable(configMap.value("reachable", false).toBool());
setBattery(configMap.value("battery", 0).toInt());
emit stateChanged();
QString lastUpdate = statesMap.value("lastupdated").toString();
if (m_lastUpdate != lastUpdate) {
m_lastUpdate = lastUpdate;
int buttonCode = statesMap.value("buttonevent").toInt();
qCDebug(dcPhilipsHue) << "button pressed" << buttonCode;
emit buttonPressed(buttonCode);
}
}

View File

@ -34,24 +34,32 @@ class HueRemote : public HueDevice
{
Q_OBJECT
public:
enum ButtonCode {
OnLongPressed = 1001,
OnPressed = 1002,
DimUpLongPressed = 2001,
DimUpPressed = 2002,
DimDownLongPressed = 3001,
DimDownPressed = 3002,
OffLongPressed = 4001,
OffPressed = 4002
};
explicit HueRemote(QObject *parent = 0);
int battery() const;
void setBattery(const int &battery);
void updateStates(const QVariantMap &statesMap);
void updateStates(const QVariantMap &statesMap, const QVariantMap &configMap);
private:
int m_battery;
QString m_lastUpdate;
signals:
void stateChanged();
void onPressed();
void brightnessUpPressed();
void brightnessDownPressed();
void offPressed();
void buttonPressed(const int &buttonCode);
public slots:
};
#endif // HUEREMOTE_H