/*
xdrv_21_wemo.ino - wemo support for Tasmota
Copyright (C) 2020 Heiko Krupp and Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined (USE_EMULATION_WEMO)
/*********************************************************************************************\
* Belkin WeMo emulation
\*********************************************************************************************/
#define XDRV_21 21
const char WEMO_MSEARCH[] PROGMEM =
"HTTP/1.1 200 OK\r\n"
"CACHE-CONTROL: max-age=86400\r\n"
"DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n"
"EXT:\r\n"
"LOCATION: http://%s:80/setup.xml\r\n"
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
"01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n"
"SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
"ST: %s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
"USN: uuid:%s::%s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice
"X-User-Agent: redsonic\r\n"
"\r\n";
String WemoSerialnumber(void)
{
char serial[16];
snprintf_P(serial, sizeof(serial), PSTR("201612K%08X"), ESP_getChipId());
return String(serial);
}
String WemoUuid(void)
{
char uuid[27];
snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), WemoSerialnumber().c_str());
return String(uuid);
}
void WemoRespondToMSearch(int echo_type)
{
char message[TOPSZ];
TickerMSearch.detach();
if (PortUdp.beginPacket(udp_remote_ip, udp_remote_port)) {
char type[24];
if (1 == echo_type) { // type1 echo 1g & dot 2g
strcpy_P(type, URN_BELKIN_DEVICE_CAP);
} else { // type2 echo 2g (echo, plus, show)
strcpy_P(type, UPNP_ROOTDEVICE);
}
char response[400];
snprintf_P(response, sizeof(response), WEMO_MSEARCH, WiFi.localIP().toString().c_str(), type, WemoUuid().c_str(), type);
PortUdp.write(response);
PortUdp.endPacket();
snprintf_P(message, sizeof(message), PSTR(D_RESPONSE_SENT));
} else {
snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE));
}
// Do not use AddLog_P2 here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
PrepLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"),
echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port);
udp_response_mutex = false;
}
/*********************************************************************************************\
* Wemo web server additions
\*********************************************************************************************/
const char WEMO_EVENTSERVICE_XML[] PROGMEM =
""
""
""
"SetBinaryState"
""
""
""
"BinaryState"
"BinaryState"
"in"
""
""
""
""
"GetBinaryState"
""
""
""
"BinaryState"
"BinaryState"
"out"
""
""
""
""
""
""
"BinaryState"
"bool"
"0"
""
""
"level"
"string"
"0"
""
""
"\r\n\r\n";
const char WEMO_METASERVICE_XML[] PROGMEM =
""
""
"1"
"0"
""
""
""
"GetMetaInfo"
""
""
"GetMetaInfo"
"MetaInfo"
"in"
""
""
""
""
""
"MetaInfo"
"string"
"0"
""
""
"\r\n\r\n";
const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM =
""
""
""
"%d"
""
""
"\r\n";
const char WEMO_SETUP_XML[] PROGMEM =
""
""
""
"urn:Belkin:device:controllee:1"
"{x1"
"Belkin International Inc."
"Socket"
"3.1415"
"uuid:{x2"
"{x3"
"0"
""
""
"urn:Belkin:service:basicevent:1"
"urn:Belkin:serviceId:basicevent1"
"/upnp/control/basicevent1"
"/upnp/event/basicevent1"
"/eventservice.xml"
""
""
"urn:Belkin:service:metainfo:1"
"urn:Belkin:serviceId:metainfo1"
"/upnp/control/metainfo1"
"/upnp/event/metainfo1"
"/metainfoservice.xml"
""
""
""
"\r\n";
/********************************************************************************************/
void HandleUpnpEvent(void)
{
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_BASIC_EVENT));
char event[500];
strlcpy(event, Webserver->arg(0).c_str(), sizeof(event));
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), event);
//differentiate get and set state
char state = 'G';
if (strstr_P(event, PSTR("SetBinaryState")) != nullptr) {
state = 'S';
uint8_t power = POWER_TOGGLE;
if (strstr_P(event, PSTR("State>10on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
Webserver->on("/eventservice.xml", HandleUpnpService);
Webserver->on("/metainfoservice.xml", HandleUpnpMetaService);
Webserver->on("/setup.xml", HandleUpnpSetupWemo);
break;
}
}
return result;
}
#endif // USE_WEBSERVER && USE_EMULATION && USE_EMULATION_WEMO