Merge PR #380: Tasmota: Add support for the gneric I/O mechanism

This commit is contained in:
Jenkins nymea 2021-02-26 10:27:57 +01:00
commit 0b0483eefb
3 changed files with 326 additions and 33 deletions

View File

@ -41,6 +41,31 @@
#include "network/mqtt/mqttprovider.h"
#include "network/mqtt/mqttchannel.h"
static QHash<QString, StateTypeId> sonoff_basicPowerStateTypeIds = {
{"POWER1", sonoff_basicPowerStateTypeId},
};
static QHash<QString, StateTypeId> sonoff_dualPowerStateTypeIds = {
{"POWER1", sonoff_dualPowerCH1StateTypeId},
{"POWER2", sonoff_dualPowerCH2StateTypeId},
};
static QHash<QString, StateTypeId> sonoff_triPowerStateTypeIds = {
{"POWER1", sonoff_triPowerCH1StateTypeId},
{"POWER2", sonoff_triPowerCH2StateTypeId},
{"POWER3", sonoff_triPowerCH3StateTypeId},
};
static QHash<QString, StateTypeId> sonoff_quadPowerStateTypeIds = {
{"POWER1", sonoff_quadPowerCH1StateTypeId},
{"POWER2", sonoff_quadPowerCH2StateTypeId},
{"POWER3", sonoff_quadPowerCH3StateTypeId},
{"POWER4", sonoff_quadPowerCH4StateTypeId},
};
static QHash<ThingClassId, QHash<QString, StateTypeId>> 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());
}
}
}

View File

@ -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"
}
]
},

View File

@ -157,7 +157,9 @@ The name of the ParamType (ThingClass: tasmotaSwitch, Type: thing, ID: {564cf6c6
<source>Power changed</source>
<extracomment>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</extracomment>
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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@ -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</extracomment>
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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set power</source>
<extracomment>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</extracomment>
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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@ -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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power channel 1</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power channel 1 changed</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power channel 2</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power channel 2 changed</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power channel 3</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power channel 3 changed</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power channel 4</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power channel 4 changed</source>
<extracomment>The name of the EventType ({4060baa0-2b11-4905-908c-b6f1c3b6a892}) of ThingClass sonoff_quad</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set power channel 1</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set power channel 2</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set power channel 3</source>
<extracomment>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</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set power channel 4</source>
<extracomment>The name of the ActionType ({4060baa0-2b11-4905-908c-b6f1c3b6a892}) of ThingClass sonoff_quad</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
</TS>