diff --git a/README.md b/README.md index cabcc4a62..cf7cd0c8b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **3.9.15** - See ```sonoff/_releasenotes.ino``` for change information. +Current version is **3.9.16** - See ```sonoff/_releasenotes.ino``` for change information. - This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic. - Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```. diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin index a44873b6e..70b1540e6 100644 Binary files a/api/arduino/sonoff.ino.bin and b/api/arduino/sonoff.ino.bin differ diff --git a/platformio.ini b/platformio.ini index fa09a40a9..e33913f18 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,4 +19,4 @@ board = esp01_1m ; board = esp8285 build_flags = -Wl,-Tesp8266.flash.1m64.ld -DMQTT_MAX_PACKET_SIZE=400 -lib_deps = PubSubClient, NeoPixelBus +lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 0c4a996dc..a98a944c3 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,9 @@ -/* 3.9.15 20170213 +/* 3.9.16 20170214 + * Update latching relay handler + * Add support for IR led using IRremoteESP8266 library (#59) + * Add Hue argument passing using ArduinoJSON library (#59) + * + * 3.9.15 20170213 * Change JSON float values from string to number according to http://json.org (#56) * Add support for exs latched relay module https://ex-store.de/ESP8266-WiFi-Relay-V31 (#58) * Add support for inverted relays diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 697c41bdd..d389ee5c2 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -10,7 +10,7 @@ * ==================================================== */ -#define VERSION 0x03090F00 // 3.9.15 +#define VERSION 0x03091000 // 3.9.16 //#define BE_MINIMAL // Compile a minimal version if upgrade memory gets tight (still 404k) // To be used as step 1. Next step is compile and use desired version @@ -56,6 +56,9 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #ifdef USE_DOMOTICZ #undef USE_DOMOTICZ // Disable Domoticz #endif +//#ifdef USE_WEBSERVER +//#undef USE_WEBSERVER // Disable Webserver +//#endif #ifdef USE_EMULATION #undef USE_EMULATION // Disable Wemo or Hue emulation #endif @@ -74,6 +77,9 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #ifdef USE_DHT #undef USE_DHT // Disable internal DHT sensor #endif +#ifdef USE_IR_REMOTE +#undef USE_IR_REMOTE // Disable IR driver +#endif #endif // BE_MINIMAL #ifndef SWITCH_MODE @@ -148,6 +154,12 @@ enum butt_t {PRESSED, NOT_PRESSED}; #ifdef USE_I2C #include // I2C support library #endif // USE_I2C +#if defined USE_EMULATION || defined USE_IR_REMOTE + #include + + const size_t bufferSize = JSON_ARRAY_SIZE(2) + JSON_OBJECT_SIZE(10) + 130; // Required size for complete HUE light JSON object or other JSON objects + DynamicJsonBuffer jsonBuffer(bufferSize); +#endif // USE_EMULATION || USE_IR_REMOTE typedef void (*rtcCallback)(); @@ -789,17 +801,16 @@ void getClient(char* output, const char* input, byte size) void setLatchingRelay(uint8_t power, uint8_t state) { power &= 1; - if (state == 2) { // Init relay + if (state == 2) { // Reset relay state = 0; + latching_power = power; + latching_relay_pulse = 0; } - else if (state == 1) { // Set port power to On + else if (state && !latching_relay_pulse) { // Set port power to On latching_power = power; latching_relay_pulse = 2; // max 200mS (initiated by stateloop()) } - else { // Set saved port to Off - power = latching_power; - } - if (pin[GPIO_REL1 +power] < 99) digitalWrite(pin[GPIO_REL1 +power], rel_inverted[power] ? !state : state); + if (pin[GPIO_REL1 +latching_power] < 99) digitalWrite(pin[GPIO_REL1 +latching_power], rel_inverted[latching_power] ? !state : state); } void setRelay(uint8_t power) @@ -1743,6 +1754,11 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) // Serviced } #endif // USE_WS2812 +#ifdef USE_IR_REMOTE + else if ((pin[GPIO_IRSEND] < 99) && ir_send_command(type, index, dataBufUc, data_len, payload, svalue, sizeof(svalue))) { + // Serviced + } +#endif // USE_IR_REMOTE else { type = NULL; } @@ -1769,6 +1785,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) #endif // USE_I2C #ifdef USE_WS2812 if (pin[GPIO_WS2812] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, Pixels, Led, Color, Dimmer, Scheme, Fade, Speed, Width, Wakeup, LedTable"), svalue); +#endif +#ifdef USE_IR_REMOTE + if (pin[GPIO_IRSEND] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, IRSend"), svalue); #endif snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue); mqtt_publish_topic_P(0, PSTR("COMMANDS3"), svalue); @@ -2540,6 +2559,10 @@ void GPIO_init() #ifdef USE_WS2812 if (pin[GPIO_WS2812] < 99) ws2812_init(); #endif // USE_WS2812 + +#ifdef USE_IR_REMOTE + if (pin[GPIO_IRSEND] < 99) ir_send_init(); +#endif // USE_IR_REMOTE } void setup() diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 532345a81..492e64218 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -12,11 +12,12 @@ enum upins_t { GPIO_I2C_SCL, // I2C SCL GPIO_I2C_SDA, // I2C SDA GPIO_WS2812, // WS2812 Led string + GPIO_IRSEND, // IR remote GPIO_SWT1, // User connected external switches GPIO_SENSOR_END }; // Text in webpage Module Parameters and commands GPIOS and GPIO -const char sensors[GPIO_SENSOR_END][8] PROGMEM = { +const char sensors[GPIO_SENSOR_END][9] PROGMEM = { "None", "DHT11", "AM2301", @@ -25,6 +26,7 @@ const char sensors[GPIO_SENSOR_END][8] PROGMEM = { "I2C SCL", "I2C SDA", "WS2812", + "IRremote", "Switch" }; // Programmer selectable GPIO functionality offset by user selectable GPIOs @@ -257,7 +259,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = { { "EXS Relay", // Latching relay https://ex-store.de/ESP8266-WiFi-Relay-V31 // Module Pin 1 VCC 3V3, Module Pin 6 GND GPIO_KEY1, // GPIO00 Module Pin 8 - Button (firmware flash) - GPIO_USER, // GPIO01 Module Pin 2 = UART0_TXD + 0, // GPIO01 Module Pin 2 = UART0_TXD GPIO_USER, // GPIO02 Module Pin 7 GPIO_USER, // GPIO03 Module Pin 3 = UART0_RXD GPIO_USER, // GPIO04 Module Pin 10 diff --git a/sonoff/support.ino b/sonoff/support.ino index 9e9dcbf52..454c49647 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -994,7 +994,7 @@ void addLog(byte loglevel, const char *line) #endif // DEBUG_ESP_PORT if (loglevel <= seriallog_level) Serial.printf("%s %s\n", mxtime, line); #ifdef USE_WEBSERVER - if (loglevel <= sysCfg.weblog_level) { + if (sysCfg.webserver && (loglevel <= sysCfg.weblog_level)) { Log[logidx] = String(mxtime) + " " + String(line); logidx++; if (logidx > MAX_LOG_LINES -1) logidx = 0; diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 1e6c6b0da..d2b90a036 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -77,7 +77,7 @@ #define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) (Optional) // -- HTTP ---------------------------------------- -#define USE_WEBSERVER // Enable web server and wifi manager (+60k code, +4k mem) - Disable by // +#define USE_WEBSERVER // Enable web server and wifi manager (+62k code, +4k mem) - Disable by // #define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa #define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin) #define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+11k code, +2k mem) @@ -124,6 +124,8 @@ #define USE_BMP // Add I2C code for BMP/BME280 sensor #define USE_HTU // Add I2C code for HTU21 sensor +#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0.3k mem) + #define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+8k code, +1k mem) - Disable by // #define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB) // #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial TXD) (+1k mem) diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index 2bcb25467..247be80ff 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -1497,6 +1497,7 @@ void hue_lights(String *path) uint8_t device = 1; int16_t pos = 0; uint8_t bri = 0; + bool on = false; char id[4]; path->remove(0,path->indexOf("/lights")); // Remove until /lights @@ -1539,29 +1540,22 @@ void hue_lights(String *path) response.replace("{cmd}", "state/on"); if (webServer->args() == 1) { - String json = webServer->arg(0); - json.replace(" ",""); // remove blanks - - if (json.indexOf("\"on\":") >= 0) // Got "on" command + JsonObject &hue_json = jsonBuffer.parseObject(webServer->arg(0)); + on = hue_json["on"]; + switch(on) { - if (json.indexOf("false") >= 0) // false -> turn device off - { - do_cmnd_power(device, 0); - response.replace("{res}", "false"); - } - else if(json.indexOf("true") >= 0) // true -> Turn device on - { - do_cmnd_power(device, 1); - response.replace("{res}", "true"); - } - else - { - response.replace("{res}", (power & (0x01 << (device-1))) ? "true" : "false"); - } + case false : do_cmnd_power(device, 0); + response.replace("{res}", "false"); + break; + case true : do_cmnd_power(device, 1); + response.replace("{res}", "true"); + break; + default : response.replace("{res}", (power & (0x01 << (device-1))) ? "true" : "false"); + break; } #ifdef USE_WS2812 - if ((pin[GPIO_WS2812] < 99) && ((pos=json.indexOf("\"bri\":")) >= 0)) { - bri = atoi(json.substring(pos+6).c_str()); + bri = hue_json["bri"]; + if (pin[GPIO_WS2812] < 99) { ws2812_changeBrightness(bri); response += ","; response += FPSTR(HUE_LIGHT_RESPONSE_JSON); @@ -1620,7 +1614,7 @@ void handle_hue_api(String *path) addLog(LOG_LEVEL_DEBUG_MORE, log); } - if (path->endsWith("/invalid/")) {} // Just ignore + if (path->endsWith("/invalid/")) {} // Just ignore else if (path->endsWith("/")) hue_auth(path); // New HUE App setup else if (path->endsWith("/config")) hue_config(path); else if (path->indexOf("/lights") >= 0) hue_lights(path); diff --git a/sonoff/xdrv_ir_send.ino b/sonoff/xdrv_ir_send.ino new file mode 100644 index 000000000..1e3a54f43 --- /dev/null +++ b/sonoff/xdrv_ir_send.ino @@ -0,0 +1,84 @@ +/* +Copyright (c) 2017 Heiko Krupp and Theo Arends. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef USE_IR_REMOTE +/*********************************************************************************************\ + * IR Remote send using IRremoteESP8266 library +\*********************************************************************************************/ + +#include + +IRsend *irsend = NULL; + +void ir_send_init(void) +{ + irsend = new IRsend(pin[GPIO_IRSEND]); // an IR led is at GPIO_IRSEND + irsend->begin(); +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +boolean ir_send_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) +{ + boolean serviced = true; + boolean error = false; + const char *protocol; + uint8_t bits = 0; + uint32_t data = 0; + + if (!strcmp(type,"IRSEND")) { + if (data_len) { + JsonObject &ir_json = jsonBuffer.parseObject(dataBuf); + if (!ir_json.success()) { + snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"Invalid JSON\"}")); // JSON decode failed + } else { + snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"Done\"}")); + protocol = ir_json["PROTOCOL"]; + bits = ir_json["BITS"]; + data = ir_json["DATA"]; + if (protocol && bits && data) { + if (!strcmp(protocol,"NEC")) irsend->sendNEC(data, bits); + else if (!strcmp(protocol,"SONY")) irsend->sendSony(data, bits); + else if (!strcmp(protocol,"RC5")) irsend->sendRC5(data, bits); + else if (!strcmp(protocol,"RC6")) irsend->sendRC6(data, bits); + else if (!strcmp(protocol,"DISH")) irsend->sendDISH(data, bits); + else if (!strcmp(protocol,"JVC")) irsend->sendJVC(data, bits, 1); + else if (!strcmp(protocol,"SAMSUNG")) irsend->sendSAMSUNG(data, bits); + else { + snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"Protocol not supported\"}")); + } + } else error = true; + } + } else error = true; + if (error) snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"No protocol, bits or data\"}")); + } + else { + serviced = false; // Unknown command + } + return serviced; +} +#endif // USE_IR_REMOTE diff --git a/sonoff/xdrv_ws2812.ino b/sonoff/xdrv_ws2812.ino index da64bde0d..d1f3c94f7 100644 --- a/sonoff/xdrv_ws2812.ino +++ b/sonoff/xdrv_ws2812.ino @@ -579,7 +579,7 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_ snprintf_P(svalue, ssvalue, PSTR("{\"Scheme\":%d}"), sysCfg.ws_scheme); } else { - serviced = false; + serviced = false; // Unknown command } return serviced; }