From 42552690a09ce5452f916ca4d08f02f332e6b463 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 23 Jan 2021 15:06:13 +0100 Subject: [PATCH 1/2] Tasmota: Add support for the gneric I/O mechanism --- tasmota/integrationplugintasmota.cpp | 107 ++++++++++++++++++------- tasmota/integrationplugintasmota.json | 110 ++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 30 deletions(-) diff --git a/tasmota/integrationplugintasmota.cpp b/tasmota/integrationplugintasmota.cpp index 801b3603..5a477e2a 100644 --- a/tasmota/integrationplugintasmota.cpp +++ b/tasmota/integrationplugintasmota.cpp @@ -41,6 +41,31 @@ #include "network/mqtt/mqttprovider.h" #include "network/mqtt/mqttchannel.h" +static QHash sonoff_basicPowerStateTypeIds = { + {"POWER1", sonoff_basicPowerStateTypeId}, +}; +static QHash sonoff_dualPowerStateTypeIds = { + {"POWER1", sonoff_dualPowerCH1StateTypeId}, + {"POWER2", sonoff_dualPowerCH2StateTypeId}, +}; +static QHash sonoff_triPowerStateTypeIds = { + {"POWER1", sonoff_triPowerCH1StateTypeId}, + {"POWER2", sonoff_triPowerCH2StateTypeId}, + {"POWER3", sonoff_triPowerCH3StateTypeId}, +}; +static QHash sonoff_quadPowerStateTypeIds = { + {"POWER1", sonoff_quadPowerCH1StateTypeId}, + {"POWER2", sonoff_quadPowerCH2StateTypeId}, + {"POWER3", sonoff_quadPowerCH3StateTypeId}, + {"POWER4", sonoff_quadPowerCH4StateTypeId}, +}; +static QHash> stateMaps = { + {sonoff_basicThingClassId, sonoff_basicPowerStateTypeIds}, + {sonoff_dualThingClassId, sonoff_dualPowerStateTypeIds}, + {sonoff_triThingClassId, sonoff_triPowerStateTypeIds}, + {sonoff_quadThingClassId, sonoff_quadPowerStateTypeIds}, +}; + IntegrationPluginTasmota::IntegrationPluginTasmota() { // Helper maps for parent devices (aka sonoff_*) @@ -257,6 +282,25 @@ void IntegrationPluginTasmota::executeAction(ThingActionInfo *info) Thing *thing = info->thing(); Action action = info->action(); + if (thing->thingClassId() == sonoff_basicThingClassId + || thing->thingClassId() == sonoff_dualThingClassId + || thing->thingClassId() == sonoff_triThingClassId + || thing->thingClassId() == sonoff_quadThingClassId) { + MqttChannel *channel = m_mqttChannels.value(thing); + if (!channel) { + qCWarning(dcTasmota()) << "No MQTT channel for this thing."; + info->finish(Thing::ThingErrorHardwareNotAvailable); + return; + } + QString channelName = stateMaps.value(thing->thingClassId()).key(action.actionTypeId()); + qCDebug(dcTasmota) << "Publishing:" << channel->topicPrefixList().first() + "/sonoff/cmnd/" + channelName << (action.paramValue(action.actionTypeId()).toBool() ? "ON" : "OFF"); + channel->publish(channel->topicPrefixList().first() + "/sonoff/cmnd/" + channelName, action.paramValue(action.actionTypeId()).toBool() ? "ON" : "OFF"); + thing->setStateValue(action.actionTypeId(), action.paramValue(action.actionTypeId())); + info->finish(Thing::ThingErrorNoError); + return; + } + + // Legacy (deprecated) connected devices if (m_powerStateTypeMap.contains(thing->thingClassId())) { Thing *parentDev = myThings().findById(thing->parentId()); MqttChannel *channel = m_mqttChannels.value(parentDev); @@ -331,40 +375,43 @@ void IntegrationPluginTasmota::onPublishReceived(MqttChannel *channel, const QSt { qCDebug(dcTasmota) << "Publish received from Sonoff thing:" << topic << qUtf8Printable(payload); Thing *thing = m_mqttChannels.key(channel); - if (m_ipAddressParamTypeMap.contains(thing->thingClassId())) { - if (topic.startsWith(channel->topicPrefixList().first() + "/sonoff/POWER")) { - QString channelName = topic.split("/").last(); + if (topic.startsWith(channel->topicPrefixList().first() + "/sonoff/POWER")) { + QString channelName = topic.split("/").last(); - foreach (Thing *child, myThings().filterByParentId(thing->id())) { - if (child->paramValue(m_channelParamTypeMap.value(child->thingClassId())).toString() != channelName) { - continue; - } - if (m_powerStateTypeMap.contains(child->thingClassId())) { - child->setStateValue(m_powerStateTypeMap.value(child->thingClassId()), payload == "ON"); - } - if (child->thingClassId() == tasmotaSwitchThingClassId) { - Event event(tasmotaSwitchPressedEventTypeId, child->id()); - emit emitEvent(event); - } + thing->setStateValue(stateMaps.value(thing->thingClassId()).value(channelName), payload == "ON"); + + // Legacy (deprecated) connected things via params + foreach (Thing *child, myThings().filterByParentId(thing->id())) { + if (child->paramValue(m_channelParamTypeMap.value(child->thingClassId())).toString() != channelName) { + continue; + } + if (m_powerStateTypeMap.contains(child->thingClassId())) { + child->setStateValue(m_powerStateTypeMap.value(child->thingClassId()), payload == "ON"); + } + if (child->thingClassId() == tasmotaSwitchThingClassId) { + Event event(tasmotaSwitchPressedEventTypeId, child->id()); + emit emitEvent(event); } } - if (topic.startsWith(channel->topicPrefixList().first() + "/sonoff/STATE")) { - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(payload, &error); - if (error.error != QJsonParseError::NoError) { - qCWarning(dcTasmota) << "Cannot parse JSON from Tasmota device" << error.errorString(); - return; - } - QVariantMap dataMap = jsonDoc.toVariant().toMap(); - thing->setStateValue(m_signalStrengthStateTypeMap.value(thing->thingClassId()), dataMap.value("Wifi").toMap().value("RSSI").toInt()); - foreach (Thing *child, myThings().filterByParentId(thing->id())) { - if (m_powerStateTypeMap.contains(child->thingClassId())) { - QString childChannel = child->paramValue(m_channelParamTypeMap.value(child->thingClassId())).toString(); - QString valueString = jsonDoc.toVariant().toMap().value(childChannel).toString(); - child->setStateValue(m_powerStateTypeMap.value(child->thingClassId()), valueString == "ON"); - } - child->setStateValue(m_signalStrengthStateTypeMap.value(child->thingClassId()), dataMap.value("Wifi").toMap().value("RSSI").toInt()); + } + if (topic.startsWith(channel->topicPrefixList().first() + "/sonoff/STATE")) { + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(payload, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcTasmota) << "Cannot parse JSON from Tasmota device" << error.errorString(); + return; + } + QVariantMap dataMap = jsonDoc.toVariant().toMap(); + thing->setStateValue(m_signalStrengthStateTypeMap.value(thing->thingClassId()), dataMap.value("Wifi").toMap().value("RSSI").toInt()); + + // Legacy (deprecated) connected things by params + foreach (Thing *child, myThings().filterByParentId(thing->id())) { + if (m_powerStateTypeMap.contains(child->thingClassId())) { + QString childChannel = child->paramValue(m_channelParamTypeMap.value(child->thingClassId())).toString(); + QString valueString = jsonDoc.toVariant().toMap().value(childChannel).toString(); + child->setStateValue(m_powerStateTypeMap.value(child->thingClassId()), valueString == "ON"); } + child->setStateValue(m_signalStrengthStateTypeMap.value(child->thingClassId()), dataMap.value("Wifi").toMap().value("RSSI").toInt()); } } } diff --git a/tasmota/integrationplugintasmota.json b/tasmota/integrationplugintasmota.json index a0a7854e..3899c872 100644 --- a/tasmota/integrationplugintasmota.json +++ b/tasmota/integrationplugintasmota.json @@ -50,6 +50,17 @@ "minValue": 0, "maxValue": 100, "defaultValue": -1 + }, + { + "id": "0b5a48c9-73b8-42ab-9909-71b8dc2227e3", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power changed", + "displayNameAction": "Set power", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" } ] }, @@ -103,6 +114,28 @@ "minValue": 0, "maxValue": 100, "defaultValue": 100 + }, + { + "id": "b8bf3085-8061-4cd6-af1f-f76a03054f46", + "name": "powerCH1", + "displayName": "Power channel 1", + "displayNameEvent": "Power channel 1 changed", + "displayNameAction": "Set power channel 1", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" + }, + { + "id": "4fbcaeb6-9242-4aa6-b462-a214fb38bcc9", + "name": "powerCH2", + "displayName": "Power channel 2", + "displayNameEvent": "Power channel 2 changed", + "displayNameAction": "Set power channel 2", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" } ] }, @@ -164,6 +197,39 @@ "minValue": 0, "maxValue": 100, "defaultValue": 100 + }, + { + "id": "27bdb42d-ef95-4905-ac3d-925bcc8a1ba1", + "name": "powerCH1", + "displayName": "Power channel 1", + "displayNameEvent": "Power channel 1 changed", + "displayNameAction": "Set power channel 1", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" + }, + { + "id": "705d8277-896a-4d56-b9ff-0a614ecfd39c", + "name": "powerCH2", + "displayName": "Power channel 2", + "displayNameEvent": "Power channel 2 changed", + "displayNameAction": "Set power channel 2", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" + }, + { + "id": "156f285d-e474-43d9-9a9d-17b3bcaef893", + "name": "powerCH3", + "displayName": "Power channel 3", + "displayNameEvent": "Power channel 3 changed", + "displayNameAction": "Set power channel 3", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" } ] }, @@ -233,6 +299,50 @@ "minValue": 0, "maxValue": 100, "defaultValue": 100 + }, + { + "id": "e8fd95c3-2323-40d8-89cf-40e0068977d8", + "name": "powerCH1", + "displayName": "Power channel 1", + "displayNameEvent": "Power channel 1 changed", + "displayNameAction": "Set power channel 1", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" + }, + { + "id": "baf0ca62-7f09-45ea-aea1-6de34764e6cb", + "name": "powerCH2", + "displayName": "Power channel 2", + "displayNameEvent": "Power channel 2 changed", + "displayNameAction": "Set power channel 2", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" + }, + { + "id": "8b939d15-3e45-40aa-bb53-9b3fb47f3cb3", + "name": "powerCH3", + "displayName": "Power channel 3", + "displayNameEvent": "Power channel 3 changed", + "displayNameAction": "Set power channel 3", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" + }, + { + "id": "4060baa0-2b11-4905-908c-b6f1c3b6a892", + "name": "powerCH4", + "displayName": "Power channel 4", + "displayNameEvent": "Power channel 4 changed", + "displayNameAction": "Set power channel 4", + "type": "bool", + "writable": true, + "defaultValue": false, + "ioType": "digitalOutput" } ] }, From e09f582d8e82430c652275e7a2923a8dc1bdd077 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sun, 14 Feb 2021 14:49:40 +0100 Subject: [PATCH 2/2] update translations --- ...6e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts | 142 +++++++++++++++++- 1 file changed, 139 insertions(+), 3 deletions(-) diff --git a/tasmota/translations/d136e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts b/tasmota/translations/d136e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts index 4661d59b..87df13a2 100644 --- a/tasmota/translations/d136e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts +++ b/tasmota/translations/d136e0c0-0cbf-4731-aabb-b2201088d6cb-en_US.ts @@ -157,7 +157,9 @@ The name of the ParamType (ThingClass: tasmotaSwitch, Type: thing, ID: {564cf6c6 Power changed The name of the EventType ({88dbdf8e-45ff-466f-8352-8654a6b5fe68}) of ThingClass tasmotaLight ---------- -The name of the EventType ({413503d7-fc9f-417a-95fa-5c350a6f69f9}) of ThingClass tasmotaSwitch +The name of the EventType ({413503d7-fc9f-417a-95fa-5c350a6f69f9}) of ThingClass tasmotaSwitch +---------- +The name of the EventType ({0b5a48c9-73b8-42ab-9909-71b8dc2227e3}) of ThingClass sonoff_basic @@ -172,14 +174,22 @@ The name of the ParamType (ThingClass: tasmotaSwitch, ActionType: power, ID: {41 ---------- The name of the ParamType (ThingClass: tasmotaSwitch, EventType: power, ID: {413503d7-fc9f-417a-95fa-5c350a6f69f9}) ---------- -The name of the StateType ({413503d7-fc9f-417a-95fa-5c350a6f69f9}) of ThingClass tasmotaSwitch +The name of the StateType ({413503d7-fc9f-417a-95fa-5c350a6f69f9}) of ThingClass tasmotaSwitch +---------- +The name of the ParamType (ThingClass: sonoff_basic, ActionType: power, ID: {0b5a48c9-73b8-42ab-9909-71b8dc2227e3}) +---------- +The name of the ParamType (ThingClass: sonoff_basic, EventType: power, ID: {0b5a48c9-73b8-42ab-9909-71b8dc2227e3}) +---------- +The name of the StateType ({0b5a48c9-73b8-42ab-9909-71b8dc2227e3}) of ThingClass sonoff_basic Set power The name of the ActionType ({88dbdf8e-45ff-466f-8352-8654a6b5fe68}) of ThingClass tasmotaLight ---------- -The name of the ActionType ({413503d7-fc9f-417a-95fa-5c350a6f69f9}) of ThingClass tasmotaSwitch +The name of the ActionType ({413503d7-fc9f-417a-95fa-5c350a6f69f9}) of ThingClass tasmotaSwitch +---------- +The name of the ActionType ({0b5a48c9-73b8-42ab-9909-71b8dc2227e3}) of ThingClass sonoff_basic @@ -301,5 +311,131 @@ The name of the EventType ({3d6a567f-d266-4711-bcf1-3ac1f53abadb}) of ThingClass The name of the EventType ({f70e202a-c178-4fbe-a778-713220d11b23}) of ThingClass sonoff_basic + + Power channel 1 + The name of the ParamType (ThingClass: sonoff_quad, ActionType: powerCH1, ID: {e8fd95c3-2323-40d8-89cf-40e0068977d8}) +---------- +The name of the ParamType (ThingClass: sonoff_quad, EventType: powerCH1, ID: {e8fd95c3-2323-40d8-89cf-40e0068977d8}) +---------- +The name of the StateType ({e8fd95c3-2323-40d8-89cf-40e0068977d8}) of ThingClass sonoff_quad +---------- +The name of the ParamType (ThingClass: sonoff_tri, ActionType: powerCH1, ID: {27bdb42d-ef95-4905-ac3d-925bcc8a1ba1}) +---------- +The name of the ParamType (ThingClass: sonoff_tri, EventType: powerCH1, ID: {27bdb42d-ef95-4905-ac3d-925bcc8a1ba1}) +---------- +The name of the StateType ({27bdb42d-ef95-4905-ac3d-925bcc8a1ba1}) of ThingClass sonoff_tri +---------- +The name of the ParamType (ThingClass: sonoff_dual, ActionType: powerCH1, ID: {b8bf3085-8061-4cd6-af1f-f76a03054f46}) +---------- +The name of the ParamType (ThingClass: sonoff_dual, EventType: powerCH1, ID: {b8bf3085-8061-4cd6-af1f-f76a03054f46}) +---------- +The name of the StateType ({b8bf3085-8061-4cd6-af1f-f76a03054f46}) of ThingClass sonoff_dual + + + + Power channel 1 changed + The name of the EventType ({e8fd95c3-2323-40d8-89cf-40e0068977d8}) of ThingClass sonoff_quad +---------- +The name of the EventType ({27bdb42d-ef95-4905-ac3d-925bcc8a1ba1}) of ThingClass sonoff_tri +---------- +The name of the EventType ({b8bf3085-8061-4cd6-af1f-f76a03054f46}) of ThingClass sonoff_dual + + + + Power channel 2 + The name of the ParamType (ThingClass: sonoff_quad, ActionType: powerCH2, ID: {baf0ca62-7f09-45ea-aea1-6de34764e6cb}) +---------- +The name of the ParamType (ThingClass: sonoff_quad, EventType: powerCH2, ID: {baf0ca62-7f09-45ea-aea1-6de34764e6cb}) +---------- +The name of the StateType ({baf0ca62-7f09-45ea-aea1-6de34764e6cb}) of ThingClass sonoff_quad +---------- +The name of the ParamType (ThingClass: sonoff_tri, ActionType: powerCH2, ID: {705d8277-896a-4d56-b9ff-0a614ecfd39c}) +---------- +The name of the ParamType (ThingClass: sonoff_tri, EventType: powerCH2, ID: {705d8277-896a-4d56-b9ff-0a614ecfd39c}) +---------- +The name of the StateType ({705d8277-896a-4d56-b9ff-0a614ecfd39c}) of ThingClass sonoff_tri +---------- +The name of the ParamType (ThingClass: sonoff_dual, ActionType: powerCH2, ID: {4fbcaeb6-9242-4aa6-b462-a214fb38bcc9}) +---------- +The name of the ParamType (ThingClass: sonoff_dual, EventType: powerCH2, ID: {4fbcaeb6-9242-4aa6-b462-a214fb38bcc9}) +---------- +The name of the StateType ({4fbcaeb6-9242-4aa6-b462-a214fb38bcc9}) of ThingClass sonoff_dual + + + + Power channel 2 changed + The name of the EventType ({baf0ca62-7f09-45ea-aea1-6de34764e6cb}) of ThingClass sonoff_quad +---------- +The name of the EventType ({705d8277-896a-4d56-b9ff-0a614ecfd39c}) of ThingClass sonoff_tri +---------- +The name of the EventType ({4fbcaeb6-9242-4aa6-b462-a214fb38bcc9}) of ThingClass sonoff_dual + + + + Power channel 3 + The name of the ParamType (ThingClass: sonoff_quad, ActionType: powerCH3, ID: {8b939d15-3e45-40aa-bb53-9b3fb47f3cb3}) +---------- +The name of the ParamType (ThingClass: sonoff_quad, EventType: powerCH3, ID: {8b939d15-3e45-40aa-bb53-9b3fb47f3cb3}) +---------- +The name of the StateType ({8b939d15-3e45-40aa-bb53-9b3fb47f3cb3}) of ThingClass sonoff_quad +---------- +The name of the ParamType (ThingClass: sonoff_tri, ActionType: powerCH3, ID: {156f285d-e474-43d9-9a9d-17b3bcaef893}) +---------- +The name of the ParamType (ThingClass: sonoff_tri, EventType: powerCH3, ID: {156f285d-e474-43d9-9a9d-17b3bcaef893}) +---------- +The name of the StateType ({156f285d-e474-43d9-9a9d-17b3bcaef893}) of ThingClass sonoff_tri + + + + Power channel 3 changed + The name of the EventType ({8b939d15-3e45-40aa-bb53-9b3fb47f3cb3}) of ThingClass sonoff_quad +---------- +The name of the EventType ({156f285d-e474-43d9-9a9d-17b3bcaef893}) of ThingClass sonoff_tri + + + + Power channel 4 + The name of the ParamType (ThingClass: sonoff_quad, ActionType: powerCH4, ID: {4060baa0-2b11-4905-908c-b6f1c3b6a892}) +---------- +The name of the ParamType (ThingClass: sonoff_quad, EventType: powerCH4, ID: {4060baa0-2b11-4905-908c-b6f1c3b6a892}) +---------- +The name of the StateType ({4060baa0-2b11-4905-908c-b6f1c3b6a892}) of ThingClass sonoff_quad + + + + Power channel 4 changed + The name of the EventType ({4060baa0-2b11-4905-908c-b6f1c3b6a892}) of ThingClass sonoff_quad + + + + Set power channel 1 + The name of the ActionType ({e8fd95c3-2323-40d8-89cf-40e0068977d8}) of ThingClass sonoff_quad +---------- +The name of the ActionType ({27bdb42d-ef95-4905-ac3d-925bcc8a1ba1}) of ThingClass sonoff_tri +---------- +The name of the ActionType ({b8bf3085-8061-4cd6-af1f-f76a03054f46}) of ThingClass sonoff_dual + + + + Set power channel 2 + The name of the ActionType ({baf0ca62-7f09-45ea-aea1-6de34764e6cb}) of ThingClass sonoff_quad +---------- +The name of the ActionType ({705d8277-896a-4d56-b9ff-0a614ecfd39c}) of ThingClass sonoff_tri +---------- +The name of the ActionType ({4fbcaeb6-9242-4aa6-b462-a214fb38bcc9}) of ThingClass sonoff_dual + + + + Set power channel 3 + The name of the ActionType ({8b939d15-3e45-40aa-bb53-9b3fb47f3cb3}) of ThingClass sonoff_quad +---------- +The name of the ActionType ({156f285d-e474-43d9-9a9d-17b3bcaef893}) of ThingClass sonoff_tri + + + + Set power channel 4 + The name of the ActionType ({4060baa0-2b11-4905-908c-b6f1c3b6a892}) of ThingClass sonoff_quad + +