diff --git a/goecharger/integrationplugingoecharger.cpp b/goecharger/integrationplugingoecharger.cpp index 0a6c5dde..e12c4f70 100644 --- a/goecharger/integrationplugingoecharger.cpp +++ b/goecharger/integrationplugingoecharger.cpp @@ -57,12 +57,16 @@ void IntegrationPluginGoECharger::discoverThings(ThingDiscoveryInfo *info) NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover(); connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ foreach (const NetworkDevice &networkDevice, discoveryReply->networkDevices()) { + qCDebug(dcGoECharger()) << "Found" << networkDevice; + if (!networkDevice.hostName().toLower().contains("go-echarger")) + continue; + QString title; if (networkDevice.hostName().isEmpty()) { title = networkDevice.address().toString(); } else { - title = networkDevice.hostName() + " (" + networkDevice.address().toString() + ")"; + title = "go-eCharger (" + networkDevice.address().toString() + ")"; } QString description; @@ -112,7 +116,6 @@ void IntegrationPluginGoECharger::setupThing(ThingSetupInfo *info) } QByteArray data = reply->readAll(); - QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { @@ -141,11 +144,63 @@ void IntegrationPluginGoECharger::thingRemoved(Thing *thing) void IntegrationPluginGoECharger::executeAction(ThingActionInfo *info) { - //Thing *thing = info->thing(); - //Action action = info->action(); + Thing *thing = info->thing(); + Action action = info->action(); + if (thing->thingClassId() != goeHomeThingClassId) { + info->finish(Thing::ThingErrorThingClassNotFound); + return; + } - info->finish(Thing::ThingErrorNoError); + if (thing->stateValue(goeHomeConnectedStateTypeId).toBool()) { + info->finish(Thing::ThingErrorHardwareNotAvailable); + return; + } + + if (thing->stateValue(goeHomeSerialNumberStateTypeId).toString().isEmpty()) { + qCDebug(dcGoECharger()) << "Could not execute action because the serial number is missing."; + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + if (action.actionTypeId() == goeHomePowerActionTypeId) { + bool power = action.paramValue(goeHomePowerActionPowerParamTypeId).toBool(); + qCDebug(dcGoECharger()) << "Setting charging allowed to" << power; + // Set the allow value + QString configuration = QString("alw=%1").arg(power ? 1: 0); + sendActionRequest(thing, info, configuration); + return; + } else if (action.actionTypeId() == goeHomeMaxChargingCurrentActionTypeId) { + int maxChargingCurrent = action.paramValue(goeHomeMaxChargingCurrentActionMaxChargingCurrentParamTypeId).toUInt(); + qCDebug(dcGoECharger()) << "Setting max charging current to" << maxChargingCurrent << "A"; + // Set the allow value + QString configuration = QString("ama=%1").arg(maxChargingCurrent); + sendActionRequest(thing, info, configuration); + return; + } else if (action.actionTypeId() == goeHomeCloudActionTypeId) { + bool enabled = action.paramValue(goeHomeCloudActionCloudParamTypeId).toBool(); + qCDebug(dcGoECharger()) << "Set cloud" << (enabled ? "enabled" : "disabled"); + // Set the allow value + QString configuration = QString("cdi=%1").arg(enabled ? 1: 0); + sendActionRequest(thing, info, configuration); + return; + } else if (action.actionTypeId() == goeHomeLedBrightnessActionTypeId) { + quint8 brightness = action.paramValue(goeHomeLedBrightnessActionLedBrightnessParamTypeId).toUInt(); + qCDebug(dcGoECharger()) << "Set led brightnss to" << brightness << "/" << 255; + // Set the allow value + QString configuration = QString("lbr=%1").arg(brightness); + sendActionRequest(thing, info, configuration); + return; + } else if (action.actionTypeId() == goeHomeLedEnergySaveActionTypeId) { + bool enabled = action.paramValue(goeHomeLedEnergySaveActionLedEnergySaveParamTypeId).toBool(); + qCDebug(dcGoECharger()) << "Set led energy saving" << (enabled ? "enabled" : "disabled"); + // Set the allow value + QString configuration = QString("lse=%1").arg(enabled ? 1: 0); + sendActionRequest(thing, info, configuration); + return; + } else { + info->finish(Thing::ThingErrorActionTypeNotFound); + } } void IntegrationPluginGoECharger::onClientConnected(MqttChannel *channel) @@ -180,7 +235,18 @@ void IntegrationPluginGoECharger::onPublishReceived(MqttChannel *channel, const return; } - qCDebug(dcGoECharger()) << thing << "publish received" << topic << qUtf8Printable(payload); + qCDebug(dcGoECharger()) << thing << "publish received" << topic; + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(payload, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcGoECharger()) << "Failed to parse status data for thing " << thing->name() << qUtf8Printable(payload) << error.errorString(); + return; + } + + QString serialNumber = thing->stateValue(goeHomeSerialNumberStateTypeId).toString(); + if (topic == QString("go-eCharger/%1/status").arg(serialNumber)) { + update(thing, jsonDoc.toVariant().toMap()); + } } void IntegrationPluginGoECharger::update(Thing *thing, const QVariantMap &statusMap) @@ -216,13 +282,24 @@ void IntegrationPluginGoECharger::update(Thing *thing, const QVariantMap &status break; } - thing->setStateValue(goeHomeTotalEnergyStateTypeId, statusMap.value("eto").toUInt() / 10.0); + QVariantList temperatureSensorList = statusMap.value("tma").toList(); + if (temperatureSensorList.count() == 4) { + thing->setStateValue(goeHomeTemperatureSensor1StateTypeId, temperatureSensorList.at(0).toDouble()); + thing->setStateValue(goeHomeTemperatureSensor2StateTypeId, temperatureSensorList.at(1).toDouble()); + thing->setStateValue(goeHomeTemperatureSensor3StateTypeId, temperatureSensorList.at(2).toDouble()); + thing->setStateValue(goeHomeTemperatureSensor4StateTypeId, temperatureSensorList.at(3).toDouble()); + } + + thing->setStateValue(goeHomeTotalEnergyConsumedStateTypeId, statusMap.value("eto").toUInt() / 10.0); thing->setStateValue(goeHomeChargeEnergyStateTypeId, statusMap.value("dws").toUInt() / 360000.0); thing->setStateValue(goeHomePowerStateTypeId, (statusMap.value("alw").toUInt() == 0 ? false : true)); thing->setStateValue(goeHomeUpdateAvailableStateTypeId, (statusMap.value("upd").toUInt() == 0 ? false : true)); + thing->setStateValue(goeHomeAdapterConnectedStateTypeId, (statusMap.value("adi").toUInt() == 0 ? false : true)); thing->setStateValue(goeHomeCloudStateTypeId, (statusMap.value("cdi").toUInt() == 0 ? false : true)); thing->setStateValue(goeHomeFirmwareVersionStateTypeId, statusMap.value("fwv").toString()); thing->setStateValue(goeHomeMaxChargingCurrentStateTypeId, statusMap.value("ama").toUInt()); + thing->setStateValue(goeHomeLedBrightnessStateTypeId, statusMap.value("lbr").toUInt()); + thing->setStateValue(goeHomeLedEnergySaveStateTypeId, statusMap.value("lse").toBool()); thing->setStateValue(goeHomeSerialNumberStateTypeId, statusMap.value("sse").toString()); } } @@ -239,6 +316,33 @@ QNetworkRequest IntegrationPluginGoECharger::buildConfigurationRequest(const QHo return QNetworkRequest(requestUrl); } +void IntegrationPluginGoECharger::sendActionRequest(Thing *thing, ThingActionInfo *info, const QString &configuration) +{ + // Lets use rest here since we get a reply on the rest request. For using MQTT publish to topic "go-eCharger//cmd/req" + QNetworkRequest request = buildConfigurationRequest(QHostAddress(thing->paramValue(goeHomeThingIpAddressParamTypeId).toString()), configuration); + QNetworkReply *reply = hardwareManager()->networkManager()->sendCustomRequest(request, "SET"); + connect(reply, &QNetworkReply::finished, thing, [=](){ + reply->deleteLater(); + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcGoECharger()) << "HTTP status reply returned error:" << reply->errorString(); + info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("The wallbox does not seem to be reachable.")); + return; + } + + QByteArray data = reply->readAll(); + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcGoECharger()) << "Failed to parse status data for thing " << thing->name() << qUtf8Printable(data) << error.errorString(); + info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("The wallbox returned invalid data.")); + return; + } + + qCDebug(dcGoECharger()) << "Action response" << jsonDoc.toJson(QJsonDocument::Compact); + info->finish(Thing::ThingErrorNoError); + }); +} + void IntegrationPluginGoECharger::setupMqttChannel(ThingSetupInfo *info, const QHostAddress &address, const QVariantMap &statusMap) { Thing *thing = info->thing(); @@ -272,7 +376,6 @@ void IntegrationPluginGoECharger::setupMqttChannel(ThingSetupInfo *info, const Q } QByteArray data = reply->readAll(); - QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { @@ -302,7 +405,6 @@ void IntegrationPluginGoECharger::setupMqttChannel(ThingSetupInfo *info, const Q } QByteArray data = reply->readAll(); - QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { @@ -332,7 +434,6 @@ void IntegrationPluginGoECharger::setupMqttChannel(ThingSetupInfo *info, const Q } QByteArray data = reply->readAll(); - QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { @@ -362,7 +463,6 @@ void IntegrationPluginGoECharger::setupMqttChannel(ThingSetupInfo *info, const Q } QByteArray data = reply->readAll(); - QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { @@ -392,7 +492,6 @@ void IntegrationPluginGoECharger::setupMqttChannel(ThingSetupInfo *info, const Q } QByteArray data = reply->readAll(); - QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { diff --git a/goecharger/integrationplugingoecharger.h b/goecharger/integrationplugingoecharger.h index e0e1c6ca..f5cc8dff 100644 --- a/goecharger/integrationplugingoecharger.h +++ b/goecharger/integrationplugingoecharger.h @@ -89,8 +89,10 @@ private: void update(Thing *thing, const QVariantMap &statusMap); QNetworkRequest buildConfigurationRequest(const QHostAddress &address, const QString &configuration); + void sendActionRequest(Thing *thing, ThingActionInfo *info, const QString &configuration); void setupMqttChannel(ThingSetupInfo *info, const QHostAddress &address, const QVariantMap &statusMap); + private slots: void onClientConnected(MqttChannel* channel); void onClientDisconnected(MqttChannel* channel); diff --git a/goecharger/integrationplugingoecharger.json b/goecharger/integrationplugingoecharger.json index a0f5eee1..62f86c99 100644 --- a/goecharger/integrationplugingoecharger.json +++ b/goecharger/integrationplugingoecharger.json @@ -13,7 +13,7 @@ "displayName": "go-eCharger Home", "id": "3b663d51-fdb5-4944-b409-c07f7933877e", "createMethods": ["Discovery", "User"], - "interfaces": ["evcharger", "connectable"], + "interfaces": ["evcharger", "smartmeter", "connectable"], "paramTypes": [ { "id": "4342b72c-99d0-41a5-abc6-ea6c1cc1352c", @@ -68,10 +68,10 @@ { "id": "8a7ab9f1-0143-494c-98ee-69f94125fe42", "name": "power", - "displayName": "Charging", + "displayName": "Allow charging", "type": "bool", - "displayNameAction": "Start charging", - "displayNameEvent": "Charging status changed", + "displayNameAction": "Allow charging", + "displayNameEvent": "Allow charging changed", "defaultValue": false, "writable": true }, @@ -106,9 +106,17 @@ "type": "bool", "defaultValue": false }, + { + "id": "d557e59e-ca22-4aff-bf80-dfee44db0f69", + "name": "adapterConnected", + "displayName": "Adapter connected", + "displayNameEvent": "Adapter connected changed", + "type": "bool", + "defaultValue": false + }, { "id": "d8f5abb6-5db3-4040-8829-553b1d881ce4", - "name": "totalEnergy", + "name": "totalEnergyConsumed", "displayName": "Total energy", "displayNameEvent": "Total energy changed", "type": "double", @@ -128,11 +136,59 @@ "id": "b06479d5-7a38-4fbd-867e-e55bdb54651b", "name": "ledBrightness", "displayName": "Led brightness", + "displayNameAction": "Set led brightness", "displayNameEvent": "Led brightness changed", "type": "int", "minValue": 0, "maxValue": 255, - "defaultValue": 255 + "defaultValue": 255, + "writable": true + }, + { + "id": "048a4c98-3ee4-4d02-ad48-6d70f31fce8c", + "name": "ledEnergySave", + "displayName": "Led energy saving enabled", + "displayNameAction": "Set led energy saving enabled", + "displayNameEvent": "Led energy saving enabled enabled changed", + "type": "bool", + "defaultValue": true, + "writable": true + }, + { + "id": "2bf1ebf1-0d8c-4209-ad35-4114d9861832", + "name": "temperatureSensor1", + "displayName": "Temperature 1", + "displayNameEvent": "Temperature 1 changed", + "type": "double", + "unit": "DegreeCelsius", + "defaultValue": 0.0 + }, + { + "id": "558e273a-4028-495a-902a-e4e932a0ae24", + "name": "temperatureSensor2", + "displayName": "Temperature 2", + "displayNameEvent": "Temperature 2 changed", + "type": "double", + "unit": "DegreeCelsius", + "defaultValue": 0.0 + }, + { + "id": "dbf8a5dc-b8f5-437a-ac0c-c4cf8a09aacb", + "name": "temperatureSensor3", + "displayName": "Temperature 3", + "displayNameEvent": "Temperature 3 changed", + "type": "double", + "unit": "DegreeCelsius", + "defaultValue": 0.0 + }, + { + "id": "1953e29f-fe28-4016-9b05-f4baf4c311ff", + "name": "temperatureSensor4", + "displayName": "Temperature 4", + "displayNameEvent": "Temperature 4 changed", + "type": "double", + "unit": "DegreeCelsius", + "defaultValue": 0.0 }, { "id": "5d18b48d-b886-409e-ab2e-336d9c94a55c", @@ -140,7 +196,8 @@ "displayName": "Firmware version", "displayNameEvent": "Firmware version changed", "type": "QString", - "defaultValue": "" + "defaultValue": "", + "cached": true }, { "id": "8ecdf24b-daca-4b7a-98b5-3236f1e6ad85", @@ -148,7 +205,8 @@ "displayName": "Serial number", "displayNameEvent": "Serial number changed", "type": "QString", - "defaultValue": "" + "defaultValue": "", + "cached": true } ] }