SonoffTasmota: Fix Tasmota device setup web command and add support for Shutters on 2CH switches
This commit is contained in:
parent
37fff92942
commit
765b2c6c75
@ -81,16 +81,20 @@ DevicePluginTasmota::DevicePluginTasmota()
|
||||
// Helper maps for virtual childs (aka tasmota*)
|
||||
m_channelParamTypeMap[tasmotaSwitchDeviceClassId] = tasmotaSwitchDeviceChannelNameParamTypeId;
|
||||
m_channelParamTypeMap[tasmotaLightDeviceClassId] = tasmotaLightDeviceChannelNameParamTypeId;
|
||||
m_openingChannelParamTypeMap[tasmotaShutterDeviceClassId] = tasmotaShutterDeviceOpeningChannelParamTypeId;
|
||||
m_closingChannelParamTypeMap[tasmotaShutterDeviceClassId] = tasmotaShutterDeviceClosingChannelParamTypeId;
|
||||
|
||||
m_powerStateTypeMap[tasmotaSwitchDeviceClassId] = tasmotaSwitchPowerStateTypeId;
|
||||
m_powerStateTypeMap[tasmotaLightDeviceClassId] = tasmotaLightPowerStateTypeId;
|
||||
|
||||
|
||||
// Helper maps for all devices
|
||||
m_connectedStateTypeMap[sonoff_basicDeviceClassId] = sonoff_basicConnectedStateTypeId;
|
||||
m_connectedStateTypeMap[sonoff_dualDeviceClassId] = sonoff_dualConnectedStateTypeId;
|
||||
m_connectedStateTypeMap[sonoff_quadDeviceClassId] = sonoff_quadConnectedStateTypeId;
|
||||
m_connectedStateTypeMap[tasmotaSwitchDeviceClassId] = tasmotaSwitchConnectedStateTypeId;
|
||||
m_connectedStateTypeMap[tasmotaLightDeviceClassId] = tasmotaLightConnectedStateTypeId;
|
||||
m_connectedStateTypeMap[tasmotaShutterDeviceClassId] = tasmotaShutterConnectedStateTypeId;
|
||||
}
|
||||
|
||||
DevicePluginTasmota::~DevicePluginTasmota()
|
||||
@ -117,17 +121,27 @@ DeviceManager::DeviceSetupStatus DevicePluginTasmota::setupDevice(Device *device
|
||||
return DeviceManager::DeviceSetupStatusFailure;
|
||||
}
|
||||
|
||||
QUrl url("http://10.10.10.90/sv");
|
||||
QUrl url(QString("http://%1/cm").arg(deviceAddress.toString()));
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("w", "2%2C1");
|
||||
query.addQueryItem("mh", channel->serverAddress().toString());
|
||||
query.addQueryItem("ml", QString::number(channel->serverPort()));
|
||||
query.addQueryItem("mc", channel->clientId());
|
||||
query.addQueryItem("mu", channel->username());
|
||||
query.addQueryItem("mp", channel->password());
|
||||
query.addQueryItem("mt", "sonoff");
|
||||
query.addQueryItem("mf", channel->topicPrefix() + "/%topic%/");
|
||||
QMap<QString, QString> configItems;
|
||||
configItems.insert("MqttHost", channel->serverAddress().toString());
|
||||
configItems.insert("MqttPort", QString::number(channel->serverPort()));
|
||||
configItems.insert("MqttClient", channel->clientId());
|
||||
configItems.insert("MqttUser", channel->username());
|
||||
configItems.insert("MqttPassword", channel->password());
|
||||
configItems.insert("Topic", "sonoff");
|
||||
configItems.insert("FullTopic", channel->topicPrefix() + "/%topic%/");
|
||||
|
||||
QStringList configList;
|
||||
foreach (const QString &key, configItems.keys()) {
|
||||
configList << key + ' ' + configItems.value(key);
|
||||
}
|
||||
QString fullCommand = "Backlog " + configList.join(';');
|
||||
query.addQueryItem("cmnd", fullCommand.toUtf8().toPercentEncoding());
|
||||
|
||||
|
||||
url.setQuery(query);
|
||||
qCDebug(dcTasmota) << "Configuring Tasmota device:" << url.toString();
|
||||
QNetworkRequest request(url);
|
||||
QNetworkReply *reply = hardwareManager()->networkManager()->get(request);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, device, channel, reply](){
|
||||
@ -167,9 +181,13 @@ DeviceManager::DeviceSetupStatus DevicePluginTasmota::setupDevice(Device *device
|
||||
|
||||
qCDebug(dcTasmota) << "Adding Tasmota connected devices";
|
||||
deviceDescriptors.clear();
|
||||
int shutterUpChannel = -1;
|
||||
int shutterDownChannel = -1;
|
||||
for (int i = 0; i < m_attachedDeviceParamTypeIdMap.value(device->deviceClassId()).count(); i++) {
|
||||
ParamTypeId attachedDeviceParamTypeId = m_attachedDeviceParamTypeIdMap.value(device->deviceClassId()).at(i);
|
||||
if (device->paramValue(attachedDeviceParamTypeId).toString() == "Light") {
|
||||
QString deviceType = device->paramValue(attachedDeviceParamTypeId).toString();
|
||||
qCDebug(dcTasmota) << "Connected Device" << i + 1 << deviceType;
|
||||
if (deviceType == "Light") {
|
||||
DeviceDescriptor descriptor(tasmotaLightDeviceClassId, device->name() + " CH" + QString::number(i+1), QString(), device->id());
|
||||
descriptor.setParentDeviceId(device->id());
|
||||
if (m_attachedDeviceParamTypeIdMap.value(device->deviceClassId()).count() == 1) {
|
||||
@ -178,11 +196,27 @@ DeviceManager::DeviceSetupStatus DevicePluginTasmota::setupDevice(Device *device
|
||||
descriptor.setParams(ParamList() << Param(tasmotaLightDeviceChannelNameParamTypeId, "POWER" + QString::number(i+1)));
|
||||
}
|
||||
deviceDescriptors << descriptor;
|
||||
} else if (deviceType == "Roller Shutter Up") {
|
||||
shutterUpChannel = i+1;
|
||||
} else if (deviceType == "Roller Shutter Down") {
|
||||
shutterDownChannel = i+1;
|
||||
}
|
||||
}
|
||||
if (!deviceDescriptors.isEmpty()) {
|
||||
emit autoDevicesAppeared(tasmotaLightDeviceClassId, deviceDescriptors);
|
||||
}
|
||||
deviceDescriptors.clear();
|
||||
if (shutterUpChannel != -1 && shutterDownChannel != -1) {
|
||||
qCDebug(dcTasmota) << "Adding Shutter device";
|
||||
DeviceDescriptor descriptor(tasmotaShutterDeviceClassId, device->name() + " Shutter", QString(), device->id());
|
||||
descriptor.setParams(ParamList()
|
||||
<< Param(tasmotaShutterDeviceOpeningChannelParamTypeId, "POWER" + QString::number(shutterUpChannel))
|
||||
<< Param(tasmotaShutterDeviceClosingChannelParamTypeId, "POWER" + QString::number(shutterDownChannel)));
|
||||
deviceDescriptors << descriptor;
|
||||
}
|
||||
if (!deviceDescriptors.isEmpty()) {
|
||||
emit autoDevicesAppeared(tasmotaShutterDeviceClassId, deviceDescriptors);
|
||||
}
|
||||
});
|
||||
return DeviceManager::DeviceSetupStatusAsync;
|
||||
}
|
||||
@ -220,6 +254,30 @@ DeviceManager::DeviceError DevicePluginTasmota::executeAction(Device *device, co
|
||||
device->setStateValue(m_powerStateTypeMap.value(device->deviceClassId()), action.param(powerActionParamTypeId).value().toBool());
|
||||
return DeviceManager::DeviceErrorNoError;
|
||||
}
|
||||
if (device->deviceClassId() == tasmotaShutterDeviceClassId) {
|
||||
Device *parentDev = myDevices().findById(device->parentId());
|
||||
MqttChannel *channel = m_mqttChannels.value(parentDev);
|
||||
ParamTypeId openingChannelParamTypeId = m_openingChannelParamTypeMap.value(device->deviceClassId());
|
||||
ParamTypeId closingChannelParamTypeId = m_closingChannelParamTypeMap.value(device->deviceClassId());
|
||||
if (action.actionTypeId() == tasmotaShutterOpenActionTypeId) {
|
||||
qCDebug(dcTasmota) << "Publishing:" << channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(closingChannelParamTypeId).toString() << "OFF";
|
||||
channel->publish(channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(closingChannelParamTypeId).toString().toLower(), "OFF");
|
||||
qCDebug(dcTasmota) << "Publishing:" << channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(openingChannelParamTypeId).toString() << "ON";
|
||||
channel->publish(channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(openingChannelParamTypeId).toString().toLower(), "ON");
|
||||
} else if (action.actionTypeId() == tasmotaShutterCloseActionTypeId) {
|
||||
qCDebug(dcTasmota) << "Publishing:" << channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(openingChannelParamTypeId).toString() << "OFF";
|
||||
channel->publish(channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(openingChannelParamTypeId).toString().toLower(), "OFF");
|
||||
qCDebug(dcTasmota) << "Publishing:" << channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(closingChannelParamTypeId).toString() << "ON";
|
||||
channel->publish(channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(closingChannelParamTypeId).toString().toLower(), "ON");
|
||||
} else { // Stop
|
||||
qCDebug(dcTasmota) << "Publishing:" << channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(openingChannelParamTypeId).toString() << "OFF";
|
||||
channel->publish(channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(openingChannelParamTypeId).toString().toLower(), "OFF");
|
||||
qCDebug(dcTasmota) << "Publishing:" << channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(closingChannelParamTypeId).toString() << "OFF";
|
||||
channel->publish(channel->topicPrefix() + "/sonoff/cmnd/" + device->paramValue(closingChannelParamTypeId).toString().toLower(), "OFF");
|
||||
}
|
||||
return DeviceManager::DeviceErrorNoError;
|
||||
}
|
||||
qCWarning(dcTasmota) << "Unhandled execute action call for device" << device;
|
||||
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
||||
}
|
||||
|
||||
@ -264,7 +322,9 @@ void DevicePluginTasmota::onPublishReceived(MqttChannel *channel, const QString
|
||||
if (child->paramValue(m_channelParamTypeMap.value(child->deviceClassId())).toString() != channelName) {
|
||||
continue;
|
||||
}
|
||||
child->setStateValue(m_powerStateTypeMap.value(child->deviceClassId()), payload == "ON");
|
||||
if (m_powerStateTypeMap.contains(child->deviceClassId())) {
|
||||
child->setStateValue(m_powerStateTypeMap.value(child->deviceClassId()), payload == "ON");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (topic.startsWith(channel->topicPrefix() + "/sonoff/STATE")) {
|
||||
@ -278,9 +338,11 @@ void DevicePluginTasmota::onPublishReceived(MqttChannel *channel, const QString
|
||||
if (child->parentId() != dev->id()) {
|
||||
continue;
|
||||
}
|
||||
QString childChannel = child->paramValue(m_channelParamTypeMap.value(child->deviceClassId())).toString();
|
||||
QString valueString = jsonDoc.toVariant().toMap().value(childChannel).toString();
|
||||
child->setStateValue(m_powerStateTypeMap.value(child->deviceClassId()), valueString == "ON");
|
||||
if (m_powerStateTypeMap.contains(child->deviceClassId())) {
|
||||
QString childChannel = child->paramValue(m_channelParamTypeMap.value(child->deviceClassId())).toString();
|
||||
QString valueString = jsonDoc.toVariant().toMap().value(childChannel).toString();
|
||||
child->setStateValue(m_powerStateTypeMap.value(child->deviceClassId()), valueString == "ON");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -57,6 +57,8 @@ private:
|
||||
|
||||
// Helpers for child devices (virtual ones, starting with tasmota)
|
||||
QHash<DeviceClassId, ParamTypeId> m_channelParamTypeMap;
|
||||
QHash<DeviceClassId, ParamTypeId> m_openingChannelParamTypeMap;
|
||||
QHash<DeviceClassId, ParamTypeId> m_closingChannelParamTypeMap;
|
||||
QHash<DeviceClassId, StateTypeId> m_powerStateTypeMap;
|
||||
|
||||
// Helpers for both devices
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
"name": "attachedDeviceCH1",
|
||||
"displayName": "Connected device 1",
|
||||
"type": "QString",
|
||||
"allowedValues": ["None", "Light"],
|
||||
"allowedValues": ["None", "Light", "Roller Shutter Up", "Roller Shutter Down"],
|
||||
"defaultValue": "None"
|
||||
},
|
||||
{
|
||||
@ -68,7 +68,7 @@
|
||||
"name": "attachedDeviceCH2",
|
||||
"displayName": "Connected device 2",
|
||||
"type": "QString",
|
||||
"allowedValues": ["None", "Light"],
|
||||
"allowedValues": ["None", "Light", "Roller Shutter Up", "Roller Shutter Down"],
|
||||
"defaultValue": "None"
|
||||
}
|
||||
],
|
||||
@ -213,6 +213,54 @@
|
||||
"writable": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "c63b02f2-3695-4e8c-9789-1b8a705f3a53",
|
||||
"name": "tasmotaShutter",
|
||||
"displayName": "Tasmota shutter",
|
||||
"createMethods": ["auto"],
|
||||
"interfaces": ["shutter", "closable", "connectable"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "4d8f113d-f816-4356-b1ff-31df3f4b515f",
|
||||
"name": "openingChannel",
|
||||
"displayName": "Opening channel",
|
||||
"type": "int"
|
||||
},
|
||||
{
|
||||
"id": "600c00fd-6a2c-46cd-8031-2d9a1b1bc710",
|
||||
"name": "closingChannel",
|
||||
"displayName": "Closing channel",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "7bbf0bbf-abb3-487e-b5e9-077f7b00d8ef",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "8e7fb2f4-2819-4d14-a5ae-95624b097bf7",
|
||||
"name": "open",
|
||||
"displayName": "Open"
|
||||
},
|
||||
{
|
||||
"id": "efbe9290-affd-4902-abb7-dd4ea74ccd1b",
|
||||
"name": "close",
|
||||
"displayName": "Close"
|
||||
},
|
||||
{
|
||||
"id": "c9c9c569-e224-4f63-abed-782cba04d61b",
|
||||
"name": "stop",
|
||||
"displayName": "Stop"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user