/* 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