diff --git a/ledalexacontrol/.cproject b/ledalexacontrol/.cproject new file mode 100644 index 0000000..c2ff27a --- /dev/null +++ b/ledalexacontrol/.cproject @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${sloeber.make_location}make + + uploadWithProgrammerWithoutBuild + true + false + true + + + ${sloeber.make_location}make + + BurnBootLoader + true + false + true + + + + \ No newline at end of file diff --git a/ledalexacontrol/.gitignore b/ledalexacontrol/.gitignore new file mode 100644 index 0000000..dcd90ee --- /dev/null +++ b/ledalexacontrol/.gitignore @@ -0,0 +1,2 @@ +/Release/ +/sloeber.ino.cpp diff --git a/ledalexacontrol/.project b/ledalexacontrol/.project new file mode 100644 index 0000000..1ecf62b --- /dev/null +++ b/ledalexacontrol/.project @@ -0,0 +1,75 @@ + + + ledalexacontrol + + + + + + io.sloeber.core.inoToCpp + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.core.ccnature + io.sloeber.arduinonature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + core/core + 2 + ECLIPSE_HOME/arduinoPlugin/packages/esp8266/hardware/esp8266/2.4.2/cores/esp8266 + + + core/variant + 2 + ECLIPSE_HOME/arduinoPlugin/packages/esp8266/hardware/esp8266/2.4.2/variants/d1_mini + + + libraries/ESP8266WiFi + 2 + ECLIPSE_HOME/arduinoPlugin/packages/esp8266/hardware/esp8266/2.4.2/libraries/ESP8266WiFi + + + libraries/ESPAsyncTCP-master + 2 + C:/Users/vogelt/Documents/Arduino/libraries/ESPAsyncTCP-master + + + libraries/ESPAsyncWebServer-master + 2 + C:/Users/vogelt/Documents/Arduino/libraries/ESPAsyncWebServer-master + + + libraries/Hash + 2 + ECLIPSE_HOME/arduinoPlugin/packages/esp8266/hardware/esp8266/2.4.2/libraries/Hash + + + libraries/HttpClient + 2 + ECLIPSE_HOME/arduinoPlugin/libraries/HttpClient/2.2.0 + + + libraries/fauxmoesp + 2 + C:/Users/vogelt/Documents/Arduino/libraries/fauxmoesp + + + diff --git a/ledalexacontrol/.settings/language.settings.xml b/ledalexacontrol/.settings/language.settings.xml new file mode 100644 index 0000000..b625904 --- /dev/null +++ b/ledalexacontrol/.settings/language.settings.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ledalexacontrol/.settings/org.eclipse.core.resources.prefs b/ledalexacontrol/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..68a0304 --- /dev/null +++ b/ledalexacontrol/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=windows-1252 diff --git a/ledalexacontrol/.sproject b/ledalexacontrol/.sproject new file mode 100644 index 0000000..8a0fbcf --- /dev/null +++ b/ledalexacontrol/.sproject @@ -0,0 +1,37 @@ +Config.Release.board.BOARD.ID=d1_mini +Config.Release.board.BOARD.MENU.CpuFrequency=80 +Config.Release.board.BOARD.MENU.Debug=Disabled +Config.Release.board.BOARD.MENU.DebugLevel=None____ +Config.Release.board.BOARD.MENU.FlashErase=none +Config.Release.board.BOARD.MENU.FlashSize=4M1M +Config.Release.board.BOARD.MENU.LwIPVariant=v2mss536 +Config.Release.board.BOARD.MENU.UploadSpeed=921600 +Config.Release.board.BOARD.MENU.VTable=flash +Config.Release.board.BOARD.MENU.baud=getMenuItemIDFromMenuItemName did not find menu item with name "115200" for menu ID "baud" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.dbg=getMenuItemIDFromMenuItemName did not find menu item with name "Disabled" for menu ID "dbg" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.eesz=getMenuItemIDFromMenuItemName did not find menu item with name "4MB (FS:2MB OTA:~1019KB)" for menu ID "eesz" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.exception=getMenuItemIDFromMenuItemName did not find menu item with name "Disabled (new aborts on oom)" for menu ID "exception" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.ip=getMenuItemIDFromMenuItemName did not find menu item with name "v2 Lower Memory" for menu ID "ip" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.lvl=getMenuItemIDFromMenuItemName did not find menu item with name "None" for menu ID "lvl" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.mmu=getMenuItemIDFromMenuItemName did not find menu item with name "32KB cache + 32KB IRAM (balanced)" for menu ID "mmu" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.non32xfer=getMenuItemIDFromMenuItemName did not find menu item with name "Use pgm_read macros for IRAM/PROGMEM" for menu ID "non32xfer" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.ssl=getMenuItemIDFromMenuItemName did not find menu item with name "All SSL ciphers (most compatible)" for menu ID "ssl" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.stacksmash=getMenuItemIDFromMenuItemName did not find menu item with name "Disabled" for menu ID "stacksmash" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.vt=getMenuItemIDFromMenuItemName did not find menu item with name "Flash" for menu ID "vt" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.wipe=getMenuItemIDFromMenuItemName did not find menu item with name "Only Sketch" for menu ID "wipe" and for boardID "d1_mini"! +Config.Release.board.BOARD.MENU.xtal=getMenuItemIDFromMenuItemName did not find menu item with name "160 MHz" for menu ID "xtal" and for boardID "d1_mini"! +Config.Release.board.BOARD.TXT=${SLOEBER_HOME}/arduinoPlugin/packages/esp8266/hardware/esp8266/2.4.2/boards.txt +Config.Release.board.PROGRAMMER.NAME= +Config.Release.board.UPLOAD.PORT=COM11 +Config.Release.compile.sloeber.extra.all= +Config.Release.compile.sloeber.extra.archive= +Config.Release.compile.sloeber.extra.assembly= +Config.Release.compile.sloeber.extra.c.compile= +Config.Release.compile.sloeber.extra.compile= +Config.Release.compile.sloeber.extra.cpp.compile= +Config.Release.compile.sloeber.extra.link= +Config.Release.compile.sloeber.size.custom= +Config.Release.compile.sloeber.size.type=RAW_RESULT +Config.Release.compile.sloeber.warning_level=NONE +Config.Release.compile.sloeber.warning_level.custom= +Config.Release.other.IS_VERSION_CONTROLLED=false diff --git a/ledalexacontrol/ledalexacontrol.ino b/ledalexacontrol/ledalexacontrol.ino new file mode 100644 index 0000000..7344ff6 --- /dev/null +++ b/ledalexacontrol/ledalexacontrol.ino @@ -0,0 +1,118 @@ +#include "Arduino.h" +#include +#include + + +fauxmoESP fauxmo; + + + +// Replace with your network credentials +const char *ssid = "FRITZ!BoxWZ"; +const char *password = "40360548708873074408"; +IPAddress ip(192, 168, 178, 14); +IPAddress subnet(255, 255, 255, 0); +IPAddress gateway(192, 168, 178, 1); + +const char* serverhost = "192.168.178.12"; + + +void httpConnect() { + WiFiClient client; + + Serial.printf("\n[Connecting to %s ... ", serverhost); + if (client.connect(serverhost,88)) + { + Serial.println("connected]"); + + client.println("PUT /ledDemoOn"); + delay(10000); + client.println("PUT /ledDemoOff"); + delay(10000); + Serial.println("[Response:]"); + while (client.connected() || client.available()) + { + if (client.available()) + { + String line = client.readStringUntil('\n'); + Serial.println(line); + } + } + client.stop(); + Serial.println("\n[Disconnected]"); + } + else + { + Serial.println("connection failed!]"); + client.stop(); + } + delay(5000); +} + +void setup() { + + Serial.begin(115200); + + + if (connectWifi()) { + fauxmo.addDevice("LED Schrank"); + fauxmo.addDevice("LED Fernseher"); + fauxmo.addDevice("LED Demo"); + + fauxmo.enable(true); + + //fauxmo.onMessage(fn) + + fauxmo.onMessage([](unsigned char device_id, const char * device_name, bool state) { + Serial.printf("[MAIN] Device #%d (%s) state: %s\n", device_id, device_name, state ? "ON" : "OFF"); + httpConnect(); +// HttpClient client; +// +// if (state == true) { +// client.begin("http://192.168.178.12:88/ledDemoOn"); //Specify request destination +// } else { +// client.begin("http://192.168.178.12:88/ledDemoOff"); //Specify request destination +// } +// int httpCode = client.GET(); +// String payload = client.getString(); +// Serial.println(payload); +// Serial.println("Test"); +// client.end(); + }); + + } + + + +} + +// ------------ FINISH ----------------- +boolean connectWifi() { + boolean stat = true; + + // Connect to Wi-Fi + WiFi.config(ip, gateway, subnet); // uncomment for dynamic IP + WiFi.begin(ssid, password); + int count = 0; + while (WiFi.status() != WL_CONNECTED) { + count++; + digitalWrite(D4, LOW); + delay(1000); + digitalWrite(D4, HIGH); + Serial.println("Connecting to WiFi.."); + if (count == 10) { + stat = false; + break; + } + } + if (stat == true) { + digitalWrite(D4, LOW); + // Print ESP Local IP Address + Serial.println(WiFi.localIP()); + } + return stat; +} + +void loop() { + fauxmo.handle(); +} diff --git a/ledalexacontrol/libraries/fauxmoesp/.gitignore b/ledalexacontrol/libraries/fauxmoesp/.gitignore new file mode 100644 index 0000000..c5742a1 --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/.gitignore @@ -0,0 +1,12 @@ +credentials.h +utils + +# Precompiled Headers +*.gch +*.pch + +# PlatformIO folders +.pio* +pio +.clang_complete +.gcc-flags.json diff --git a/ledalexacontrol/libraries/fauxmoesp/CHANGELOG.md b/ledalexacontrol/libraries/fauxmoesp/CHANGELOG.md new file mode 100644 index 0000000..d7b4de7 --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/CHANGELOG.md @@ -0,0 +1,35 @@ +# fauxmoESP change log + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [2.1.0] 2017-02-15 +### Added +- ESPAsyncWebServer to manage TCP connections + +### Fixed +- Memory leaks in UDP and TCP connections + +## [2.0.0] 2017-01-05 +### Added +- Different discovery strategies to maximize device discovery +- UDP polling required (call handle() in your loop) + +### Changed +- ```onMessage``` callback signature changed to add device_id + +### Removed +- Removed dependency on ESPAsyncUDP for compatibility with current stable release of Arduino Code for ESP8266 + +## [1.0.0] 2016-11-26 +### Added +- Support for multiple virtual devices + +### Changed +- ```onMessage``` callback signature has changed to allow passing the device name + +### Deprecated +- ```setDeviceName``` no longer exists, use ```addDevice``` instead + +## [0.1.0] 2016-11-21 +- Initial working version diff --git a/ledalexacontrol/libraries/fauxmoesp/LICENSE b/ledalexacontrol/libraries/fauxmoesp/LICENSE new file mode 100644 index 0000000..d8b23d6 --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (C) 2016 by Xose Pérez + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ledalexacontrol/libraries/fauxmoesp/README.md b/ledalexacontrol/libraries/fauxmoesp/README.md new file mode 100644 index 0000000..c6329fb --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/README.md @@ -0,0 +1,89 @@ +# fauxmoESP + +Amazon Alexa support for ESP8266 devices. + +This is a library for ESP8266-based devices that emulates a Belkin WeMo device and thus allows you to control them using this protocol, in particular from Alexa-powered devices like the Amazon Echo or the Dot. + +This library is a port of Maker Musings' [Fauxmo Python library][6]. + +**Current Version is 2.1.0**, this version shows some backwards incompatibilities with version 1.0.0. Check the examples to rewrite your code if you were using a previous version and read the [changelog](CHANGELOG.md). + +## Dependencies + +This library uses [ESPAsyncTCP][3] and [ESPAsyncWebServer][4] libraries by [me-no-dev][5]. + +### PlatformIO + +If you are using PlatformIO (check the section bellow on how to compile it) you can install them by adding the dependencies to your ```platformio.ini``` file: + +``` + +lib_deps = + ESPAsyncTCP + ESPAsyncWebServer +``` + +### Arduino IDE + +You will need to install the required library from sources. Your best option is to download the library as a ZIP file and install it using the option under "Sketch > Include Library > Add .ZIP Library...". + +You can look for it manually but I have gathered the URL here for convenience: + +|Library|Repository|ZIP| +|-|-|-| +|**ESPAsyncTCP** by Hristo Gochkov|[GIT](https://github.com/me-no-dev/ESPAsyncTCP)|[ZIP](https://github.com/me-no-dev/ESPAsyncTCP/archive/master.zip)| +|**ESPAsyncWebServer** by Hristo Gochkov|[GIT](https://github.com/me-no-dev/ESPAsyncWebServer)|[ZIP](https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip)|| + +## Usage + +The library is very easy to use, basically instantiate an object, connect to the Wifi, add one or more virtual devices and bind the callback to get the messages. An schematic example could be: + +``` +#include + +fauxmoESP fauxmo; + +void setup() { + + Serial.begin(115200); + + ... connect to wifi ... + + fauxmo.addDevice("light one"); + fauxmo.addDevice("light two"); + fauxmo.addDevice("light three"); + fauxmo.addDevice("light four"); + fauxmo.onMessage([](unsigned char device_id, const char * device_name, bool state) { + Serial.printf("[MAIN] Device #%d (%s) state: %s\n", device_id, device_name, state ? "ON" : "OFF"); + }); + +} + +void loop() { + fauxmoESP.handle(); +} + +``` + +(Check the examples folder) + +Then run the "discover devices" option from your Alexa app or web (in the Smart Home section). A new device with the name you have configured should appear. Tell Alexa to switch it on or off and check your terminal ;) + +## Device discovery + +Device discovery can be incomplete when you have lots of devices defined. Since version 2.0.0 different strategies are used to maximize the chance of getting all of them discovered during the first round. + +Tests have been run with up to 16 devices with success but your experience might be different. If not all of them are discovered on the first run, execute the Discover Devices option again from your Alexa app or tell your Echo/Dot to do it. Once they pop up in your devices list (even if they are flagged as "Offline") they should work just fine. + +The strategies the library uses to improve discoverability are: + +* Space UDP responses to help Echo/Dot and the device itself to perform setup queries +* Repeat UDP responses for devices not queried +* Randomize UDP responses + +[1]:https://github.com/esp8266/Arduino +[2]:http://docs.platformio.org/en/stable/platforms/espressif8266.html#using-arduino-framework-with-staging-version +[3]:https://github.com/me-no-dev/ESPAsyncTCP +[4]:https://github.com/me-no-dev/ESPAsyncWebServer +[5]:https://github.com/me-no-dev +[6]:https://github.com/makermusings/fauxmo diff --git a/ledalexacontrol/libraries/fauxmoesp/docs/setup.xml b/ledalexacontrol/libraries/fauxmoesp/docs/setup.xml new file mode 100644 index 0000000..4fe0f30 --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/docs/setup.xml @@ -0,0 +1,20 @@ + + + + urn:Belkin:device:controllee:1 + %s + Belkin International Inc. + FauxmoESP + 2.0.0 + uuid:Socket-1_0-%s + + + urn:Belkin:service:basicevent:1 + urn:Belkin:serviceId:basicevent1 + /upnp/control/basicevent1 + /upnp/event/basicevent1 + /eventservice.xml + + + + diff --git a/ledalexacontrol/libraries/fauxmoesp/examples/fauxmoESP_Basic/credentials.sample.h b/ledalexacontrol/libraries/fauxmoesp/examples/fauxmoESP_Basic/credentials.sample.h new file mode 100644 index 0000000..703ce93 --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/examples/fauxmoESP_Basic/credentials.sample.h @@ -0,0 +1,2 @@ +#define WIFI_SSID "..." +#define WIFI_PASS "..." diff --git a/ledalexacontrol/libraries/fauxmoesp/examples/fauxmoESP_Basic/fauxmoESP_Basic.ino b/ledalexacontrol/libraries/fauxmoesp/examples/fauxmoESP_Basic/fauxmoESP_Basic.ino new file mode 100644 index 0000000..0fac1d3 --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/examples/fauxmoESP_Basic/fauxmoESP_Basic.ino @@ -0,0 +1,82 @@ +#include +#include +#include "fauxmoESP.h" +#include "credentials.h" + +#define SERIAL_BAUDRATE 115200 +#define LED 2 + +fauxmoESP fauxmo; + +// ----------------------------------------------------------------------------- +// Wifi +// ----------------------------------------------------------------------------- + +void wifiSetup() { + + // Set WIFI module to STA mode + WiFi.mode(WIFI_STA); + + // Connect + Serial.printf("[WIFI] Connecting to %s ", WIFI_SSID); + WiFi.begin(WIFI_SSID, WIFI_PASS); + + // Wait + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // Connected! + Serial.printf("[WIFI] STATION Mode, SSID: %s, IP address: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str()); + +} + +void setup() { + + // Init serial port and clean garbage + Serial.begin(SERIAL_BAUDRATE); + Serial.println(); + Serial.println(); + + // Wifi + wifiSetup(); + + // LED + pinMode(LED, OUTPUT); + digitalWrite(LED, HIGH); + + // Fauxmo + fauxmo.addDevice("light one"); + fauxmo.addDevice("light two"); + fauxmo.addDevice("light three"); + fauxmo.addDevice("light four"); + + // fauxmoESP 2.0.0 has changed the callback signature to add the device_id, this WARRANTY + // it's easier to match devices to action without having to compare strings. + fauxmo.onMessage([](unsigned char device_id, const char * device_name, bool state) { + Serial.printf("[MAIN] Device #%d (%s) state: %s\n", device_id, device_name, state ? "ON" : "OFF"); + digitalWrite(LED, !state); + }); + +} + +void loop() { + + // Since fauxmoESP 2.0 the library uses the "compatibility" mode by + // default, this means that it uses WiFiUdp class instead of AsyncUDP. + // The later requires the Arduino Core for ESP8266 staging version + // whilst the former works fine with current stable 2.3.0 version. + // But, since it's not "async" anymore we have to manually poll for UDP + // packets + fauxmo.handle(); + + + static unsigned long last = millis(); + if (millis() - last > 5000) { + last = millis(); + Serial.printf("[MAIN] Free heap: %d bytes\n", ESP.getFreeHeap()); + } + +} diff --git a/ledalexacontrol/libraries/fauxmoesp/library.json b/ledalexacontrol/libraries/fauxmoesp/library.json new file mode 100644 index 0000000..1c0391b --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/library.json @@ -0,0 +1,26 @@ +{ + "name": "FauxmoESP", + "keywords": "belkin,wemo,fauxmo,esp8266,alexa,amazon,echo,dot", + "description": "Amazon Alexa support for ESP8266 (Amazon Echo & Dot)", + "repository": { + "type": "git", + "url": "https://bitbucket.org/xoseperez/fauxmoesp.git" + }, + "version": "2.1.0", + "license": "MIT", + "exclude": "tests", + "frameworks": "arduino", + "platforms": "espressif8266", + "dependencies": [ + { "name": "ESPAsyncTCP" } + ], + "authors": { + "name": "Xose Perez", + "email": "xose.perez@gmail.com", + "url": "http://tinkerman.cat", + "maintainer": true + }, + "examples": [ + "examples/*/src/*.ino" + ] +} diff --git a/ledalexacontrol/libraries/fauxmoesp/library.properties b/ledalexacontrol/libraries/fauxmoesp/library.properties new file mode 100644 index 0000000..2cdb373 --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/library.properties @@ -0,0 +1,9 @@ +name=FauxmoESP +version=2.1.0 +author=Xose Perez +maintainer=Xose Perez +sentence=Amazon Alexa support for ESP8266 +paragraph=Amazon Alexa support for ESP8266 +category=Other +url=https://bitbucket.org/xoseperez/fauxmoESP +architectures=* diff --git a/ledalexacontrol/libraries/fauxmoesp/src/fauxmoESP.cpp b/ledalexacontrol/libraries/fauxmoesp/src/fauxmoESP.cpp new file mode 100644 index 0000000..dec8456 --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/src/fauxmoESP.cpp @@ -0,0 +1,207 @@ +/* + +FAUXMO ESP 2.0.0 + +Copyright (C) 2016 by Xose Pérez + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#include +#include +#include "fauxmoESP.h" + +void fauxmoESP::_sendUDPResponse(unsigned int device_id) { + + fauxmoesp_device_t device = _devices[device_id]; + DEBUG_MSG_FAUXMO("[FAUXMO] UDP response for device #%d (%s)\n", _current, device.name); + + char buffer[16]; + IPAddress ip = WiFi.localIP(); + sprintf(buffer, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + + char response[strlen(UDP_TEMPLATE) + 40]; + sprintf_P(response, UDP_TEMPLATE, + buffer, + _base_port + _current, + device.uuid, + device.uuid + ); + + _udp.beginPacket(_remoteIP, _remotePort); + _udp.write(response); + _udp.endPacket(); + +} + +void fauxmoESP::_nextUDPResponse() { + + while (_roundsLeft) { + if (_devices[_current].hit == false) break; + if (++_current == _devices.size()) { + --_roundsLeft; + _current = 0; + } + } + + if (_roundsLeft > 0) { + _sendUDPResponse(_current); + if (++_current == _devices.size()) { + --_roundsLeft; + _current = 0; + } + } +} + +void fauxmoESP::_handleUDPPacket(IPAddress remoteIP, unsigned int remotePort, uint8_t *data, size_t len) { + + if (!_enabled) return; + + data[len] = 0; + + if (strstr((char *) data, UDP_SEARCH_PATTERN) == (char *) data) { + if (strstr((char *) data, UDP_DEVICE_PATTERN) != NULL) { + + #ifdef DEBUG_FAUXMO + char buffer[16]; + sprintf(buffer, "%d.%d.%d.%d", remoteIP[0], remoteIP[1], remoteIP[2], remoteIP[3]); + DEBUG_MSG_FAUXMO("[FAUXMO] Search request from %s\n", buffer); + #endif + + // Set hits to false + for (unsigned int i = 0; i < _devices.size(); i++) { + _devices[i].hit = false; + } + + // Send responses + _remoteIP = remoteIP; + _remotePort = remotePort; + _current = random(0, _devices.size()); + _roundsLeft = UDP_RESPONSES_TRIES; + + } + } + +} + +void fauxmoESP::_handleSetup(AsyncWebServerRequest *request, unsigned int device_id) { + + if (!_enabled) return; + + DEBUG_MSG_FAUXMO("[FAUXMO] Device #%d /setup.xml\n", device_id); + _devices[device_id].hit = true; + + fauxmoesp_device_t device = _devices[device_id]; + char response[strlen(SETUP_TEMPLATE) + 50]; + sprintf_P(response, SETUP_TEMPLATE, device.name, device.uuid); + request->send(200, "text/xml", response); + +} + +void fauxmoESP::_handleContent(AsyncWebServerRequest *request, unsigned int device_id, char * content) { + + if (!_enabled) return; + + DEBUG_MSG_FAUXMO("[FAUXMO] Device #%d /upnp/control/basicevent1\n", device_id); + fauxmoesp_device_t device = _devices[device_id]; + + if (strstr(content, "0") != NULL) { + if (_callback) _callback(device_id, device.name, false); + } + + if (strstr(content, "1") != NULL) { + if (_callback) _callback(device_id, device.name, true); + } + +} + +void fauxmoESP::addDevice(const char * device_name) { + + fauxmoesp_device_t new_device; + unsigned int device_id = _devices.size(); + + // Copy name + new_device.name = strdup(device_name); + + // Create UUID + char uuid[15]; + sprintf(uuid, "444556%06X%02X\0", ESP.getChipId(), device_id); // "DEV" + CHIPID + DEV_ID + new_device.uuid = strdup(uuid); + + // TCP Server + new_device.server = new AsyncWebServer(_base_port + device_id); + new_device.server->on("/setup.xml", HTTP_GET, [this, device_id](AsyncWebServerRequest *request){ + _handleSetup(request, device_id); + }); + new_device.server->on("/upnp/control/basicevent1", HTTP_POST, + [](AsyncWebServerRequest *request) { + request->send(200); + }, + NULL, + [this, device_id](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { + data[len] = 0; + _handleContent(request, device_id, (char *) data); + } + ); + + new_device.server->begin(); + + // Attach + _devices.push_back(new_device); + + DEBUG_MSG_FAUXMO("[FAUXMO] Device '%s' added (#%d)\n", device_name, device_id); + +} + +void fauxmoESP::handle() { + + int len = _udp.parsePacket(); + if (len > 0) { + IPAddress remoteIP = _udp.remoteIP(); + unsigned int remotePort = _udp.remotePort(); + uint8_t data[len]; + _udp.read(data, len); + _handleUDPPacket(remoteIP, remotePort, data, len); + } + + if (_roundsLeft > 0) { + if (millis() - _lastTick > UDP_RESPONSES_INTERVAL) { + _lastTick = millis(); + _nextUDPResponse(); + } + } + +} + +void fauxmoESP::enable(bool enable) { + DEBUG_MSG_FAUXMO("[FAUXMO] %s\n", enable ? "Enabled" : "Disabled"); + _enabled = enable; +} + +fauxmoESP::fauxmoESP(unsigned int port) { + + _base_port = port; + + // UDP Server + _udp.beginMulticast(WiFi.localIP(), UDP_MULTICAST_IP, UDP_MULTICAST_PORT); + +} diff --git a/ledalexacontrol/libraries/fauxmoesp/src/fauxmoESP.h b/ledalexacontrol/libraries/fauxmoesp/src/fauxmoESP.h new file mode 100644 index 0000000..b2593a8 --- /dev/null +++ b/ledalexacontrol/libraries/fauxmoesp/src/fauxmoESP.h @@ -0,0 +1,132 @@ +/* + +FAUXMO ESP 2.0.0 + +Copyright (C) 2016 by Xose Pérez + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef FAUXMOESP_h +#define FAUXMOESP_h + +#define DEFAULT_TCP_BASE_PORT 52000 +#define UDP_MULTICAST_IP IPAddress(239,255,255,250) +#define UDP_MULTICAST_PORT 1900 +#define TCP_MAX_CLIENTS 10 + +#define UDP_SEARCH_PATTERN "M-SEARCH" +#define UDP_DEVICE_PATTERN "urn:Belkin:device:**" + +#define UDP_RESPONSES_INTERVAL 250 +#define UDP_RESPONSES_TRIES 5 + +const char UDP_TEMPLATE[] PROGMEM = + "HTTP/1.1 200 OK\r\n" + "CACHE-CONTROL: max-age=86400\r\n" + "DATE: Sun, 20 Nov 2016 00:00:00 GMT\r\n" + "EXT:\r\n" + "LOCATION: http://%s:%d/setup.xml\r\n" + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" + "01-NLS: %s\r\n" + "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n" + "ST: urn:Belkin:device:**\r\n" + "USN: uuid:Socket-1_0-%s::urn:Belkin:device:**\r\n\r\n"; + +const char SETUP_TEMPLATE[] PROGMEM = + "" + "" + "urn:Belkin:device:controllee:1" + "%s" + "Belkin International Inc." + "FauxmoESP" + "2.0.0" + "uuid:Socket-1_0-%s" + ""; + +const char HEADERS[] PROGMEM = + "HTTP/1.1 200 OK\r\n" + "CONTENT-LENGTH: %d\r\n" + "CONTENT-TYPE: text/xml\r\n" + "DATE: Sun, 01 Jan 2017 00:00:00 GMT\r\n" + "LAST-MODIFIED: Sat, 01 Jan 2017 00:00:00 GMT\r\n" + "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n" + "X-USER-AGENT: redsonic\r\n" + "CONNECTION: close\r\n\r\n" + "%s\r\n"; + +#ifdef DEBUG_FAUXMO + #define DEBUG_MSG_FAUXMO(...) DEBUG_FAUXMO.printf( __VA_ARGS__ ) +#else + #define DEBUG_MSG_FAUXMO(...) +#endif + +#include +#include +#include +#include +#include +#include +#include + +typedef std::function TStateFunction; + +typedef struct { + char * name; + char * uuid; + bool hit; + AsyncWebServer * server; +} fauxmoesp_device_t; + +class fauxmoESP { + + public: + + fauxmoESP(unsigned int port = DEFAULT_TCP_BASE_PORT); + void addDevice(const char * device_name); + void onMessage(TStateFunction fn) { _callback = fn; } + void enable(bool enable); + void handle(); + + private: + + bool _enabled = true; + unsigned int _base_port = DEFAULT_TCP_BASE_PORT; + std::vector _devices; + WiFiUDP _udp; + TStateFunction _callback = NULL; + + unsigned int _roundsLeft = 0; + unsigned int _current = 0; + unsigned long _lastTick; + IPAddress _remoteIP; + unsigned int _remotePort; + + void _sendUDPResponse(unsigned int device_id); + void _nextUDPResponse(); + void _handleUDPPacket(const IPAddress remoteIP, unsigned int remotePort, uint8_t *data, size_t len); + void _handleSetup(AsyncWebServerRequest *request, unsigned int device_id); + void _handleContent(AsyncWebServerRequest *request, unsigned int device_id, char * content); + +}; + +#endif diff --git a/ledalexacontrol/spec.d b/ledalexacontrol/spec.d new file mode 100644 index 0000000..2f70fb7 --- /dev/null +++ b/ledalexacontrol/spec.d @@ -0,0 +1,2 @@ +spec.o: \ + C:/workspace/Arduino/.metadata/.plugins/org.eclipse.cdt.managedbuilder.core/spec.cpp diff --git a/ledcontroler/.settings/language.settings.xml b/ledcontroler/.settings/language.settings.xml index 1fd3f28..3a338c1 100644 --- a/ledcontroler/.settings/language.settings.xml +++ b/ledcontroler/.settings/language.settings.xml @@ -2,7 +2,7 @@ - +