From a84b38dae2b542f5c0a596b05084d15e482a63ed Mon Sep 17 00:00:00 2001 From: Staars Date: Thu, 27 Sep 2018 08:34:12 +0200 Subject: [PATCH 01/66] intermediate version for aTime-adjustment --- sonoff/xsns_27_apds9960.ino | 91 +++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 20 deletions(-) diff --git a/sonoff/xsns_27_apds9960.ino b/sonoff/xsns_27_apds9960.ino index 2907bc030..d2e5dbc8b 100644 --- a/sonoff/xsns_27_apds9960.ino +++ b/sonoff/xsns_27_apds9960.ino @@ -39,7 +39,7 @@ * I2C Address: 0x39 \*********************************************************************************************/ -#if defined(USE_SHT) || defined(USE_VEML6070) +#if defined(USE_SHT) || defined(USE_VEML6070) || defined(USE_TSL2561) #warning **** Turned off conflicting drivers SHT and VEML6070 **** #ifdef USE_SHT #undef USE_SHT // SHT-Driver blocks gesture sensor @@ -47,6 +47,9 @@ #ifdef USE_VEML6070 #undef USE_VEML6070 // address conflict on the I2C-bus #endif + #ifdef USE_TSL2561 + #undef USE_TSL2561 // possible address conflict on the I2C-bus + #endif #endif #define APDS9960_I2C_ADDR 0x39 @@ -64,10 +67,11 @@ uint8_t APDS9960addr; uint8_t APDS9960type = 0; -char APDS9960stype[7]; +char APDS9960stype[9]; char currentGesture[6]; uint8_t gesture_mode = 1; + volatile uint8_t recovery_loop_counter = 0; //count number of stateloops to switch the sensor off, if needed #define APDS9960_LONG_RECOVERY 50 //long pause after sensor overload in loops #define APDS9960_MAX_GESTURE_CYCLES 50 //how many FIFO-reads are allowed to prevent crash @@ -78,8 +82,7 @@ const char HTTP_APDS_9960_SNS[] PROGMEM = "%s" "{s}" "Red" "{m}%s{e}" "{s}" "Green" "{m}%s{e}" "{s}" "Blue" "{m}%s{e}" - "{s}" "Ambient" "{m}%s{e}" - "{s}" "Illuminance" "{m}%s " D_UNIT_LUX "{e}" + "{s}" "Ambient" "{m}%s " D_UNIT_LUX "{e}" "{s}" "CCT" "{m}%s " "K" "{e}" // calculated color temperature in Kelvin "{s}" "Proximity" "{m}%s{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER @@ -209,7 +212,7 @@ const char HTTP_APDS_9960_SNS[] PROGMEM = "%s" #define GWTIME_39_2MS 7 /* Default values */ -#define DEFAULT_ATIME 219 // 103ms +#define DEFAULT_ATIME 0xdb // 103ms = 0xdb #define DEFAULT_WTIME 246 // 27ms #define DEFAULT_PROX_PPULSE 0x87 // 16us, 8 pulses #define DEFAULT_GESTURE_PPULSE 0x89 // 16us, 10 pulses ---89 @@ -218,7 +221,7 @@ const char HTTP_APDS_9960_SNS[] PROGMEM = "%s" #define DEFAULT_CONFIG1 0x60 // No 12x wait (WTIME) factor #define DEFAULT_LDRIVE LED_DRIVE_100MA #define DEFAULT_PGAIN PGAIN_4X -#define DEFAULT_AGAIN AGAIN_4X +#define DEFAULT_AGAIN AGAIN_4X // we have to divide by the same facot at the end #define DEFAULT_PILT 0 // Low proximity threshold #define DEFAULT_PIHT 50 // High proximity threshold #define DEFAULT_AILT 0xFFFF // Force interrupt for calibration @@ -287,6 +290,7 @@ typedef struct gesture_data_type { } color_data_type; color_data_type color_data; + uint8_t APDS9960_aTime = DEFAULT_ATIME; /******************************************************************************* @@ -360,7 +364,7 @@ void calculateColorTemperature() /* and 60W incandescent values for a wide range. */ /* Note: Y = Illuminance or lux */ X = (-0.14282F * color_data.r) + (1.54924F * color_data.g) + (-0.95641F * color_data.b); - Y = (-0.32466F * color_data.r) + (1.57837F * color_data.g) + (-0.73191F * color_data.b); // this is Lux + Y = (-0.32466F * color_data.r) + (1.57837F * color_data.g) + (-0.73191F * color_data.b); // this is Lux ... under certain circumstances Z = (-0.68202F * color_data.r) + (0.77073F * color_data.g) + ( 0.56332F * color_data.b); /* 2. Calculate the chromaticity co-ordinates */ @@ -372,7 +376,6 @@ void calculateColorTemperature() /* Calculate the final CCT */ color_data.cct = (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F; - color_data.lux = Y; // according to Adafruit code comments this seems to be not a perfect solution return; } @@ -1611,7 +1614,7 @@ void readAllColorAndProximityData() if (I2cReadBuffer(APDS9960_I2C_ADDR, APDS9960_CDATAL, (uint8_t *) &color_data, (uint16_t)9)) { // not absolutely shure, if this is a correct way to do this, but it is very short - // we fill the struct byte by byte + // we fill the struct byte by byte } } @@ -1803,11 +1806,11 @@ void handleGesture() { break; case DIR_LEFT: snprintf_P(log, sizeof(log), PSTR("LEFT")); - snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Left")); + snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Left")); break; case DIR_RIGHT: snprintf_P(log, sizeof(log), PSTR("RIGHT")); - snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Right")); + snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Right")); break; default: if(APDS9960_overload) @@ -1832,6 +1835,41 @@ void handleGesture() { } } +void APDS9960_adjustATime(void) // not really used atm +{ + //readAllColorAndProximityData(); + I2cValidRead16LE(&color_data.a, APDS9960_I2C_ADDR, APDS9960_CDATAL); + //disablePower(); + + if (color_data.a < (uint16_t)20){ + APDS9960_aTime = 0x40; + } + else if (color_data.a < (uint16_t)40){ + APDS9960_aTime = 0x80; + } + else if (color_data.a < (uint16_t)50){ + APDS9960_aTime = DEFAULT_ATIME; + } + else if (color_data.a < (uint16_t)70){ + APDS9960_aTime = 0xc0; + } + if (color_data.a < 200){ + APDS9960_aTime = 0xe9; + } +/* if (color_data.a < 10000){ + APDS9960_aTime = 0xF0; + }*/ + else{ + APDS9960_aTime = 0xff; + } + + //disableLightSensor(); + I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, APDS9960_aTime); + enablePower(); + enableLightSensor(); + delay(20); +} + void APDS9960_loop() { @@ -1910,29 +1948,30 @@ void APDS9960_show(boolean json) char green_chr[10]; char blue_chr[10]; char ambient_chr[10]; - char illuminance_chr[10]; char cct_chr[10]; char prox_chr[10]; readAllColorAndProximityData(); - sprintf (ambient_chr, "%u", color_data.a); + + sprintf (ambient_chr, "%u", color_data.a/4); sprintf (red_chr, "%u", color_data.r); sprintf (green_chr, "%u", color_data.g); sprintf (blue_chr, "%u", color_data.b ); sprintf (prox_chr, "%u", color_data.p ); + /* disableLightSensor(); + I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, DEFAULT_ATIME); // reset to default + enableLightSensor();*/ + calculateColorTemperature(); // and calculate Lux sprintf (cct_chr, "%u", color_data.cct); - sprintf (illuminance_chr, "%u", color_data.lux); - - if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"Red\":%s,\"Green\":%s,\"Blue\":%s,\"Ambient\":%s,\"Illuminance\":%s,\"CCT\":%s,\"Proximity\":%s}"), - mqtt_data, APDS9960stype, red_chr, green_chr, blue_chr, ambient_chr, illuminance_chr, cct_chr, prox_chr); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"Red\":%s,\"Green\":%s,\"Blue\":%s,\"Ambient\":%s,\"CCT\":%s,\"Proximity\":%s}"), + mqtt_data, APDS9960stype, red_chr, green_chr, blue_chr, ambient_chr, cct_chr, prox_chr); #ifdef USE_WEBSERVER } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_APDS_9960_SNS, mqtt_data, red_chr, green_chr, blue_chr, ambient_chr, illuminance_chr, cct_chr, prox_chr ); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_APDS_9960_SNS, mqtt_data, red_chr, green_chr, blue_chr, ambient_chr, cct_chr, prox_chr ); #endif // USE_WEBSERVER } } @@ -1952,6 +1991,7 @@ void APDS9960_show(boolean json) * Sensor27 | | Show current gesture mode * Sensor27 | 0 / Off | Disable gesture mode * Sensor27 | 1 / On | Enable gesture mode + * Sensor27 | 2 / On | Enable gesture mode with half gain \*********************************************************************************************/ bool APDS9960CommandSensor() @@ -1973,7 +2013,8 @@ bool APDS9960CommandSensor() enableGestureSensor(); gesture_mode = 1; } - case 2: + break; + case 2: // gain of 2x , needed for some models if (APDS9960type) { setGestureGain(GGAIN_2X); setProximityGain(PGAIN_2X); @@ -1981,6 +2022,16 @@ bool APDS9960CommandSensor() enableGestureSensor(); gesture_mode = 1; } + break; + default: + int temp_aTime = (uint8_t)XdrvMailbox.payload; + if (temp_aTime > 2 && temp_aTime < 256){ + disablePower(); + I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, temp_aTime); + enablePower(); + enableLightSensor(); + } + break; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_27, GetStateText(gesture_mode)); From aa0407493731ed841d9dfe3819247d9052dbb12c Mon Sep 17 00:00:00 2001 From: znanev <20048364+znanev@users.noreply.github.com> Date: Fri, 28 Sep 2018 23:21:17 +0100 Subject: [PATCH 02/66] Fix dead links to wiki pages --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 498cd2f80..524ad49ab 100644 --- a/README.md +++ b/README.md @@ -93,8 +93,8 @@ The following devices are supported: - [BlitzWolf BW-SHP2 Smart Socket with Energy Monitoring](https://www.banggood.com/BlitzWolf-BW-SHP2-Smart-WIFI-Socket-EU-Plug-220V-16A-Work-with-Amazon-Alexa-Google-Assistant-p-1292899.html) - [Luani HVIO board](https://luani.de/projekte/esp8266-hvio/) - [Wemos D1 mini](https://wiki.wemos.cc/products:d1:d1_mini) -- [HuaFan Smart Socket](HuaFan-Smart-Socket) -- [Hyleton-313 Smart Plug](Hyleton-313-Smart-Plug) +- [HuaFan Smart Socket](https://github.com/arendst/Sonoff-Tasmota/wiki/HuaFan-Smart-Socket) +- [Hyleton-313 Smart Plug](https://github.com/arendst/Sonoff-Tasmota/wiki/Hyleton-313-Smart-Plug) - [Allterco Shelly 1](https://shelly.cloud/shelly1-open-source/) - [Allterco Shelly 2 with Energy Monitoring](https://shelly.cloud/shelly2/) - NodeMcu and Ledunia From 8255c001b6ac687a6b5007846b194ca708c3fa23 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 29 Sep 2018 10:12:32 +0200 Subject: [PATCH 03/66] Use color2 command (HASS sends normalized RGB) --- sonoff/xdrv_12_home_assistant.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xdrv_12_home_assistant.ino b/sonoff/xdrv_12_home_assistant.ino index b085947ae..304d5fc2f 100644 --- a/sonoff/xdrv_12_home_assistant.ino +++ b/sonoff/xdrv_12_home_assistant.ino @@ -50,7 +50,7 @@ const char HASS_DISCOVER_LIGHT_DIMMER[] PROGMEM = "\"brightness_value_template\":\"{{value_json." D_CMND_DIMMER "}}\""; const char HASS_DISCOVER_LIGHT_COLOR[] PROGMEM = - "%s,\"rgb_command_topic\":\"%s\"," // cmnd/led2/Color + "%s,\"rgb_command_topic\":\"%s2\"," // cmnd/led2/Color2 "\"rgb_state_topic\":\"%s\"," // stat/led2/RESULT "\"rgb_value_template\":\"{{value_json." D_CMND_COLOR "}}\""; // "\"rgb_value_template\":\"{{value_json." D_CMND_COLOR " | join(',')}}\""; From 2252be521ab58afed0bd65f0247ed2f3c445b74b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 29 Sep 2018 12:34:24 +0200 Subject: [PATCH 04/66] Fix I2CScan invalid JSON Fix I2CScan invalid JSON error message (#3925) --- sonoff/_changelog.ino | 1 + sonoff/sonoff_template.h | 34 ++++++++++++++++------------------ sonoff/support.ino | 24 ++++++++++++++++-------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index efd0944b7..2cc23ac4a 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.2.1.9 20180928 * Add Apparent Power and Reactive Power to Energy Monitoring devices (#251) * Add RF Receiver control to module MagicHome to be used on Arilux LC10 (#3792) + * Fix I2CScan invalid JSON error message (#3925) * * 6.2.1.8 20180926 * Change status JSON message providing more switch and retain information diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index d083675d3..55b1ce3aa 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -855,35 +855,19 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0, 0, 0, 0, 0, // Flash connection 0, 0, 0, 0, 0 }, -/* - { "MagicHome", // Magic Home (aka Flux-light) (ESP8266) - // https://www.aliexpress.com/item/Magic-Home-Mini-RGB-RGBW-Wifi-Controller-For-Led-Strip-Panel-light-Timing-Function-16million-colors/32686853650.html - 0, - GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED1_INV, // GPIO02 Blue onboard LED - GPIO_USER, // GPIO03 Serial TXD and Optional sensor - GPIO_USER, // GPIO04 IR receiver (optional) - GPIO_PWM2, // GPIO05 RGB LED Green - 0, 0, 0, 0, 0, 0, // Flash connection - GPIO_PWM3, // GPIO12 RGB LED Blue - GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White) - GPIO_PWM1, // GPIO14 RGB LED Red - 0, 0, 0 - }, -*/ { "MagicHome", // Magic Home (aka Flux-light) (ESP8266) and Arilux LC10 (ESP8285) // https://www.aliexpress.com/item/Magic-Home-Mini-RGB-RGBW-Wifi-Controller-For-Led-Strip-Panel-light-Timing-Function-16million-colors/32686853650.html 0, GPIO_USER, // GPIO01 Serial RXD and Optional sensor GPIO_LED1_INV, // GPIO02 Blue onboard LED GPIO_USER, // GPIO03 Serial TXD and Optional sensor - GPIO_ARIRFRCV, // GPIO04 IR or RF receiver (optional) + GPIO_ARIRFRCV, // GPIO04 IR or RF receiver (optional) (Arilux LC10) GPIO_PWM2, // GPIO05 RGB LED Green 0, 0, 0, 0, 0, 0, // Flash connection GPIO_PWM3, // GPIO12 RGB LED Blue GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White as used on Arilux LC10) GPIO_PWM1, // GPIO14 RGB LED Red - GPIO_LED2_INV, // GPIO15 RF receiver control + GPIO_LED2_INV, // GPIO15 RF receiver control (Arilux LC10) 0, 0 }, { "Luani HVIO", // ESP8266_HVIO @@ -1089,6 +1073,20 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { /* Optionals + { "MagicHome", // Magic Home (aka Flux-light) (ESP8266) + // https://www.aliexpress.com/item/Magic-Home-Mini-RGB-RGBW-Wifi-Controller-For-Led-Strip-Panel-light-Timing-Function-16million-colors/32686853650.html + 0, + GPIO_USER, // GPIO01 Serial RXD and Optional sensor + GPIO_LED1_INV, // GPIO02 Blue onboard LED + GPIO_USER, // GPIO03 Serial TXD and Optional sensor + GPIO_USER, // GPIO04 IR receiver (optional) + GPIO_PWM2, // GPIO05 RGB LED Green + 0, 0, 0, 0, 0, 0, // Flash connection + GPIO_PWM3, // GPIO12 RGB LED Blue + GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White) + GPIO_PWM1, // GPIO14 RGB LED Red + 0, 0, 0 + }, { "Arilux LC10", // Arilux LC10 (ESP8285), RGBW + RF // https://github.com/arendst/Sonoff-Tasmota/wiki/MagicHome-with-ESP8285 // https://www.aliexpress.com/item/DC5-24V-Wireless-WIFI-LED-RGB-Controller-RGBW-Controller-IR-RF-Remote-Control-IOS-Android-for/32827253255.html diff --git a/sonoff/support.ino b/sonoff/support.ino index fc73e726e..3665650dd 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -1775,27 +1775,35 @@ int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len void I2cScan(char *devs, unsigned int devs_len) { - byte error; - byte address; + // Return error codes defined in twi.h and core_esp8266_si2c.c + // I2C_OK 0 + // I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover + // I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond slave clock stretch time + // I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by slave/another_master after n bits + // I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master? + + byte error = 0; + byte address = 0; byte any = 0; - char tstr[10]; snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_DEVICES_FOUND_AT)); for (address = 1; address <= 127; address++) { Wire.beginTransmission(address); error = Wire.endTransmission(); if (0 == error) { - snprintf_P(tstr, sizeof(tstr), PSTR(" 0x%2x"), address); - strncat(devs, tstr, devs_len); any = 1; + snprintf_P(devs, devs_len, PSTR("%s 0x%02x"), devs, address); } - else if (4 == error) { - snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_UNKNOWN_ERROR_AT " 0x%2x\"}"), address); + else if (error != 2) { // Seems to happen anyway using this scan + any = 2; + snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x"), error, address); + break; } } if (any) { strncat(devs, "\"}", devs_len); - } else { + } + else { snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_NO_DEVICES_FOUND "\"}")); } } From 3b3579f1db1c5e06fafa90050e2a3ef63f0b53e5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 29 Sep 2018 13:09:51 +0200 Subject: [PATCH 05/66] Fix config crc errors Fix invalid configuration restores and decode_config.py crc error when savedata = 0 (#3918) --- sonoff/_changelog.ino | 1 + sonoff/xdrv_02_webserver.ino | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 2cc23ac4a..0a113a04f 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -2,6 +2,7 @@ * Add Apparent Power and Reactive Power to Energy Monitoring devices (#251) * Add RF Receiver control to module MagicHome to be used on Arilux LC10 (#3792) * Fix I2CScan invalid JSON error message (#3925) + * Fix invalid configuration restores and decode_config.py crc error when savedata = 0 (#3918) * * 6.2.1.8 20180926 * Change status JSON message providing more switch and retain information diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index 5182b7051..6a939dc24 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -1013,6 +1013,10 @@ void HandleBackupConfiguration() WebServer->sendHeader(F("Content-Disposition"), attachment); WebServer->send(200, FPSTR(HDR_CTYPE_STREAM), ""); + + uint16_t cfg_crc = Settings.cfg_crc; + Settings.cfg_crc = GetSettingsCrc(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918) + memcpy(settings_buffer, &Settings, sizeof(Settings)); if (config_xor_on_set) { for (uint16_t i = 2; i < sizeof(Settings); i++) { @@ -1030,6 +1034,8 @@ void HandleBackupConfiguration() #endif SettingsBufferFree(); + + Settings.cfg_crc = cfg_crc; // Restore crc in case savedata = 0 to make sure settings will be noted as changed } void HandleSaveSettings() From 3997792429d92b24d441911952a93bc51fe51e9c Mon Sep 17 00:00:00 2001 From: Norbert Richter Date: Sat, 29 Sep 2018 13:37:42 +0200 Subject: [PATCH 06/66] v1.5.0011: 'decode-config.py' fixes & enhancements - add configuration data header to json and binary outputs --add template @v and @f for output filename - add output of crc values on crc error - add '--exit-on-error-only' arg make it possible to process partly valid data - replaced '--sort ' by '--unsort' - changed data size and data crc error into warnings - changed output always in json format - removed arg '--format' (obsolete) - removed collections module (obsolete) v1.5.0010: 'decode-config.py' add more detailed outputs - add bit structure for struct TimeRule, Timer, Mcp230xxCfg - add program return code desc - add error handling for additonal python modules - changed 'Settings' definition to handle array of struct - changed field conversion string to formular evaluation for values - fix and enhance output values --- tools/decode-config.py | 1631 ++++++++++++++++++++++++---------------- 1 file changed, 983 insertions(+), 648 deletions(-) diff --git a/tools/decode-config.py b/tools/decode-config.py index dc51e0f42..284904fb9 100644 --- a/tools/decode-config.py +++ b/tools/decode-config.py @@ -19,23 +19,25 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . + Requirements: - Python - pip install json pycurl urllib2 configargparse + Instructions: - Execute command with option -d to retrieve config data from device or - use -f to read out a previously saved configuration file. + Execute command with option -d to retrieve config data from a host + or use -f to read out a configuration file saved using Tasmota Web-UI For help execute command with argument -h Usage: decode-config.py [-h] [-f ] [-d ] [-u ] - [-p ] [--format ] - [--json-indent ] [--json-compact] - [--sort ] [--raw] [--unhide-pw] [-o ] - [-c ] [-V] + [-p ] [--json-indent ] + [--json-compact] [--unsort] [--raw] [--unhide-pw] + [-o ] [--output-file-format ] + [-c ] [--exit-on-error-only] [-V] Decode configuration of Sonoff-Tasmota device. Args that start with '--' (eg. -f) can also be set in a config file (specified via -c). Config file syntax @@ -48,89 +50,84 @@ Usage: -c , --config Config file, can be used instead of command parameter (default: None) + --exit-on-error-only exit on error only (default: exit on ERROR and + WARNING). Not recommended, used by your own + responsibility! source: -f , --file file to retrieve Tasmota configuration from (default: - None) + None)' -d , --device hostname or IP address to retrieve Tasmota configuration from (default: None) -u , --username - host http access username (default: admin) + host HTTP access username (default: admin) -p , --password - host http access password (default: None) + host HTTP access password (default: None) output: - --format output format ("json" or "text", default: "json") --json-indent pretty-printed JSON output using indent level - (default: "None") + (default: 'None') --json-compact compact JSON output by eliminate whitespace (default: - "not compact") - --sort sort result - can be "none" or "name" (default: - "name") - --raw output raw values (default: processed) + normal) + --unsort do not sort results (default: sort) + --raw output raw values (default: process) --unhide-pw unhide passwords (default: hide) -o , --output-file - file to store decrypted raw binary configuration to - (default: None) + file to store configuration to (default: None) Macros: + @v=Tasmota version, @f=friendly name + --output-file-format + output format ('json' or 'binary', default: 'json') info: -V, --version show program's version number and exit Either argument -d or -f must be given. - -Examples: - Read configuration from hostname 'sonoff1' and output default json config - ./decode-config.py -d sonoff1 - - Read configuration from file 'Config__6.2.1.dmp' and output default json config - ./decode-config.py -f Config__6.2.1.dmp - - Read configuration from hostname 'sonoff1' using web login data - ./decode-config.py -d sonoff1 -u admin -p xxxx - - Read configuration from hostname 'sonoff1' using web login data and unhide passwords - ./decode-config.py -d sonoff1 -u admin -p xxxx --unhide-pw - - Read configuration from hostname 'sonoff1' using web login data, unhide passwords - and sort key names - ./decode-config.py -d sonoff1 -u admin -p xxxx --unhide-pw --sort name """ import os.path import io import sys -import configargparse -import collections import struct import re -import json +import math +from datetime import datetime +try: + import json +except ImportError: + print("module not found. Try 'pip install json' to install it") + sys.exit(9) +try: + import configargparse +except ImportError: + print("module not found. Try 'pip install configargparse' to install it") + sys.exit(9) try: import pycurl except ImportError: - print("module not found. Try 'pip pycurl' to install it") + print("module not found. Try 'pip install pycurl' to install it") sys.exit(9) try: import urllib2 except ImportError: - print("module not found. Try 'pip urllib2' to install it") + print("module not found. Try 'pip install urllib2' to install it") sys.exit(9) -VER = '1.5.0009' +VER = '1.5.0011' PROG='{} v{} by Norbert Richter'.format(os.path.basename(sys.argv[0]),VER) CONFIG_FILE_XOR = 0x5A - args = {} DEFAULTS = { 'DEFAULT': { 'configfile': None, + 'exitonwarning':True, }, 'source': { @@ -141,15 +138,16 @@ DEFAULTS = { }, 'output': { - 'format': 'json', 'jsonindent': None, 'jsoncompact': False, - 'sort': 'name', + 'unsort': False, 'raw': False, 'unhide-pw': False, 'outputfile': None, + 'outputfileformat': 'json', }, } +exitcode = 0 """ @@ -163,11 +161,35 @@ Settings dictionary describes the config file fields definition: format Define the data interpretation. - For details see struct module format string - https://docs.python.org/2.7/library/struct.html#format-strings + It is either a string or a tuple containing a string and a + sub-Settings dictionary. + 'xxx': + A string is used to interpret the data at + The string defines the format interpretion as described + in 'struct module format string', see + https://docs.python.org/2.7/library/struct.html#format-strings + In addition to this format string there is as special + meaning of a dot '.' - this means a bit with an optional + prefix length. If no prefix is given, 1 is assumed. + {}: + A dictionary describes itself a 'Settings' dictonary (recursive) baseaddr - The address (starting from 0) within config data + The address (starting from 0) within config data. + For bit fields must be a tuple. + n: + Defines a simple address within config data. + must be a positive integer. + (n, b, s): + A tuple defines a bit field: + + is the address within config data (integer) + + how many bits are used (positive integer) + + bit shift (integer) + positive shift the result right bits + negative shift the result left bits datadef Define the field interpretation different from simple @@ -182,91 +204,74 @@ Settings dictionary describes the config file fields definition: Defines a one-dimensional array of size [n, n <,n...>] Defines a multi-dimensional array - [{} <,{}...] - Defines a bit struct. The items are simply dict - {'bitname', bitlen}, the dict order is important. convert (optional) Define an output/conversion methode, can be a simple string or a previously defined function name. - 'xxx': - a string defines a format specification of the string - formatter, see - https://docs.python.org/2.7/library/string.html#format-string-syntax + 'xxx?': + a string will be evaluate as is replacing all '?' chars + with the current value. This can also be contain pyhton + code. func: a function defines the name of a formating function """ # config data conversion function and helper -def baudrate(value): - return value * 1200 - def int2ip(value): return '{:d}.{:d}.{:d}.{:d}'.format(value & 0xff, value>>8 & 0xff, value>>16 & 0xff, value>>24 & 0xff) -def int2geo(value): - return float(value) / 1000000 - def password(value): if args.unhidepw: return value return '********' -def fingerprintstr(value): - s = list(value) - result = '' - for c in s: - if c in '0123456789abcdefABCDEF': - result += c - return result - - Setting_6_2_1 = { 'cfg_holder': (' from fielddef[0] """ + return fielddef[0] - length=0 - if fielddef[2] is not None: - # fielddef[2] contains a array or int - # calc size recursive by sum of all elements +def GetFieldBaseAddr(fielddef): + """ + Return the format item of field definition - # tuple 2 contains a list with integer or an integer value - if (isinstance(fielddef[2], list) and len(fielddef[2])>0 and isinstance(fielddef[2][0], int)) or isinstance(fielddef[2], int): - for i in range(0, fielddef[2][0] if isinstance(fielddef[2], list) else fielddef[2] ): - # multidimensional array - if isinstance(fielddef[2], list) and len(fielddef[2])>1: - length += GetFieldLength( (fielddef[0], fielddef[1], fielddef[2][1:]) ) - else: - length += GetFieldLength( (fielddef[0], fielddef[1], None) ) - else: - if fielddef[0][-1:].lower() in ['b','c','?']: - length=1 - elif fielddef[0][-1:].lower() in ['h']: - length=2 - elif fielddef[0][-1:].lower() in ['i','l','f']: - length=4 - elif fielddef[0][-1:].lower() in ['q','d']: - length=8 - elif fielddef[0][-1:].lower() in ['s','p']: - # s and p needs prefix as length - match = re.search("\s*(\d+)", fielddef[0]) - if match: - length=int(match.group(0)) + @param fielddef: + field format - see "Settings dictionary" above + + @return: ,, from fielddef[1] + + """ + baseaddr = fielddef[1] + if isinstance(baseaddr, tuple): + return baseaddr[0], baseaddr[1], baseaddr[2] + + return baseaddr, 0, 0 + + +def MakeFieldBaseAddr(baseaddr, bitlen, bitshift): + """ + Return a based on given arguments + + @param baseaddr: + baseaddr from Settings definition + @param bitlen: + 0 or bitlen + @param bitshift: + 0 or bitshift + + @return: (,,) if bitlen != 0 + baseaddr if bitlen == 0 + + """ + if bitlen!=0: + return (baseaddr, bitlen, bitshift) + return baseaddr - # it's a single value - return length def ConvertFieldValue(value, fielddef, raw=False): """ @@ -1682,21 +1850,94 @@ def ConvertFieldValue(value, fielddef, raw=False): @param value: original value read from binary data @param fielddef - field definition (contains possible conversion defiinition) + field definition - see "Settings dictionary" above @param raw return raw values (True) or converted values (False) @return: (un)converted value """ if not raw and len(fielddef)>3: - if isinstance(fielddef[3],str): # use a format string - return fielddef[3].format(value) - elif callable(fielddef[3]): # use a format function - return fielddef[3](value) + convert = fielddef[3] + if isinstance(convert,str): # evaluate strings + try: + return eval(convert.replace('?','value')) + except: + return value + elif callable(convert): # use as format function + return convert(value) return value -def GetField(dobj, fieldname, fielddef, raw=False): +def GetFieldLength(fielddef): + """ + Return length of a field in bytes based on field format definition + + @param fielddef: + field format - see "Settings dictionary" above + + @return: length of field in bytes + + """ + + length=0 + format_ = GetFieldFormat(fielddef) + + # get datadef from field definition + datadef = None + if len(fielddef)>2: + datadef = fielddef[2] + + if datadef is not None: + # fielddef[2] contains a array or int + # calc size recursive by sum of all elements + + # contains a integer list or an single integer value + if (isinstance(datadef, list) \ + and len(datadef)>0 \ + and isinstance(datadef[0], int)) \ + or isinstance(datadef, int): + + for i in range(0, datadef[0] if isinstance(datadef, list) else datadef ): + + # multidimensional array + if isinstance(datadef, list) and len(datadef)>1: + length += GetFieldLength( (fielddef[0], fielddef[1], fielddef[2][1:]) ) + + # single array + else: + length += GetFieldLength( (fielddef[0], fielddef[1], None) ) + + else: + if isinstance(fielddef[0], dict): + # -> iterate through format_ + addr = -1 + setting = fielddef[0] + for name in setting: + baseaddr, bitlen, bitshift = GetFieldBaseAddr(setting[name]) + len_ = GetFieldLength(setting[name]) + if addr != baseaddr: + addr = baseaddr + length += len_ + + else: + if format_[-1:].lower() in ['b','c','?']: + length=1 + elif format_[-1:].lower() in ['h']: + length=2 + elif format_[-1:].lower() in ['i','l','f']: + length=4 + elif format_[-1:].lower() in ['q','d']: + length=8 + elif format_[-1:].lower() in ['s','p']: + # s and p may have a prefix as length + match = re.search("\s*(\d+)", format_) + if match: + length=int(match.group(0)) + + return length + + +def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0): """ Get field value from definition @@ -1714,45 +1955,78 @@ def GetField(dobj, fieldname, fielddef, raw=False): result = None - if fielddef[2] is not None: + # get format from field definition + format_ = GetFieldFormat(fielddef) + + # get baseaddr from field definition + baseaddr, bitlen, bitshift = GetFieldBaseAddr(fielddef) + + # get datadef from field definition + datadef = None + if len(fielddef)>2: + datadef = fielddef[2] + + if datadef is not None: result = [] - # tuple 2 contains a list with integer or an integer value - if (isinstance(fielddef[2], list) and len(fielddef[2])>0 and isinstance(fielddef[2][0], int)) or isinstance(fielddef[2], int): - addr = fielddef[1] - for i in range(0, fielddef[2][0] if isinstance(fielddef[2], list) else fielddef[2] ): + # contains a integer list or an single integer value + if (isinstance(datadef, list) \ + and len(datadef)>0 \ + and isinstance(datadef[0], int)) \ + or isinstance(datadef, int): + + offset = 0 + for i in range(0, datadef[0] if isinstance(datadef, list) else datadef): + # multidimensional array - if isinstance(fielddef[2], list) and len(fielddef[2])>1: - subfielddef = (fielddef[0], addr, fielddef[2][1:], None if len(fielddef)<4 else fielddef[3]) - else: # single array - subfielddef = (fielddef[0], addr, None, None if len(fielddef)<4 else fielddef[3]) + if isinstance(datadef, list) and len(datadef)>1: + if len(fielddef)<4: + subfielddef = (fielddef[0], MakeFieldBaseAddr(baseaddr, bitlen, bitshift), datadef[1:]) + else: + subfielddef = (fielddef[0], MakeFieldBaseAddr(baseaddr, bitlen, bitshift), datadef[1:], fielddef[3]) + + # single array + else: + if len(fielddef)<4: + subfielddef = (fielddef[0], MakeFieldBaseAddr(baseaddr, bitlen, bitshift), None) + else: + subfielddef = (fielddef[0], MakeFieldBaseAddr(baseaddr, bitlen, bitshift), None, fielddef[3]) + length = GetFieldLength(subfielddef) if length != 0: - result.append(GetField(dobj, fieldname, subfielddef, raw)) - addr += length - # tuple 2 contains a list with dict - elif isinstance(fielddef[2], list) and len(fielddef[2])>0 and isinstance(fielddef[2][0], dict): - d = {} - value = struct.unpack_from(fielddef[0], dobj, fielddef[1])[0] - d['base'] = ConvertFieldValue(value, fielddef, raw); - union = fielddef[2] - i = 0 - for l in union: - for name,bits in l.items(): - bitval = (value & ( ((1<> i - d[name] = bitval - i += bits - result = d + result.append(GetField(dobj, fieldname, subfielddef, raw=raw, addroffset=addroffset+offset)) + offset += length + else: - # it's a single value - if GetFieldLength(fielddef) != 0: - result = struct.unpack_from(fielddef[0], dobj, fielddef[1])[0] - if fielddef[0][-1:].lower() in ['s','p']: - if ord(result[:1])==0x00 or ord(result[:1])==0xff: - result = '' - s = str(result).split('\0')[0] - result = unicode(s, errors='replace') - result = ConvertFieldValue(result, fielddef, raw) + # contains a dict + if isinstance(fielddef[0], dict): + # -> iterate through format_ + setting = fielddef[0] + config = {} + for name in setting: + config[name] = GetField(dobj, name, setting[name], raw=args.raw, addroffset=addroffset) + result = config + else: + # a simple value + if GetFieldLength(fielddef) != 0: + result = struct.unpack_from(format_, dobj, baseaddr+addroffset)[0] + + if not format_[-1:].lower() in ['s','p']: + if bitshift>=0: + result >>= bitshift + else: + result <<= abs(bitshift) + if bitlen>0: + result &= (1< 127 + result = unicode(s, errors='ignore') + + result = ConvertFieldValue(result, fielddef, raw) return result @@ -1779,6 +2053,8 @@ def Decode(obj): @param obj: binary config data (decrypted) + + @return: configuration dictionary """ # get header data version = GetField(obj, 'version', Setting_6_2_1['version'], raw=True) @@ -1792,16 +2068,20 @@ def Decode(obj): # if we did not found a mathching setting if template is None: - exit(2, "Can't handle Tasmota configuration data for version 0x{:x}".format(version) ) - + exit(2, "Tasmota configuration version 0x{:x} not supported".format(version) ) + setting = template[2] # check size if exists if 'cfg_size' in setting: cfg_size = GetField(obj, 'cfg_size', setting['cfg_size'], raw=True) - # if we did not found a mathching setting - if cfg_size != template[1]: - exit(2, "Data size does not match. Expected {} bytes, read {} bytes.".format(template[1], cfg_size) ) + # read size should be same as definied in template + if cfg_size > template[1]: + # may be processed + exit(3, "Number of bytes read does ot match - read {}, expected {} byte".format(cfg_size, template[1]), typ='WARNING', doexit=args.exitonwarning) + elif cfg_size < template[1]: + # less number of bytes can not be processed + exit(3, "Number of bytes read to small to process - read {}, expected {} byte".format(cfg_size, template[1]), typ='ERROR') # check crc if exists if 'cfg_crc' in setting: @@ -1809,25 +2089,34 @@ def Decode(obj): else: cfg_crc = GetSettingsCrc(obj) if cfg_crc != GetSettingsCrc(obj): - exit(3, 'Data crc error' ) + exit(4, 'Data CRC error, read 0x{:x} should be 0x{:x}'.format(cfg_crc, GetSettingsCrc(obj)), typ='WARNING', doexit=args.exitonwarning) config = {} - config['version_template'] = '0x{:x}'.format(template[0]) for name in setting: - config[name] = GetField(obj, name, setting[name], args.raw) + config[name] = GetField(obj, name, setting[name], raw=args.raw) - if args.sort == 'name': - config = collections.OrderedDict(sorted(config.items())) - - if args.format == 'json': - print json.dumps(config, sort_keys=args.sort=='name', indent=args.jsonindent, separators=(',', ':') if args.jsoncompact else (', ', ': ') ) - else: - for key,value in config.items(): - print '{} = {}'.format(key, repr(value)) + # add header info + timestamp = datetime.now() + config['header'] = { 'timestamp': timestamp.strftime("%Y-%m-%d %H:%M:%S"), + 'data': { + 'crc': hex(GetSettingsCrc(obj)), + 'size': len(obj), + 'template_version': hex(template[0]), + 'content': { + 'crc': hex(cfg_crc), + 'size': cfg_size, + 'version': hex(version), + }, + }, + 'scriptname': os.path.basename(__file__), + 'scriptversion': VER, + } + return config if __name__ == "__main__": + # program argument processing parser = configargparse.ArgumentParser(description='Decode configuration of Sonoff-Tasmota device.', epilog='Either argument -d or -f must be given.') @@ -1836,80 +2125,89 @@ if __name__ == "__main__": metavar='', dest='tasmotafile', default=DEFAULTS['source']['tasmotafile'], - help='file to retrieve Tasmota configuration from (default: {})'.format(DEFAULTS['source']['tasmotafile'])) + help="file to retrieve Tasmota configuration from (default: {})'".format(DEFAULTS['source']['tasmotafile'])) source.add_argument('-d', '--device', metavar='', dest='device', default=DEFAULTS['source']['device'], - help='hostname or IP address to retrieve Tasmota configuration from (default: {})'.format(DEFAULTS['source']['device']) ) + help="hostname or IP address to retrieve Tasmota configuration from (default: {})".format(DEFAULTS['source']['device']) ) source.add_argument('-u', '--username', metavar='', dest='username', default=DEFAULTS['source']['username'], - help='host http access username (default: {})'.format(DEFAULTS['source']['username'])) + help="host HTTP access username (default: {})".format(DEFAULTS['source']['username'])) source.add_argument('-p', '--password', metavar='', dest='password', default=DEFAULTS['source']['password'], - help='host http access password (default: {})'.format(DEFAULTS['source']['password'])) + help="host HTTP access password (default: {})".format(DEFAULTS['source']['password'])) output = parser.add_argument_group('output') - output.add_argument('--format', - metavar='', - dest='format', - choices=['json', 'text'], - default=DEFAULTS['output']['format'], - help='output format ("json" or "text", default: "{}")'.format(DEFAULTS['output']['format']) ) output.add_argument('--json-indent', metavar='', dest='jsonindent', type=int, default=DEFAULTS['output']['jsonindent'], - help='pretty-printed JSON output using indent level (default: "{}")'.format(DEFAULTS['output']['jsonindent']) ) + help="pretty-printed JSON output using indent level (default: '{}')".format(DEFAULTS['output']['jsonindent']) ) output.add_argument('--json-compact', dest='jsoncompact', action='store_true', default=DEFAULTS['output']['jsoncompact'], - help='compact JSON output by eliminate whitespace (default: "{}")'.format('compact' if DEFAULTS['output']['jsoncompact'] else 'not compact') ) - output.add_argument('--sort', - metavar='', - dest='sort', - choices=['none', 'name'], - default=DEFAULTS['output']['sort'], - help='sort result - can be "none" or "name" (default: "{}")'.format(DEFAULTS['output']['sort']) ) + help="compact JSON output by eliminate whitespace (default: {})".format('normal' if not DEFAULTS['output']['jsoncompact'] else 'compact') ) + output.add_argument('--unsort', + dest='unsort', + action='store_true', + default=DEFAULTS['output']['unsort'], + help="do not sort results (default: {})".format('sort' if not DEFAULTS['output']['unsort'] else 'unsort') ) output.add_argument('--raw', dest='raw', action='store_true', default=DEFAULTS['output']['raw'], - help='output raw values (default: {})'.format('raw' if DEFAULTS['output']['raw'] else 'processed') ) + help="output raw values (default: {})".format('raw' if DEFAULTS['output']['raw'] else 'process') ) output.add_argument('--unhide-pw', dest='unhidepw', action='store_true', default=DEFAULTS['output']['unhide-pw'], - help='unhide passwords (default: {})'.format('unhide' if DEFAULTS['output']['unhide-pw'] else 'hide') ) + help="unhide passwords (default: {})".format('unhide' if DEFAULTS['output']['unhide-pw'] else 'hide') ) output.add_argument('-o', '--output-file', metavar='', dest='outputfile', default=DEFAULTS['output']['outputfile'], - help='file to store decrypted raw binary configuration to (default: {})'.format(DEFAULTS['output']['outputfile'])) + help="file to store configuration to (default: {}) Macros: @v=Tasmota version, @f=friendly name".format(DEFAULTS['output']['outputfile'])) + output.add_argument('--output-file-format', + metavar='', + dest='outputfileformat', + choices=['json', 'binary'], + default=DEFAULTS['output']['outputfileformat'], + help="output format ('json' or 'binary', default: '{}')".format(DEFAULTS['output']['outputfileformat']) ) parser.add_argument('-c', '--config', metavar='', dest='configfile', default=DEFAULTS['DEFAULT']['configfile'], is_config_file=True, - help='Config file, can be used instead of command parameter (default: {})'.format(DEFAULTS['DEFAULT']['configfile']) ) + help="Config file, can be used instead of command parameter (default: {})".format(DEFAULTS['DEFAULT']['configfile']) ) + parser.add_argument('--exit-on-error-only', + dest='exitonwarning', + action='store_false', + default=DEFAULTS['DEFAULT']['exitonwarning'], + help="exit on error only (default: {}). Not recommended, used by your own responsibility!".format('exit on ERROR and WARNING' if DEFAULTS['DEFAULT']['exitonwarning'] else 'exit on ERROR') ) info = parser.add_argument_group('info') info.add_argument('-V', '--version', action='version', version=PROG) args = parser.parse_args() - + + # default no configuration available configobj = None - + + # check source args + if args.device is not None and args.tasmotafile is not None: + exit(6, "Only one source allowed. Do not use -d and -f together") + + # read config direct from device via http if args.device is not None: - # read config direct from device via http buffer = io.BytesIO() url = str("http://{}/dl".format(args.device)) c = pycurl.Curl() @@ -1930,11 +2228,11 @@ if __name__ == "__main__": configobj = buffer.getvalue() + # read config from a file elif args.tasmotafile is not None: - # read config from a file if not os.path.isfile(args.tasmotafile): # check file exists - exit(1, "file '{}' not found".format(args.tasmotafile)) + exit(1, "File '{}' not found".format(args.tasmotafile)) try: tasmotafile = open(args.tasmotafile, "rb") configobj = tasmotafile.read() @@ -1942,22 +2240,59 @@ if __name__ == "__main__": except Exception, e: exit(e[0], e[1]) + # no config source given else: parser.print_help() sys.exit(0) + if configobj is not None and len(configobj)>0: cfg = DeEncrypt(configobj) - if args.outputfile is not None: - outputfile = open(args.outputfile, "wb") - outputfile.write(cfg) - outputfile.close() + config = Decode(cfg) - Decode(cfg) + # output to file + if args.outputfile is not None: + outputfilename = args.outputfile + v = f1 = f2 = f3 = f4 = '' + if 'version' in config: + ver = int(str(config['version']), 0) + major = ((ver>>24) & 0xff) + minor = ((ver>>16) & 0xff) + release = ((ver>> 8) & 0xff) + subrelease = (ver & 0xff) + if major>=6: + if subrelease>0: + subreleasestr = str(subrelease) + else: + subreleasestr = '' + else: + if subrelease>0: + subreleasestr = str(chr(subrelease+ord('a')-1)) + else: + subreleasestr = '' + v = "{:d}.{:d}.{:d}{}{}".format( major, minor, release, '.' if major>=6 else '', subreleasestr) + outputfilename = outputfilename.replace('@v', v) + if 'friendlyname' in config: + outputfilename = outputfilename.replace('@f', config['friendlyname'][0] ) + + if args.outputfileformat == 'binary': + outputfile = open(outputfilename, "wb") + outputfile.write(struct.pack(' Date: Sat, 29 Sep 2018 16:55:53 +0200 Subject: [PATCH 07/66] Add basic support for color calibration --- sonoff/i18n.h | 1 + sonoff/settings.h | 4 +++- sonoff/settings.ino | 9 +++++++++ sonoff/sonoff_version.h | 2 +- sonoff/xdrv_04_light.ino | 34 +++++++++++++++++++++++++++++++--- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 2090f4793..bc161c078 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -317,6 +317,7 @@ #define D_CMND_LEDTABLE "LedTable" #define D_CMND_FADE "Fade" #define D_CMND_PIXELS "Pixels" +#define D_CMND_RGBWWTABLE "RGBWWTable" #define D_CMND_ROTATION "Rotation" #define D_CMND_SCHEME "Scheme" #define D_CMND_SPEED "Speed" diff --git a/sonoff/settings.h b/sonoff/settings.h index bf862dd51..7dfb91089 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -322,7 +322,9 @@ struct SYSCFG { uint16_t mcp230xx_int_timer; // 718 - byte free_71A[174]; // 71A + uint8_t rgbwwTable[5]; // 71A + + byte free_71A[169]; // 71F unsigned long energy_frequency_calibration; // 7C8 diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 95e6ce367..4116a1c6d 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -624,6 +624,10 @@ void SettingsDefaultSet2() Settings.button_debounce = KEY_DEBOUNCE_TIME; Settings.switch_debounce = SWITCH_DEBOUNCE_TIME; + + for (byte j = 0; j < 5; j++) { + Settings.rgbwwTable[j] = 255; + } } /********************************************************************************************/ @@ -827,6 +831,11 @@ void SettingsDelta() Settings.button_debounce = KEY_DEBOUNCE_TIME; Settings.switch_debounce = SWITCH_DEBOUNCE_TIME; } + if (Settings.version < 0x0602010A) { + for (byte j = 0; j < 5; j++) { + Settings.rgbwwTable[j] = 255; + } + } Settings.version = VERSION; SettingsSave(1); diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 4f2b5c0ec..c5765ec38 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x06020109 +#define VERSION 0x0602010A #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino index 2a5a15b0c..6c8aa938d 100644 --- a/sonoff/xdrv_04_light.ino +++ b/sonoff/xdrv_04_light.ino @@ -55,11 +55,11 @@ enum LightCommands { CMND_COLOR, CMND_COLORTEMPERATURE, CMND_DIMMER, CMND_LED, CMND_LEDTABLE, CMND_FADE, - CMND_PIXELS, CMND_ROTATION, CMND_SCHEME, CMND_SPEED, CMND_WAKEUP, CMND_WAKEUPDURATION, + CMND_PIXELS, CMND_RGBWWTABLE, CMND_ROTATION, CMND_SCHEME, CMND_SPEED, CMND_WAKEUP, CMND_WAKEUPDURATION, CMND_WIDTH, CMND_CHANNEL, CMND_HSBCOLOR, CMND_UNDOCA }; const char kLightCommands[] PROGMEM = D_CMND_COLOR "|" D_CMND_COLORTEMPERATURE "|" D_CMND_DIMMER "|" D_CMND_LED "|" D_CMND_LEDTABLE "|" D_CMND_FADE "|" - D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|" + D_CMND_PIXELS "|" D_CMND_RGBWWTABLE "|" D_CMND_ROTATION "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|" D_CMND_WIDTH "|" D_CMND_CHANNEL "|" D_CMND_HSBCOLOR "|UNDOCA" ; struct LRgbColor { @@ -799,7 +799,8 @@ void LightAnimate() light_update = 0; for (byte i = 0; i < light_subtype; i++) { light_last_color[i] = light_new_color[i]; - cur_col[i] = (Settings.light_correction) ? ledTable[light_last_color[i]] : light_last_color[i]; + cur_col[i] = light_last_color[i]*Settings.rgbwwTable[i]/255; + cur_col[i] = (Settings.light_correction) ? ledTable[cur_col[i]] : cur_col[i]; if (light_type < LT_PWM6) { if (pin[GPIO_PWM1 +i] < 99) { if (cur_col[i] > 0xFC) { @@ -1279,6 +1280,33 @@ boolean LightCommand() } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.light_correction)); } + else if (CMND_RGBWWTABLE == command_code) { + bool validtable = (XdrvMailbox.data_len > 0); + char scolor[25]; + if (validtable) { + uint16_t HSB[3]; + if (strstr(XdrvMailbox.data, ",")) { // Command with up to 5 comma separated parameters + for (int i = 0; i < LST_RGBWC; i++) { + char *substr; + + if (0 == i) { + substr = strtok(XdrvMailbox.data, ","); + } else { + substr = strtok(NULL, ","); + } + if (substr != NULL) { + Settings.rgbwwTable[i] = atoi(substr); + } + } + } + light_update = 1; + } + scolor[0] = '\0'; + for (byte i = 0; i < LST_RGBWC; i++) { + snprintf_P(scolor, 25, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", Settings.rgbwwTable[i]); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, scolor); + } else if (CMND_FADE == command_code) { switch (XdrvMailbox.payload) { case 0: // Off From cdc8a4d9ebc6043db47aaf7f79a5f8132ad68350 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 30 Sep 2018 10:54:52 +0200 Subject: [PATCH 08/66] tiny change --- sonoff/settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/settings.h b/sonoff/settings.h index 7dfb91089..978b72b24 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -324,7 +324,7 @@ struct SYSCFG { uint8_t rgbwwTable[5]; // 71A - byte free_71A[169]; // 71F + byte free_71F[169]; // 71F unsigned long energy_frequency_calibration; // 7C8 From 6a1a21f03a1d9fcaab3bfe81162a8eb1b575c778 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 30 Sep 2018 11:02:47 +0200 Subject: [PATCH 09/66] 6.2.1.10 Add RGBWWTable 6.2.1.10 20180930 * Add command RGBWWTable to support color calibration (#3933) --- sonoff/_changelog.ino | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 0a113a04f..d4c609f14 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,8 +1,11 @@ -/* 6.2.1.9 20180928 +/* 6.2.1.10 20180930 + * Add command RGBWWTable to support color calibration (#3933) + * + * 6.2.1.9 20180928 * Add Apparent Power and Reactive Power to Energy Monitoring devices (#251) * Add RF Receiver control to module MagicHome to be used on Arilux LC10 (#3792) * Fix I2CScan invalid JSON error message (#3925) - * Fix invalid configuration restores and decode_config.py crc error when savedata = 0 (#3918) + * Fix invalid configuration restores and decode_config.py crc error when savedata = 0 (#3918) * * 6.2.1.8 20180926 * Change status JSON message providing more switch and retain information From 2fd42446e99b0582545521f875f044ad6345f435 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 30 Sep 2018 14:33:26 +0200 Subject: [PATCH 10/66] Add ESP Switch support Add support for Michael Haustein ESP Switch --- sonoff/_changelog.ino | 3 ++- sonoff/sonoff_template.h | 43 +++++++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index d4c609f14..20cbded76 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.2.1.10 20180930 * Add command RGBWWTable to support color calibration (#3933) - * + * Add support for Michael Haustein ESP Switch + * * 6.2.1.9 20180928 * Add Apparent Power and Reactive Power to Energy Monitoring devices (#251) * Add RF Receiver control to module MagicHome to be used on Arilux LC10 (#3792) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 55b1ce3aa..e51e918fe 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -232,6 +232,7 @@ enum SupportedModules { SHELLY2, PHILIPS, NEO_COOLCAM, + ESP_SWITCH, MAXMODULE }; /********************************************************************************************/ @@ -392,6 +393,7 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { SHELLY2, BLITZWOLF_BWSHP2, NEO_COOLCAM, + ESP_SWITCH, H801, MAGICHOME, ARILUX_LC01, @@ -598,21 +600,22 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_LED1, // GPIO16 Green/Blue Led (1 = On, 0 = Off) GPIO_ADC0 // ADC0 A0 Analog input }, - { "EXS Relay", // Latching relay (ESP8266) + { "EXS Relay(s)", // ES-Store Latching relay(s) (ESP8266) // 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 - GPIO_USER, // GPIO02 Module Pin 7 - GPIO_USER, // GPIO03 Module Pin 3 = UART0_RXD - GPIO_USER, // GPIO04 Module Pin 10 - GPIO_USER, // GPIO05 Module Pin 9 + // V3.1 Module Pin 1 VCC 3V3, Module Pin 6 GND + // https://ex-store.de/2-Kanal-WiFi-WLan-Relay-V5-Blackline-fuer-Unterputzmontage + GPIO_USER, // GPIO00 V3.1 Module Pin 8 - V5.0 Module Pin 4 + GPIO_USER, // GPIO01 UART0_TXD V3.1 Module Pin 2 - V5.0 Module Pin 3 + GPIO_USER, // GPIO02 V3.1 Module Pin 7 + GPIO_USER, // GPIO03 UART0_RXD V3.1 Module Pin 3 + GPIO_USER, // GPIO04 V3.1 Module Pin 10 - V5.0 Module Pin 2 + GPIO_USER, // GPIO05 V3.1 Module Pin 9 - V5.0 Module Pin 1 0, 0, 0, 0, 0, 0, // Flash connection GPIO_REL1, // GPIO12 Relay1 ( 1 = Off) GPIO_REL2, // GPIO13 Relay1 ( 1 = On) - GPIO_USER, // GPIO14 Module Pin 5 - 0, - GPIO_USER, // GPIO16 Module Pin 4 + GPIO_USER, // GPIO14 V3.1 Module Pin 5 - V5.0 Relay2 ( 1 = Off) + GPIO_LED1, // GPIO15 V5.0 LED1 + GPIO_USER, // GPIO16 V3.1 Module Pin 4 - V5.0 Relay2 ( 1 = On) 0 }, { "WiOn", // Indoor Tap (ESP8266) @@ -1061,12 +1064,28 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { { "Neo Coolcam", // Neo Coolcam (ESP8266) // https://www.banggood.com/NEO-COOLCAM-WiFi-Mini-Smart-Plug-APP-Remote-Control-Timing-Smart-Socket-EU-Plug-p-1288562.html?cur_warehouse=CN 0, 0, 0, 0, - GPIO_LED1_INV, // GPIO13 Red Led (0 = On, 1 = Off) + GPIO_LED1_INV, // GPIO04 Red Led (0 = On, 1 = Off) 0, 0, 0, 0, 0, 0, 0, // Flash connection GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) GPIO_KEY1, // GPIO13 Button 0, 0, 0, 0 + }, + { "ESP Switch", // Michael Haustein 4 channel wall switch (ESP07 = ESP8266) + // Use rules for further actions like - rule on power1#state do publish cmnd/other_device/power %value% endon + GPIO_KEY2, // GPIO00 Button 2 + GPIO_USER, // GPIO01 Serial RXD and Optional sensor + GPIO_REL3_INV, // GPIO02 Yellow Led 3 (0 = On, 1 = Off) + GPIO_USER, // GPIO03 Serial TXD and Optional sensor + GPIO_KEY1, // GPIO04 Button 1 + GPIO_REL2_INV, // GPIO05 Red Led 2 (0 = On, 1 = Off) + 0, 0, 0, 0, 0, 0, // Flash connection + GPIO_REL4_INV, // GPIO12 Blue Led 4 (0 = On, 1 = Off) + GPIO_KEY4, // GPIO13 Button 4 + GPIO_KEY3, // GPIO14 Button 3 + GPIO_LED1, // GPIO15 Optional sensor + GPIO_REL1_INV, // GPIO16 Green Led 1 (0 = On, 1 = Off) + 0 } }; From 191df17b13fa4e3c1204421d68060c8bca4f61b6 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 30 Sep 2018 16:52:25 +0200 Subject: [PATCH 11/66] Add support for EXS Relay V5.0 Add support for EXS Relay V5.0 (#3810) --- sonoff/_changelog.ino | 1 + sonoff/sonoff.ino | 35 +++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 20cbded76..da3db4570 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.2.1.10 20180930 * Add command RGBWWTable to support color calibration (#3933) * Add support for Michael Haustein ESP Switch + * Add support for EXS Relay V5.0 (#3810) * * 6.2.1.9 20180928 * Add Apparent Power and Reactive Power to Energy Monitoring devices (#251) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 6b354bb24..b89ffe138 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -296,20 +296,23 @@ char* GetStateText(byte state) /********************************************************************************************/ -void SetLatchingRelay(power_t power, uint8_t state) +void SetLatchingRelay(power_t lpower, uint8_t state) { - power &= 1; - if (2 == state) { // Reset relay - state = 0; - latching_power = power; - latching_relay_pulse = 0; + // power xx00 - toggle REL1 (Off) and REL3 (Off) - device 1 Off, device 2 Off + // power xx01 - toggle REL2 (On) and REL3 (Off) - device 1 On, device 2 Off + // power xx10 - toggle REL1 (Off) and REL4 (On) - device 1 Off, device 2 On + // power xx11 - toggle REL2 (On) and REL4 (On) - device 1 On, device 2 On + + if (state && !latching_relay_pulse) { // Set latching relay to power if previous pulse has finished + latching_power = lpower; + latching_relay_pulse = 2; // max 200mS (initiated by stateloop()) } - else if (state && !latching_relay_pulse) { // Set port power to On - latching_power = power; - latching_relay_pulse = 2; // max 200mS (initiated by stateloop()) - } - if (pin[GPIO_REL1 +latching_power] < 99) { - digitalWrite(pin[GPIO_REL1 +latching_power], bitRead(rel_inverted, latching_power) ? !state : state); + + for (byte i = 0; i < devices_present; i++) { + uint8_t port = (i << 1) + ((latching_power >> i) &1); + if (pin[GPIO_REL1 +port] < 99) { + digitalWrite(pin[GPIO_REL1 +port], bitRead(rel_inverted, port) ? !state : state); + } } } @@ -2453,6 +2456,10 @@ void GpioInit() if (pin[GPIO_REL1 +i] < 99) { pinMode(pin[GPIO_REL1 +i], OUTPUT); devices_present++; + if (EXS_RELAY == Settings.module) { + digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0); + if (i &1) { devices_present--; } + } } } } @@ -2493,10 +2500,6 @@ void GpioInit() } } - if (EXS_RELAY == Settings.module) { - SetLatchingRelay(0,2); - SetLatchingRelay(1,2); - } SetLedPower(Settings.ledstate &8); XdrvCall(FUNC_PRE_INIT); From b9b6d132f53753987ef8a86e28aa104f03844512 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 30 Sep 2018 17:52:41 +0200 Subject: [PATCH 12/66] Fix timer offset -00:00 Fix timer offset -00:00 causing 12:00 hour offset (#3923) --- sonoff/_changelog.ino | 1 + sonoff/xdrv_09_timers.ino | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index da3db4570..21e00702e 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -2,6 +2,7 @@ * Add command RGBWWTable to support color calibration (#3933) * Add support for Michael Haustein ESP Switch * Add support for EXS Relay V5.0 (#3810) + * Fix timer offset -00:00 causing 12:00 hour offset (#3923) * * 6.2.1.9 20180928 * Add Apparent Power and Reactive Power to Energy Monitoring devices (#251) diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index 66bf93614..124b41534 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -194,7 +194,7 @@ void ApplyTimerOffsets(Timer *duskdawn) // apply offsets, check for over- and underflows uint16_t timeBuffer; - if ((uint16_t)stored.time > 720) { + if ((uint16_t)stored.time > 719) { // negative offset, time after 12:00 timeBuffer = (uint16_t)stored.time - 720; // check for underflow From 89825907d05b8e3816f22ad1194734b8bc9327da Mon Sep 17 00:00:00 2001 From: Florian Schroen Date: Sun, 30 Sep 2018 18:38:01 +0200 Subject: [PATCH 13/66] Add support for OBI smart socket Model tested: WFG-1 Models maybe working: WFF-1, WFE-1, WFI-1, WFD-1, WFR-1, WFA-1, WFU-1 Manufactured by: Cixi Yidong Electronics Co. Ltd - http://www.cn-yidong.com/ Sold by: OBI DIY market in Germany - https://www.obi.de/ --- sonoff/sonoff_template.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index e51e918fe..0a4f98d35 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -233,6 +233,7 @@ enum SupportedModules { PHILIPS, NEO_COOLCAM, ESP_SWITCH, + OBI, MAXMODULE }; /********************************************************************************************/ @@ -394,6 +395,7 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { BLITZWOLF_BWSHP2, NEO_COOLCAM, ESP_SWITCH, + OBI, H801, MAGICHOME, ARILUX_LC01, @@ -1085,7 +1087,21 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_KEY3, // GPIO14 Button 3 GPIO_LED1, // GPIO15 Optional sensor GPIO_REL1_INV, // GPIO16 Green Led 1 (0 = On, 1 = Off) - 0 + }, + { "OBI Socket", // OBI socket (ESP8266) - https://www.obi.de/hausfunksteuerung/wifi-stecker-schuko/p/2291706 + 0, // GPIO00 Flash jumper - not available + 0, // GPIO01 + 0, // GPIO02 + 0, // GPIO03 + GPIO_LED1, // GPIO04 LED on top and in switch button + GPIO_REL1, // GPIO05 Relay 1 (0 = Off, 1 = On) + 0, 0, 0, 0, 0, 0, // Flash connection + GPIO_LED2, // GPIO12 + 0, // GPIO13 + GPIO_KEY1, // GPIO14 switch button + 0, // GPIO15 + 0, // GPIO16 + 0 // GPIO17 } }; From ee0ef227dcf6830ae5c4a53ed7bb95f5b29d3aee Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sun, 30 Sep 2018 23:07:46 +0200 Subject: [PATCH 14/66] Add ability to set default PWM Freq using #define #define USE_PCA9685_FREQ --- sonoff/user_config.h | 1 + sonoff/xdrv_15_pca9685.ino | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index eceadc68d..72aa97d53 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -302,6 +302,7 @@ // #define USE_MCP230xx_DISPLAYOUTPUT // Enable MCP23008/MCP23017 to display state of OUTPUT pins on Web UI (+0k2 code) // #define USE_PCA9685 // Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) // #define USE_PCA9685_ADDR 0x40 // Enable PCA9685 I2C Address to use (Must be within range 0x40 through 0x47 - set according to your wired setup) +// #define USE_PCA9685_FREQ 50 // Define default PWM frequency in Hz to be used (must be within 24 to 1526) - If other value is used, it will rever to 50Hz // #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) // #define USE_CCS811 // Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) // #define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code) diff --git a/sonoff/xdrv_15_pca9685.ino b/sonoff/xdrv_15_pca9685.ino index e53b8d17f..c17ec3bee 100644 --- a/sonoff/xdrv_15_pca9685.ino +++ b/sonoff/xdrv_15_pca9685.ino @@ -27,7 +27,7 @@ #define PCA9685_REG_PRE_SCALE 0xFE uint8_t pca9685_detected = 0; -uint16_t pca9685_freq = 50; +uint16_t pca9685_freq = USE_PCA9685_FREQ; void PCA9685_Detect(void) { @@ -51,7 +51,7 @@ void PCA9685_Detect(void) void PCA9685_Reset(void) { I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, 0x80); - PCA9685_SetPWMfreq(50); + PCA9685_SetPWMfreq(USE_PCA9685_FREQ); for (uint8_t pin=0;pin<16;pin++) { PCA9685_SetPWM(pin,0,false); } @@ -63,9 +63,13 @@ void PCA9685_SetPWMfreq(double freq) { 7.3.5 from datasheet prescale value = round(25000000/(4096*freq))-1; */ - pca9685_freq=freq; - uint8_t pre_scale_osc = round(25000000/(4096*freq))-1; - if (1526 == freq) pre_scale_osc=0xFF; // force setting for 24hz because rounding causes 1526 to be 254 + if (freq > 23 && freq < 1527) { + pca9685_freq=freq; + } else { + pca9685_freq=50; + } + uint8_t pre_scale_osc = round(25000000/(4096*pca9685_freq))-1; + if (1526 == pca9685_freq) pre_scale_osc=0xFF; // force setting for 24hz because rounding causes 1526 to be 254 uint8_t current_mode1 = I2cRead8(USE_PCA9685_ADDR, PCA9685_REG_MODE1); // read current value of MODE1 register uint8_t sleep_mode1 = (current_mode1&0x7F) | 0x10; // Determine register value to put PCA to sleep I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, sleep_mode1); // Let's sleep a little From 068211cae9857bb93373690772f35b33b3f48c4d Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sun, 30 Sep 2018 23:33:14 +0200 Subject: [PATCH 15/66] Add #define USE_PCA9685_FREQ 50 if not defined Add #define USE_PCA9685_FREQ 50 if not defined in user_config.h --- sonoff/xdrv_15_pca9685.ino | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sonoff/xdrv_15_pca9685.ino b/sonoff/xdrv_15_pca9685.ino index c17ec3bee..3114aa461 100644 --- a/sonoff/xdrv_15_pca9685.ino +++ b/sonoff/xdrv_15_pca9685.ino @@ -26,6 +26,10 @@ #define PCA9685_REG_LED0_ON_L 0x06 #define PCA9685_REG_PRE_SCALE 0xFE +#ifndef USE_PCA9685_FREQ + #define USE_PCA9685_FREQ 50 +#endif + uint8_t pca9685_detected = 0; uint16_t pca9685_freq = USE_PCA9685_FREQ; From da0b283fe7249e8b3b1c46f8808bb9a7251ff14f Mon Sep 17 00:00:00 2001 From: andrethomas Date: Mon, 1 Oct 2018 00:18:37 +0200 Subject: [PATCH 16/66] PCA9685 - Add telemetry output --- sonoff/xdrv_15_pca9685.ino | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/sonoff/xdrv_15_pca9685.ino b/sonoff/xdrv_15_pca9685.ino index 3114aa461..841ae22ab 100644 --- a/sonoff/xdrv_15_pca9685.ino +++ b/sonoff/xdrv_15_pca9685.ino @@ -32,6 +32,7 @@ uint8_t pca9685_detected = 0; uint16_t pca9685_freq = USE_PCA9685_FREQ; +uint16_t pca9685_pin_pwm_value[16]; void PCA9685_Detect(void) { @@ -57,7 +58,8 @@ void PCA9685_Reset(void) I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, 0x80); PCA9685_SetPWMfreq(USE_PCA9685_FREQ); for (uint8_t pin=0;pin<16;pin++) { - PCA9685_SetPWM(pin,0,false); + PCA9685_SetPWM(pin,0,false); + pca9685_pin_pwm_value[pin] = 0; } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"RESET\":\"OK\"}}")); } @@ -115,6 +117,7 @@ bool PCA9685_Command(void) if (',' == XdrvMailbox.data[ca]) { paramcount++; } } UpperCase(XdrvMailbox.data,XdrvMailbox.data); + if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"RESET")) { PCA9685_Reset(); return serviced; } if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"PWMF")) { @@ -122,7 +125,7 @@ bool PCA9685_Command(void) uint16_t new_freq = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); if ((new_freq >= 24) && (new_freq <= 1526)) { PCA9685_SetPWMfreq(new_freq); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PWMF\":%i, \"Result\":\"OK\"}}")); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PWMF\":%i, \"Result\":\"OK\"}}"),new_freq); return serviced; } } else { // No parameter was given for setfreq, so we return current setting @@ -159,6 +162,17 @@ bool PCA9685_Command(void) return serviced; } +void PCA9685_OutputTelemetry(void) { + if (0 == pca9685_detected) { return; } // We do not do this if the PCA9685 has not been detected + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"PCA9685\": {"), GetDateAndTime(DT_LOCAL).c_str()); + snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"PWM_FREQ\":%i,"),mqtt_data,pca9685_freq); + for (uint8_t pin=0;pin<16;pin++) { + snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"PWM%i\":%i,"),mqtt_data,pin,pca9685_pin_pwm_value[pin]); + } + snprintf_P(mqtt_data,sizeof(mqtt_data),PSTR("%s\"END\":1}}"),mqtt_data); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); +} + boolean Xdrv15(byte function) { boolean result = false; @@ -169,6 +183,9 @@ boolean Xdrv15(byte function) break; case FUNC_EVERY_SECOND: PCA9685_Detect(); + if (tele_period == 0) { + PCA9685_OutputTelemetry(); + } break; case FUNC_EVERY_50_MSECOND: break; From 047f430ad8c8ae65e8a376928b7792a88074810e Mon Sep 17 00:00:00 2001 From: andrethomas Date: Mon, 1 Oct 2018 00:27:16 +0200 Subject: [PATCH 17/66] PCA9685 - Remove unused callbacks in Xdrv15() --- sonoff/xdrv_15_pca9685.ino | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sonoff/xdrv_15_pca9685.ino b/sonoff/xdrv_15_pca9685.ino index 841ae22ab..9cb9292a0 100644 --- a/sonoff/xdrv_15_pca9685.ino +++ b/sonoff/xdrv_15_pca9685.ino @@ -179,25 +179,17 @@ boolean Xdrv15(byte function) if (i2c_flg) { switch (function) { - case FUNC_MQTT_DATA: - break; case FUNC_EVERY_SECOND: PCA9685_Detect(); if (tele_period == 0) { PCA9685_OutputTelemetry(); } break; - case FUNC_EVERY_50_MSECOND: - break; - case FUNC_JSON_APPEND: - break; case FUNC_COMMAND: if (XDRV_15 == XdrvMailbox.index) { PCA9685_Command(); } break; - case FUNC_WEB_APPEND: - break; default: break; } From 9e5aaef51f9cdf2cca08bd23e08aead10c03c7d9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 1 Oct 2018 12:19:58 +0200 Subject: [PATCH 18/66] Add OBI/Teckin Socket support * Add support for OBI Power Socket (#1988, #3944) * Add support for Teckin Power Socket with Energy Monitoring (#3950) --- sonoff/_changelog.ino | 2 ++ sonoff/sonoff_template.h | 66 +++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 21e00702e..04f209e10 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -3,6 +3,8 @@ * Add support for Michael Haustein ESP Switch * Add support for EXS Relay V5.0 (#3810) * Fix timer offset -00:00 causing 12:00 hour offset (#3923) + * Add support for OBI Power Socket (#1988, #3944) + * Add support for Teckin Power Socket with Energy Monitoring (#3950) * * 6.2.1.9 20180928 * Add Apparent Power and Reactive Power to Energy Monitoring devices (#251) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 0a4f98d35..aad498f3b 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -234,6 +234,7 @@ enum SupportedModules { NEO_COOLCAM, ESP_SWITCH, OBI, + TECKIN, MAXMODULE }; /********************************************************************************************/ @@ -357,31 +358,31 @@ const uint8_t kGpioNiceList[GPIO_SENSOR_END] PROGMEM = { }; const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { - SONOFF_BASIC, + SONOFF_BASIC, // Sonoff Relay Devices SONOFF_RF, SONOFF_TH, SONOFF_DUAL, SONOFF_DUAL_R2, SONOFF_POW, SONOFF_POW_R2, - SONOFF_S31, SONOFF_4CH, SONOFF_4CHPRO, - SONOFF_SV, - SONOFF_DEV, - SONOFF_S2X, - SLAMPHER, - SONOFF_TOUCH, + SONOFF_S31, // Sonoff Socket Relay Devices with Energy Monitoring + SONOFF_S2X, // Sonoff Socket Relay Devices + SONOFF_TOUCH, // Sonoff Switch Devices SONOFF_T11, SONOFF_T12, SONOFF_T13, - SONOFF_SC, - SONOFF_B1, - SONOFF_LED, + SONOFF_LED, // Sonoff Light Devices SONOFF_BN, - SONOFF_IFAN02, - SONOFF_BRIDGE, - CH1, + SONOFF_B1, // Sonoff Light Bulbs + SLAMPHER, + SONOFF_SC, // Sonoff Environmemtal Sensor + SONOFF_IFAN02, // Sonoff Fan + SONOFF_BRIDGE, // Sonoff Bridge + SONOFF_SV, // Sonoff Development Devices + SONOFF_DEV, + CH1, // Relay Devices CH4, MOTOR, ELECTRODRAGON, @@ -392,11 +393,12 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { WION, SHELLY1, SHELLY2, - BLITZWOLF_BWSHP2, - NEO_COOLCAM, - ESP_SWITCH, + BLITZWOLF_BWSHP2, // Socket Relay Devices with Energy Monitoring + TECKIN, + NEO_COOLCAM, // Socket Relay Devices OBI, - H801, + ESP_SWITCH, // Switch Devices + H801, // Light Devices MAGICHOME, ARILUX_LC01, ARILUX_LC06, @@ -404,9 +406,9 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { ZENGGE_ZF_WF017, HUAFAN_SS, KMC_70011, - AILIGHT, + AILIGHT, // Light Bulbs PHILIPS, - WITTY, + WITTY, // Development Devices WEMOS }; @@ -615,9 +617,9 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0, 0, 0, 0, 0, // Flash connection GPIO_REL1, // GPIO12 Relay1 ( 1 = Off) GPIO_REL2, // GPIO13 Relay1 ( 1 = On) - GPIO_USER, // GPIO14 V3.1 Module Pin 5 - V5.0 Relay2 ( 1 = Off) + GPIO_USER, // GPIO14 V3.1 Module Pin 5 - V5.0 GPIO_REL3_INV Relay2 ( 1 = Off) GPIO_LED1, // GPIO15 V5.0 LED1 - GPIO_USER, // GPIO16 V3.1 Module Pin 4 - V5.0 Relay2 ( 1 = On) + GPIO_USER, // GPIO16 V3.1 Module Pin 4 - V5.0 GPIO_REL4_INV Relay2 ( 1 = On) 0 }, { "WiOn", // Indoor Tap (ESP8266) @@ -1089,19 +1091,27 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_REL1_INV, // GPIO16 Green Led 1 (0 = On, 1 = Off) }, { "OBI Socket", // OBI socket (ESP8266) - https://www.obi.de/hausfunksteuerung/wifi-stecker-schuko/p/2291706 - 0, // GPIO00 Flash jumper - not available - 0, // GPIO01 - 0, // GPIO02 - 0, // GPIO03 + 0, 0, 0, 0, GPIO_LED1, // GPIO04 LED on top and in switch button GPIO_REL1, // GPIO05 Relay 1 (0 = Off, 1 = On) 0, 0, 0, 0, 0, 0, // Flash connection GPIO_LED2, // GPIO12 0, // GPIO13 GPIO_KEY1, // GPIO14 switch button - 0, // GPIO15 - 0, // GPIO16 - 0 // GPIO17 + 0, 0, 0 + }, + { "Teckin", // https://www.amazon.de/gp/product/B07D5V139R + 0, + GPIO_KEY1, // GPIO01 Serial TXD and Button + 0, + GPIO_LED2_INV, // GPIO03 Serial RXD and Red Led (0 = On, 1 = Off) + GPIO_HLW_CF, // GPIO04 BL0937 or HJL-01 CF power + GPIO_HLW_CF1, // GPIO05 BL0937 or HJL-01 CF1 voltage / current + 0, 0, 0, 0, 0, 0, // Flash connection + GPIO_HLW_SEL, // GPIO12 BL0937 or HJL-01 Sel output + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On) + 0, 0, 0 } }; From 13d37a144aa83a6f8f2114b80f490bcb823707f7 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 1 Oct 2018 18:06:25 +0200 Subject: [PATCH 19/66] Fixed wrong sensor name Fixed a wrong sensor name in line 23. It's not the SPG30, it's the CSS811 --- sonoff/xsns_31_ccs811.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_31_ccs811.ino b/sonoff/xsns_31_ccs811.ino index 482572cdb..d57c9cb06 100644 --- a/sonoff/xsns_31_ccs811.ino +++ b/sonoff/xsns_31_ccs811.ino @@ -20,7 +20,7 @@ #ifdef USE_I2C #ifdef USE_CCS811 /*********************************************************************************************\ - * SGP30 - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2) + * CCS811 - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2) * * Source: Adafruit * From bcc9432214961fdd8dd4f8ab6daa44f6516bd6cb Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Mon, 1 Oct 2018 13:13:47 -0300 Subject: [PATCH 20/66] Added Dimmer Trigger for Rules For example rule on Dimmer#state<30 do ... endon rule on Dimmer#boot<10 do ... endon --- sonoff/xdrv_10_rules.ino | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index b13dfc771..54fcb3f08 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -83,6 +83,7 @@ unsigned long rules_timer[MAX_RULE_TIMERS] = { 0 }; uint8_t rules_quota = 0; long rules_new_power = -1; long rules_old_power = -1; +long rules_old_dimm = -1; uint32_t rules_triggers[MAX_RULE_SETS] = { 0 }; uint16_t rules_last_minute = 60; @@ -398,6 +399,16 @@ void RulesEvery50ms() } rules_old_power = rules_new_power; } + else if (rules_old_dimm != Settings.light_dimmer) { + if (rules_old_dimm != -1) { + snprintf_P(json_event, sizeof(json_event), PSTR("{\"Dimmer\":{\"State\":%d}}"), Settings.light_dimmer); + } else { + // Boot time DIMMER VALUE + snprintf_P(json_event, sizeof(json_event), PSTR("{\"Dimmer\":{\"Boot\":%d}}"), Settings.light_dimmer); + } + RulesProcessEvent(json_event); + rules_old_dimm = Settings.light_dimmer; + } else if (event_data[0]) { char *event; char *parameter; From 2f85a4728b238fcc548d393ce04eb2c7aa8314f4 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Mon, 1 Oct 2018 19:32:55 +0200 Subject: [PATCH 21/66] PCA9685 - bugfix for telemetry + status command --- sonoff/xdrv_15_pca9685.ino | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sonoff/xdrv_15_pca9685.ino b/sonoff/xdrv_15_pca9685.ino index 9cb9292a0..b29e85a5b 100644 --- a/sonoff/xdrv_15_pca9685.ino +++ b/sonoff/xdrv_15_pca9685.ino @@ -98,6 +98,7 @@ void PCA9685_SetPWM(uint8_t pin, uint16_t pwm, bool inverted) { } else { PCA9685_SetPWM_Reg(pin, 0, pwm); } + pca9685_pin_pwm_value[pin] = pwm; } bool PCA9685_Command(void) @@ -120,6 +121,8 @@ bool PCA9685_Command(void) if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"RESET")) { PCA9685_Reset(); return serviced; } + if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"STATUS")) { PCA9685_OutputTelemetry(false); return serviced; } + if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"PWMF")) { if (paramcount > 1) { uint16_t new_freq = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); @@ -162,7 +165,7 @@ bool PCA9685_Command(void) return serviced; } -void PCA9685_OutputTelemetry(void) { +void PCA9685_OutputTelemetry(bool telemetry) { if (0 == pca9685_detected) { return; } // We do not do this if the PCA9685 has not been detected snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"PCA9685\": {"), GetDateAndTime(DT_LOCAL).c_str()); snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"PWM_FREQ\":%i,"),mqtt_data,pca9685_freq); @@ -170,7 +173,9 @@ void PCA9685_OutputTelemetry(void) { snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"PWM%i\":%i,"),mqtt_data,pin,pca9685_pin_pwm_value[pin]); } snprintf_P(mqtt_data,sizeof(mqtt_data),PSTR("%s\"END\":1}}"),mqtt_data); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); + if (telemetry) { + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); + } } boolean Xdrv15(byte function) @@ -182,7 +187,7 @@ boolean Xdrv15(byte function) case FUNC_EVERY_SECOND: PCA9685_Detect(); if (tele_period == 0) { - PCA9685_OutputTelemetry(); + PCA9685_OutputTelemetry(true); } break; case FUNC_COMMAND: From 3280c7d177f07282ecd72b9aa881325136b55569 Mon Sep 17 00:00:00 2001 From: "Christian W. Zuckschwerdt" Date: Mon, 1 Oct 2018 14:28:21 +0000 Subject: [PATCH 22/66] Add W1_PARASITE_POWER optimization for DS18X20 --- sonoff/user_config.h | 1 + sonoff/xsns_05_ds18x20.ino | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 72aa97d53..ee77854bc 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -271,6 +271,7 @@ // -- One wire sensors ---------------------------- // WARNING: Select none for default one DS18B20 sensor or enable one of the following two options for multiple sensors #define USE_DS18x20 // Optional for more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code) +//#define W1_PARASITE_POWER // If using USE_DS18x20 then optimize for parasite powered sensors //#define USE_DS18x20_LEGACY // Optional for more than one DS18x20 sensors with dynamic scan using library OneWire (+1k5 code) // -- I2C sensors --------------------------------- diff --git a/sonoff/xsns_05_ds18x20.ino b/sonoff/xsns_05_ds18x20.ino index 869deac8e..474f26e2e 100644 --- a/sonoff/xsns_05_ds18x20.ino +++ b/sonoff/xsns_05_ds18x20.ino @@ -49,6 +49,10 @@ struct DS18X20STRUCT { uint8_t ds18x20_sensors = 0; uint8_t ds18x20_pin = 0; char ds18x20_types[12]; +#ifdef W1_PARASITE_POWER +uint8_t ds18x20_sensor_curr = 0; +unsigned long w1_power_until = 0; +#endif /*********************************************************************************************\ * Embedded tuned OneWire library @@ -285,7 +289,14 @@ void Ds18x20Init() void Ds18x20Convert() { OneWireReset(); +#ifdef W1_PARASITE_POWER + // With parasite power address one sensor at a time + if (++ds18x20_sensor_curr >= ds18x20_sensors) + ds18x20_sensor_curr = 0; + OneWireSelect(ds18x20_sensor[ds18x20_sensor_curr].address); +#else OneWireWrite(W1_SKIP_ROM); // Address all Sensors on Bus +#endif OneWireWrite(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end // delay(750); // 750ms should be enough for 12bit conv } @@ -334,6 +345,9 @@ bool Ds18x20Read(uint8_t sensor) OneWireWrite(data[4]); // Configuration Register OneWireSelect(ds18x20_sensor[index].address); OneWireWrite(W1_WRITE_EEPROM); // Save scratchpad to EEPROM +#ifdef W1_PARASITE_POWER + w1_power_until = millis() + 10; // 10ms specified duration for EEPROM write +#endif } temp12 = (data[1] << 8) + data[0]; if (temp12 > 2047) { @@ -374,7 +388,18 @@ void Ds18x20Name(uint8_t sensor) void Ds18x20EverySecond() { - if (uptime &1) { +#ifdef W1_PARASITE_POWER + // skip access if there is still an eeprom write ongoing + unsigned long now = millis(); + if (now < w1_power_until) + return; +#endif + if (uptime & 1 +#ifdef W1_PARASITE_POWER + // if more than 1 sensor and only parasite power: convert every cycle + || ds18x20_sensors >= 2 +#endif + ) { // 2mS Ds18x20Convert(); // Start conversion, takes up to one second } else { From 3ed06695bade88e21778afa99d5609455e6e8427 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 2 Oct 2018 09:38:36 +0200 Subject: [PATCH 23/66] Fix Teckin energy monitoring Fix Teckin energy monitoring (#3950) --- sonoff/xnrg_01_hlw8012.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino index 025ccff44..902df89ae 100644 --- a/sonoff/xnrg_01_hlw8012.ino +++ b/sonoff/xnrg_01_hlw8012.ino @@ -177,7 +177,7 @@ void HlwSnsInit() Settings.energy_current_calibration = HLW_IREF_PULSE; } - if (BLITZWOLF_BWSHP2 == Settings.module) { + if ((BLITZWOLF_BWSHP2 == Settings.module) || (TECKIN == Settings.module)) { hlw_power_ratio = HJL_PREF; hlw_voltage_ratio = HJL_UREF; hlw_current_ratio = HJL_IREF; From 7dcb10a91172d6b9391912a7d0a205e4cb898643 Mon Sep 17 00:00:00 2001 From: Norbert Richter Date: Tue, 2 Oct 2018 13:42:21 +0200 Subject: [PATCH 24/66] v1.5.0012: 'decode-config.py' add args, add 6.2.1.x settings, fix filename with @ - add: developer version settings 6.2.1.2, 6.2.1.3, 6.2.1.6, 6.2.1.10 - add: args '--raw-keys', '--no-raw-keys', '--raw-values', '--no-raw-values', '--hide-pw' - add: value -1 for arg '--json-indent' to disable indent if default is enabled - changed: json output to file use always raw values - fix: add again removed return code desc - fix: needless dot . in filename for @v - fix: rule(123) none-raw outputs --- tools/decode-config.py | 1317 +++++++++++++++++++++++++++++++++++----- 1 file changed, 1177 insertions(+), 140 deletions(-) diff --git a/tools/decode-config.py b/tools/decode-config.py index 284904fb9..258a8accd 100644 --- a/tools/decode-config.py +++ b/tools/decode-config.py @@ -1,5 +1,7 @@ #!/usr/bin/env python +#!/usr/bin/env python # -*- coding: utf-8 -*- +VER = '1.5.0012' """ decode-config.py - Decode configuration of Sonoff-Tasmota device @@ -35,9 +37,11 @@ Instructions: Usage: decode-config.py [-h] [-f ] [-d ] [-u ] [-p ] [--json-indent ] - [--json-compact] [--unsort] [--raw] [--unhide-pw] - [-o ] [--output-file-format ] - [-c ] [--exit-on-error-only] [-V] + [--json-compact] [--sort] [--unsort] [--raw-values] + [--no-raw-values] [--raw-keys] [--no-raw-keys] + [--hide-pw] [--unhide-pw] [-o ] + [--output-file-format ] [-c ] + [--exit-on-error-only] [-V] Decode configuration of Sonoff-Tasmota device. Args that start with '--' (eg. -f) can also be set in a config file (specified via -c). Config file syntax @@ -66,18 +70,23 @@ Usage: -p , --password host HTTP access password (default: None) - output: + config: --json-indent pretty-printed JSON output using indent level - (default: 'None') - --json-compact compact JSON output by eliminate whitespace (default: - normal) - --unsort do not sort results (default: sort) - --raw output raw values (default: process) - --unhide-pw unhide passwords (default: hide) + (default: 'None'). Use values greater equal 0 to + indent or -1 to disabled indent. + --json-compact compact JSON output by eliminate whitespace + --sort sort json keywords (default) + --unsort do not sort json keywords + --raw-values, --raw output raw values + --no-raw-values output human readable values (default) + --raw-keys output bitfield raw keys (default) + --no-raw-keys do not output bitfield raw keys + --hide-pw hide passwords (default) + --unhide-pw unhide passwords -o , --output-file - file to store configuration to (default: None) Macros: - @v=Tasmota version, @f=friendly name + file to store configuration to (default: None). + Replacements: @v=Tasmota version, @f=friendly name --output-file-format output format ('json' or 'binary', default: 'json') @@ -86,41 +95,44 @@ Usage: Either argument -d or -f must be given. + +Returns: + 0: successful + 1: file not found + 2: configuration version not supported + 3: data size mismatch + 4: data CRC error + 5: configuration file read error + 6: argument error + 9: python module is missing + 4xx, 5xx: HTTP error + """ import os.path import io import sys -import struct -import re -import math -from datetime import datetime +def ModuleImportError(module): + er = str(module) + print("{}. Try 'pip install {}' to install it".format(er,er.split(' ')[len(er.split(' '))-1]) ) + sys.exit(9) try: + import struct + import re + import math + from datetime import datetime import json -except ImportError: - print("module not found. Try 'pip install json' to install it") - sys.exit(9) -try: import configargparse -except ImportError: - print("module not found. Try 'pip install configargparse' to install it") - sys.exit(9) -try: import pycurl -except ImportError: - print("module not found. Try 'pip install pycurl' to install it") - sys.exit(9) -try: import urllib2 -except ImportError: - print("module not found. Try 'pip install urllib2' to install it") - sys.exit(9) +except ImportError, e: + ModuleImportError(e) -VER = '1.5.0011' PROG='{} v{} by Norbert Richter'.format(os.path.basename(sys.argv[0]),VER) CONFIG_FILE_XOR = 0x5A +BINARYFILE_MAGIC = 0x63576223 args = {} DEFAULTS = { @@ -136,13 +148,14 @@ DEFAULTS = { 'password': None, 'tasmotafile': None, }, - 'output': + 'config': { 'jsonindent': None, 'jsoncompact': False, - 'unsort': False, - 'raw': False, - 'unhide-pw': False, + 'sort': True, + 'rawvalues': False, + 'rawkeys': True, + 'hidepw': True, 'outputfile': None, 'outputfileformat': 'json', }, @@ -166,7 +179,7 @@ Settings dictionary describes the config file fields definition: 'xxx': A string is used to interpret the data at The string defines the format interpretion as described - in 'struct module format string', see + in 'struct module format string', see https://docs.python.org/2.7/library/struct.html#format-strings In addition to this format string there is as special meaning of a dot '.' - this means a bit with an optional @@ -178,7 +191,7 @@ Settings dictionary describes the config file fields definition: The address (starting from 0) within config data. For bit fields must be a tuple. n: - Defines a simple address within config data. + Defines a simple address within config data. must be a positive integer. (n, b, s): A tuple defines a bit field: @@ -221,11 +234,12 @@ def int2ip(value): return '{:d}.{:d}.{:d}.{:d}'.format(value & 0xff, value>>8 & 0xff, value>>16 & 0xff, value>>24 & 0xff) def password(value): - if args.unhidepw: - return value - return '********' + if args.hidepw: + return '********' + return value -Setting_6_2_1 = { + +Setting_6_2_1_10 = { 'cfg_holder': ('>24) & 0xff) + minor = ((ver>>16) & 0xff) + release = ((ver>> 8) & 0xff) + subrelease = (ver & 0xff) + if major>=6: + if subrelease>0: + subreleasestr = str(subrelease) + else: + subreleasestr = '' + else: + if subrelease>0: + subreleasestr = str(chr(subrelease+ord('a')-1)) + else: + subreleasestr = '' + v = "{:d}.{:d}.{:d}{}{}".format( major, minor, release, '.' if (major>=6 and subreleasestr!='') else '', subreleasestr) + filename = filename.replace('@v', v) + if 'friendlyname' in configuration: + filename = filename.replace('@f', configuration['friendlyname'][0] ) + + return filename + + def GetSettingsCrc(dobj): """ Return binary config data calclulated crc @param dobj: - uncrypted binary config data + decrypted binary config data @return: 2 byte unsigned integer crc value @@ -1918,7 +2928,7 @@ def GetFieldLength(fielddef): if addr != baseaddr: addr = baseaddr length += len_ - + else: if format_[-1:].lower() in ['b','c','?']: length=1 @@ -1942,13 +2952,15 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0): Get field value from definition @param dobj: - uncrypted binary config data + decrypted binary config data @param fieldname: name of the field @param fielddef: see Settings desc above @param raw return raw values (True) or converted values (False) + @param addroffset + use offset for baseaddr (used for recursive calls) @return: read field value """ @@ -1963,7 +2975,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0): # get datadef from field definition datadef = None - if len(fielddef)>2: + if fielddef is not None and len(fielddef)>2: datadef = fielddef[2] if datadef is not None: @@ -1993,7 +3005,7 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0): subfielddef = (fielddef[0], MakeFieldBaseAddr(baseaddr, bitlen, bitshift), None, fielddef[3]) length = GetFieldLength(subfielddef) - if length != 0: + if length != 0 and (fieldname != 'raw' or args.rawkeys): result.append(GetField(dobj, fieldname, subfielddef, raw=raw, addroffset=addroffset+offset)) offset += length @@ -2004,7 +3016,8 @@ def GetField(dobj, fieldname, fielddef, raw=False, addroffset=0): setting = fielddef[0] config = {} for name in setting: - config[name] = GetField(dobj, name, setting[name], raw=args.raw, addroffset=addroffset) + if name != 'raw' or args.rawkeys: + config[name] = GetField(dobj, name, setting[name], raw=raw, addroffset=addroffset) result = config else: # a simple value @@ -2047,39 +3060,56 @@ def DeEncrypt(obj): return dobj -def Decode(obj): +def GetTemplateSetting(version): + """ + Search for template, settings and size to be used depending on given version number + + @param version: + version number from read binary data to search for + + @return: template, settings to use, None if version is invalid + """ + # search setting definition + template = None + setting = None + size = None + for cfg in Settings: + if version >= cfg[0]: + template = cfg + size = template[1] + setting = template[2] + break + + return template, size, setting + + +def Decode(obj, raw=True): """ Decodes binary data stream @param obj: binary config data (decrypted) - + @param raw + decode raw values (True) or converted values (False) + @return: configuration dictionary """ # get header data version = GetField(obj, 'version', Setting_6_2_1['version'], raw=True) - # search setting definition - template = None - for cfg in Settings: - if version >= cfg[0]: - template = cfg - break - + template, size, setting = GetTemplateSetting(version) # if we did not found a mathching setting if template is None: exit(2, "Tasmota configuration version 0x{:x} not supported".format(version) ) - - setting = template[2] # check size if exists if 'cfg_size' in setting: cfg_size = GetField(obj, 'cfg_size', setting['cfg_size'], raw=True) # read size should be same as definied in template - if cfg_size > template[1]: + if cfg_size > size: # may be processed exit(3, "Number of bytes read does ot match - read {}, expected {} byte".format(cfg_size, template[1]), typ='WARNING', doexit=args.exitonwarning) - elif cfg_size < template[1]: + elif cfg_size < size: # less number of bytes can not be processed exit(3, "Number of bytes read to small to process - read {}, expected {} byte".format(cfg_size, template[1]), typ='ERROR') @@ -2091,9 +3121,8 @@ def Decode(obj): if cfg_crc != GetSettingsCrc(obj): exit(4, 'Data CRC error, read 0x{:x} should be 0x{:x}'.format(cfg_crc, GetSettingsCrc(obj)), typ='WARNING', doexit=args.exitonwarning) - config = {} - for name in setting: - config[name] = GetField(obj, name, setting[name], raw=args.raw) + # get config + config = GetField(obj, None, (setting,None,None), raw=raw) # add header info timestamp = datetime.now() @@ -2142,44 +3171,74 @@ if __name__ == "__main__": default=DEFAULTS['source']['password'], help="host HTTP access password (default: {})".format(DEFAULTS['source']['password'])) - output = parser.add_argument_group('output') - output.add_argument('--json-indent', + config = parser.add_argument_group('config') + config.add_argument('--json-indent', metavar='', dest='jsonindent', type=int, - default=DEFAULTS['output']['jsonindent'], - help="pretty-printed JSON output using indent level (default: '{}')".format(DEFAULTS['output']['jsonindent']) ) - output.add_argument('--json-compact', + default=DEFAULTS['config']['jsonindent'], + help="pretty-printed JSON output using indent level (default: '{}'). Use values greater equal 0 to indent or -1 to disabled indent.".format(DEFAULTS['config']['jsonindent']) ) + config.add_argument('--json-compact', dest='jsoncompact', action='store_true', - default=DEFAULTS['output']['jsoncompact'], - help="compact JSON output by eliminate whitespace (default: {})".format('normal' if not DEFAULTS['output']['jsoncompact'] else 'compact') ) - output.add_argument('--unsort', - dest='unsort', + default=DEFAULTS['config']['jsoncompact'], + help="compact JSON output by eliminate whitespace{}".format(' (default)' if DEFAULTS['config']['jsoncompact'] else '') ) + + config.add_argument('--sort', + dest='sort', action='store_true', - default=DEFAULTS['output']['unsort'], - help="do not sort results (default: {})".format('sort' if not DEFAULTS['output']['unsort'] else 'unsort') ) - output.add_argument('--raw', - dest='raw', + default=DEFAULTS['config']['sort'], + help="sort json keywords{}".format(' (default)' if DEFAULTS['config']['sort'] else '') ) + config.add_argument('--unsort', + dest='sort', + action='store_false', + default=DEFAULTS['config']['sort'], + help="do not sort json keywords{}".format(' (default)' if not DEFAULTS['config']['sort'] else '') ) + + config.add_argument('--raw-values', '--raw', + dest='rawvalues', action='store_true', - default=DEFAULTS['output']['raw'], - help="output raw values (default: {})".format('raw' if DEFAULTS['output']['raw'] else 'process') ) - output.add_argument('--unhide-pw', - dest='unhidepw', + default=DEFAULTS['config']['rawvalues'], + help="output raw values{}".format(' (default)' if DEFAULTS['config']['rawvalues'] else '') ) + config.add_argument('--no-raw-values', + dest='rawvalues', + action='store_false', + default=DEFAULTS['config']['rawvalues'], + help="output human readable values{}".format(' (default)' if not DEFAULTS['config']['rawvalues'] else '') ) + + config.add_argument('--raw-keys', + dest='rawkeys', action='store_true', - default=DEFAULTS['output']['unhide-pw'], - help="unhide passwords (default: {})".format('unhide' if DEFAULTS['output']['unhide-pw'] else 'hide') ) - output.add_argument('-o', '--output-file', + default=DEFAULTS['config']['rawkeys'], + help="output bitfield raw keys{}".format(' (default)' if DEFAULTS['config']['rawkeys'] else '') ) + config.add_argument('--no-raw-keys', + dest='rawkeys', + action='store_false', + default=DEFAULTS['config']['rawkeys'], + help="do not output bitfield raw keys{}".format(' (default)' if not DEFAULTS['config']['rawkeys'] else '') ) + + config.add_argument('--hide-pw', + dest='hidepw', + action='store_true', + default=DEFAULTS['config']['hidepw'], + help="hide passwords{}".format(' (default)' if DEFAULTS['config']['hidepw'] else '') ) + config.add_argument('--unhide-pw', + dest='hidepw', + action='store_false', + default=DEFAULTS['config']['hidepw'], + help="unhide passwords{}".format(' (default)' if not DEFAULTS['config']['hidepw'] else '') ) + + config.add_argument('-o', '--output-file', metavar='', dest='outputfile', - default=DEFAULTS['output']['outputfile'], - help="file to store configuration to (default: {}) Macros: @v=Tasmota version, @f=friendly name".format(DEFAULTS['output']['outputfile'])) - output.add_argument('--output-file-format', + default=DEFAULTS['config']['outputfile'], + help="file to store configuration to (default: {}). Replacements: @v=Tasmota version, @f=friendly name".format(DEFAULTS['config']['outputfile'])) + config.add_argument('--output-file-format', metavar='', dest='outputfileformat', choices=['json', 'binary'], - default=DEFAULTS['output']['outputfileformat'], - help="output format ('json' or 'binary', default: '{}')".format(DEFAULTS['output']['outputfileformat']) ) + default=DEFAULTS['config']['outputfileformat'], + help="output format ('json' or 'binary', default: '{}')".format(DEFAULTS['config']['outputfileformat']) ) parser.add_argument('-c', '--config', metavar='', @@ -2197,14 +3256,14 @@ if __name__ == "__main__": info.add_argument('-V', '--version', action='version', version=PROG) args = parser.parse_args() - + # default no configuration available configobj = None - + # check source args if args.device is not None and args.tasmotafile is not None: exit(6, "Only one source allowed. Do not use -d and -f together") - + # read config direct from device via http if args.device is not None: @@ -2245,51 +3304,29 @@ if __name__ == "__main__": parser.print_help() sys.exit(0) - if configobj is not None and len(configobj)>0: cfg = DeEncrypt(configobj) - config = Decode(cfg) + configuration = Decode(cfg, args.rawvalues) # output to file if args.outputfile is not None: - outputfilename = args.outputfile - v = f1 = f2 = f3 = f4 = '' - if 'version' in config: - ver = int(str(config['version']), 0) - major = ((ver>>24) & 0xff) - minor = ((ver>>16) & 0xff) - release = ((ver>> 8) & 0xff) - subrelease = (ver & 0xff) - if major>=6: - if subrelease>0: - subreleasestr = str(subrelease) - else: - subreleasestr = '' - else: - if subrelease>0: - subreleasestr = str(chr(subrelease+ord('a')-1)) - else: - subreleasestr = '' - v = "{:d}.{:d}.{:d}{}{}".format( major, minor, release, '.' if major>=6 else '', subreleasestr) - outputfilename = outputfilename.replace('@v', v) - if 'friendlyname' in config: - outputfilename = outputfilename.replace('@f', config['friendlyname'][0] ) - + outputfilename = GetFilenameReplaced(args.outputfile, configuration) if args.outputfileformat == 'binary': outputfile = open(outputfilename, "wb") outputfile.write(struct.pack(' Date: Tue, 2 Oct 2018 17:07:30 +0200 Subject: [PATCH 25/66] 6.2.1.11 Add MQTT Client 6.2.1.11 20191002 * Remove support for MQTT Client based on esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO * Add support for MQTT Client based on lwmqtt to be selected by #define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT --- sonoff/_changelog.ino | 6 ++- sonoff/sonoff.h | 7 +++- sonoff/sonoff_version.h | 2 +- sonoff/support.ino | 5 ++- sonoff/user_config.h | 8 ++-- sonoff/xdrv_01_mqtt.ino | 84 ++++++++++++++++++++++---------------- sonoff/xnrg_01_hlw8012.ino | 2 +- tools/decode-status.py | 2 +- 8 files changed, 71 insertions(+), 45 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 04f209e10..217b665ff 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,8 @@ -/* 6.2.1.10 20180930 +/* 6.2.1.11 20191002 + * Remove support for MQTT Client based on esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO + * Add support for MQTT Client based on lwmqtt to be selected by #define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT + * + * 6.2.1.10 20180930 * Add command RGBWWTable to support color calibration (#3933) * Add support for Michael Haustein ESP Switch * Add support for EXS Relay V5.0 (#3810) diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 80356d475..f891e387a 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -20,6 +20,11 @@ #ifndef _SONOFF_H_ #define _SONOFF_H_ +#define USE_DHT // Default DHT11 sensor needs no external library +#define USE_ENERGY_SENSOR // Use energy sensors (+14k code) +#define USE_HLW8012 // Use energy sensor for Sonoff Pow and WolfBlitz +#define USE_CSE7766 // Use energy sensor for Sonoff S31 and Pow R2 + /*********************************************************************************************\ * Power Type \*********************************************************************************************/ @@ -136,7 +141,7 @@ typedef unsigned long power_t; // Power (Relay) type #define MQTT_PUBSUBCLIENT 1 // Mqtt PubSubClient library #define MQTT_TASMOTAMQTT 2 // Mqtt TasmotaMqtt library based on esp-mqtt-arduino -#define MQTT_ESPMQTTARDUINO 3 // Mqtt esp-mqtt-arduino library by Ingo Randolf +#define MQTT_ARDUINOMQTT 3 // Mqtt arduino-mqtt library by Joel Gaehwiler (https://github.com/256dpi/arduino-mqtt) // Sunrise and Sunset DawnType #define DAWN_NORMAL -0.8333 diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index c5765ec38..60a044326 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x0602010A +#define VERSION 0x0602010B #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/support.ino b/sonoff/support.ino index 3665650dd..d2b38bb09 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -876,7 +876,7 @@ void GetFeatures() #if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT) feature_drv1 |= 0x00000800; // xdrv_01_mqtt.ino #endif -#if (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) +#if (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) // Obsolete since 6.2.1.11 feature_drv1 |= 0x00001000; // xdrv_01_mqtt.ino #endif #ifdef MQTT_HOST_DISCOVERY @@ -933,6 +933,9 @@ void GetFeatures() #ifdef USE_SMARTCONFIG feature_drv1 |= 0x40000000; // support.ino #endif +#if (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT) + feature_drv1 |= 0x80000000; // xdrv_01_mqtt.ino +#endif /*********************************************************************************************/ diff --git a/sonoff/user_config.h b/sonoff/user_config.h index ee77854bc..11b8c1d61 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -216,14 +216,14 @@ //#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+13k code) /*-------------------------------------------------------------------------------------------*\ - * Select ONE of possible three MQTT library types below + * Select ONE of possible MQTT library types below \*-------------------------------------------------------------------------------------------*/ // Default MQTT driver for both non-TLS and TLS connections. Blocks network if MQTT server is unavailable. #define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library // Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support -//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 code, +4k mem) - non-TLS only - // Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support -//#define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO // Use (patched) esp-mqtt-arduino library (+4k8 code, +4k mem) - non-TLS only +//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 (core 2.3.0), +14k4 (core 2.4.2 lwip2) code, +4k mem) - non-TLS only + // Alternative MQTT driver does not block network when MQTT server is unavailable. TLS should work but needs to be tested. +//#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT // Use arduino-mqtt (lwmqtt) library (+3k3 code, +2k mem) // -- MQTT ---------------------------------------- #define MQTT_TELE_RETAIN 0 // Tele messages may send retain flag (0 = off, 1 = on) diff --git a/sonoff/xdrv_01_mqtt.ino b/sonoff/xdrv_01_mqtt.ino index f3f33d693..42214216a 100644 --- a/sonoff/xdrv_01_mqtt.ino +++ b/sonoff/xdrv_01_mqtt.ino @@ -23,19 +23,29 @@ // Default MQTT driver for both non-TLS and TLS connections. Blocks network if MQTT server is unavailable. //#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library // Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support -//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 code, +4k mem) - non-TLS only -// Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support -//#define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO // Use (patched) esp-mqtt-arduino library (+4k8 code, +4k mem) - non-TLS only +//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 (core 2.3.0), +14k4 (core 2.4.2 lwip2) code, +4k mem) - non-TLS only +// Alternative MQTT driver does not block network when MQTT server is unavailable. TLS should work but needs to be tested. +//#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT // Use arduino-mqtt (lwmqtt) library (+3k3 code, +2k mem) #ifdef USE_MQTT_TLS + +/* #ifdef MQTT_LIBRARY_TYPE #undef MQTT_LIBRARY_TYPE #endif #define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as it only supports TLS +*/ +#if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT) +#undef MQTT_LIBRARY_TYPE +#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as it only supports TLS +#endif + #else + #ifndef MQTT_LIBRARY_TYPE #define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as default #endif + #endif /*********************************************************************************************/ @@ -136,48 +146,48 @@ void MqttLoop() { } -#elif (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) /*******************************************/ +#elif (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT) /**********************************************/ -#include -MQTT *MqttClient = NULL; +#include +MQTTClient MqttClient(MQTT_MAX_PACKET_SIZE); bool MqttIsConnected() { - return mqtt_connected; + return MqttClient.connected(); } void MqttDisconnect() { - if (MqttClient) MqttClient->disconnect(); + MqttClient.disconnect(); } -void MqttDisconnectedCb() +/* +void MqttMyDataCb(MQTTClient* client, char* topic, char* data, int data_len) +//void MqttMyDataCb(MQTTClient *client, char topic[], char data[], int data_len) { - MqttDisconnected(MqttClient->getState()); // status codes are documented in file mqtt.h as tConnState +// MqttDataHandler((char*)topic, (byte*)data, data_len); } +*/ -void MqttMyDataCb(const char* topic, uint32_t topic_len, const char* data, uint32_t data_len) +void MqttMyDataCb(String &topic, String &data) { - char topic_copy[topic_len +1]; - - memcpy(topic_copy, topic, topic_len); - topic_copy[topic_len] = 0; - if (0 == data_len) data = (const char*)&topic_copy + topic_len; - MqttDataHandler((char*)topic_copy, (byte*)data, data_len); + MqttDataHandler((char*)topic.c_str(), (byte*)data.c_str(), data.length()); } void MqttSubscribeLib(char *topic) { - MqttClient->subscribe(topic); + MqttClient.subscribe(topic, 0); } bool MqttPublishLib(const char* topic, boolean retained) { - return MqttClient->publish(topic, mqtt_data, strlen(mqtt_data), 0, retained); + return MqttClient.publish(topic, mqtt_data, strlen(mqtt_data), retained, 0); } void MqttLoop() { + MqttClient.loop(); +// delay(10); } #endif // MQTT_LIBRARY_TYPE @@ -467,6 +477,14 @@ void MqttReconnect() GetTopic_P(stopic, TELE, mqtt_topic, S_LWT); snprintf_P(mqtt_data, sizeof(mqtt_data), S_OFFLINE); +//#ifdef ARDUINO_ESP8266_RELEASE_2_4_1 +#ifdef USE_MQTT_TLS + EspClient = WiFiClientSecure(); // Wifi Secure Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497) +#else + EspClient = WiFiClient(); // Wifi Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497) +#endif +//#endif + if (2 == mqtt_initial_connection_state) { // Executed once just after power on and wifi is connected #ifdef USE_MQTT_TLS if (!MqttCheckTls()) return; @@ -479,25 +497,17 @@ void MqttReconnect() MqttClient.OnConnected(MqttConnected); MqttClient.OnDisconnected(MqttDisconnectedCb); MqttClient.OnData(MqttDataHandler); -#elif (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) - MqttClient = new MQTT(mqtt_client, Settings.mqtt_host, Settings.mqtt_port, stopic, 1, true, mqtt_data); - MqttClient->setUserPwd(mqtt_user, mqtt_pwd); - MqttClient->onConnected(MqttConnected); - MqttClient->onDisconnected(MqttDisconnectedCb); - MqttClient->onData(MqttMyDataCb); +#elif (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT) + MqttClient.begin(Settings.mqtt_host, Settings.mqtt_port, EspClient); + MqttClient.setWill(stopic, mqtt_data, true, 1); + MqttClient.setOptions(MQTT_KEEPALIVE, true, 1000); +// MqttClient.onMessageAdvanced(MqttMyDataCb); + MqttClient.onMessage(MqttMyDataCb); #endif mqtt_initial_connection_state = 1; } -//#ifdef ARDUINO_ESP8266_RELEASE_2_4_1 -#ifdef USE_MQTT_TLS - EspClient = WiFiClientSecure(); // Wifi Secure Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497) -#else - EspClient = WiFiClient(); // Wifi Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497) -#endif -//#endif - #if (MQTT_LIBRARY_TYPE == MQTT_PUBSUBCLIENT) MqttClient.setCallback(MqttDataHandler); MqttClient.setServer(Settings.mqtt_host, Settings.mqtt_port); @@ -508,8 +518,12 @@ void MqttReconnect() } #elif (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT) MqttClient.Connect(); -#elif (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) - MqttClient->connect(); +#elif (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT) + if (MqttClient.connect(mqtt_client, mqtt_user, mqtt_pwd)) { + MqttConnected(); + } else { + MqttDisconnected(MqttClient.lastError()); // status codes are documented here https://github.com/256dpi/lwmqtt/blob/master/include/lwmqtt.h#L11 + } #endif // MQTT_LIBRARY_TYPE } diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino index 902df89ae..0bcfa9060 100644 --- a/sonoff/xnrg_01_hlw8012.ino +++ b/sonoff/xnrg_01_hlw8012.ino @@ -33,7 +33,7 @@ #define HLW_IREF 4545 // 4.545A #define HLW_SEL_VOLTAGE 1 -// HJL-01 based (BlitzWolf, Homecube, Gosund) +// HJL-01 based (BlitzWolf, Homecube, Gosund, Teckin) #define HJL_PREF 1362 #define HJL_UREF 822 #define HJL_IREF 3300 diff --git a/tools/decode-status.py b/tools/decode-status.py index 74b10a57c..99c73af69 100644 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -105,7 +105,7 @@ a_features = [[ "USE_WS2812_DMA","USE_IR_REMOTE","USE_IR_HVAC","USE_IR_RECEIVE", "USE_DOMOTICZ","USE_DISPLAY","USE_HOME_ASSISTANT","USE_SERIAL_BRIDGE", "USE_TIMERS","USE_SUNRISE","USE_TIMERS_WEB","USE_RULES", - "USE_KNX","USE_WPS","USE_SMARTCONFIG","" + "USE_KNX","USE_WPS","USE_SMARTCONFIG","MQTT_ARDUINOMQTT" ],[ "USE_CONFIG_OVERRIDE","BE_MINIMAL","USE_SENSORS","USE_CLASSIC", "USE_KNX_NO_EMULATION","USE_DISPLAY_MODES1TO5","USE_DISPLAY_GRAPH","USE_DISPLAY_LCD", From 6cd59d2b3e3b983778532bf5d437dfba42b131f1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 2 Oct 2018 17:19:02 +0200 Subject: [PATCH 26/66] Forgot the library swap --- lib/arduino-mqtt-2.3.3.02/.editorconfig | 7 + lib/arduino-mqtt-2.3.3.02/.gitignore | 2 + lib/arduino-mqtt-2.3.3.02/.travis.yml | 46 + lib/arduino-mqtt-2.3.3.02/CMakeLists.txt | 40 + lib/arduino-mqtt-2.3.3.02/LICENSE.md | 21 + lib/arduino-mqtt-2.3.3.02/Makefile | 14 + lib/arduino-mqtt-2.3.3.02/README.md | 225 ++++ .../AdafruitHuzzahESP8266.ino | 69 ++ .../AdafruitHuzzahESP8266Secure.ino | 71 ++ .../ArduinoEthernetShield.ino | 62 + .../ArduinoMKRGSM1400/ArduinoMKRGSM1400.ino | 84 ++ .../ArduinoMKRGSM1400Secure.ino | 86 ++ .../ArduinoWiFi101/ArduinoWiFi101.ino | 70 ++ .../ArduinoWiFi101Secure.ino | 75 ++ .../ArduinoWiFiShield/ArduinoWiFiShield.ino | 68 ++ .../examples/ArduinoYun/ArduinoYun.ino | 60 + .../ArduinoYunSecure/ArduinoYunSecure.ino | 62 + .../ESP32DevelopmentBoard.ino | 69 ++ .../ESP32DevelopmentBoardSecure.ino | 71 ++ lib/arduino-mqtt-2.3.3.02/library.properties | 9 + lib/arduino-mqtt-2.3.3.02/src/MQTTClient.h | 386 ++++++ lib/arduino-mqtt-2.3.3.02/src/MQTTlw.h | 6 + lib/arduino-mqtt-2.3.3.02/src/lwmqtt/client.c | 618 ++++++++++ .../src/lwmqtt/helpers.c | 249 ++++ .../src/lwmqtt/helpers.h | 137 +++ lib/arduino-mqtt-2.3.3.02/src/lwmqtt/lwmqtt.h | 381 ++++++ lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.c | 742 ++++++++++++ lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.h | 185 +++ lib/arduino-mqtt-2.3.3.02/src/lwmqtt/string.c | 38 + lib/arduino-mqtt-2.3.3.02/src/system.cpp | 48 + lib/arduino-mqtt-2.3.3.02/src/system.h | 26 + lib/esp-mqtt-arduino-1.0.1.02.1/.gitignore | 28 - lib/esp-mqtt-arduino-1.0.1.02.1/README.md | 15 - .../examples/mqtt_pub/mqtt_pub.ino | 102 -- .../examples/mqtt_sub/mqtt_sub.ino | 95 -- lib/esp-mqtt-arduino-1.0.1.02.1/keywords.txt | 43 - .../library.properties | 9 - lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.cpp | 269 ----- lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.h | 93 -- .../src/mqtt/debug.h | 19 - .../src/mqtt/mqtt.c | 1048 ----------------- .../src/mqtt/mqtt.h | 152 --- .../src/mqtt/mqtt_config.h | 19 - .../src/mqtt/mqtt_msg.c | 487 -------- .../src/mqtt/mqtt_msg.h | 141 --- .../src/mqtt/proto.c | 129 -- .../src/mqtt/proto.h | 32 - .../src/mqtt/queue.c | 75 -- .../src/mqtt/queue.h | 44 - .../src/mqtt/ringbuf.c | 67 -- .../src/mqtt/ringbuf.h | 19 - .../src/mqtt/typedef.h | 17 - .../src/mqtt/utils.c | 149 --- .../src/mqtt/utils.h | 9 - 54 files changed, 4027 insertions(+), 3061 deletions(-) create mode 100644 lib/arduino-mqtt-2.3.3.02/.editorconfig create mode 100644 lib/arduino-mqtt-2.3.3.02/.gitignore create mode 100644 lib/arduino-mqtt-2.3.3.02/.travis.yml create mode 100644 lib/arduino-mqtt-2.3.3.02/CMakeLists.txt create mode 100644 lib/arduino-mqtt-2.3.3.02/LICENSE.md create mode 100644 lib/arduino-mqtt-2.3.3.02/Makefile create mode 100644 lib/arduino-mqtt-2.3.3.02/README.md create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/AdafruitHuzzahESP8266/AdafruitHuzzahESP8266.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/AdafruitHuzzahESP8266Secure/AdafruitHuzzahESP8266Secure.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ArduinoEthernetShield/ArduinoEthernetShield.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ArduinoMKRGSM1400/ArduinoMKRGSM1400.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ArduinoMKRGSM1400Secure/ArduinoMKRGSM1400Secure.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFi101/ArduinoWiFi101.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFi101Secure/ArduinoWiFi101Secure.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFiShield/ArduinoWiFiShield.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ArduinoYun/ArduinoYun.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ArduinoYunSecure/ArduinoYunSecure.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/examples/ESP32DevelopmentBoardSecure/ESP32DevelopmentBoardSecure.ino create mode 100644 lib/arduino-mqtt-2.3.3.02/library.properties create mode 100644 lib/arduino-mqtt-2.3.3.02/src/MQTTClient.h create mode 100644 lib/arduino-mqtt-2.3.3.02/src/MQTTlw.h create mode 100644 lib/arduino-mqtt-2.3.3.02/src/lwmqtt/client.c create mode 100644 lib/arduino-mqtt-2.3.3.02/src/lwmqtt/helpers.c create mode 100644 lib/arduino-mqtt-2.3.3.02/src/lwmqtt/helpers.h create mode 100644 lib/arduino-mqtt-2.3.3.02/src/lwmqtt/lwmqtt.h create mode 100644 lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.c create mode 100644 lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.h create mode 100644 lib/arduino-mqtt-2.3.3.02/src/lwmqtt/string.c create mode 100644 lib/arduino-mqtt-2.3.3.02/src/system.cpp create mode 100644 lib/arduino-mqtt-2.3.3.02/src/system.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/.gitignore delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/README.md delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/examples/mqtt_pub/mqtt_pub.ino delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/examples/mqtt_sub/mqtt_sub.ino delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/keywords.txt delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/library.properties delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.cpp delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/debug.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt.c delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_config.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_msg.c delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_msg.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/proto.c delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/proto.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/queue.c delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/queue.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/ringbuf.c delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/ringbuf.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/typedef.h delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/utils.c delete mode 100644 lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/utils.h diff --git a/lib/arduino-mqtt-2.3.3.02/.editorconfig b/lib/arduino-mqtt-2.3.3.02/.editorconfig new file mode 100644 index 000000000..3edae7b53 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/.editorconfig @@ -0,0 +1,7 @@ +[Makefile] +indent_style = tab +indent_size = 4 + +[src/*.h,src/*.cpp,examples/**.ino] +indent_style = space +indent_size = 2 diff --git a/lib/arduino-mqtt-2.3.3.02/.gitignore b/lib/arduino-mqtt-2.3.3.02/.gitignore new file mode 100644 index 000000000..0c4fe4711 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +cmake-build-debug/ diff --git a/lib/arduino-mqtt-2.3.3.02/.travis.yml b/lib/arduino-mqtt-2.3.3.02/.travis.yml new file mode 100644 index 000000000..b59599cef --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/.travis.yml @@ -0,0 +1,46 @@ +language: generic +env: + global: + - IDE_VERSION=1.8.5 + matrix: + - EXAMPLE="AdafruitHuzzahESP8266" BOARD="esp8266:esp8266:huzzah:FlashSize=4M3M,CpuFrequency=80" + - EXAMPLE="AdafruitHuzzahESP8266Secure" BOARD="esp8266:esp8266:huzzah:FlashSize=4M3M,CpuFrequency=80" + - EXAMPLE="ArduinoEthernetShield" BOARD="arduino:avr:uno" + - EXAMPLE="ArduinoMKRGSM1400" BOARD="arduino:samd:mkrgsm1400" + - EXAMPLE="ArduinoMKRGSM1400Secure" BOARD="arduino:samd:mkrgsm1400" + - EXAMPLE="ArduinoWiFi101Secure" BOARD="arduino:avr:uno" + - EXAMPLE="ArduinoWiFiShield" BOARD="arduino:avr:uno" + - EXAMPLE="ArduinoYun" BOARD="arduino:avr:yun" + - EXAMPLE="ArduinoYunSecure" BOARD="arduino:avr:yun" + - EXAMPLE="ESP32DevelopmentBoard" BOARD="espressif:esp32:esp32:FlashFreq=80" + - EXAMPLE="ESP32DevelopmentBoardSecure" BOARD="espressif:esp32:esp32:FlashFreq=80" +before_install: + - /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16 + - sleep 3 + - export DISPLAY=:1.0 + - wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz + - tar xf arduino-$IDE_VERSION-linux64.tar.xz + - mv arduino-$IDE_VERSION ~/arduino-ide + - export PATH=$PATH:~/arduino-ide + - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then + arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json" --install-boards esp8266:esp8266; + arduino --pref "boardsmanager.additional.urls=" --save-prefs; + fi + - if [[ "$BOARD" =~ "espressif:esp32:" ]]; then + mkdir -p ~/Arduino/hardware/espressif && + cd ~/Arduino/hardware/espressif && + git clone https://github.com/espressif/arduino-esp32.git esp32 && + cd esp32/tools/ && + python get.py && + cd $TRAVIS_BUILD_DIR; + fi + - if [[ "$BOARD" =~ "arduino:samd:mkrgsm1400" ]]; then + arduino --install-boards arduino:samd; + arduino --install-library MKRGSM; + fi + - arduino --install-library WiFi101 +install: + - mkdir -p ~/Arduino/libraries + - ln -s $PWD ~/Arduino/libraries/. +script: + - arduino --verbose-build --verify --board $BOARD $PWD/examples/$EXAMPLE/$EXAMPLE.ino; diff --git a/lib/arduino-mqtt-2.3.3.02/CMakeLists.txt b/lib/arduino-mqtt-2.3.3.02/CMakeLists.txt new file mode 100644 index 000000000..58b0e31c9 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/CMakeLists.txt @@ -0,0 +1,40 @@ +# Uncompilable CMake File to enable project editing with CLion IDE + +cmake_minimum_required(VERSION 2.8.4) +project(arduino-mqtt) + +include_directories( + /Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/ + /Users/256dpi/Development/Arduino/libraries/Ethernet/src + /Users/256dpi/Development/Arduino/libraries/WiFi101/src + /Users/256dpi/Development/Arduino/libraries/MKRGSM/src + /Applications/Arduino.app/Contents/Java/libraries/Bridge/src + /Users/256dpi/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266WiFi/src + /Users/256dpi/Development/Arduino/hardware/espressif/esp32/libraries/WiFi/src + /Users/256dpi/Development/Arduino/hardware/espressif/esp32/libraries/WiFiClientSecure/src + src/) + +include_directories(src/) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +set(SOURCE_FILES + examples/AdafruitHuzzahESP8266/AdafruitHuzzahESP8266.ino + examples/AdafruitHuzzahESP8266Secure/AdafruitHuzzahESP8266Secure.ino + examples/ArduinoEthernetShield/ArduinoEthernetShield.ino + examples/ArduinoMKRGSM1400/ArduinoMKRGSM1400.ino + examples/ArduinoMKRGSM1400Secure/ArduinoMKRGSM1400Secure.ino + examples/ArduinoWiFi101/ArduinoWiFi101.ino + examples/ArduinoWiFi101Secure/ArduinoWiFi101Secure.ino + examples/ArduinoWiFiShield/ArduinoWiFiShield.ino + examples/ArduinoYun/ArduinoYun.ino + examples/ArduinoYunSecure/ArduinoYunSecure.ino + examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino + examples/ESP32DevelopmentBoardSecure/ESP32DevelopmentBoardSecure.ino + src/lwmqtt + src/MQTT.h + src/MQTTClient.h + src/system.cpp + src/system.h) + +add_executable(arduino-mqtt ${SOURCE_FILES}) diff --git a/lib/arduino-mqtt-2.3.3.02/LICENSE.md b/lib/arduino-mqtt-2.3.3.02/LICENSE.md new file mode 100644 index 000000000..325e07cff --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Joël Gähwiler + +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/lib/arduino-mqtt-2.3.3.02/Makefile b/lib/arduino-mqtt-2.3.3.02/Makefile new file mode 100644 index 000000000..cfd69e49c --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/Makefile @@ -0,0 +1,14 @@ +all: fmt + +fmt: + clang-format -i src/*.cpp src/*.h -style="{BasedOnStyle: Google, ColumnLimit: 120}" + +update: + rm -rf ./lwmqtt + git clone --branch v0.6.2 https://github.com/256dpi/lwmqtt.git ./lwmqtt + mkdir -p ./src/lwmqtt + cp -r ./lwmqtt/src/*.c ./src/lwmqtt/ + cp -r ./lwmqtt/src/*.h ./src/lwmqtt/ + cp -r ./lwmqtt/include/*.h ./src/lwmqtt/ + rm -rf ./lwmqtt + sed -i '' "s//\"lwmqtt.h\"/g" ./src/lwmqtt/* diff --git a/lib/arduino-mqtt-2.3.3.02/README.md b/lib/arduino-mqtt-2.3.3.02/README.md new file mode 100644 index 000000000..470c4a58c --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/README.md @@ -0,0 +1,225 @@ +# arduino-mqtt + +[![Build Status](https://travis-ci.org/256dpi/arduino-mqtt.svg?branch=master)](https://travis-ci.org/256dpi/arduino-mqtt) +[![GitHub release](https://img.shields.io/github/release/256dpi/arduino-mqtt.svg)](https://github.com/256dpi/arduino-mqtt/releases) + +This library bundles the [lwmqtt](https://github.com/256dpi/lwmqtt) MQTT 3.1.1 client and adds a thin wrapper to get an Arduino like API. + +Download the latest version from the [release](https://github.com/256dpi/arduino-mqtt/releases) section. Or even better use the builtin Library Manager in the Arduino IDE and search for "MQTT". + +The library is also available on [PlatformIO](https://platformio.org/lib/show/617/MQTT). You can install it by running: `pio lib install "MQTT"`. + +## Compatibility + +The following examples show how you can use the library with various Arduino compatible hardware: + +- [Arduino Yun & Yun-Shield](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoYun/ArduinoYun.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoYunSecure/ArduinoYunSecure.ino)) +- [Arduino Ethernet Shield](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoEthernetShield/ArduinoEthernetShield.ino) +- [Arduino WiFi Shield](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoWiFiShield/ArduinoWiFiShield.ino) +- [Adafruit HUZZAH ESP8266](https://github.com/256dpi/arduino-mqtt/blob/master/examples/AdafruitHuzzahESP8266/AdafruitHuzzahESP8266.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/AdafruitHuzzahESP8266Secure/AdafruitHuzzahESP8266Secure.ino)) +- [Arduino/Genuino WiFi101 Shield](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoWiFi101/ArduinoWiFi101.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoWiFi101Secure/ArduinoWiFi101Secure.ino)) +- [Arduino MKR GSM 1400](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoMKRGSM1400/ArduinoMKRGSM1400.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoMKRGSM1400Secure/ArduinoMKRGSM1400Secure.ino)) +- [ESP32 Development Board](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ESP32DevelopmentBoardSecure/ESP32DevelopmentBoardSecure.ino)) + +Other shields and boards should also work if they provide a [Client](https://www.arduino.cc/en/Reference/ClientConstructor) based network implementation. + +## Notes + +- The maximum size for packets being published and received is set by default to 128 bytes. To change the buffer sizes, you need to use `MQTTClient client(256)` instead of just `MQTTClient client` on the top of your sketch. The passed value denotes the read and write buffer size. + +- On the ESP8266 it has been reported that an additional `delay(10);` after `client.loop();` fixes many stability issues with WiFi connections. + +- To use the library with shiftr.io, you need to provide the token key (username) and token secret (password) as the second and third argument to `client.connect(name, key, secret)`. + +## Example + +The following example uses an Arduino MKR1000 to connect to shiftr.io. You can check on your device after a successful connection here: https://shiftr.io/try. + +```c++ +#include +#include +#include + +const char ssid[] = "ssid"; +const char pass[] = "pass"; + +WiFiClient net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("checking wifi..."); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(1000); + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, pass); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + client.begin("broker.shiftr.io", net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} +``` + +## API + +Initialize the object using the hostname of the broker, the brokers port (default: `1883`) and the underlying Client class for network transport: + +```c++ +void begin(const char hostname[], Client &client); +void begin(const char hostname[], int port, Client &client); +``` + +- Specify port `8883` when using secure clients for encrypted connections. +- Local domain names (e.g. `Computer.local` on OSX) are not supported by Arduino. You need to set the IP address directly. + +The hostname and port can also be changed after calling `begin()`: + +```c++ +void setHost(const char hostname[]); +void setHost(const char hostname[], int port); +``` + +Set a will message (last testament) that gets registered on the broker after connecting. `setWill()` has to be called before calling `connect()`: + +```c++ +void setWill(const char topic[]); +void setWill(const char topic[], const char payload[]); +void setWill(const char topic[], const char payload[], bool retained, int qos); +void clearWill(); +``` + +Register a callback to receive messages: + +```c++ +void onMessage(MQTTClientCallbackSimple); +// Callback signature: void messageReceived(String &topic, String &payload) {} + +void onMessageAdvanced(MQTTClientCallbackAdvanced); +// Callback signature: void messageReceived(MQTTClient *client, char topic[], char payload[], int payload_length) {} +``` + +- The set callback is mostly called during a call to `loop()` but may also be called during a call to `subscribe()`, `unsubscribe()` or `publish() // QoS > 0` if messages have been received before receiving the required acknowledgement. Therefore, it is strongly recommended to not call `subscribe()`, `unsubscribe()` or `publish() // QoS > 0` directly in the callback. + +Set more advanced options: + +```c++ +void setOptions(int keepAlive, bool cleanSession, int timeout); +``` + +- The `keepAlive` option controls the keep alive interval in seconds (default: 10). +- The `cleanSession` option controls the session retention on the broker side (default: true). +- The `timeout` option controls the default timeout for all commands in milliseconds (default: 1000). + +Connect to broker using the supplied client id and an optional username and password: + +```c++ +bool connect(const char clientId[]); +bool connect(const char clientId[], const char username[]); +bool connect(const char clientId[], const char username[], const char password[]); +``` + +- This functions returns a boolean that indicates if the connection has been established successfully. + +Publishes a message to the broker with an optional payload: + +```c++ +bool publish(const String &topic); +bool publish(const char topic[]); +bool publish(const String &topic, const String &payload); +bool publish(const String &topic, const String &payload, bool retained, int qos); +bool publish(const char topic[], const String &payload); +bool publish(const char topic[], const String &payload, bool retained, int qos); +bool publish(const char topic[], const char payload[]); +bool publish(const char topic[], const char payload[], bool retained, int qos); +bool publish(const char topic[], const char payload[], int length); +bool publish(const char topic[], const char payload[], int length, bool retained, int qos); +``` + +Subscribe to a topic: + +```c++ +bool subscribe(const String &topic); +bool subscribe(const String &topic, int qos); +bool subscribe(const char topic[]); +bool subscribe(const char topic[], int qos); +``` + +Unsubscribe from a topic: + +```c++ +bool unsubscribe(const String &topic); +bool unsubscribe(const char topic[]); +``` + +Sends and receives packets: + +```c++ +bool loop(); +``` + +- This function should be called in every `loop`. + +Check if the client is currently connected: + +```c++ +bool connected(); +``` + +Access low-level information for debugging: + +```c++ +lwmqtt_err_t lastError(); +lwmqtt_return_code_t returnCode(); +``` + +- The error codes can be found [here](https://github.com/256dpi/lwmqtt/blob/master/include/lwmqtt.h#L11). +- The return codes can be found [here](https://github.com/256dpi/lwmqtt/blob/master/include/lwmqtt.h#L243). + +Disconnect from the broker: + +```c++ +bool disconnect(); +``` + +## Release Management + +- Update version in `library.properties`. +- Create release on GitHub. diff --git a/lib/arduino-mqtt-2.3.3.02/examples/AdafruitHuzzahESP8266/AdafruitHuzzahESP8266.ino b/lib/arduino-mqtt-2.3.3.02/examples/AdafruitHuzzahESP8266/AdafruitHuzzahESP8266.ino new file mode 100644 index 000000000..ca5a22607 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/AdafruitHuzzahESP8266/AdafruitHuzzahESP8266.ino @@ -0,0 +1,69 @@ +// This example uses an Adafruit Huzzah ESP8266 +// to connect to shiftr.io. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Joël Gähwiler +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +const char ssid[] = "ssid"; +const char pass[] = "pass"; + +WiFiClient net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("checking wifi..."); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(1000); + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, pass); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + client.begin("broker.shiftr.io", net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + delay(10); // <- fixes some issues with WiFi stability + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/AdafruitHuzzahESP8266Secure/AdafruitHuzzahESP8266Secure.ino b/lib/arduino-mqtt-2.3.3.02/examples/AdafruitHuzzahESP8266Secure/AdafruitHuzzahESP8266Secure.ino new file mode 100644 index 000000000..1def5678d --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/AdafruitHuzzahESP8266Secure/AdafruitHuzzahESP8266Secure.ino @@ -0,0 +1,71 @@ +// This example uses an Adafruit Huzzah ESP8266 +// to connect to shiftr.io. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Joël Gähwiler +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +const char ssid[] = "ssid"; +const char pass[] = "pass"; + +WiFiClientSecure net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("checking wifi..."); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(1000); + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, pass); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + // + // MQTT brokers usually use port 8883 for secure connections. + client.begin("broker.shiftr.io", 8883, net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + delay(10); // <- fixes some issues with WiFi stability + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ArduinoEthernetShield/ArduinoEthernetShield.ino b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoEthernetShield/ArduinoEthernetShield.ino new file mode 100644 index 000000000..8386c7788 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoEthernetShield/ArduinoEthernetShield.ino @@ -0,0 +1,62 @@ +// This example uses an Arduino Uno together with +// an Ethernet Shield to connect to shiftr.io. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Joël Gähwiler +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +byte ip[] = {192, 168, 1, 177}; // <- change to match your network + +EthernetClient net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("connecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + Ethernet.begin(mac, ip); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + client.begin("broker.shiftr.io", net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ArduinoMKRGSM1400/ArduinoMKRGSM1400.ino b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoMKRGSM1400/ArduinoMKRGSM1400.ino new file mode 100644 index 000000000..dd56d5e21 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoMKRGSM1400/ArduinoMKRGSM1400.ino @@ -0,0 +1,84 @@ +// This example uses an Arduino MKR GSM 1400 board +// to connect to shiftr.io. +// +// IMPORTANT: This example uses the new MKRGSM library. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Sandeep Mistry +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +const char pin[] = ""; +const char apn[] = "apn"; +const char login[] = "login"; +const char password[] = "password"; + +GSMClient net; +GPRS gprs; +GSM gsmAccess; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + // connection state + bool connected = false; + + Serial.print("connecting to cellular network ..."); + + // After starting the modem with gsmAccess.begin() + // attach to the GPRS network with the APN, login and password + while (!connected) { + if ((gsmAccess.begin(pin) == GSM_READY) && + (gprs.attachGPRS(apn, login, password) == GPRS_READY)) { + connected = true; + } else { + Serial.print("."); + delay(1000); + } + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + client.begin("broker.shiftr.io", net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ArduinoMKRGSM1400Secure/ArduinoMKRGSM1400Secure.ino b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoMKRGSM1400Secure/ArduinoMKRGSM1400Secure.ino new file mode 100644 index 000000000..1b172ab6e --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoMKRGSM1400Secure/ArduinoMKRGSM1400Secure.ino @@ -0,0 +1,86 @@ +// This example uses an Arduino MKR GSM 1400 board +// to securely connect to shiftr.io. +// +// IMPORTANT: This example uses the new MKRGSM library. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Sandeep Mistry +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +const char pin[] = ""; +const char apn[] = "apn"; +const char login[] = "login"; +const char password[] = "password"; + +GSMSSLClient net; +GPRS gprs; +GSM gsmAccess; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + // connection state + bool connected = false; + + Serial.print("connecting to cellular network ..."); + + // After starting the modem with gsmAccess.begin() + // attach to the GPRS network with the APN, login and password + while (!connected) { + if ((gsmAccess.begin(pin) == GSM_READY) && + (gprs.attachGPRS(apn, login, password) == GPRS_READY)) { + connected = true; + } else { + Serial.print("."); + delay(1000); + } + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + // + // MQTT brokers usually use port 8883 for secure connections. + client.begin("broker.shiftr.io", 8883, net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFi101/ArduinoWiFi101.ino b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFi101/ArduinoWiFi101.ino new file mode 100644 index 000000000..a36bd65aa --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFi101/ArduinoWiFi101.ino @@ -0,0 +1,70 @@ +// This example uses an Arduino/Genuino Zero together with +// a WiFi101 Shield or a MKR1000 to connect to shiftr.io. +// +// IMPORTANT: This example uses the new WiFi101 library. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Gilberto Conti +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +const char ssid[] = "ssid"; +const char pass[] = "pass"; + +WiFiClient net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("checking wifi..."); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(1000); + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, pass); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + client.begin("broker.shiftr.io", net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFi101Secure/ArduinoWiFi101Secure.ino b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFi101Secure/ArduinoWiFi101Secure.ino new file mode 100644 index 000000000..c21e7ae99 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFi101Secure/ArduinoWiFi101Secure.ino @@ -0,0 +1,75 @@ +// This example uses an Arduino/Genuino Zero together with +// a WiFi101 Shield or a MKR1000 to connect to shiftr.io. +// +// IMPORTANT: This example uses the new WiFi101 library. +// +// IMPORTANT: You need to install/update the SSL certificates first: +// https://github.com/arduino-libraries/WiFi101-FirmwareUpdater#to-update-ssl-certificates +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Gilberto Conti +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +const char ssid[] = "ssid"; +const char pass[] = "pass"; + +WiFiSSLClient net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("checking wifi..."); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(1000); + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, pass); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + // + // MQTT brokers usually use port 8883 for secure connections. + client.begin("broker.shiftr.io", 8883, net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFiShield/ArduinoWiFiShield.ino b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFiShield/ArduinoWiFiShield.ino new file mode 100644 index 000000000..4aff769f4 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoWiFiShield/ArduinoWiFiShield.ino @@ -0,0 +1,68 @@ +// This example uses an Arduino Uno together with +// a WiFi Shield to connect to shiftr.io. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Joël Gähwiler +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +const char ssid[] = "ssid"; +const char pass[] = "pass"; + +WiFiClient net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("checking wifi..."); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(1000); + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, pass); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + client.begin("broker.shiftr.io", net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ArduinoYun/ArduinoYun.ino b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoYun/ArduinoYun.ino new file mode 100644 index 000000000..823bdff36 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoYun/ArduinoYun.ino @@ -0,0 +1,60 @@ +// This example uses an Arduino Yun or a Yun-Shield +// and the MQTTClient to connect to shiftr.io. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Joël Gähwiler +// https://github.com/256dpi/arduino-mqtt + +#include +#include +#include + +BridgeClient net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("connecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Bridge.begin(); + Serial.begin(115200); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + client.begin("broker.shiftr.io", net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ArduinoYunSecure/ArduinoYunSecure.ino b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoYunSecure/ArduinoYunSecure.ino new file mode 100644 index 000000000..46c068ab2 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ArduinoYunSecure/ArduinoYunSecure.ino @@ -0,0 +1,62 @@ +// This example uses an Arduino Yun or a Yun-Shield +// and the MQTTClient to connect to shiftr.io. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Joël Gähwiler +// https://github.com/256dpi/arduino-mqtt + +#include +#include +#include + +BridgeSSLClient net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("connecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Bridge.begin(); + Serial.begin(115200); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + // + // MQTT brokers usually use port 8883 for secure connections. + client.begin("broker.shiftr.io", 8883, net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino b/lib/arduino-mqtt-2.3.3.02/examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino new file mode 100644 index 000000000..c6919280d --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino @@ -0,0 +1,69 @@ +// This example uses an ESP32 Development Board +// to connect to shiftr.io. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Joël Gähwiler +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +const char ssid[] = "ssid"; +const char pass[] = "pass"; + +WiFiClient net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("checking wifi..."); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(1000); + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, pass); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + client.begin("broker.shiftr.io", net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + delay(10); // <- fixes some issues with WiFi stability + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/examples/ESP32DevelopmentBoardSecure/ESP32DevelopmentBoardSecure.ino b/lib/arduino-mqtt-2.3.3.02/examples/ESP32DevelopmentBoardSecure/ESP32DevelopmentBoardSecure.ino new file mode 100644 index 000000000..cff75379e --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/examples/ESP32DevelopmentBoardSecure/ESP32DevelopmentBoardSecure.ino @@ -0,0 +1,71 @@ +// This example uses an ESP32 Development Board +// to connect to shiftr.io. +// +// You can check on your device after a successful +// connection here: https://shiftr.io/try. +// +// by Joël Gähwiler +// https://github.com/256dpi/arduino-mqtt + +#include +#include + +const char ssid[] = "ssid"; +const char pass[] = "pass"; + +WiFiClientSecure net; +MQTTClient client; + +unsigned long lastMillis = 0; + +void connect() { + Serial.print("checking wifi..."); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(1000); + } + + Serial.print("\nconnecting..."); + while (!client.connect("arduino", "try", "try")) { + Serial.print("."); + delay(1000); + } + + Serial.println("\nconnected!"); + + client.subscribe("/hello"); + // client.unsubscribe("/hello"); +} + +void messageReceived(String &topic, String &payload) { + Serial.println("incoming: " + topic + " - " + payload); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, pass); + + // Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino. + // You need to set the IP address directly. + // + // MQTT brokers usually use port 8883 for secure connections. + client.begin("broker.shiftr.io", 8883, net); + client.onMessage(messageReceived); + + connect(); +} + +void loop() { + client.loop(); + delay(10); // <- fixes some issues with WiFi stability + + if (!client.connected()) { + connect(); + } + + // publish a message roughly every second. + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + client.publish("/hello", "world"); + } +} diff --git a/lib/arduino-mqtt-2.3.3.02/library.properties b/lib/arduino-mqtt-2.3.3.02/library.properties new file mode 100644 index 000000000..a5ce4138a --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/library.properties @@ -0,0 +1,9 @@ +name=MQTT +version=2.3.3 +author=Joel Gaehwiler +maintainer=Joel Gaehwiler +sentence=MQTT library for Arduino +paragraph=This library bundles the lwmqtt client and adds a thin wrapper to get an Arduino like API. +category=Communication +url=https://github.com/256dpi/arduino-mqtt +architectures=* diff --git a/lib/arduino-mqtt-2.3.3.02/src/MQTTClient.h b/lib/arduino-mqtt-2.3.3.02/src/MQTTClient.h new file mode 100644 index 000000000..ecb69ec1d --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/MQTTClient.h @@ -0,0 +1,386 @@ +#ifndef MQTT_CLIENT_H +#define MQTT_CLIENT_H + +#include +#include +#include + +#include "system.h" + +class MQTTClient; + +typedef void (*MQTTClientCallbackSimple)(String &topic, String &payload); +typedef void (*MQTTClientCallbackAdvanced)(MQTTClient *client, char topic[], char bytes[], int length); + +typedef struct { + MQTTClient *client = nullptr; + MQTTClientCallbackSimple simple = nullptr; + MQTTClientCallbackAdvanced advanced = nullptr; +} MQTTClientCallback; + +static void MQTTClientHandler(lwmqtt_client_t * /*client*/, void *ref, lwmqtt_string_t topic, + lwmqtt_message_t message) { + // get callback + auto cb = (MQTTClientCallback *)ref; + + // null terminate topic + char terminated_topic[topic.len + 1]; + memcpy(terminated_topic, topic.data, topic.len); + terminated_topic[topic.len] = '\0'; + + // null terminate payload if available + if (message.payload != nullptr) { + message.payload[message.payload_len] = '\0'; + } + + // call the advanced callback and return if available + if (cb->advanced != nullptr) { + cb->advanced(cb->client, terminated_topic, (char *)message.payload, (int)message.payload_len); + return; + } + + // return if simple callback is not set + if (cb->simple == nullptr) { + return; + } + + // create topic string + String str_topic = String(terminated_topic); + + // create payload string + String str_payload; + if (message.payload != nullptr) { + str_payload = String((const char *)message.payload); + } + + // call simple callback + cb->simple(str_topic, str_payload); +} + +class MQTTClient { + private: + size_t bufSize = 0; + uint8_t *readBuf = nullptr; + uint8_t *writeBuf = nullptr; + + uint16_t keepAlive = 10; + bool cleanSession = true; + uint32_t timeout = 1000; + + Client *netClient = nullptr; + const char *hostname = nullptr; + int port = 0; + lwmqtt_will_t will = lwmqtt_default_will; + bool hasWill = false; + MQTTClientCallback callback; + + lwmqtt_arduino_network_t network = {nullptr}; + lwmqtt_arduino_timer_t timer1 = {0}; + lwmqtt_arduino_timer_t timer2 = {0}; + lwmqtt_client_t client; + + bool _connected = false; + lwmqtt_return_code_t _returnCode = (lwmqtt_return_code_t)0; + lwmqtt_err_t _lastError = (lwmqtt_err_t)0; + + public: + explicit MQTTClient(int bufSize = 128) { + memset(&client, 0, sizeof(client)); + this->bufSize = (size_t)bufSize; + this->readBuf = (uint8_t *)malloc((size_t)bufSize + 1); + this->writeBuf = (uint8_t *)malloc((size_t)bufSize); + } + + ~MQTTClient() { + free(this->readBuf); + free(this->writeBuf); + } + + void begin(const char hostname[], Client &client) { this->begin(hostname, 1883, client); } + + void begin(const char hostname[], int port, Client &client) { + // set hostname and port + this->setHost(hostname, port); + + // set client + this->netClient = &client; + + // initialize client + lwmqtt_init(&this->client, this->writeBuf, this->bufSize, this->readBuf, this->bufSize); + + // set timers + lwmqtt_set_timers(&this->client, &this->timer1, &this->timer2, lwmqtt_arduino_timer_set, lwmqtt_arduino_timer_get); + + // set network + lwmqtt_set_network(&this->client, &this->network, lwmqtt_arduino_network_read, lwmqtt_arduino_network_write); + + // set callback + lwmqtt_set_callback(&this->client, (void *)&this->callback, MQTTClientHandler); + } + + void onMessage(MQTTClientCallbackSimple cb) { + // set callback + this->callback.client = this; + this->callback.simple = cb; + this->callback.advanced = nullptr; + } + + void onMessageAdvanced(MQTTClientCallbackAdvanced cb) { + // set callback + this->callback.client = this; + this->callback.simple = nullptr; + this->callback.advanced = cb; + } + + void setHost(const char hostname[]) { this->setHost(hostname, 1883); } + + void setHost(const char hostname[], int port) { + // free hostname if set + if(this->hostname != nullptr) { + free((void *)this->hostname); + } + + // set hostname and port + this->hostname = strdup(hostname); + this->port = port; + } + + void setWill(const char topic[]) { this->setWill(topic, ""); } + + void setWill(const char topic[], const char payload[]) { this->setWill(topic, payload, false, 0); } + + void setWill(const char topic[], const char payload[], bool retained, int qos) { + this->hasWill = true; + this->will.topic = lwmqtt_string(topic); + this->will.payload = lwmqtt_string(payload); + this->will.retained = retained; + this->will.qos = (lwmqtt_qos_t)qos; + } + + void clearWill() { this->hasWill = false; } + + void setOptions(int keepAlive, bool cleanSession, int timeout) { + this->keepAlive = (uint16_t)keepAlive; + this->cleanSession = cleanSession; + this->timeout = (uint32_t)timeout; + } + + bool connect(const char clientId[]) { return this->connect(clientId, nullptr, nullptr); } + + bool connect(const char clientId[], const char username[]) { return this->connect(clientId, username, nullptr); } + + bool connect(const char clientId[], const char username[], const char password[]) { + // close left open connection if still connected + if (this->connected()) { + this->close(); + } + + // save client + this->network.client = this->netClient; + + // connect to host + if (this->netClient->connect(this->hostname, (uint16_t)this->port) < 0) { + return false; + } + + // prepare options + lwmqtt_options_t options = lwmqtt_default_options; + options.keep_alive = this->keepAlive; + options.clean_session = this->cleanSession; + options.client_id = lwmqtt_string(clientId); + + // set username and password if available + if (username != nullptr) { + options.username = lwmqtt_string(username); + + if (password != nullptr) { + options.password = lwmqtt_string(password); + } + } + + // prepare will reference + lwmqtt_will_t *will = nullptr; + if (this->hasWill) { + will = &this->will; + } + + // connect to broker + this->_lastError = lwmqtt_connect(&this->client, options, will, &this->_returnCode, this->timeout); + if (this->_lastError != LWMQTT_SUCCESS) { + // close connection + this->close(); + + return false; + } + + // set flag + this->_connected = true; + + return true; + } + + bool publish(const String &topic) { return this->publish(topic.c_str(), ""); } + + bool publish(const char topic[]) { return this->publish(topic, ""); } + + bool publish(const String &topic, const String &payload) { return this->publish(topic.c_str(), payload.c_str()); } + + bool publish(const String &topic, const String &payload, bool retained, int qos) { + return this->publish(topic.c_str(), payload.c_str(), retained, qos); + } + + bool publish(const char topic[], const String &payload) { return this->publish(topic, payload.c_str()); } + + bool publish(const char topic[], const String &payload, bool retained, int qos) { + return this->publish(topic, payload.c_str(), retained, qos); + } + + bool publish(const char topic[], const char payload[]) { + return this->publish(topic, (char *)payload, (int)strlen(payload)); + } + + bool publish(const char topic[], const char payload[], bool retained, int qos) { + return this->publish(topic, (char *)payload, (int)strlen(payload), retained, qos); + } + + bool publish(const char topic[], const char payload[], int length) { + return this->publish(topic, payload, length, false, 0); + } + + bool publish(const char topic[], const char payload[], int length, bool retained, int qos) { + // return immediately if not connected + if (!this->connected()) { + return false; + } + + // prepare message + lwmqtt_message_t message = lwmqtt_default_message; + message.payload = (uint8_t *)payload; + message.payload_len = (size_t)length; + message.retained = retained; + message.qos = lwmqtt_qos_t(qos); + + // publish message + this->_lastError = lwmqtt_publish(&this->client, lwmqtt_string(topic), message, this->timeout); + if (this->_lastError != LWMQTT_SUCCESS) { + // close connection + this->close(); + + return false; + } + + return true; + } + + bool subscribe(const String &topic) { return this->subscribe(topic.c_str()); } + + bool subscribe(const String &topic, int qos) { return this->subscribe(topic.c_str(), qos); } + + bool subscribe(const char topic[]) { return this->subscribe(topic, 0); } + + bool subscribe(const char topic[], int qos) { + // return immediately if not connected + if (!this->connected()) { + return false; + } + + // subscribe to topic + this->_lastError = lwmqtt_subscribe_one(&this->client, lwmqtt_string(topic), (lwmqtt_qos_t)qos, this->timeout); + if (this->_lastError != LWMQTT_SUCCESS) { + // close connection + this->close(); + + return false; + } + + return true; + } + + bool unsubscribe(const String &topic) { return this->unsubscribe(topic.c_str()); } + + bool unsubscribe(const char topic[]) { + // return immediately if not connected + if (!this->connected()) { + return false; + } + + // unsubscribe from topic + this->_lastError = lwmqtt_unsubscribe_one(&this->client, lwmqtt_string(topic), this->timeout); + if (this->_lastError != LWMQTT_SUCCESS) { + // close connection + this->close(); + + return false; + } + + return true; + } + + bool loop() { + // return immediately if not connected + if (!this->connected()) { + return false; + } + + // get available bytes on the network + auto available = (size_t)this->netClient->available(); + + // yield if data is available + if (available > 0) { + this->_lastError = lwmqtt_yield(&this->client, available, this->timeout); + if (this->_lastError != LWMQTT_SUCCESS) { + // close connection + this->close(); + + return false; + } + } + + // keep the connection alive + this->_lastError = lwmqtt_keep_alive(&this->client, this->timeout); + if (this->_lastError != LWMQTT_SUCCESS) { + // close connection + this->close(); + + return false; + } + + return true; + } + + bool connected() { + // a client is connected if the network is connected, a client is available and + // the connection has been properly initiated + return this->netClient != nullptr && this->netClient->connected() == 1 && this->_connected; + } + + lwmqtt_err_t lastError() { return this->_lastError; } + + lwmqtt_return_code_t returnCode() { return this->_returnCode; } + + bool disconnect() { + // return immediately if not connected anymore + if (!this->connected()) { + return false; + } + + // cleanly disconnect + this->_lastError = lwmqtt_disconnect(&this->client, this->timeout); + + // close + this->close(); + + return this->_lastError == LWMQTT_SUCCESS; + } + + private: + void close() { + // set flag + this->_connected = false; + + // close network + this->netClient->stop(); + } +}; + +#endif diff --git a/lib/arduino-mqtt-2.3.3.02/src/MQTTlw.h b/lib/arduino-mqtt-2.3.3.02/src/MQTTlw.h new file mode 100644 index 000000000..35652c45f --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/MQTTlw.h @@ -0,0 +1,6 @@ +#ifndef MQTT_H +#define MQTT_H + +#include "MQTTClient.h" + +#endif diff --git a/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/client.c b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/client.c new file mode 100644 index 000000000..b1772b9f7 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/client.c @@ -0,0 +1,618 @@ +#include "packet.h" + +void lwmqtt_init(lwmqtt_client_t *client, uint8_t *write_buf, size_t write_buf_size, uint8_t *read_buf, + size_t read_buf_size) { + client->last_packet_id = 1; + client->keep_alive_interval = 0; + client->pong_pending = false; + + client->write_buf = write_buf; + client->write_buf_size = write_buf_size; + client->read_buf = read_buf; + client->read_buf_size = read_buf_size; + + client->callback = NULL; + client->callback_ref = NULL; + + client->network = NULL; + client->network_read = NULL; + client->network_write = NULL; + + client->keep_alive_timer = NULL; + client->command_timer = NULL; + client->timer_set = NULL; + client->timer_get = NULL; +} + +void lwmqtt_set_network(lwmqtt_client_t *client, void *ref, lwmqtt_network_read_t read, lwmqtt_network_write_t write) { + client->network = ref; + client->network_read = read; + client->network_write = write; +} + +void lwmqtt_set_timers(lwmqtt_client_t *client, void *keep_alive_timer, void *command_timer, lwmqtt_timer_set_t set, + lwmqtt_timer_get_t get) { + client->keep_alive_timer = keep_alive_timer; + client->command_timer = command_timer; + client->timer_set = set; + client->timer_get = get; + + client->timer_set(client->keep_alive_timer, 0); + client->timer_set(client->command_timer, 0); +} + +void lwmqtt_set_callback(lwmqtt_client_t *client, void *ref, lwmqtt_callback_t cb) { + client->callback_ref = ref; + client->callback = cb; +} + +static uint16_t lwmqtt_get_next_packet_id(lwmqtt_client_t *client) { + // check overflow + if (client->last_packet_id == 65535) { + client->last_packet_id = 1; + return 1; + } + + // increment packet id + client->last_packet_id++; + + return client->last_packet_id; +} + +static lwmqtt_err_t lwmqtt_read_from_network(lwmqtt_client_t *client, size_t offset, size_t len) { + // check read buffer capacity + if (client->read_buf_size < offset + len) { + return LWMQTT_BUFFER_TOO_SHORT; + } + + // prepare counter + size_t read = 0; + + // read while data is missing + while (read < len) { + // check remaining time + int32_t remaining_time = client->timer_get(client->command_timer); + if (remaining_time <= 0) { + return LWMQTT_NETWORK_TIMEOUT; + } + + // read + size_t partial_read = 0; + lwmqtt_err_t err = client->network_read(client->network, client->read_buf + offset + read, len - read, + &partial_read, (uint32_t)remaining_time); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // increment counter + read += partial_read; + } + + return LWMQTT_SUCCESS; +} + +static lwmqtt_err_t lwmqtt_write_to_network(lwmqtt_client_t *client, size_t offset, size_t len) { + // prepare counter + size_t written = 0; + + // write while data is left + while (written < len) { + // check remaining time + int32_t remaining_time = client->timer_get(client->command_timer); + if (remaining_time <= 0) { + return LWMQTT_NETWORK_TIMEOUT; + } + + // write + size_t partial_write = 0; + lwmqtt_err_t err = client->network_write(client->network, client->write_buf + offset + written, len - written, + &partial_write, (uint32_t)remaining_time); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // increment counter + written += partial_write; + } + + return LWMQTT_SUCCESS; +} + +static lwmqtt_err_t lwmqtt_read_packet_in_buffer(lwmqtt_client_t *client, size_t *read, + lwmqtt_packet_type_t *packet_type) { + // preset packet type + *packet_type = LWMQTT_NO_PACKET; + + // read or wait for header byte + lwmqtt_err_t err = lwmqtt_read_from_network(client, 0, 1); + if (err == LWMQTT_NETWORK_TIMEOUT) { + // this is ok as no data has been read at all + return LWMQTT_SUCCESS; + } else if (err != LWMQTT_SUCCESS) { + return err; + } + + // detect packet type + err = lwmqtt_detect_packet_type(client->read_buf, 1, packet_type); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // prepare variables + size_t len = 0; + uint32_t rem_len = 0; + + do { + // adjust len + len++; + + // read next byte + err = lwmqtt_read_from_network(client, len, 1); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // attempt to detect remaining length + err = lwmqtt_detect_remaining_length(client->read_buf + 1, len, &rem_len); + } while (err == LWMQTT_BUFFER_TOO_SHORT); + + // check final error + if (err != LWMQTT_SUCCESS) { + return err; + } + + // read the rest of the buffer if needed + if (rem_len > 0) { + err = lwmqtt_read_from_network(client, 1 + len, rem_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + } + + // adjust counter + *read += 1 + len + rem_len; + + return LWMQTT_SUCCESS; +} + +static lwmqtt_err_t lwmqtt_send_packet_in_buffer(lwmqtt_client_t *client, size_t length) { + // write to network + lwmqtt_err_t err = lwmqtt_write_to_network(client, 0, length); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // reset keep alive timer + client->timer_set(client->keep_alive_timer, client->keep_alive_interval); + + return LWMQTT_SUCCESS; +} + +static lwmqtt_err_t lwmqtt_cycle(lwmqtt_client_t *client, size_t *read, lwmqtt_packet_type_t *packet_type) { + // read next packet from the network + lwmqtt_err_t err = lwmqtt_read_packet_in_buffer(client, read, packet_type); + if (err != LWMQTT_SUCCESS) { + return err; + } else if (*packet_type == LWMQTT_NO_PACKET) { + return LWMQTT_SUCCESS; + } + + switch (*packet_type) { + // handle publish packets + case LWMQTT_PUBLISH_PACKET: { + // decode publish packet + bool dup; + uint16_t packet_id; + lwmqtt_string_t topic; + lwmqtt_message_t msg; + err = lwmqtt_decode_publish(client->read_buf, client->read_buf_size, &dup, &packet_id, &topic, &msg); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // call callback if set + if (client->callback != NULL) { + client->callback(client, client->callback_ref, topic, msg); + } + + // break early on qos zero + if (msg.qos == LWMQTT_QOS0) { + break; + } + + // define ack packet + lwmqtt_packet_type_t ack_type = LWMQTT_NO_PACKET; + if (msg.qos == LWMQTT_QOS1) { + ack_type = LWMQTT_PUBACK_PACKET; + } else if (msg.qos == LWMQTT_QOS2) { + ack_type = LWMQTT_PUBREC_PACKET; + } + + // encode ack packet + size_t len; + err = lwmqtt_encode_ack(client->write_buf, client->write_buf_size, &len, ack_type, false, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // send ack packet + err = lwmqtt_send_packet_in_buffer(client, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + break; + } + + // handle pubrec packets + case LWMQTT_PUBREC_PACKET: { + // decode pubrec packet + bool dup; + uint16_t packet_id; + err = lwmqtt_decode_ack(client->read_buf, client->read_buf_size, LWMQTT_PUBREC_PACKET, &dup, &packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // encode pubrel packet + size_t len; + err = lwmqtt_encode_ack(client->write_buf, client->write_buf_size, &len, LWMQTT_PUBREL_PACKET, 0, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // send pubrel packet + err = lwmqtt_send_packet_in_buffer(client, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + break; + } + + // handle pubrel packets + case LWMQTT_PUBREL_PACKET: { + // decode pubrec packet + bool dup; + uint16_t packet_id; + err = lwmqtt_decode_ack(client->read_buf, client->read_buf_size, LWMQTT_PUBREL_PACKET, &dup, &packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // encode pubcomp packet + size_t len; + err = lwmqtt_encode_ack(client->write_buf, client->write_buf_size, &len, LWMQTT_PUBCOMP_PACKET, 0, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // send pubcomp packet + err = lwmqtt_send_packet_in_buffer(client, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + break; + } + + // handle pingresp packets + case LWMQTT_PINGRESP_PACKET: { + // set flag + client->pong_pending = false; + + break; + } + + // handle all other packets + default: { break; } + } + + return LWMQTT_SUCCESS; +} + +static lwmqtt_err_t lwmqtt_cycle_until(lwmqtt_client_t *client, lwmqtt_packet_type_t *packet_type, size_t available, + lwmqtt_packet_type_t needle) { + // prepare counter + size_t read = 0; + + // loop until timeout has been reached + do { + // do one cycle + lwmqtt_err_t err = lwmqtt_cycle(client, &read, packet_type); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // return when one packet has been successfully read when no availability has been given + if (needle == LWMQTT_NO_PACKET && available == 0) { + return LWMQTT_SUCCESS; + } + + // otherwise check if needle has been found + if (*packet_type == needle) { + return LWMQTT_SUCCESS; + } + } while (client->timer_get(client->command_timer) > 0 && (available == 0 || read < available)); + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_yield(lwmqtt_client_t *client, size_t available, uint32_t timeout) { + // set command timer + client->timer_set(client->command_timer, timeout); + + // cycle until timeout has been reached + lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET; + lwmqtt_err_t err = lwmqtt_cycle_until(client, &packet_type, available, LWMQTT_NO_PACKET); + if (err != LWMQTT_SUCCESS) { + return err; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_connect(lwmqtt_client_t *client, lwmqtt_options_t options, lwmqtt_will_t *will, + lwmqtt_return_code_t *return_code, uint32_t timeout) { + // set command timer + client->timer_set(client->command_timer, timeout); + + // save keep alive interval (take 75% to be a little earlier than actually needed) + client->keep_alive_interval = (uint32_t)(options.keep_alive * 750); + + // set keep alive timer + client->timer_set(client->keep_alive_timer, client->keep_alive_interval); + + // reset pong pending flag + client->pong_pending = false; + + // initialize return code + *return_code = LWMQTT_UNKNOWN_RETURN_CODE; + + // encode connect packet + size_t len; + lwmqtt_err_t err = lwmqtt_encode_connect(client->write_buf, client->write_buf_size, &len, options, will); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // send packet + err = lwmqtt_send_packet_in_buffer(client, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // wait for connack packet + lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET; + err = lwmqtt_cycle_until(client, &packet_type, 0, LWMQTT_CONNACK_PACKET); + if (err != LWMQTT_SUCCESS) { + return err; + } else if (packet_type != LWMQTT_CONNACK_PACKET) { + return LWMQTT_MISSING_OR_WRONG_PACKET; + } + + // decode connack packet + bool session_present; + err = lwmqtt_decode_connack(client->read_buf, client->read_buf_size, &session_present, return_code); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // return error if connection was not accepted + if (*return_code != LWMQTT_CONNECTION_ACCEPTED) { + return LWMQTT_CONNECTION_DENIED; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_subscribe(lwmqtt_client_t *client, int count, lwmqtt_string_t *topic_filter, lwmqtt_qos_t *qos, + uint32_t timeout) { + // set command timer + client->timer_set(client->command_timer, timeout); + + // encode subscribe packet + size_t len; + lwmqtt_err_t err = lwmqtt_encode_subscribe(client->write_buf, client->write_buf_size, &len, + lwmqtt_get_next_packet_id(client), count, topic_filter, qos); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // send packet + err = lwmqtt_send_packet_in_buffer(client, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // wait for suback packet + lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET; + err = lwmqtt_cycle_until(client, &packet_type, 0, LWMQTT_SUBACK_PACKET); + if (err != LWMQTT_SUCCESS) { + return err; + } else if (packet_type != LWMQTT_SUBACK_PACKET) { + return LWMQTT_MISSING_OR_WRONG_PACKET; + } + + // decode packet + int suback_count = 0; + lwmqtt_qos_t granted_qos[count]; + uint16_t packet_id; + err = lwmqtt_decode_suback(client->read_buf, client->read_buf_size, &packet_id, count, &suback_count, granted_qos); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // check suback codes + for (int i = 0; i < suback_count; i++) { + if (granted_qos[i] == LWMQTT_QOS_FAILURE) { + return LWMQTT_FAILED_SUBSCRIPTION; + } + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_subscribe_one(lwmqtt_client_t *client, lwmqtt_string_t topic_filter, lwmqtt_qos_t qos, + uint32_t timeout) { + return lwmqtt_subscribe(client, 1, &topic_filter, &qos, timeout); +} + +lwmqtt_err_t lwmqtt_unsubscribe(lwmqtt_client_t *client, int count, lwmqtt_string_t *topic_filter, uint32_t timeout) { + // set command timer + client->timer_set(client->command_timer, timeout); + + // encode unsubscribe packet + size_t len; + lwmqtt_err_t err = lwmqtt_encode_unsubscribe(client->write_buf, client->write_buf_size, &len, + lwmqtt_get_next_packet_id(client), count, topic_filter); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // send unsubscribe packet + err = lwmqtt_send_packet_in_buffer(client, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // wait for unsuback packet + lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET; + err = lwmqtt_cycle_until(client, &packet_type, 0, LWMQTT_UNSUBACK_PACKET); + if (err != LWMQTT_SUCCESS) { + return err; + } else if (packet_type != LWMQTT_UNSUBACK_PACKET) { + return LWMQTT_MISSING_OR_WRONG_PACKET; + } + + // decode unsuback packet + bool dup; + uint16_t packet_id; + err = lwmqtt_decode_ack(client->read_buf, client->read_buf_size, LWMQTT_UNSUBACK_PACKET, &dup, &packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_unsubscribe_one(lwmqtt_client_t *client, lwmqtt_string_t topic_filter, uint32_t timeout) { + return lwmqtt_unsubscribe(client, 1, &topic_filter, timeout); +} + +lwmqtt_err_t lwmqtt_publish(lwmqtt_client_t *client, lwmqtt_string_t topic, lwmqtt_message_t message, + uint32_t timeout) { + // set command timer + client->timer_set(client->command_timer, timeout); + + // add packet id if at least qos 1 + uint16_t packet_id = 0; + if (message.qos == LWMQTT_QOS1 || message.qos == LWMQTT_QOS2) { + packet_id = lwmqtt_get_next_packet_id(client); + } + + // encode publish packet + size_t len = 0; + lwmqtt_err_t err = + lwmqtt_encode_publish(client->write_buf, client->write_buf_size, &len, 0, packet_id, topic, message); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // send packet + err = lwmqtt_send_packet_in_buffer(client, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // immediately return on qos zero + if (message.qos == LWMQTT_QOS0) { + return LWMQTT_SUCCESS; + } + + // define ack packet + lwmqtt_packet_type_t ack_type = LWMQTT_NO_PACKET; + if (message.qos == LWMQTT_QOS1) { + ack_type = LWMQTT_PUBACK_PACKET; + } else if (message.qos == LWMQTT_QOS2) { + ack_type = LWMQTT_PUBCOMP_PACKET; + } + + // wait for ack packet + lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET; + err = lwmqtt_cycle_until(client, &packet_type, 0, ack_type); + if (err != LWMQTT_SUCCESS) { + return err; + } else if (packet_type != ack_type) { + return LWMQTT_MISSING_OR_WRONG_PACKET; + } + + // decode ack packet + bool dup; + err = lwmqtt_decode_ack(client->read_buf, client->read_buf_size, ack_type, &dup, &packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_disconnect(lwmqtt_client_t *client, uint32_t timeout) { + // set command timer + client->timer_set(client->command_timer, timeout); + + // encode disconnect packet + size_t len; + lwmqtt_err_t err = lwmqtt_encode_zero(client->write_buf, client->write_buf_size, &len, LWMQTT_DISCONNECT_PACKET); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // send disconnected packet + err = lwmqtt_send_packet_in_buffer(client, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_keep_alive(lwmqtt_client_t *client, uint32_t timeout) { + // set command timer + client->timer_set(client->command_timer, timeout); + + // return immediately if keep alive interval is zero + if (client->keep_alive_interval == 0) { + return LWMQTT_SUCCESS; + } + + // return immediately if no ping is due + if (client->timer_get(client->keep_alive_timer) > 0) { + return LWMQTT_SUCCESS; + } + + // a ping is due + + // fail immediately if a pong is already pending + if (client->pong_pending) { + return LWMQTT_PONG_TIMEOUT; + } + + // encode pingreq packet + size_t len; + lwmqtt_err_t err = lwmqtt_encode_zero(client->write_buf, client->write_buf_size, &len, LWMQTT_PINGREQ_PACKET); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // send packet + err = lwmqtt_send_packet_in_buffer(client, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // set flag + client->pong_pending = true; + + return LWMQTT_SUCCESS; +} diff --git a/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/helpers.c b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/helpers.c new file mode 100644 index 000000000..9c78f4eaf --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/helpers.c @@ -0,0 +1,249 @@ +#include + +#include "helpers.h" + +uint8_t lwmqtt_read_bits(uint8_t byte, int pos, int num) { return (byte & (uint8_t)((~(0xFF << num)) << pos)) >> pos; } + +void lwmqtt_write_bits(uint8_t *byte, uint8_t value, int pos, int num) { + *byte = (*byte & ~(uint8_t)((~(0xFF << num)) << pos)) | (value << pos); +} + +lwmqtt_err_t lwmqtt_read_data(uint8_t **buf, const uint8_t *buf_end, uint8_t **data, size_t len) { + // check zero length + if (len == 0) { + *data = NULL; + return LWMQTT_SUCCESS; + } + + // check buffer size + if ((size_t)(buf_end - (*buf)) < len) { + return LWMQTT_BUFFER_TOO_SHORT; + } + + // read data + *data = *buf; + + // advance pointer + *buf += len; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_write_data(uint8_t **buf, const uint8_t *buf_end, uint8_t *data, size_t len) { + // check zero length + if (len == 0) { + return LWMQTT_SUCCESS; + } + + // check buffer size + if ((size_t)(buf_end - (*buf)) < len) { + return LWMQTT_BUFFER_TOO_SHORT; + } + + // write data + memcpy(*buf, data, len); + + // advance pointer + *buf += len; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_read_num(uint8_t **buf, const uint8_t *buf_end, uint16_t *num) { + // check buffer size + if ((size_t)(buf_end - (*buf)) < 2) { + *num = 0; + return LWMQTT_BUFFER_TOO_SHORT; + } + + // read two byte integer + *num = (uint16_t)256 * (*buf)[0] + (*buf)[1]; + + // adjust pointer + *buf += 2; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_write_num(uint8_t **buf, const uint8_t *buf_end, uint16_t num) { + // check buffer size + if ((size_t)(buf_end - (*buf)) < 2) { + return LWMQTT_BUFFER_TOO_SHORT; + } + + // write bytes + (*buf)[0] = (uint8_t)(num / 256); + (*buf)[1] = (uint8_t)(num % 256); + + // adjust pointer + *buf += 2; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_read_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t *str) { + // read length + uint16_t len; + lwmqtt_err_t err = lwmqtt_read_num(buf, buf_end, &len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // read data + err = lwmqtt_read_data(buf, buf_end, (uint8_t **)&str->data, len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // set length + str->len = len; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_write_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t str) { + // write string length + lwmqtt_err_t err = lwmqtt_write_num(buf, buf_end, str.len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write data + err = lwmqtt_write_data(buf, buf_end, (uint8_t *)str.data, str.len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_read_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t *byte) { + // check buffer size + if ((size_t)(buf_end - (*buf)) < 1) { + *byte = 0; + return LWMQTT_BUFFER_TOO_SHORT; + } + + // read byte + *byte = (*buf)[0]; + + // adjust pointer + *buf += 1; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_write_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t byte) { + // check buffer size + if ((size_t)(buf_end - (*buf)) < 1) { + return LWMQTT_BUFFER_TOO_SHORT; + } + + // write byte + (*buf)[0] = byte; + + // adjust pointer + *buf += 1; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_varnum_length(uint32_t varnum, int *len) { + if (varnum < 128) { + *len = 1; + return LWMQTT_SUCCESS; + } else if (varnum < 16384) { + *len = 2; + return LWMQTT_SUCCESS; + } else if (varnum < 2097151) { + *len = 3; + return LWMQTT_SUCCESS; + } else if (varnum < 268435455) { + *len = 4; + return LWMQTT_SUCCESS; + } else { + *len = 0; + return LWMQTT_VARNUM_OVERFLOW; + } +} + +lwmqtt_err_t lwmqtt_read_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t *varnum) { + // prepare last byte + uint8_t byte; + + // prepare multiplier + uint32_t multiplier = 1; + + // prepare length + size_t len = 0; + + // initialize number + *varnum = 0; + + // decode variadic number + do { + // increment length + len++; + + // return error if buffer is to small + if ((size_t)(buf_end - (*buf)) < len) { + return LWMQTT_BUFFER_TOO_SHORT; + } + + // return error if the length has overflowed + if (len > 4) { + return LWMQTT_VARNUM_OVERFLOW; + } + + // read byte + byte = (*buf)[len - 1]; + + // add byte to number + *varnum += (byte & 127) * multiplier; + + // increase multiplier + multiplier *= 128; + } while ((byte & 128) != 0); + + // adjust pointer + *buf += len; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_write_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t varnum) { + // init len counter + size_t len = 0; + + // encode variadic number + do { + // check overflow + if (len == 4) { + return LWMQTT_VARNUM_OVERFLOW; + } + + // return error if buffer is to small + if ((size_t)(buf_end - (*buf)) < len + 1) { + return LWMQTT_BUFFER_TOO_SHORT; + } + + // calculate current byte + uint8_t byte = (uint8_t)(varnum % 128); + + // change remaining length + varnum /= 128; + + // set the top bit of this byte if there are more to encode + if (varnum > 0) { + byte |= 0x80; + } + + // write byte + (*buf)[len++] = byte; + } while (varnum > 0); + + // adjust pointer + *buf += len; + + return LWMQTT_SUCCESS; +} diff --git a/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/helpers.h b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/helpers.h new file mode 100644 index 000000000..978eaf4a5 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/helpers.h @@ -0,0 +1,137 @@ +#ifndef LWMQTT_HELPERS_H +#define LWMQTT_HELPERS_H + +#include "lwmqtt.h" + +/** + * Reads bits from a byte. + * + * @param byte - The byte to read from. + * @param pos - The position of the first bit. + * @param num - The number of bits to read. + * @return The read bits as a byte. + */ +uint8_t lwmqtt_read_bits(uint8_t byte, int pos, int num); + +/** + * Write bits to a byte. + * + * @param byte - The byte to write bits to. + * @param value - The bits to write as a byte. + * @param pos - The position of the first bit. + * @param num - The number of bits to write. + */ +void lwmqtt_write_bits(uint8_t *byte, uint8_t value, int pos, int num); + +/** + * Reads arbitrary data from the specified buffer. The pointer is incremented by bytes read. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param data - Pointer to beginning of data. + * @param len - The amount of data to read. + * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT. + */ +lwmqtt_err_t lwmqtt_read_data(uint8_t **buf, const uint8_t *buf_end, uint8_t **data, size_t len); + +/** + * Writes arbitrary data to the specified buffer. The pointer is incremented by the bytes written. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param data - Pointer to the to be written data. + * @param len - The amount of data to write. + * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT. + */ +lwmqtt_err_t lwmqtt_write_data(uint8_t **buf, const uint8_t *buf_end, uint8_t *data, size_t len); + +/** + * Reads two byte number from the specified buffer. The pointer is incremented by two. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param num - The read number. + * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT. + */ +lwmqtt_err_t lwmqtt_read_num(uint8_t **buf, const uint8_t *buf_end, uint16_t *num); + +/** + * Writes a two byte number to the specified buffer. The pointer is incremented by two. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param num - The number to write. + * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT. + */ +lwmqtt_err_t lwmqtt_write_num(uint8_t **buf, const uint8_t *buf_end, uint16_t num); + +/** + * Reads a string from the specified buffer into the passed object. The pointer is incremented by the bytes read. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param str - The object into which the data is to be read. + * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT. + */ +lwmqtt_err_t lwmqtt_read_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t *str); + +/** + * Writes a string to the specified buffer. The pointer is incremented by the bytes written. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param str - The string to write. + * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT. + */ +lwmqtt_err_t lwmqtt_write_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t str); + +/** + * Reads one byte from the buffer. The pointer is incremented by one. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param byte - The read byte. + * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT. + */ +lwmqtt_err_t lwmqtt_read_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t *byte); + +/** + * Writes one byte to the specified buffer. The pointer is incremented by one. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param byte - The byte to write. + * @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT. + */ +lwmqtt_err_t lwmqtt_write_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t byte); + +/** + * Returns the amount of bytes required by the variable number. + * + * @param varnum - The number to check. + * @param len - The required length; + * @return LWMQTT_SUCCESS or LWMQTT_VARNUM_OVERFLOW. + */ +lwmqtt_err_t lwmqtt_varnum_length(uint32_t varnum, int *len); + +/** + * Reads a variable number from the specified buffer. The pointer is incremented by the bytes read. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param varnum - The read varnum. + * @return LWMQTT_SUCCESS, LWMQTT_BUFFER_TOO_SHORT or LWMQTT_VARNUM_OVERFLOW. + */ +lwmqtt_err_t lwmqtt_read_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t *varnum); + +/** + * Writes a variable number to the specified buffer. The pointer is incremented by the bytes written. + * + * @param buf - Pointer to the buffer. + * @param buf_end - Pointer to the end of the buffer. + * @param varnum - The number to write. + * @return LWMQTT_SUCCESS, LWMQTT_BUFFER_TOO_SHORT or LWMQTT_VARNUM_OVERFLOW. + */ +lwmqtt_err_t lwmqtt_write_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t varnum); + +#endif diff --git a/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/lwmqtt.h b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/lwmqtt.h new file mode 100644 index 000000000..7a7f142cc --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/lwmqtt.h @@ -0,0 +1,381 @@ +#ifndef LWMQTT_H +#define LWMQTT_H + +#include +#include +#include + +/** + * The error type used by all exposed APIs. + * + * If a function returns an error that operates on a connected client (e.g publish, keep_alive, etc.) the caller should + * switch into a disconnected state, close and cleanup the current connection and start over by creating a new + * connection. + */ +typedef enum { + LWMQTT_SUCCESS = 0, + LWMQTT_BUFFER_TOO_SHORT = -1, + LWMQTT_VARNUM_OVERFLOW = -2, + LWMQTT_NETWORK_FAILED_CONNECT = -3, + LWMQTT_NETWORK_TIMEOUT = -4, + LWMQTT_NETWORK_FAILED_READ = -5, + LWMQTT_NETWORK_FAILED_WRITE = -6, + LWMQTT_REMAINING_LENGTH_OVERFLOW = -7, + LWMQTT_REMAINING_LENGTH_MISMATCH = -8, + LWMQTT_MISSING_OR_WRONG_PACKET = -9, + LWMQTT_CONNECTION_DENIED = -10, + LWMQTT_FAILED_SUBSCRIPTION = -11, + LWMQTT_SUBACK_ARRAY_OVERFLOW = -12, + LWMQTT_PONG_TIMEOUT = -13, +} lwmqtt_err_t; + +/** + * A common string object. + */ +typedef struct { + uint16_t len; + char *data; +} lwmqtt_string_t; + +/** + * The initializer for string objects. + */ +#define lwmqtt_default_string \ + { 0, NULL } + +/** + * Returns a string object for the passed C string. + * + * @param str - The C string. + * @return A string object. + */ +lwmqtt_string_t lwmqtt_string(const char *str); + +/** + * Compares a string object to a C string. + * + * @param a - The string object to compare. + * @param b - The C string to compare. + * @return Similarity e.g. strcmp(). + */ +int lwmqtt_strcmp(lwmqtt_string_t a, const char *b); + +/** + * The available QOS levels. + */ +typedef enum { LWMQTT_QOS0 = 0, LWMQTT_QOS1 = 1, LWMQTT_QOS2 = 2, LWMQTT_QOS_FAILURE = 128 } lwmqtt_qos_t; + +/** + * The message object used to publish and receive messages. + */ +typedef struct { + lwmqtt_qos_t qos; + bool retained; + uint8_t *payload; + size_t payload_len; +} lwmqtt_message_t; + +/** + * The initializer for message objects. + */ +#define lwmqtt_default_message \ + { LWMQTT_QOS0, false, NULL, 0 } + +/** + * Forward declaration of the client object. + */ +typedef struct lwmqtt_client_t lwmqtt_client_t; + +/** + * The callback used to read from a network object. + * + * The callbacks is expected to read up to the amount of bytes in to the passed buffer. It should block the specified + * timeout and wait for more incoming data. + * + * @param ref - A custom reference. + * @param buf - The buffer. + * @param len - The length of the buffer. + * @param read - Variable that must be set with the amount of read bytes. + * @param timeout - The timeout in milliseconds for the operation. + */ +typedef lwmqtt_err_t (*lwmqtt_network_read_t)(void *ref, uint8_t *buf, size_t len, size_t *read, uint32_t timeout); + +/** + * The callback used to write to a network object. + * + * The callback is expected to write up to the amount of bytes from the passed buffer. It should wait up to the + * specified timeout to write the specified data to the network. + * + * @param ref - A custom reference. + * @param buf - The buffer. + * @param len - The length of the buffer. + * @param sent - Variable that must be set with the amount of written bytes. + * @param timeout - The timeout in milliseconds for the operation. + */ +typedef lwmqtt_err_t (*lwmqtt_network_write_t)(void *ref, uint8_t *buf, size_t len, size_t *sent, uint32_t timeout); + +/** + * The callback used to set a timer. + * + * @param ref - A custom reference. + * @param timeout - The amount of milliseconds until the deadline. + */ +typedef void (*lwmqtt_timer_set_t)(void *ref, uint32_t timeout); + +/** + * The callback used to get a timers value. + * + * @param - A custom reference. + * @return The amount of milliseconds until the deadline. May return negative numbers if the deadline has been reached. + */ +typedef int32_t (*lwmqtt_timer_get_t)(void *ref); + +/** + * The callback used to forward incoming messages. + * + * Note: The callback is mostly executed because of a call to lwmqtt_yield() that processes incoming messages. However, + * it is possible that the callback is also executed during a call to lwmqtt_subscribe(), lwmqtt_publish() or + * lwmqtt_unsubscribe() if incoming messages are received between the required acknowledgements. It is therefore not + * recommended to call any further lwmqtt methods in the callback as this might result in weird call stacks. The + * callback should place the received messages in a queue and dispatch them after the caller has returned. + */ +typedef void (*lwmqtt_callback_t)(lwmqtt_client_t *client, void *ref, lwmqtt_string_t str, lwmqtt_message_t msg); + +/** + * The client object. + */ +struct lwmqtt_client_t { + uint16_t last_packet_id; + uint32_t keep_alive_interval; + bool pong_pending; + + size_t write_buf_size, read_buf_size; + uint8_t *write_buf, *read_buf; + + lwmqtt_callback_t callback; + void *callback_ref; + + void *network; + lwmqtt_network_read_t network_read; + lwmqtt_network_write_t network_write; + + void *keep_alive_timer; + void *command_timer; + lwmqtt_timer_set_t timer_set; + lwmqtt_timer_get_t timer_get; +}; + +/** + * Will initialize the specified client object. + * + * @param client - The client object. + * @param write_buf - The write buffer. + * @param write_buf_size - The write buffer size. + * @param read_buf - The read buffer. + * @param read_buf_size - The read buffer size. + */ +void lwmqtt_init(lwmqtt_client_t *client, uint8_t *write_buf, size_t write_buf_size, uint8_t *read_buf, + size_t read_buf_size); + +/** + * Will set the network reference and callbacks for this client object. + * + * @param client - The client object. + * @param ref - The reference to the network object. + * @param read - The read callback. + * @param write - The write callback. + */ +void lwmqtt_set_network(lwmqtt_client_t *client, void *ref, lwmqtt_network_read_t read, lwmqtt_network_write_t write); + +/** + * Will set the timer references and callbacks for this client object. + * + * @param client - The client object. + * @param keep_alive_timer - The reference to the keep alive timer. + * @param command_timer - The reference to the command timer. + * @param set - The set callback. + * @param get - The get callback. + */ +void lwmqtt_set_timers(lwmqtt_client_t *client, void *keep_alive_timer, void *command_timer, lwmqtt_timer_set_t set, + lwmqtt_timer_get_t get); + +/** + * Will set the callback used to receive incoming messages. + * + * @param client - The client object. + * @param ref - A custom reference that will passed to the callback. + * @param cb - The callback to be called. + */ +void lwmqtt_set_callback(lwmqtt_client_t *client, void *ref, lwmqtt_callback_t cb); + +/** + * The object defining the last will of a client. + */ +typedef struct { + lwmqtt_string_t topic; + lwmqtt_qos_t qos; + bool retained; + lwmqtt_string_t payload; +} lwmqtt_will_t; + +/** + * The default initializer for the will object. + */ +#define lwmqtt_default_will \ + { lwmqtt_default_string, LWMQTT_QOS0, false, lwmqtt_default_string } + +/** + * The object containing the connection options for a client. + */ +typedef struct { + lwmqtt_string_t client_id; + uint16_t keep_alive; + bool clean_session; + lwmqtt_string_t username; + lwmqtt_string_t password; +} lwmqtt_options_t; + +/** + * The default initializer for the options object. + */ +#define lwmqtt_default_options \ + { lwmqtt_default_string, 60, true, lwmqtt_default_string, lwmqtt_default_string } + +/** + * The available return codes transported by the connack packet. + */ +typedef enum { + LWMQTT_CONNECTION_ACCEPTED = 0, + LWMQTT_UNACCEPTABLE_PROTOCOL = 1, + LWMQTT_IDENTIFIER_REJECTED = 2, + LWMQTT_SERVER_UNAVAILABLE = 3, + LWMQTT_BAD_USERNAME_OR_PASSWORD = 4, + LWMQTT_NOT_AUTHORIZED = 5, + LWMQTT_UNKNOWN_RETURN_CODE = 6 +} lwmqtt_return_code_t; + +/** + * Will send a connect packet and wait for a connack response and set the return code. + * + * The network object must already be connected to the server. An error is returned if the broker rejects the + * connection. + * + * @param client - The client object. + * @param options - The options object. + * @param will - The will object. + * @param return_code - The variable that will receive the return code. + * @param timeout - The command timeout. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_connect(lwmqtt_client_t *client, lwmqtt_options_t options, lwmqtt_will_t *will, + lwmqtt_return_code_t *return_code, uint32_t timeout); + +/** + * Will send a publish packet and wait for all acks to complete. + * + * Note: The message callback might be called with incoming messages as part of this call. + * + * @param client - The client object. + * @param topic - The topic. + * @param message - The message. + * @param timeout - The command timeout. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_publish(lwmqtt_client_t *client, lwmqtt_string_t topic, lwmqtt_message_t msg, uint32_t timeout); + +/** + * Will send a subscribe packet with multiple topic filters plus QOS levels and wait for the suback to complete. + * + * Note: The message callback might be called with incoming messages as part of this call. + * + * @param client - The client object. + * @param count - The number of topic filters and QOS levels. + * @param topic_filter - The list of topic filters. + * @param qos - The list of QOS levels. + * @param timeout - The command timeout. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_subscribe(lwmqtt_client_t *client, int count, lwmqtt_string_t *topic_filter, lwmqtt_qos_t *qos, + uint32_t timeout); + +/** + * Will send a subscribe packet with a single topic filter plus QOS level and wait for the suback to complete. + * + * Note: The message callback might be called with incoming messages as part of this call. + * + * @param client - The client object. + * @param topic_filter - The topic filter. + * @param qos - The QOS level. + * @param timeout - The command timeout. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_subscribe_one(lwmqtt_client_t *client, lwmqtt_string_t topic_filter, lwmqtt_qos_t qos, + uint32_t timeout); + +/** + * Will send an unsubscribe packet with multiple topic filters and wait for the unsuback to complete. + * + * Note: The message callback might be called with incoming messages as part of this call. + * + * @param client - The client object. + * @param count - The number of topic filters. + * @param topic_filter - The topic filter. + * @param timeout - The command timeout. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_unsubscribe(lwmqtt_client_t *client, int count, lwmqtt_string_t *topic_filter, uint32_t timeout); + +/** + * Will send an unsubscribe packet with a single topic filter and wait for the unsuback to complete. + * + * Note: The message callback might be called with incoming messages as part of this call. + * + * @param client - The client object. + * @param topic_filter - The topic filter. + * @param timeout - The command timeout. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_unsubscribe_one(lwmqtt_client_t *client, lwmqtt_string_t topic_filter, uint32_t timeout); + +/** + * Will send a disconnect packet and finish the client. + * + * @param client - The client object. + * @param timeout - The command timeout. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_disconnect(lwmqtt_client_t *client, uint32_t timeout); + +/** + * Will yield control to the client and receive incoming packets from the network. + * + * Single-threaded applications may peek on the network and assess if data is available to read before calling yield and + * potentially block until the timeout is reached. Multi-threaded applications may select on the socket and block until + * data is available and then yield to the client if data is available. All applications may specify the amount of bytes + * available to read in order to constrain the yield to only receive packets that are already in-flight. + * + * If no availability info is given the yield will return after one packet has been successfully read or the deadline + * has been reached but no single bytes has been received. + * + * Note: The message callback might be called with incoming messages as part of this call. + * + * @param client - The client object. + * @param available - The available bytes to read. + * @param timeout - The command timeout. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_yield(lwmqtt_client_t *client, size_t available, uint32_t timeout); + +/** + * Will yield control to the client to keep the connection alive. + * + * This functions must be called at a rate slightly lower than 25% of the configured keep alive. If keep alive is zero, + * the function must not be called at all. + * + * @param client - The client object. + * @param timeout - The command timeout. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_keep_alive(lwmqtt_client_t *client, uint32_t timeout); + +#endif // LWMQTT_H diff --git a/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.c b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.c new file mode 100644 index 000000000..512b44d94 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.c @@ -0,0 +1,742 @@ +#include "packet.h" + +lwmqtt_err_t lwmqtt_detect_packet_type(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t *packet_type) { + // set default packet type + *packet_type = LWMQTT_NO_PACKET; + + // prepare pointer + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // prepare header + uint8_t header; + + // read header + lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // get packet type + *packet_type = (lwmqtt_packet_type_t)lwmqtt_read_bits(header, 4, 4); + + // check if packet type is correct and can be received + switch (*packet_type) { + case LWMQTT_CONNACK_PACKET: + case LWMQTT_PUBLISH_PACKET: + case LWMQTT_PUBACK_PACKET: + case LWMQTT_PUBREC_PACKET: + case LWMQTT_PUBREL_PACKET: + case LWMQTT_PUBCOMP_PACKET: + case LWMQTT_SUBACK_PACKET: + case LWMQTT_UNSUBACK_PACKET: + case LWMQTT_PINGRESP_PACKET: + return LWMQTT_SUCCESS; + default: + *packet_type = LWMQTT_NO_PACKET; + return LWMQTT_MISSING_OR_WRONG_PACKET; + } +} + +lwmqtt_err_t lwmqtt_detect_remaining_length(uint8_t *buf, size_t buf_len, uint32_t *rem_len) { + // prepare pointer + uint8_t *ptr = buf; + + // attempt to decode remaining length + lwmqtt_err_t err = lwmqtt_read_varnum(&ptr, buf + buf_len, rem_len); + if (err == LWMQTT_VARNUM_OVERFLOW) { + *rem_len = 0; + return LWMQTT_REMAINING_LENGTH_OVERFLOW; + } else if (err != LWMQTT_SUCCESS) { + *rem_len = 0; + return err; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_encode_connect(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_options_t options, + lwmqtt_will_t *will) { + // prepare pointers + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // fixed header is 10 + uint32_t rem_len = 10; + + // add client id to remaining length + rem_len += options.client_id.len + 2; + + // add will if present to remaining length + if (will != NULL) { + rem_len += will->topic.len + 2 + will->payload.len + 2; + } + + // add username if present to remaining length + if (options.username.len > 0) { + rem_len += options.username.len + 2; + + // add password if present to remaining length + if (options.password.len > 0) { + rem_len += options.password.len + 2; + } + } + + // check remaining length length + int rem_len_len; + lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len); + if (err == LWMQTT_VARNUM_OVERFLOW) { + return LWMQTT_REMAINING_LENGTH_OVERFLOW; + } + + // prepare header + uint8_t header = 0; + lwmqtt_write_bits(&header, LWMQTT_CONNECT_PACKET, 4, 4); + + // write header + err = lwmqtt_write_byte(&buf_ptr, buf_end, header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write remaining length + err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write version string + err = lwmqtt_write_string(&buf_ptr, buf_end, lwmqtt_string("MQTT")); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write version number + err = lwmqtt_write_byte(&buf_ptr, buf_end, 4); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // prepare flags + uint8_t flags = 0; + + // set clean session + lwmqtt_write_bits(&flags, (uint8_t)(options.clean_session), 1, 1); + + // set will flags if present + if (will != NULL) { + lwmqtt_write_bits(&flags, 1, 2, 1); + lwmqtt_write_bits(&flags, will->qos, 3, 2); + lwmqtt_write_bits(&flags, (uint8_t)(will->retained), 5, 1); + } + + // set username flag if present + if (options.username.len > 0) { + lwmqtt_write_bits(&flags, 1, 7, 1); + + // set password flag if present + if (options.password.len > 0) { + lwmqtt_write_bits(&flags, 1, 6, 1); + } + } + + // write flags + err = lwmqtt_write_byte(&buf_ptr, buf_end, flags); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write keep alive + err = lwmqtt_write_num(&buf_ptr, buf_end, options.keep_alive); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write client id + err = lwmqtt_write_string(&buf_ptr, buf_end, options.client_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write will if present + if (will != NULL) { + // write topic + err = lwmqtt_write_string(&buf_ptr, buf_end, will->topic); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write payload length + err = lwmqtt_write_num(&buf_ptr, buf_end, (uint16_t)will->payload.len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write payload + err = lwmqtt_write_data(&buf_ptr, buf_end, (uint8_t *)will->payload.data, will->payload.len); + if (err != LWMQTT_SUCCESS) { + return err; + } + } + + // write username if present + if (options.username.len > 0) { + err = lwmqtt_write_string(&buf_ptr, buf_end, options.username); + if (err != LWMQTT_SUCCESS) { + return err; + } + } + + // write password if present + if (options.username.len > 0 && options.password.len > 0) { + err = lwmqtt_write_string(&buf_ptr, buf_end, options.password); + if (err != LWMQTT_SUCCESS) { + return err; + } + } + + // set written length + *len = buf_ptr - buf; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_decode_connack(uint8_t *buf, size_t buf_len, bool *session_present, + lwmqtt_return_code_t *return_code) { + // prepare pointers + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // read header + uint8_t header; + lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // check packet type + if (lwmqtt_read_bits(header, 4, 4) != LWMQTT_CONNACK_PACKET) { + return LWMQTT_MISSING_OR_WRONG_PACKET; + } + + // read remaining length + uint32_t rem_len; + err = lwmqtt_read_varnum(&buf_ptr, buf_end, &rem_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // check remaining length + if (rem_len != 2) { + return LWMQTT_REMAINING_LENGTH_MISMATCH; + } + + // read flags + uint8_t flags; + err = lwmqtt_read_byte(&buf_ptr, buf_end, &flags); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // read return code + uint8_t raw_return_code; + err = lwmqtt_read_byte(&buf_ptr, buf_end, &raw_return_code); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // get session present + *session_present = lwmqtt_read_bits(flags, 7, 1) == 1; + + // get return code + switch (raw_return_code) { + case 0: + *return_code = LWMQTT_CONNECTION_ACCEPTED; + break; + case 1: + *return_code = LWMQTT_UNACCEPTABLE_PROTOCOL; + break; + case 2: + *return_code = LWMQTT_IDENTIFIER_REJECTED; + break; + case 3: + *return_code = LWMQTT_SERVER_UNAVAILABLE; + break; + case 4: + *return_code = LWMQTT_BAD_USERNAME_OR_PASSWORD; + break; + case 5: + *return_code = LWMQTT_NOT_AUTHORIZED; + break; + default: + *return_code = LWMQTT_UNKNOWN_RETURN_CODE; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_encode_zero(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type) { + // prepare pointer + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // write header + uint8_t header = 0; + lwmqtt_write_bits(&header, packet_type, 4, 4); + lwmqtt_err_t err = lwmqtt_write_byte(&buf_ptr, buf_end, header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write remaining length + err = lwmqtt_write_varnum(&buf_ptr, buf_end, 0); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // set length + *len = buf_ptr - buf; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_decode_ack(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t packet_type, bool *dup, + uint16_t *packet_id) { + // prepare pointer + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // read header + uint8_t header = 0; + lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // check packet type + if (lwmqtt_read_bits(header, 4, 4) != packet_type) { + return LWMQTT_MISSING_OR_WRONG_PACKET; + } + + // get dup + *dup = lwmqtt_read_bits(header, 3, 1) == 1; + + // read remaining length + uint32_t rem_len; + err = lwmqtt_read_varnum(&buf_ptr, buf + buf_len, &rem_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // check remaining length + if (rem_len != 2) { + return LWMQTT_REMAINING_LENGTH_MISMATCH; + } + + // read packet id + err = lwmqtt_read_num(&buf_ptr, buf_end, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_encode_ack(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type, bool dup, + uint16_t packet_id) { + // prepare pointer + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // prepare header + uint8_t header = 0; + + // set packet type + lwmqtt_write_bits(&header, packet_type, 4, 4); + + // set dup + lwmqtt_write_bits(&header, (uint8_t)(dup), 3, 1); + + // set qos + lwmqtt_write_bits(&header, (uint8_t)(packet_type == LWMQTT_PUBREL_PACKET ? LWMQTT_QOS1 : LWMQTT_QOS0), 1, 2); + + // write header + lwmqtt_err_t err = lwmqtt_write_byte(&buf_ptr, buf_end, header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write remaining length + err = lwmqtt_write_varnum(&buf_ptr, buf_end, 2); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write packet id + err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // set written length + *len = buf_ptr - buf; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_decode_publish(uint8_t *buf, size_t buf_len, bool *dup, uint16_t *packet_id, lwmqtt_string_t *topic, + lwmqtt_message_t *msg) { + // prepare pointer + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // read header + uint8_t header; + lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // check packet type + if (lwmqtt_read_bits(header, 4, 4) != LWMQTT_PUBLISH_PACKET) { + return LWMQTT_MISSING_OR_WRONG_PACKET; + } + + // get dup + *dup = lwmqtt_read_bits(header, 3, 1) == 1; + + // get retained + msg->retained = lwmqtt_read_bits(header, 0, 1) == 1; + + // get qos + switch (lwmqtt_read_bits(header, 1, 2)) { + case 0: + msg->qos = LWMQTT_QOS0; + break; + case 1: + msg->qos = LWMQTT_QOS1; + break; + case 2: + msg->qos = LWMQTT_QOS2; + break; + default: + msg->qos = LWMQTT_QOS0; + break; + } + + // read remaining length + uint32_t rem_len; + err = lwmqtt_read_varnum(&buf_ptr, buf_end, &rem_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // check remaining length (topic length) + if (rem_len < 2) { + return LWMQTT_REMAINING_LENGTH_MISMATCH; + } + + // check buffer capacity + if ((uint32_t)(buf_end - buf_ptr) < rem_len) { + return LWMQTT_BUFFER_TOO_SHORT; + } + + // reset buf end + buf_end = buf_ptr + rem_len; + + // read topic + err = lwmqtt_read_string(&buf_ptr, buf_end, topic); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // read packet id if qos is at least 1 + if (msg->qos > 0) { + err = lwmqtt_read_num(&buf_ptr, buf_end, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + } else { + *packet_id = 0; + } + + // set payload length + msg->payload_len = buf_end - buf_ptr; + + // read payload + err = lwmqtt_read_data(&buf_ptr, buf_end, &msg->payload, buf_end - buf_ptr); + if (err != LWMQTT_SUCCESS) { + return err; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_encode_publish(uint8_t *buf, size_t buf_len, size_t *len, bool dup, uint16_t packet_id, + lwmqtt_string_t topic, lwmqtt_message_t msg) { + // prepare pointer + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // calculate remaining length + uint32_t rem_len = 2 + topic.len + (uint32_t)msg.payload_len; + if (msg.qos > 0) { + rem_len += 2; + } + + // check remaining length length + int rem_len_len; + lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len); + if (err == LWMQTT_VARNUM_OVERFLOW) { + return LWMQTT_REMAINING_LENGTH_OVERFLOW; + } + + // prepare header + uint8_t header = 0; + + // set packet type + lwmqtt_write_bits(&header, LWMQTT_PUBLISH_PACKET, 4, 4); + + // set dup + lwmqtt_write_bits(&header, (uint8_t)(dup), 3, 1); + + // set qos + lwmqtt_write_bits(&header, msg.qos, 1, 2); + + // set retained + lwmqtt_write_bits(&header, (uint8_t)(msg.retained), 0, 1); + + // write header + err = lwmqtt_write_byte(&buf_ptr, buf_end, header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write remaining length + err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write topic + err = lwmqtt_write_string(&buf_ptr, buf_end, topic); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write packet id if qos is at least 1 + if (msg.qos > 0) { + err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + } + + // write payload + err = lwmqtt_write_data(&buf_ptr, buf_end, msg.payload, msg.payload_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // set length + *len = buf_ptr - buf; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_encode_subscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count, + lwmqtt_string_t *topic_filters, lwmqtt_qos_t *qos_levels) { + // prepare pointer + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // calculate remaining length + uint32_t rem_len = 2; + for (int i = 0; i < count; i++) { + rem_len += 2 + topic_filters[i].len + 1; + } + + // check remaining length length + int rem_len_len; + lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len); + if (err == LWMQTT_VARNUM_OVERFLOW) { + return LWMQTT_REMAINING_LENGTH_OVERFLOW; + } + + // prepare header + uint8_t header = 0; + + // set packet type + lwmqtt_write_bits(&header, LWMQTT_SUBSCRIBE_PACKET, 4, 4); + + // set qos + lwmqtt_write_bits(&header, LWMQTT_QOS1, 1, 2); + + // write header + err = lwmqtt_write_byte(&buf_ptr, buf_end, header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write remaining length + err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write packet id + err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write all subscriptions + for (int i = 0; i < count; i++) { + // write topic + err = lwmqtt_write_string(&buf_ptr, buf_end, topic_filters[i]); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write qos level + err = lwmqtt_write_byte(&buf_ptr, buf_end, (uint8_t)qos_levels[i]); + if (err != LWMQTT_SUCCESS) { + return err; + } + } + + // set length + *len = buf_ptr - buf; + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_decode_suback(uint8_t *buf, size_t buf_len, uint16_t *packet_id, int max_count, int *count, + lwmqtt_qos_t *granted_qos_levels) { + // prepare pointer + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // read header + uint8_t header; + lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // check packet type + if (lwmqtt_read_bits(header, 4, 4) != LWMQTT_SUBACK_PACKET) { + return LWMQTT_MISSING_OR_WRONG_PACKET; + } + + // read remaining length + uint32_t rem_len; + err = lwmqtt_read_varnum(&buf_ptr, buf_end, &rem_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // check remaining length (packet id + min. one suback code) + if (rem_len < 3) { + return LWMQTT_REMAINING_LENGTH_MISMATCH; + } + + // read packet id + err = lwmqtt_read_num(&buf_ptr, buf_end, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // read all suback codes + for (*count = 0; *count < (int)rem_len - 2; (*count)++) { + // check max count + if (*count > max_count) { + return LWMQTT_SUBACK_ARRAY_OVERFLOW; + } + + // read qos level + uint8_t raw_qos_level; + err = lwmqtt_read_byte(&buf_ptr, buf_end, &raw_qos_level); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // set qos level + switch (raw_qos_level) { + case 0: + granted_qos_levels[*count] = LWMQTT_QOS0; + break; + case 1: + granted_qos_levels[*count] = LWMQTT_QOS1; + break; + case 2: + granted_qos_levels[*count] = LWMQTT_QOS2; + break; + default: + granted_qos_levels[*count] = LWMQTT_QOS_FAILURE; + break; + } + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_encode_unsubscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count, + lwmqtt_string_t *topic_filters) { + // prepare pointer + uint8_t *buf_ptr = buf; + uint8_t *buf_end = buf + buf_len; + + // calculate remaining length + uint32_t rem_len = 2; + for (int i = 0; i < count; i++) { + rem_len += 2 + topic_filters[i].len; + } + + // check remaining length length + int rem_len_len; + lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len); + if (err == LWMQTT_VARNUM_OVERFLOW) { + return LWMQTT_REMAINING_LENGTH_OVERFLOW; + } + + // prepare header + uint8_t header = 0; + + // set packet type + lwmqtt_write_bits(&header, LWMQTT_UNSUBSCRIBE_PACKET, 4, 4); + + // set qos + lwmqtt_write_bits(&header, LWMQTT_QOS1, 1, 2); + + // write header + err = lwmqtt_write_byte(&buf_ptr, buf_end, header); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write remaining length + err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write packet id + err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id); + if (err != LWMQTT_SUCCESS) { + return err; + } + + // write topics + for (int i = 0; i < count; i++) { + err = lwmqtt_write_string(&buf_ptr, buf_end, topic_filters[i]); + if (err != LWMQTT_SUCCESS) { + return err; + } + } + + // set length + *len = buf_ptr - buf; + + return LWMQTT_SUCCESS; +} diff --git a/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.h b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.h new file mode 100644 index 000000000..5fe9e50f1 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/packet.h @@ -0,0 +1,185 @@ +#ifndef LWMQTT_PACKET_H +#define LWMQTT_PACKET_H + +#include "helpers.h" + +/** + * The available packet types. + */ +typedef enum { + LWMQTT_NO_PACKET = 0, + LWMQTT_CONNECT_PACKET = 1, + LWMQTT_CONNACK_PACKET, + LWMQTT_PUBLISH_PACKET, + LWMQTT_PUBACK_PACKET, + LWMQTT_PUBREC_PACKET, + LWMQTT_PUBREL_PACKET, + LWMQTT_PUBCOMP_PACKET, + LWMQTT_SUBSCRIBE_PACKET, + LWMQTT_SUBACK_PACKET, + LWMQTT_UNSUBSCRIBE_PACKET, + LWMQTT_UNSUBACK_PACKET, + LWMQTT_PINGREQ_PACKET, + LWMQTT_PINGRESP_PACKET, + LWMQTT_DISCONNECT_PACKET +} lwmqtt_packet_type_t; + +/** + * Will detect the packet type from the at least one byte long buffer. + * + * @param buf - The buffer from which the packet type will be detected. + * @param buf_len - The length of the specified buffer. + * @param packet_type - The packet type. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_detect_packet_type(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t *packet_type); + +/** + * Will detect the remaining length form the at least on byte long buffer. + * + * It will return LWMQTT_BUFFER_TOO_SHORT if the buffer is to short and an additional byte should be read from the + * network. In case the remaining length is overflowed it will return LWMQTT_REMAINING_LENGTH_OVERFLOW. + * + * @param buf - The buffer from which the remaining length will be detected. + * @param buf_len - The length of the specified buffer. + * @param rem_len - The detected remaining length. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_detect_remaining_length(uint8_t *buf, size_t buf_len, uint32_t *rem_len); + +/** + * Encodes a connect packet into the supplied buffer. + * + * @param buf - The buffer into which the packet will be encoded. + * @param buf_len - The length of the specified buffer. + * @param len - The encoded length of the packet. + * @param options - The options to be used to build the connect packet. + * @param will - The last will and testament. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_encode_connect(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_options_t options, + lwmqtt_will_t *will); + +/** + * Decodes a connack packet from the supplied buffer. + * + * @param buf - The raw buffer data. + * @param buf_len - The length of the specified buffer. + * @param session_present - The session present flag. + * @param return_code - The return code. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_decode_connack(uint8_t *buf, size_t buf_len, bool *session_present, + lwmqtt_return_code_t *return_code); + +/** + * Encodes a zero (disconnect, pingreq) packet into the supplied buffer. + * + * @param buf - The buffer into which the packet will be encoded. + * @param buf_len - The length of the specified buffer. + * @param len - The encoded length of the packet. + * @param packet_type - The packets type. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_encode_zero(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type); + +/** + * Decodes an ack (puback, pubrec, pubrel, pubcomp, unsuback) packet from the supplied buffer. + * + * @param buf - The raw buffer data. + * @param buf_len - The length of the specified buffer. + * @param packet_type - The packet type. + * @param dup - The dup flag. + * @param packet_id - The packet id. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_decode_ack(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t packet_type, bool *dup, + uint16_t *packet_id); + +/** + * Encodes an ack (puback, pubrec, pubrel, pubcomp) packet into the supplied buffer. + * + * @param buf - The buffer into which the packet will be encoded. + * @param buf_len - The length of the specified buffer. + * @param len - The encoded length of the packet. + * @param packet_type - The packets type. + * @param dup - The dup flag. + * @param packet_id - The packet id. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_encode_ack(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type, bool dup, + uint16_t packet_id); + +/** + * Decodes a publish packet from the supplied buffer. + * + * @param buf - The raw buffer data. + * @param buf_len - The length of the specified buffer. + * @param dup - The dup flag. + * @param packet_id - The packet id. + * @param topic - The topic. + * @parma msg - The message. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_decode_publish(uint8_t *buf, size_t buf_len, bool *dup, uint16_t *packet_id, lwmqtt_string_t *topic, + lwmqtt_message_t *msg); + +/** + * Encodes a publish packet into the supplied buffer. + * + * @param buf - The buffer into which the packet will be encoded. + * @param buf_len - The length of the specified buffer. + * @param len - The encoded length of the packet. + * @param dup - The dup flag. + * @param packet_id - The packet id. + * @param topic - The topic. + * @param msg - The message. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_encode_publish(uint8_t *buf, size_t buf_len, size_t *len, bool dup, uint16_t packet_id, + lwmqtt_string_t topic, lwmqtt_message_t msg); + +/** + * Encodes a subscribe packet into the supplied buffer. + * + * @param buf - The buffer into which the packet will be encoded. + * @param buf_len - The length of the specified buffer. + * @param len - The encoded length of the packet. + * @param packet_id - The packet id. + * @param count - The number of members in the topic_filters and qos_levels array. + * @param topic_filters - The array of topic filter. + * @param qos_levels - The array of requested QoS levels. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_encode_subscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count, + lwmqtt_string_t *topic_filters, lwmqtt_qos_t *qos_levels); + +/** + * Decodes a suback packet from the supplied buffer. + * + * @param buf - The raw buffer data. + * @param buf_len - The length of the specified buffer. + * @param packet_id - The packet id. + * @param max_count - The maximum number of members allowed in the granted_qos_levels array. + * @param count - The number of members in the granted_qos_levels array. + * @param granted_qos_levels - The granted QoS levels. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_decode_suback(uint8_t *buf, size_t buf_len, uint16_t *packet_id, int max_count, int *count, + lwmqtt_qos_t *granted_qos_levels); + +/** + * Encodes the supplied unsubscribe data into the supplied buffer, ready for sending + * + * @param buf - The buffer into which the packet will be encoded. + * @param buf_len - The length of the specified buffer. + * @param len - The encoded length of the packet. + * @param packet_id - The packet id. + * @param count - The number of members in the topic_filters array. + * @param topic_filters - The array of topic filters. + * @return An error value. + */ +lwmqtt_err_t lwmqtt_encode_unsubscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count, + lwmqtt_string_t *topic_filters); + +#endif // LWMQTT_PACKET_H diff --git a/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/string.c b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/string.c new file mode 100644 index 000000000..c27dc94e3 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/lwmqtt/string.c @@ -0,0 +1,38 @@ +#include + +#include "lwmqtt.h" + +lwmqtt_string_t lwmqtt_string(const char *str) { + // check for null + if (str == NULL) { + return (lwmqtt_string_t){0, NULL}; + } + + // get length + uint16_t len = (uint16_t)strlen(str); + + // check zero length + if (len == 0) { + return (lwmqtt_string_t){0, NULL}; + } + + return (lwmqtt_string_t){len, (char *)str}; +} + +int lwmqtt_strcmp(lwmqtt_string_t a, const char *b) { + // get string of b + lwmqtt_string_t b_str = lwmqtt_string(b); + + // return if both are zero length + if (a.len == 0 && b_str.len == 0) { + return 0; + } + + // return if lengths are different + if (a.len != b_str.len) { + return -1; + } + + // compare memory of same length + return strncmp(a.data, b_str.data, a.len); +} diff --git a/lib/arduino-mqtt-2.3.3.02/src/system.cpp b/lib/arduino-mqtt-2.3.3.02/src/system.cpp new file mode 100644 index 000000000..cfd8c4740 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/system.cpp @@ -0,0 +1,48 @@ +#include + +#include "system.h" + +void lwmqtt_arduino_timer_set(void *ref, uint32_t timeout) { + // cast timer reference + auto t = (lwmqtt_arduino_timer_t *)ref; + + // set future end time + t->end = (uint32_t)(millis() + timeout); +} + +int32_t lwmqtt_arduino_timer_get(void *ref) { + // cast timer reference + auto t = (lwmqtt_arduino_timer_t *)ref; + + // get difference to end time + return (int32_t)t->end - (int32_t)millis(); +} + +lwmqtt_err_t lwmqtt_arduino_network_read(void *ref, uint8_t *buffer, size_t len, size_t *read, uint32_t timeout) { + // cast network reference + auto n = (lwmqtt_arduino_network_t *)ref; + + // set timeout + n->client->setTimeout(timeout); + + // read bytes + *read = n->client->readBytes(buffer, len); + if (*read <= 0) { + return LWMQTT_NETWORK_FAILED_READ; + } + + return LWMQTT_SUCCESS; +} + +lwmqtt_err_t lwmqtt_arduino_network_write(void *ref, uint8_t *buffer, size_t len, size_t *sent, uint32_t /*timeout*/) { + // cast network reference + auto n = (lwmqtt_arduino_network_t *)ref; + + // write bytes + *sent = n->client->write(buffer, len); + if (*sent <= 0) { + return LWMQTT_NETWORK_FAILED_WRITE; + }; + + return LWMQTT_SUCCESS; +} diff --git a/lib/arduino-mqtt-2.3.3.02/src/system.h b/lib/arduino-mqtt-2.3.3.02/src/system.h new file mode 100644 index 000000000..e51739fb8 --- /dev/null +++ b/lib/arduino-mqtt-2.3.3.02/src/system.h @@ -0,0 +1,26 @@ +#ifndef LWMQTT_ARDUINO_H +#define LWMQTT_ARDUINO_H + +#include +#include + +extern "C" { +#include "lwmqtt/lwmqtt.h" +}; + +typedef struct { + uint32_t end; +} lwmqtt_arduino_timer_t; + +void lwmqtt_arduino_timer_set(void *ref, uint32_t timeout); + +int32_t lwmqtt_arduino_timer_get(void *ref); + +typedef struct { + Client *client; +} lwmqtt_arduino_network_t; + +lwmqtt_err_t lwmqtt_arduino_network_read(void *ref, uint8_t *buf, size_t len, size_t *read, uint32_t timeout); +lwmqtt_err_t lwmqtt_arduino_network_write(void *ref, uint8_t *buf, size_t len, size_t *sent, uint32_t timeout); + +#endif // LWMQTT_ARDUINO_H diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/.gitignore b/lib/esp-mqtt-arduino-1.0.1.02.1/.gitignore deleted file mode 100644 index 2ee75414c..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/.gitignore +++ /dev/null @@ -1,28 +0,0 @@ -# C++ objects and libs - -*.slo -*.lo -*.o -#*.a -*.la -*.lai -*.so -*.dll -*.dylib - -#Makefile -*-build-* -build-* -*.autosave - -# .log files (usually created by QtTest - thanks to VestniK) -*.log - - -# Editors temporary files -*~ - - -#OSX -.DS_Store -._* diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/README.md b/lib/esp-mqtt-arduino-1.0.1.02.1/README.md deleted file mode 100644 index a7ddbecac..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/README.md +++ /dev/null @@ -1,15 +0,0 @@ -MQTT -==== - -A Wrapper around mqtt for Arduino to be used with esp8266 modules. - -It wraps a slightly modified version of mqtt for esp8266 ported by Tuan PM. -Original code for esp: https://github.com/tuanpmt/esp_mqtt -Original code for contiki: https://github.com/esar/contiki-mqtt - - -==== - -**secure libssl:** - -If you want to use secure communication, please use the `secure`-branch! diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/examples/mqtt_pub/mqtt_pub.ino b/lib/esp-mqtt-arduino-1.0.1.02.1/examples/mqtt_pub/mqtt_pub.ino deleted file mode 100644 index 17b3be8db..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/examples/mqtt_pub/mqtt_pub.ino +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include - -void myDataCb(String& topic, String& data); -void myPublishedCb(); -void myDisconnectedCb(); -void myConnectedCb(); - -#define CLIENT_ID "client1" - -// create MQTT object -MQTT myMqtt(CLIENT_ID, "192.168.0.1", 1883); - -// -const char* ssid = "ssid"; -const char* password = "ssid_password"; - - -// -void setup() { - Serial.begin(115200); - delay(1000); - - Serial.println(); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(ssid); - - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - - Serial.println("Connecting to MQTT server"); - - // setup callbacks - myMqtt.onConnected(myConnectedCb); - myMqtt.onDisconnected(myDisconnectedCb); - myMqtt.onPublished(myPublishedCb); - myMqtt.onData(myDataCb); - - Serial.println("connect mqtt..."); - myMqtt.connect(); - - delay(10); -} - -// -void loop() { - - int value = analogRead(A0); - - String topic("/"); - topic += CLIENT_ID; - topic += "/value"; - - String valueStr(value); - - // publish value to topic - boolean result = myMqtt.publish(topic, valueStr); - - delay(1000); -} - - -/* - * - */ -void myConnectedCb() -{ - Serial.println("connected to MQTT server"); -} - -void myDisconnectedCb() -{ - Serial.println("disconnected. try to reconnect..."); - delay(500); - myMqtt.connect(); -} - -void myPublishedCb() -{ - //Serial.println("published."); -} - -void myDataCb(String& topic, String& data) -{ - - Serial.print(topic); - Serial.print(": "); - Serial.println(data); -} - - - diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/examples/mqtt_sub/mqtt_sub.ino b/lib/esp-mqtt-arduino-1.0.1.02.1/examples/mqtt_sub/mqtt_sub.ino deleted file mode 100644 index 1f7591617..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/examples/mqtt_sub/mqtt_sub.ino +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include - -void myDataCb(String& topic, String& data); -void myPublishedCb(); -void myDisconnectedCb(); -void myConnectedCb(); - -#define CLIENT_ID "client3" -#define TOPIC "/client1/value" - - -// create MQTT -MQTT myMqtt(CLIENT_ID, "192.168.0.1", 1883); - - -const char* ssid = "ssid"; -const char* password = "ssid_password"; - - -// -void setup() { - Serial.begin(115200); - delay(1000); - - Serial.println(); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(ssid); - - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - - - Serial.println("Connecting to MQTT server"); - - // setup callbacks - myMqtt.onConnected(myConnectedCb); - myMqtt.onDisconnected(myDisconnectedCb); - myMqtt.onPublished(myPublishedCb); - myMqtt.onData(myDataCb); - - Serial.println("connect mqtt..."); - myMqtt.connect(); - - Serial.println("subscribe to topic..."); - myMqtt.subscribe(TOPIC); - - delay(10); -} - -// -void loop() { -} - - -/* - * - */ -void myConnectedCb() -{ - Serial.println("connected to MQTT server"); -} - -void myDisconnectedCb() -{ - Serial.println("disconnected. try to reconnect..."); - delay(500); - myMqtt.connect(); -} - -void myPublishedCb() -{ - //Serial.println("published."); -} - -void myDataCb(String& topic, String& data) -{ - - Serial.print(topic); - Serial.print(": "); - Serial.println(data); -} - - - diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/keywords.txt b/lib/esp-mqtt-arduino-1.0.1.02.1/keywords.txt deleted file mode 100644 index 527b5bf0c..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/keywords.txt +++ /dev/null @@ -1,43 +0,0 @@ -####################################### -# Syntax Coloring Map For Test -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -MQTT.h KEYWORD1 - -MQTT KEYWORD1 - - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -setClientId KEYWORD2 -setUserPwd KEYWORD2 - -connect KEYWORD2 -disconnect KEYWORD2 -isConnected KEYWORD2 - -publish KEYWORD2 -subscribe KEYWORD2 - -getState KEYWORD2 - -#general -onConnected KEYWORD2 -onDisconnected KEYWORD2 -onPublished KEYWORD2 -onData KEYWORD2 - -####################################### -# Instances (KEYWORD2) -####################################### - -####################################### -# Constants (LITERAL1) -####################################### - diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/library.properties b/lib/esp-mqtt-arduino-1.0.1.02.1/library.properties deleted file mode 100644 index 110da0ac4..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=ESP MQTT -version=1.0.1 -author=Ingo Randolf -maintainer=Ingo Randolf -sentence=A Wrapper around mqtt for Arduino to be used with esp8266 modules. -paragraph=It wraps a slightly modified version of mqtt for esp8266 ported by Tuan PM. Original code for esp: https://github.com/tuanpmt/esp_mqtt (7ec2ef8e1df0422b77348fe1da7885568e0c9d01) Original code for contiki: https://github.com/esar/contiki-mqtt -category=Communication -url=https://github.com/i-n-g-o/esp-mqtt-arduino -architectures=esp8266 \ No newline at end of file diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.cpp b/lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.cpp deleted file mode 100644 index b330bad4b..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/*//------------------------------------------------------------------------------- - * MQTT.cpp - * - * Implementation file for MQTT Wrapper - * - * Wrapper for Arduino written by Ingo Randolf during - * eTextiles Summercamp 2015. - * - * This library is intended to be used with esp8266 modules. - * - * - * This class wraps a slightly modified version of mqtt - * for esp8266 written by Tuan PM. - * Original code: https://github.com/tuanpmt/esp_mqtt - * - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - //-------------------------------------------------------------------------------*/ -#include "MQTT.h" - -#include "user_interface.h" -#include "osapi.h" -#include "os_type.h" -#include "mqtt/debug.h" - - -//------------------------------------------------------------------------------------ -// mqtt internal callbacks -//------------------------------------------------------------------------------------ -static void mqttConnectedCb(uint32_t *args) -{ - MQTT_Client* client = (MQTT_Client*)args; - - MQTT* _this = (MQTT*)client->user_data; - - if (_this && _this->onMqttConnectedCb) { - _this->onMqttConnectedCb(); - } -} - -static void mqttDisconnectedCb(uint32_t *args) -{ - MQTT_Client* client = (MQTT_Client*)args; - - MQTT* _this = (MQTT*)client->user_data; - - if (_this && _this->onMqttDisconnectedCb) { - _this->onMqttDisconnectedCb(); - } -} - -static void mqttPublishedCb(uint32_t *args) -{ - MQTT_Client* client = (MQTT_Client*)args; - - MQTT* _this = (MQTT*)client->user_data; - - if (_this && _this->onMqttPublishedCb) { - _this->onMqttPublishedCb(); - } -} - -static void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) -{ - MQTT_Client* client = (MQTT_Client*)args; - - MQTT* _this = (MQTT*)client->user_data; - - if (_this) { - - _this->_onMqttDataCb(topic, topic_len, data, data_len); - } -} - -static void mqttTimeoutCb(uint32_t *args) -{ - MQTT_Client* client = (MQTT_Client*)args; - - MQTT* _this = (MQTT*)client->user_data; - -// if (_this && _this->onMqttTimeoutCb) { -// _this->onMqttTimeoutCb(); -// } -} - - -//------------------------------------------------------------------------------------ -// MQTT class implementation -//------------------------------------------------------------------------------------ - -//MQTT::MQTT(const char* client_id, const char* host, uint32_t port) : -MQTT::MQTT(const char* client_id, const char* host, uint32_t port, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) : - onMqttConnectedCb(0) - ,onMqttDisconnectedCb(0) - ,onMqttPublishedCb(0) - ,onMqttDataCb(0) - ,onMqttDataRawCb(0) -{ - // init connections - MQTT_InitConnection(&mqttClient, (uint8_t*)host, port, 0); - - // init client - if ( !MQTT_InitClient(&mqttClient, (uint8_t*)client_id, (uint8_t*)"", (uint8_t*)"", 15, 1) ) { - MQTT_INFO("Failed to initialize properly. Check MQTT version.\r\n"); - } - - // init LWT -// MQTT_InitLWT(&mqttClient, (uint8_t*)"/lwt", (uint8_t*)"offline", 0, 0); - MQTT_InitLWT(&mqttClient, (uint8_t*)willTopic, (uint8_t*)willMessage, willQos, (uint8_t)willRetain); - - // set user data - mqttClient.user_data = (void*)this; - - // setup callbacks - MQTT_OnConnected(&mqttClient, mqttConnectedCb); - MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb); - MQTT_OnPublished(&mqttClient, mqttPublishedCb); - MQTT_OnData(&mqttClient, mqttDataCb); - - MQTT_OnTimeout(&mqttClient, mqttTimeoutCb); -} - - -MQTT::~MQTT() -{ - MQTT_DeleteClient(&mqttClient); -} - - -/* - */ -void MQTT::setClientId(const char* client_id) -{ - MQTT_SetUserId(&mqttClient, client_id); -} - -void MQTT::setUserPwd(const char* user, const char* pwd) -{ - MQTT_SetUserPwd(&mqttClient, user, pwd); -} - - -/* - */ -void MQTT::connect() -{ - MQTT_Connect(&mqttClient); -} - -void MQTT::disconnect() -{ - MQTT_Disconnect(&mqttClient); -} - -bool MQTT::isConnected() -{ - return (mqttClient.connState >= TCP_CONNECTED); -} - -/* - */ -bool MQTT::publish(const char* topic, const char* buf, uint32_t buf_len, int qos, int retain) -{ - return MQTT_Publish(&mqttClient, topic, buf, buf_len, qos, retain); -} - -bool MQTT::publish(String& topic, String& data, int qos, int retain) -{ - return publish(topic.c_str(), data.c_str(), data.length(), qos, retain); -} - -bool MQTT::publish(String& topic, const char* buf, uint32_t buf_len, int qos, int retain) -{ - return publish(topic.c_str(), buf, buf_len, qos, retain); -} - -bool MQTT::publish(const char* topic, String& data, int qos, int retain) -{ - return publish(topic, data.c_str(), data.length(), qos, retain); -} - - -/* - */ -bool MQTT::subscribe(const char* topic, uint8_t qos) -{ - return MQTT_Subscribe(&mqttClient, (char*)topic, qos); -} - -bool MQTT::subscribe(const String& topic, uint8_t qos) -{ - return MQTT_Subscribe(&mqttClient, (char*)topic.c_str(), qos); -} - - - -//------------------------------------------------------------------------------- -// set user callback functions -//------------------------------------------------------------------------------- -void MQTT::onConnected( void (*function)(void) ) -{ - onMqttConnectedCb = function; -} - -void MQTT::onDisconnected( void (*function)(void) ) -{ - onMqttDisconnectedCb = function; -} - -void MQTT::onPublished( void (*function)(void) ) -{ - onMqttPublishedCb = function; -} - -void MQTT::onData( void (*function)(String&, String&) ) -{ - onMqttDataCb = function; -} - -void MQTT::onData( void (*function)(const char*, uint32_t, const char*, uint32_t) ) -{ - onMqttDataRawCb = function; -} - - -// internal callback, calling user CB -void MQTT::_onMqttDataCb(const char* topic, uint32_t topic_len, const char* buf, uint32_t buf_len) -{ - if (onMqttDataRawCb) { - onMqttDataRawCb(topic, topic_len, buf, buf_len); - } - - if (onMqttDataCb) { - - char* topicCpy = (char*)malloc(topic_len+1); - memcpy(topicCpy, topic, topic_len); - topicCpy[topic_len] = 0; - // string it - String topicStr(topicCpy); - - char* bufCpy = (char*)malloc(buf_len+1); - memcpy(bufCpy, buf, buf_len); - bufCpy[buf_len] = 0; - // string it - String bufStr(bufCpy); - - onMqttDataCb(topicStr, bufStr); - - free(topicCpy); - free(bufCpy); - } -} - - - - - - - - - diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.h deleted file mode 100644 index 8838ef482..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/MQTT.h +++ /dev/null @@ -1,93 +0,0 @@ -/*//------------------------------------------------------------------------------- - * MQTT.h - * - * Header file for MQTT Wrapper - * - * Wrapper for Arduino written by Ingo Randolf during - * eTextiles Summercamp 2015. - * - * This library is intended to be used with esp8266 modules. - * - * - * This class wraps a slightly modified version of mqtt - * for esp8266 written by Tuan PM. - * Original code: https://github.com/tuanpmt/esp_mqtt - * - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - //-------------------------------------------------------------------------------*/ -#ifndef MQTT_WRAPPER_H -#define MQTT_WRAPPER_H - -#include - -#include -#include -#include -#include -#include - -extern "C" { - #include - #include "mqtt/mqtt.h" -} - -class MQTT -{ -public: -// MQTT(const char* client_id, const char* host, uint32_t port); - MQTT(const char* client_id, const char* host, uint32_t port, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); - - ~MQTT(); - - void setClientId(const char* client_id); - void setUserPwd(const char* user, const char* pwd); - - void connect(); - void disconnect(); - bool isConnected(); - - bool publish(const char* topic, const char* buf, uint32_t buf_len, int qos = 0, int retain = 0); - bool publish(String& topic, String& data, int qos = 0, int retain = 0); - bool publish(String& topic, const char* buf, uint32_t buf_len, int qos = 0, int retain = 0); - bool publish(const char* topic, String& data, int qos = 0, int retain = 0); - - bool subscribe(const char* topic, uint8_t qos = 0); - bool subscribe(const String& topic, uint8_t qos = 0); - - int getState() { return mqttClient.connState; }; - - // set callbacks - void onConnected( void (*)(void) ); - void onDisconnected( void (*)(void) ); - void onPublished( void (*)(void) ); - void onData( void (*)(String&, String&) ); - void onData( void (*)(const char*, uint32_t, const char*, uint32_t) ); - - // user callbacks - void (*onMqttConnectedCb)(void); - void (*onMqttDisconnectedCb)(void); - void (*onMqttPublishedCb)(void); - void (*onMqttDataCb) (String&, String&); - void (*onMqttDataRawCb) (const char*, uint32_t, const char*, uint32_t); - - // internal callback - void _onMqttDataCb(const char*, uint32_t, const char*, uint32_t); - -private: - MQTT_Client mqttClient; - -}; - - - - -#endif \ No newline at end of file diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/debug.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/debug.h deleted file mode 100644 index f45dd6d8d..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/debug.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * debug.h - * - * Created on: Dec 4, 2014 - * Author: Minh - */ - -#ifndef USER_DEBUG_H_ -#define USER_DEBUG_H_ - - -#if defined(MQTT_DEBUG_ON) -#define MQTT_INFO( format, ... ) os_printf( format, ## __VA_ARGS__ ) -#else -#define MQTT_INFO( format, ... ) -#endif - - -#endif /* USER_DEBUG_H_ */ diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt.c b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt.c deleted file mode 100644 index ed63d713a..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* mqtt.c -* Protocol: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html -* -* Copyright (c) 2014-2015, Tuan PM -* 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. -* * Neither the name of Redis nor the names of its contributors may be used -* to endorse or promote products derived from this software without -* specific prior written permission. -* -* 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 OWNER 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. -*/ - -#include "user_interface.h" -#include "osapi.h" -#include "espconn.h" -#include "os_type.h" -#include "mem.h" -#include "mqtt_msg.h" -#include "debug.h" -#include "user_config.h" -#include "mqtt.h" -#include "queue.h" - -#define MQTT_TASK_PRIO 1 -#define MQTT_TASK_QUEUE_SIZE 1 -#define MQTT_SEND_TIMOUT 5 - -#ifndef MQTT_SSL_SIZE -#define MQTT_SSL_SIZE 5120 -#endif - -#ifndef QUEUE_BUFFER_SIZE -#define QUEUE_BUFFER_SIZE 2048 -#endif - - -os_event_t mqtt_procTaskQueue[MQTT_TASK_QUEUE_SIZE]; - -#ifdef PROTOCOL_NAMEv311 -LOCAL uint8_t zero_len_id[2] = { 0, 0 }; -#endif - -LOCAL void ICACHE_FLASH_ATTR -mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) -{ - struct espconn *pConn = (struct espconn *)arg; - MQTT_Client* client = (MQTT_Client *)pConn->reverse; - - - if (ipaddr == NULL) - { - MQTT_INFO("DNS: Found, but got no ip, try to reconnect\r\n"); - client->connState = TCP_RECONNECT_REQ; - return; - } - - MQTT_INFO("DNS: found ip %d.%d.%d.%d\n", - *((uint8 *) &ipaddr->addr), - *((uint8 *) &ipaddr->addr + 1), - *((uint8 *) &ipaddr->addr + 2), - *((uint8 *) &ipaddr->addr + 3)); - - if (client->ip.addr == 0 && ipaddr->addr != 0) - { - os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); - if (client->security) { -#ifdef MQTT_SSL_ENABLE - espconn_secure_set_size(ESPCONN_CLIENT, MQTT_SSL_SIZE); - espconn_secure_connect(client->pCon); -#else - MQTT_INFO("TCP: Do not support SSL\r\n"); -#endif - } - else { - espconn_connect(client->pCon); - } - - client->connState = TCP_CONNECTING; - MQTT_INFO("TCP: connecting...\r\n"); - } - - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); -} - - - -LOCAL void ICACHE_FLASH_ATTR -deliver_publish(MQTT_Client* client, uint8_t* message, int length) -{ - mqtt_event_data_t event_data; - - event_data.topic_length = length; - event_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length); - event_data.data_length = length; - event_data.data = mqtt_get_publish_data(message, &event_data.data_length); - - if (client->dataCb) - client->dataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length); - -} - -void ICACHE_FLASH_ATTR -mqtt_send_keepalive(MQTT_Client *client) -{ - MQTT_INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port); - client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); - client->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ; - client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); - client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); - - - client->sendTimeout = MQTT_SEND_TIMOUT; - MQTT_INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); - err_t result = ESPCONN_OK; - if (client->security) { -#ifdef MQTT_SSL_ENABLE - result = espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); -#else - MQTT_INFO("TCP: Do not support SSL\r\n"); -#endif - } - else { - result = espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); - } - - client->mqtt_state.outbound_message = NULL; - if (ESPCONN_OK == result) { - client->keepAliveTick = 0; - client->connState = MQTT_DATA; - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); - } - else { - client->connState = TCP_RECONNECT_DISCONNECTING; - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); - } -} - -/** - * @brief Delete tcp client and free all memory - * @param mqttClient: The mqtt client which contain TCP client - * @retval None - */ -void ICACHE_FLASH_ATTR -mqtt_tcpclient_delete(MQTT_Client *mqttClient) -{ - if (mqttClient->pCon != NULL) { - MQTT_INFO("TCP: Free memory\r\n"); - // Force abort connections - espconn_abort(mqttClient->pCon); - // Delete connections - espconn_delete(mqttClient->pCon); - - if (mqttClient->pCon->proto.tcp) { - os_free(mqttClient->pCon->proto.tcp); - mqttClient->pCon->proto.tcp = NULL; - } - os_free(mqttClient->pCon); - mqttClient->pCon = NULL; - } -} - -/** - * @brief Delete MQTT client and free all memory - * @param mqttClient: The mqtt client - * @retval None - */ -void ICACHE_FLASH_ATTR -mqtt_client_delete(MQTT_Client *mqttClient) -{ - if (mqttClient == NULL) - return; - - if (mqttClient->pCon != NULL) { - mqtt_tcpclient_delete(mqttClient); - } - - if (mqttClient->host != NULL) { - os_free(mqttClient->host); - mqttClient->host = NULL; - } - - if (mqttClient->user_data != NULL) { - os_free(mqttClient->user_data); - mqttClient->user_data = NULL; - } - - if (mqttClient->mqtt_state.in_buffer != NULL) { - os_free(mqttClient->mqtt_state.in_buffer); - mqttClient->mqtt_state.in_buffer = NULL; - } - - if (mqttClient->mqtt_state.out_buffer != NULL) { - os_free(mqttClient->mqtt_state.out_buffer); - mqttClient->mqtt_state.out_buffer = NULL; - } - - if (mqttClient->mqtt_state.outbound_message != NULL) { - if (mqttClient->mqtt_state.outbound_message->data != NULL) - { - os_free(mqttClient->mqtt_state.outbound_message->data); - mqttClient->mqtt_state.outbound_message->data = NULL; - } - } - - if (mqttClient->mqtt_state.mqtt_connection.buffer != NULL) { - // Already freed but not NULL - mqttClient->mqtt_state.mqtt_connection.buffer = NULL; - } - - if (mqttClient->connect_info.client_id != NULL) { -#ifdef PROTOCOL_NAMEv311 - /* Don't attempt to free if it's the zero_len array */ - if ( ((uint8_t*)mqttClient->connect_info.client_id) != zero_len_id ) - os_free(mqttClient->connect_info.client_id); -#else - os_free(mqttClient->connect_info.client_id); -#endif - mqttClient->connect_info.client_id = NULL; - } - - if (mqttClient->connect_info.username != NULL) { - os_free(mqttClient->connect_info.username); - mqttClient->connect_info.username = NULL; - } - - if (mqttClient->connect_info.password != NULL) { - os_free(mqttClient->connect_info.password); - mqttClient->connect_info.password = NULL; - } - - if (mqttClient->connect_info.will_topic != NULL) { - os_free(mqttClient->connect_info.will_topic); - mqttClient->connect_info.will_topic = NULL; - } - - if (mqttClient->connect_info.will_message != NULL) { - os_free(mqttClient->connect_info.will_message); - mqttClient->connect_info.will_message = NULL; - } - - if (mqttClient->msgQueue.buf != NULL) { - os_free(mqttClient->msgQueue.buf); - mqttClient->msgQueue.buf = NULL; - } - - // Initialize state - mqttClient->connState = WIFI_INIT; - // Clear callback functions to avoid abnormal callback - mqttClient->connectedCb = NULL; - mqttClient->disconnectedCb = NULL; - mqttClient->publishedCb = NULL; - mqttClient->timeoutCb = NULL; - mqttClient->dataCb = NULL; - - MQTT_INFO("MQTT: client already deleted\r\n"); -} - - -/** - * @brief Client received callback function. - * @param arg: contain the ip link information - * @param pdata: received data - * @param len: the lenght of received data - * @retval None - */ -void ICACHE_FLASH_ATTR -mqtt_tcpclient_recv(void *arg, char *pdata, unsigned short len) -{ - uint8_t msg_type; - uint8_t msg_qos; - uint16_t msg_id; - uint8_t msg_conn_ret; - - struct espconn *pCon = (struct espconn*)arg; - MQTT_Client *client = (MQTT_Client *)pCon->reverse; - -READPACKET: - MQTT_INFO("TCP: data received %d bytes\r\n", len); - // MQTT_INFO("STATE: %d\r\n", client->connState); - if (len < MQTT_BUF_SIZE && len > 0) { - os_memcpy(client->mqtt_state.in_buffer, pdata, len); - - msg_type = mqtt_get_type(client->mqtt_state.in_buffer); - msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer); - msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length); - switch (client->connState) { - case MQTT_CONNECT_SENDING: - if (msg_type == MQTT_MSG_TYPE_CONNACK) { - if (client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT) { - MQTT_INFO("MQTT: Invalid packet\r\n"); - if (client->security) { -#ifdef MQTT_SSL_ENABLE - espconn_secure_disconnect(client->pCon); -#else - MQTT_INFO("TCP: Do not support SSL\r\n"); -#endif - } - else { - espconn_disconnect(client->pCon); - } - } else { - msg_conn_ret = mqtt_get_connect_return_code(client->mqtt_state.in_buffer); - switch (msg_conn_ret) { - case CONNECTION_ACCEPTED: - MQTT_INFO("MQTT: Connected to %s:%d\r\n", client->host, client->port); - client->connState = MQTT_DATA; - if (client->connectedCb) - client->connectedCb((uint32_t*)client); - break; - case CONNECTION_REFUSE_PROTOCOL: - case CONNECTION_REFUSE_SERVER_UNAVAILABLE: - case CONNECTION_REFUSE_BAD_USERNAME: - case CONNECTION_REFUSE_NOT_AUTHORIZED: - MQTT_INFO("MQTT: Connection refuse, reason code: %d\r\n", msg_conn_ret); - default: - if (client->security) { -#ifdef MQTT_SSL_ENABLE - espconn_secure_disconnect(client->pCon); -#else - MQTT_INFO("TCP: Do not support SSL\r\n"); -#endif - } - else { - espconn_disconnect(client->pCon); - } - - } - - } - - } - break; - case MQTT_DATA: - case MQTT_KEEPALIVE_SEND: - client->mqtt_state.message_length_read = len; - client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); - - - switch (msg_type) - { - - case MQTT_MSG_TYPE_SUBACK: - if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) - MQTT_INFO("MQTT: Subscribe successful\r\n"); - break; - case MQTT_MSG_TYPE_UNSUBACK: - if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id) - MQTT_INFO("MQTT: UnSubscribe successful\r\n"); - break; - case MQTT_MSG_TYPE_PUBLISH: - if (msg_qos == 1) - client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id); - else if (msg_qos == 2) - client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id); - if (msg_qos == 1 || msg_qos == 2) { - MQTT_INFO("MQTT: Queue response QoS: %d\r\n", msg_qos); - if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { - MQTT_INFO("MQTT: Queue full\r\n"); - } - } - - deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read); - break; - case MQTT_MSG_TYPE_PUBACK: - if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) { - MQTT_INFO("MQTT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish\r\n"); - } - - break; - case MQTT_MSG_TYPE_PUBREC: - client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id); - if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { - MQTT_INFO("MQTT: Queue full\r\n"); - } - break; - case MQTT_MSG_TYPE_PUBREL: - client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id); - if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { - MQTT_INFO("MQTT: Queue full\r\n"); - } - break; - case MQTT_MSG_TYPE_PUBCOMP: - if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) { - MQTT_INFO("MQTT: receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish\r\n"); - } - break; - case MQTT_MSG_TYPE_PINGREQ: - client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection); - if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { - MQTT_INFO("MQTT: Queue full\r\n"); - } - break; - case MQTT_MSG_TYPE_PINGRESP: - // Ignore - break; - } - // NOTE: this is done down here and not in the switch case above - // because the PSOCK_READBUF_LEN() won't work inside a switch - // statement due to the way protothreads resume. - if (msg_type == MQTT_MSG_TYPE_PUBLISH) - { - len = client->mqtt_state.message_length_read; - - if (client->mqtt_state.message_length < client->mqtt_state.message_length_read) - { - //client->connState = MQTT_PUBLISH_RECV; - //Not Implement yet - len -= client->mqtt_state.message_length; - pdata += client->mqtt_state.message_length; - - MQTT_INFO("Get another published message\r\n"); - goto READPACKET; - } - - } - break; - } - } else { - MQTT_INFO("ERROR: Message too long\r\n"); - } - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); -} - -/** - * @brief Client send over callback function. - * @param arg: contain the ip link information - * @retval None - */ -void ICACHE_FLASH_ATTR -mqtt_tcpclient_sent_cb(void *arg) -{ - struct espconn *pCon = (struct espconn *)arg; - MQTT_Client* client = (MQTT_Client *)pCon->reverse; - MQTT_INFO("TCP: Sent\r\n"); - client->sendTimeout = 0; - client->keepAliveTick = 0; - - if ((client->connState == MQTT_DATA || client->connState == MQTT_KEEPALIVE_SEND) - && client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH) { - if (client->publishedCb) - client->publishedCb((uint32_t*)client); - } - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); -} - -void ICACHE_FLASH_ATTR mqtt_timer(void *arg) -{ - MQTT_Client* client = (MQTT_Client*)arg; - - if (client->connState == MQTT_DATA) { - client->keepAliveTick ++; - if (client->keepAliveTick > (client->mqtt_state.connect_info->keepalive / 2)) { - client->connState = MQTT_KEEPALIVE_SEND; - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); - } - - } else if (client->connState == TCP_RECONNECT_REQ) { - client->reconnectTick ++; - if (client->reconnectTick > MQTT_RECONNECT_TIMEOUT) { - client->reconnectTick = 0; - client->connState = TCP_RECONNECT; - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); - if (client->timeoutCb) - client->timeoutCb((uint32_t*)client); - } - } - if (client->sendTimeout > 0) - client->sendTimeout --; -} - -void ICACHE_FLASH_ATTR -mqtt_tcpclient_discon_cb(void *arg) -{ - - struct espconn *pespconn = (struct espconn *)arg; - MQTT_Client* client = (MQTT_Client *)pespconn->reverse; - MQTT_INFO("TCP: Disconnected callback\r\n"); - if (TCP_DISCONNECTING == client->connState) { - client->connState = TCP_DISCONNECTED; - } - else if (MQTT_DELETING == client->connState) { - client->connState = MQTT_DELETED; - } - else { - client->connState = TCP_RECONNECT_REQ; - } - if (client->disconnectedCb) - client->disconnectedCb((uint32_t*)client); - - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); -} - - - -/** - * @brief Tcp client connect success callback function. - * @param arg: contain the ip link information - * @retval None - */ -void ICACHE_FLASH_ATTR -mqtt_tcpclient_connect_cb(void *arg) -{ - struct espconn *pCon = (struct espconn *)arg; - MQTT_Client* client = (MQTT_Client *)pCon->reverse; - - espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb); - espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);//////// - espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);/////// - MQTT_INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port); - - mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length); - client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info); - client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); - client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); - - - client->sendTimeout = MQTT_SEND_TIMOUT; - MQTT_INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); - if (client->security) { -#ifdef MQTT_SSL_ENABLE - espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); -#else - MQTT_INFO("TCP: Do not support SSL\r\n"); -#endif - } - else { - espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); - } - - client->mqtt_state.outbound_message = NULL; - client->connState = MQTT_CONNECT_SENDING; - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); -} - -/** - * @brief Tcp client connect repeat callback function. - * @param arg: contain the ip link information - * @retval None - */ -void ICACHE_FLASH_ATTR -mqtt_tcpclient_recon_cb(void *arg, sint8 errType) -{ - struct espconn *pCon = (struct espconn *)arg; - MQTT_Client* client = (MQTT_Client *)pCon->reverse; - - MQTT_INFO("TCP: Reconnect to %s:%d\r\n", client->host, client->port); - - client->connState = TCP_RECONNECT_REQ; - - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); - -} - -/** - * @brief MQTT publish function. - * @param client: MQTT_Client reference - * @param topic: string topic will publish to - * @param data: buffer data send point to - * @param data_length: length of data - * @param qos: qos - * @param retain: retain - * @retval TRUE if success queue - */ -BOOL ICACHE_FLASH_ATTR -MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain) -{ - uint8_t dataBuffer[MQTT_BUF_SIZE]; - uint16_t dataLen; - client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection, - topic, data, data_length, - qos, retain, - &client->mqtt_state.pending_msg_id); - if (client->mqtt_state.outbound_message->length == 0) { - MQTT_INFO("MQTT: Queuing publish failed\r\n"); - return FALSE; - } - MQTT_INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size); - while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { - MQTT_INFO("MQTT: Queue full\r\n"); - if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { - MQTT_INFO("MQTT: Serious buffer error\r\n"); - return FALSE; - } - } - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); - return TRUE; -} - -/** - * @brief MQTT subscibe function. - * @param client: MQTT_Client reference - * @param topic: string topic will subscribe - * @param qos: qos - * @retval TRUE if success queue - */ -BOOL ICACHE_FLASH_ATTR -MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos) -{ - uint8_t dataBuffer[MQTT_BUF_SIZE]; - uint16_t dataLen; - - client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection, - topic, qos, - &client->mqtt_state.pending_msg_id); - MQTT_INFO("MQTT: queue subscribe, topic\"%s\", id: %d\r\n", topic, client->mqtt_state.pending_msg_id); - while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { - MQTT_INFO("MQTT: Queue full\r\n"); - if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { - MQTT_INFO("MQTT: Serious buffer error\r\n"); - return FALSE; - } - } - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); - - return TRUE; -} - -/** - * @brief MQTT un-subscibe function. - * @param client: MQTT_Client reference - * @param topic: String topic will un-subscribe - * @retval TRUE if success queue - */ -BOOL ICACHE_FLASH_ATTR -MQTT_UnSubscribe(MQTT_Client *client, char* topic) -{ - uint8_t dataBuffer[MQTT_BUF_SIZE]; - uint16_t dataLen; - client->mqtt_state.outbound_message = mqtt_msg_unsubscribe(&client->mqtt_state.mqtt_connection, - topic, - &client->mqtt_state.pending_msg_id); - MQTT_INFO("MQTT: queue un-subscribe, topic\"%s\", id: %d\r\n", topic, client->mqtt_state.pending_msg_id); - while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { - MQTT_INFO("MQTT: Queue full\r\n"); - if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { - MQTT_INFO("MQTT: Serious buffer error\r\n"); - return FALSE; - } - } - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); - return TRUE; -} - -/** - * @brief MQTT ping function. - * @param client: MQTT_Client reference - * @retval TRUE if success queue - */ -BOOL ICACHE_FLASH_ATTR -MQTT_Ping(MQTT_Client *client) -{ - uint8_t dataBuffer[MQTT_BUF_SIZE]; - uint16_t dataLen; - client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection); - if (client->mqtt_state.outbound_message->length == 0) { - MQTT_INFO("MQTT: Queuing publish failed\r\n"); - return FALSE; - } - MQTT_INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size); - while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) { - MQTT_INFO("MQTT: Queue full\r\n"); - if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) { - MQTT_INFO("MQTT: Serious buffer error\r\n"); - return FALSE; - } - } - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); - return TRUE; -} - -void ICACHE_FLASH_ATTR -MQTT_Task(os_event_t *e) -{ - MQTT_Client* client = (MQTT_Client*)e->par; - uint8_t dataBuffer[MQTT_BUF_SIZE]; - uint16_t dataLen; - if (e->par == 0) - return; - switch (client->connState) { - - case TCP_RECONNECT_REQ: - break; - case TCP_RECONNECT: - mqtt_tcpclient_delete(client); - MQTT_Connect(client); - MQTT_INFO("TCP: Reconnect to: %s:%d\r\n", client->host, client->port); - client->connState = TCP_CONNECTING; - break; - case MQTT_DELETING: - case TCP_DISCONNECTING: - case TCP_RECONNECT_DISCONNECTING: - if (client->security) { -#ifdef MQTT_SSL_ENABLE - espconn_secure_disconnect(client->pCon); -#else - MQTT_INFO("TCP: Do not support SSL\r\n"); -#endif - } - else { - espconn_disconnect(client->pCon); - } - break; - case TCP_DISCONNECTED: - MQTT_INFO("MQTT: Disconnected\r\n"); - mqtt_tcpclient_delete(client); - break; - case MQTT_DELETED: - MQTT_INFO("MQTT: Deleted client\r\n"); - mqtt_client_delete(client); - break; - case MQTT_KEEPALIVE_SEND: - mqtt_send_keepalive(client); - break; - case MQTT_DATA: - if (QUEUE_IsEmpty(&client->msgQueue) || client->sendTimeout != 0) { - break; - } - if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0) { - client->mqtt_state.pending_msg_type = mqtt_get_type(dataBuffer); - client->mqtt_state.pending_msg_id = mqtt_get_id(dataBuffer, dataLen); - - - client->sendTimeout = MQTT_SEND_TIMOUT; - MQTT_INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); - client->keepAliveTick = 0; - if (client->security) { -#ifdef MQTT_SSL_ENABLE - espconn_secure_send(client->pCon, dataBuffer, dataLen); -#else - MQTT_INFO("TCP: Do not support SSL\r\n"); -#endif - } - else { - espconn_send(client->pCon, dataBuffer, dataLen); - } - - client->mqtt_state.outbound_message = NULL; - break; - } - break; - } -} - -/** - * @brief MQTT initialization connection function - * @param client: MQTT_Client reference - * @param host: Domain or IP string - * @param port: Port to connect - * @param security: 1 for ssl, 0 for none - * @retval None - */ -void ICACHE_FLASH_ATTR -MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security) -{ - uint32_t temp; - MQTT_INFO("MQTT:InitConnection\r\n"); - os_memset(mqttClient, 0, sizeof(MQTT_Client)); - temp = os_strlen(host); - mqttClient->host = (uint8_t*)os_zalloc(temp + 1); - os_strcpy(mqttClient->host, host); - mqttClient->host[temp] = 0; - mqttClient->port = port; - mqttClient->security = security; - -} - -/** - * @brief MQTT initialization mqtt client function - * @param client: MQTT_Client reference - * @param clientid: MQTT client id - * @param client_user:MQTT client user - * @param client_pass:MQTT client password - * @param client_pass:MQTT keep alive timer, in second - * @retval None - */ -BOOL ICACHE_FLASH_ATTR -MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession) -{ - uint32_t temp; - MQTT_INFO("MQTT:InitClient\r\n"); - - os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t)); - - if ( !client_id ) - { - /* Should be allowed by broker, but clean session flag must be set. */ - #ifdef PROTOCOL_NAMEv311 - if (cleanSession) - { - mqttClient->connect_info.client_id = zero_len_id; - } else { - MQTT_INFO("cleanSession must be set to use 0 length client_id\r\n"); - return false; - } - /* Not supported. Return. */ - #else - MQTT_INFO("Client ID required for MQTT < 3.1.1!\r\n"); - return false; - #endif - } - - /* If connect_info's client_id is still NULL and we get here, we can * - * assume the passed client_id is non-NULL. */ - if ( !(mqttClient->connect_info.client_id) ) - { - temp = os_strlen(client_id); - mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1); - os_strcpy(mqttClient->connect_info.client_id, client_id); - mqttClient->connect_info.client_id[temp] = 0; - } - - if (client_user) - { - temp = os_strlen(client_user); - mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1); - os_strcpy(mqttClient->connect_info.username, client_user); - mqttClient->connect_info.username[temp] = 0; - } - - if (client_pass) - { - temp = os_strlen(client_pass); - mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1); - os_strcpy(mqttClient->connect_info.password, client_pass); - mqttClient->connect_info.password[temp] = 0; - } - - - mqttClient->connect_info.keepalive = keepAliveTime; - mqttClient->connect_info.clean_session = cleanSession; - - mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); - mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; - mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); - mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; - mqttClient->mqtt_state.connect_info = &mqttClient->connect_info; - - mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length); - - QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE); - - system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE); - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); - return true; -} -void ICACHE_FLASH_ATTR -MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain) -{ - uint32_t temp; - temp = os_strlen(will_topic); - mqttClient->connect_info.will_topic = (uint8_t*)os_zalloc(temp + 1); - os_strcpy(mqttClient->connect_info.will_topic, will_topic); - mqttClient->connect_info.will_topic[temp] = 0; - - temp = os_strlen(will_msg); - mqttClient->connect_info.will_message = (uint8_t*)os_zalloc(temp + 1); - os_strcpy(mqttClient->connect_info.will_message, will_msg); - mqttClient->connect_info.will_message[temp] = 0; - - - mqttClient->connect_info.will_qos = will_qos; - mqttClient->connect_info.will_retain = will_retain; -} -/** - * @brief Begin connect to MQTT broker - * @param client: MQTT_Client reference - * @retval None - */ -void ICACHE_FLASH_ATTR -MQTT_Connect(MQTT_Client *mqttClient) -{ - if (mqttClient->pCon) { - // Clean up the old connection forcefully - using MQTT_Disconnect - // does not actually release the old connection until the - // disconnection callback is invoked. - mqtt_tcpclient_delete(mqttClient); - } - mqttClient->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn)); - mqttClient->pCon->type = ESPCONN_TCP; - mqttClient->pCon->state = ESPCONN_NONE; - mqttClient->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); - mqttClient->pCon->proto.tcp->local_port = espconn_port(); - mqttClient->pCon->proto.tcp->remote_port = mqttClient->port; - mqttClient->pCon->reverse = mqttClient; - espconn_regist_connectcb(mqttClient->pCon, mqtt_tcpclient_connect_cb); - espconn_regist_reconcb(mqttClient->pCon, mqtt_tcpclient_recon_cb); - - mqttClient->keepAliveTick = 0; - mqttClient->reconnectTick = 0; - - - os_timer_disarm(&mqttClient->mqttTimer); - os_timer_setfn(&mqttClient->mqttTimer, (os_timer_func_t *)mqtt_timer, mqttClient); - os_timer_arm(&mqttClient->mqttTimer, 1000, 1); - - if (UTILS_StrToIP(mqttClient->host, &mqttClient->pCon->proto.tcp->remote_ip)) { - MQTT_INFO("TCP: Connect to ip %s:%d\r\n", mqttClient->host, mqttClient->port); - if (mqttClient->security) - { -#ifdef MQTT_SSL_ENABLE - espconn_secure_set_size(ESPCONN_CLIENT, MQTT_SSL_SIZE); - espconn_secure_connect(mqttClient->pCon); -#else - MQTT_INFO("TCP: Do not support SSL\r\n"); -#endif - } - else - { - espconn_connect(mqttClient->pCon); - } - } - else { - MQTT_INFO("TCP: Connect to domain %s:%d\r\n", mqttClient->host, mqttClient->port); - espconn_gethostbyname(mqttClient->pCon, mqttClient->host, &mqttClient->ip, mqtt_dns_found); - } - mqttClient->connState = TCP_CONNECTING; -} - -void ICACHE_FLASH_ATTR -MQTT_Disconnect(MQTT_Client *mqttClient) -{ - mqttClient->connState = TCP_DISCONNECTING; - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); - os_timer_disarm(&mqttClient->mqttTimer); -} - -void ICACHE_FLASH_ATTR -MQTT_DeleteClient(MQTT_Client *mqttClient) -{ - if (NULL == mqttClient) - return; - - mqttClient->connState = MQTT_DELETED; - // if(TCP_DISCONNECTED == mqttClient->connState) { - // mqttClient->connState = MQTT_DELETED; - // } else if(MQTT_DELETED != mqttClient->connState) { - // mqttClient->connState = MQTT_DELETING; - // } - - system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); - os_timer_disarm(&mqttClient->mqttTimer); -} - -void ICACHE_FLASH_ATTR -MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb) -{ - mqttClient->connectedCb = connectedCb; -} - -void ICACHE_FLASH_ATTR -MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb) -{ - mqttClient->disconnectedCb = disconnectedCb; -} - -void ICACHE_FLASH_ATTR -MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb) -{ - mqttClient->dataCb = dataCb; -} - -void ICACHE_FLASH_ATTR -MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb) -{ - mqttClient->publishedCb = publishedCb; -} - -void ICACHE_FLASH_ATTR -MQTT_OnTimeout(MQTT_Client *mqttClient, MqttCallback timeoutCb) -{ - mqttClient->timeoutCb = timeoutCb; -} - - - -void ICACHE_FLASH_ATTR -MQTT_SetUserId(MQTT_Client *mqttClient, const char* client_id) -{ - if (mqttClient->connect_info.client_id != 0) { - os_free(mqttClient->connect_info.client_id); - mqttClient->connect_info.client_id = 0; - } - - - uint32_t len = os_strlen(client_id); - - mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(len + 1); - if (len) { - os_strcpy(mqttClient->connect_info.client_id, client_id); - } - mqttClient->connect_info.client_id[len] = 0; -} - -void ICACHE_FLASH_ATTR -MQTT_SetUserPwd(MQTT_Client *mqttClient, const char* user, const char* pwd) -{ - uint32_t len; - - // free username - if (mqttClient->connect_info.username != 0) { - os_free(mqttClient->connect_info.username); - mqttClient->connect_info.username = 0; - } - // free password - if (mqttClient->connect_info.password != 0) { - os_free(mqttClient->connect_info.password); - mqttClient->connect_info.password = 0; - } - - - // copy username - len = os_strlen(user); - mqttClient->connect_info.username = (uint8_t*)os_zalloc(len + 1); - if (len) { - os_strcpy(mqttClient->connect_info.username, user); - } - mqttClient->connect_info.username[len] = 0; - - - // copy password - len = os_strlen(pwd); - mqttClient->connect_info.password = (uint8_t*)os_zalloc(len + 1); - if (len) { - os_strcpy(mqttClient->connect_info.password, pwd); - } - mqttClient->connect_info.password[len] = 0; - -} - diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt.h deleted file mode 100644 index 6ef619433..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt.h +++ /dev/null @@ -1,152 +0,0 @@ -/* mqtt.h -* -* Copyright (c) 2014-2015, Tuan PM -* 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. -* * Neither the name of Redis nor the names of its contributors may be used -* to endorse or promote products derived from this software without -* specific prior written permission. -* -* 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 OWNER 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. -*/ -#ifndef USER_AT_MQTT_H_ -#define USER_AT_MQTT_H_ -#include "mqtt_config.h" -#include "mqtt_msg.h" -#include "user_interface.h" - -#include "queue.h" -typedef struct mqtt_event_data_t -{ - uint8_t type; - const char* topic; - const char* data; - uint16_t topic_length; - uint16_t data_length; - uint16_t data_offset; -} mqtt_event_data_t; - -typedef struct mqtt_state_t -{ - uint16_t port; - int auto_reconnect; - mqtt_connect_info_t* connect_info; - uint8_t* in_buffer; - uint8_t* out_buffer; - int in_buffer_length; - int out_buffer_length; - uint16_t message_length; - uint16_t message_length_read; - mqtt_message_t* outbound_message; - mqtt_connection_t mqtt_connection; - uint16_t pending_msg_id; - int pending_msg_type; - int pending_publish_qos; -} mqtt_state_t; - -typedef enum { - WIFI_INIT, - WIFI_CONNECTING, - WIFI_CONNECTING_ERROR, - WIFI_CONNECTED, - DNS_RESOLVE, - TCP_DISCONNECTING, - TCP_DISCONNECTED, - TCP_RECONNECT_DISCONNECTING, - TCP_RECONNECT_REQ, - TCP_RECONNECT, - TCP_CONNECTING, - TCP_CONNECTING_ERROR, - TCP_CONNECTED, - MQTT_CONNECT_SEND, - MQTT_CONNECT_SENDING, - MQTT_SUBSCIBE_SEND, - MQTT_SUBSCIBE_SENDING, - MQTT_DATA, - MQTT_KEEPALIVE_SEND, - MQTT_PUBLISH_RECV, - MQTT_PUBLISHING, - MQTT_DELETING, - MQTT_DELETED, -} tConnState; - -typedef void (*MqttCallback)(uint32_t *args); -typedef void (*MqttDataCallback)(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t lengh); - -typedef struct { - struct espconn *pCon; - uint8_t security; - uint8_t* host; - uint32_t port; - ip_addr_t ip; - mqtt_state_t mqtt_state; - mqtt_connect_info_t connect_info; - MqttCallback connectedCb; - MqttCallback disconnectedCb; - MqttCallback publishedCb; - MqttCallback timeoutCb; - MqttDataCallback dataCb; - ETSTimer mqttTimer; - uint32_t keepAliveTick; - uint32_t reconnectTick; - uint32_t sendTimeout; - tConnState connState; - QUEUE msgQueue; - void* user_data; -} MQTT_Client; - -#define SEC_NONSSL 0 -#define SEC_SSL 1 - -#define MQTT_FLAG_CONNECTED 1 -#define MQTT_FLAG_READY 2 -#define MQTT_FLAG_EXIT 4 - -#define MQTT_EVENT_TYPE_NONE 0 -#define MQTT_EVENT_TYPE_CONNECTED 1 -#define MQTT_EVENT_TYPE_DISCONNECTED 2 -#define MQTT_EVENT_TYPE_SUBSCRIBED 3 -#define MQTT_EVENT_TYPE_UNSUBSCRIBED 4 -#define MQTT_EVENT_TYPE_PUBLISH 5 -#define MQTT_EVENT_TYPE_PUBLISHED 6 -#define MQTT_EVENT_TYPE_EXITED 7 -#define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8 - -void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security); -bool ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession); -void ICACHE_FLASH_ATTR MQTT_DeleteClient(MQTT_Client *mqttClient); -void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain); - -void ICACHE_FLASH_ATTR MQTT_SetUserId(MQTT_Client *mqttClient, const char* client_id); -void ICACHE_FLASH_ATTR MQTT_SetUserPwd(MQTT_Client *mqttClient, const char* user_id, const char* pwd); - -void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb); -void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb); -void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb); -void ICACHE_FLASH_ATTR MQTT_OnTimeout(MQTT_Client *mqttClient, MqttCallback timeoutCb); -void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb); -bool ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos); -bool ICACHE_FLASH_ATTR MQTT_UnSubscribe(MQTT_Client *client, char* topic); -void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client *mqttClient); -void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client *mqttClient); -bool ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain); - -#endif /* USER_AT_MQTT_H_ */ diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_config.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_config.h deleted file mode 100644 index 5332f82ee..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_config.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __MQTT_CONFIG_H__ -#define __MQTT_CONFIG_H__ - -//#define MQTT_SSL_ENABLE - -/*DEFAULT CONFIGURATIONS*/ - -#define MQTT_BUF_SIZE 1024 -//#define MQTT_KEEPALIVE 120 /*second*/ -#define MQTT_KEEPALIVE 15 /*second*/ - -#define MQTT_RECONNECT_TIMEOUT 5 /*second*/ - -#define QUEUE_BUFFER_SIZE 2048 - -//#define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/ -#define PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/ - -#endif // __MQTT_CONFIG_H__ \ No newline at end of file diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_msg.c b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_msg.c deleted file mode 100644 index c2b320311..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_msg.c +++ /dev/null @@ -1,487 +0,0 @@ -/* -* Copyright (c) 2014, Stephen Robinson -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. 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. -* 3. Neither the name of the copyright holder nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* 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. -* -*/ - -#include -#include "mqtt_msg.h" -#include "mqtt_config.h" -#define MQTT_MAX_FIXED_HEADER_SIZE 3 - -enum mqtt_connect_flag -{ - MQTT_CONNECT_FLAG_USERNAME = 1 << 7, - MQTT_CONNECT_FLAG_PASSWORD = 1 << 6, - MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5, - MQTT_CONNECT_FLAG_WILL = 1 << 2, - MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1 -}; - -struct __attribute((__packed__)) mqtt_connect_variable_header -{ - uint8_t lengthMsb; - uint8_t lengthLsb; -#if defined(PROTOCOL_NAMEv31) - uint8_t magic[6]; -#elif defined(PROTOCOL_NAMEv311) - uint8_t magic[4]; -#else -#error "Please define protocol name" -#endif - uint8_t version; - uint8_t flags; - uint8_t keepaliveMsb; - uint8_t keepaliveLsb; -}; - -static int ICACHE_FLASH_ATTR append_string(mqtt_connection_t* connection, const char* string, int len) -{ - if (connection->message.length + len + 2 > connection->buffer_length) - return -1; - - connection->buffer[connection->message.length++] = len >> 8; - connection->buffer[connection->message.length++] = len & 0xff; - memcpy(connection->buffer + connection->message.length, string, len); - connection->message.length += len; - - return len + 2; -} - -static uint16_t ICACHE_FLASH_ATTR append_message_id(mqtt_connection_t* connection, uint16_t message_id) -{ - // If message_id is zero then we should assign one, otherwise - // we'll use the one supplied by the caller - while (message_id == 0) - message_id = ++connection->message_id; - - if (connection->message.length + 2 > connection->buffer_length) - return 0; - - connection->buffer[connection->message.length++] = message_id >> 8; - connection->buffer[connection->message.length++] = message_id & 0xff; - - return message_id; -} - -static int ICACHE_FLASH_ATTR init_message(mqtt_connection_t* connection) -{ - connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE; - return MQTT_MAX_FIXED_HEADER_SIZE; -} - -static mqtt_message_t* ICACHE_FLASH_ATTR fail_message(mqtt_connection_t* connection) -{ - connection->message.data = connection->buffer; - connection->message.length = 0; - return &connection->message; -} - -static mqtt_message_t* ICACHE_FLASH_ATTR fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) -{ - int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; - - if (remaining_length > 127) - { - connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); - connection->buffer[1] = 0x80 | (remaining_length % 128); - connection->buffer[2] = remaining_length / 128; - connection->message.length = remaining_length + 3; - connection->message.data = connection->buffer; - } - else - { - connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); - connection->buffer[2] = remaining_length; - connection->message.length = remaining_length + 2; - connection->message.data = connection->buffer + 1; - } - - return &connection->message; -} - -void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length) -{ - memset(connection, 0, sizeof(mqtt_connection_t)); - connection->buffer = buffer; - connection->buffer_length = buffer_length; -} - -int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length) -{ - int i; - int totlen = 0; - - for (i = 1; i < length; ++i) - { - totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) - { - ++i; - break; - } - } - totlen += i; - - return totlen; -} - -const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length) -{ - int i; - int totlen = 0; - int topiclen; - - for (i = 1; i < *length; ++i) - { - totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) - { - ++i; - break; - } - } - totlen += i; - - if (i + 2 >= *length) - return NULL; - topiclen = buffer[i++] << 8; - topiclen |= buffer[i++]; - - if (i + topiclen > *length) - return NULL; - - *length = topiclen; - return (const char*)(buffer + i); -} - -const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length) -{ - int i; - int totlen = 0; - int topiclen; - int blength = *length; - *length = 0; - - for (i = 1; i < blength; ++i) - { - totlen += (buffer[i] & 0x7f) << (7 * (i - 1)); - if ((buffer[i] & 0x80) == 0) - { - ++i; - break; - } - } - totlen += i; - - if (i + 2 >= blength) - return NULL; - topiclen = buffer[i++] << 8; - topiclen |= buffer[i++]; - - if (i + topiclen >= blength) - return NULL; - - i += topiclen; - - if (mqtt_get_qos(buffer) > 0) - { - if (i + 2 >= blength) - return NULL; - i += 2; - } - - if (totlen < i) - return NULL; - - if (totlen <= blength) - *length = totlen - i; - else - *length = blength - i; - return (const char*)(buffer + i); -} - -uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length) -{ - if (length < 1) - return 0; - - switch (mqtt_get_type(buffer)) - { - case MQTT_MSG_TYPE_PUBLISH: - { - int i; - int topiclen; - - for (i = 1; i < length; ++i) - { - if ((buffer[i] & 0x80) == 0) - { - ++i; - break; - } - } - - if (i + 2 >= length) - return 0; - topiclen = buffer[i++] << 8; - topiclen |= buffer[i++]; - - if (i + topiclen >= length) - return 0; - i += topiclen; - - if (mqtt_get_qos(buffer) > 0) - { - if (i + 2 >= length) - return 0; - //i += 2; - } else { - return 0; - } - - return (buffer[i] << 8) | buffer[i + 1]; - } - case MQTT_MSG_TYPE_PUBACK: - case MQTT_MSG_TYPE_PUBREC: - case MQTT_MSG_TYPE_PUBREL: - case MQTT_MSG_TYPE_PUBCOMP: - case MQTT_MSG_TYPE_SUBACK: - case MQTT_MSG_TYPE_UNSUBACK: - case MQTT_MSG_TYPE_SUBSCRIBE: - { - // This requires the remaining length to be encoded in 1 byte, - // which it should be. - if (length >= 4 && (buffer[1] & 0x80) == 0) - return (buffer[2] << 8) | buffer[3]; - else - return 0; - } - - default: - return 0; - } -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) -{ - struct mqtt_connect_variable_header* variable_header; - - init_message(connection); - - if (connection->message.length + sizeof(*variable_header) > connection->buffer_length) - return fail_message(connection); - variable_header = (void*)(connection->buffer + connection->message.length); - connection->message.length += sizeof(*variable_header); - - variable_header->lengthMsb = 0; -#if defined(PROTOCOL_NAMEv31) - variable_header->lengthLsb = 6; - memcpy(variable_header->magic, "MQIsdp", 6); - variable_header->version = 3; -#elif defined(PROTOCOL_NAMEv311) - variable_header->lengthLsb = 4; - memcpy(variable_header->magic, "MQTT", 4); - variable_header->version = 4; -#else -#error "Please define protocol name" -#endif - - variable_header->flags = 0; - variable_header->keepaliveMsb = info->keepalive >> 8; - variable_header->keepaliveLsb = info->keepalive & 0xff; - - if (info->clean_session) - variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION; - - if (info->client_id == NULL) - { - /* Never allowed */ - return fail_message(connection); - } - else if (info->client_id[0] == '\0') - { -#ifdef PROTOCOL_NAMEv311 - /* Allowed. Format 0 Length ID */ - append_string(connection, info->client_id, 2) ; -#else - /* 0 Length not allowed */ - return fail_message(connection); -#endif - } - else - { - /* No 0 data and at least 1 long. Good to go. */ - if(append_string(connection, info->client_id, strlen(info->client_id)) < 0) - return fail_message(connection); - } - - if (info->will_topic != NULL && info->will_topic[0] != '\0') - { - if (append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) - return fail_message(connection); - - if (append_string(connection, info->will_message, strlen(info->will_message)) < 0) - return fail_message(connection); - - variable_header->flags |= MQTT_CONNECT_FLAG_WILL; - if (info->will_retain) - variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN; - variable_header->flags |= (info->will_qos & 3) << 3; - } - - if (info->username != NULL && info->username[0] != '\0') - { - if (append_string(connection, info->username, strlen(info->username)) < 0) - return fail_message(connection); - - variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME; - } - - if (info->password != NULL && info->password[0] != '\0') - { - if (append_string(connection, info->password, strlen(info->password)) < 0) - return fail_message(connection); - - variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD; - } - - return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id) -{ - init_message(connection); - - if (topic == NULL || topic[0] == '\0') - return fail_message(connection); - - if (append_string(connection, topic, strlen(topic)) < 0) - return fail_message(connection); - - if (qos > 0) - { - if ((*message_id = append_message_id(connection, 0)) == 0) - return fail_message(connection); - } - else - *message_id = 0; - - if (connection->message.length + data_length > connection->buffer_length) - return fail_message(connection); - memcpy(connection->buffer + connection->message.length, data, data_length); - connection->message.length += data_length; - - return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) - return fail_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) - return fail_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) - return fail_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) -{ - init_message(connection); - if (append_message_id(connection, message_id) == 0) - return fail_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id) -{ - init_message(connection); - - if (topic == NULL || topic[0] == '\0') - return fail_message(connection); - - if ((*message_id = append_message_id(connection, 0)) == 0) - return fail_message(connection); - - if (append_string(connection, topic, strlen(topic)) < 0) - return fail_message(connection); - - if (connection->message.length + 1 > connection->buffer_length) - return fail_message(connection); - connection->buffer[connection->message.length++] = qos; - - return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id) -{ - init_message(connection); - - if (topic == NULL || topic[0] == '\0') - return fail_message(connection); - - if ((*message_id = append_message_id(connection, 0)) == 0) - return fail_message(connection); - - if (append_string(connection, topic, strlen(topic)) < 0) - return fail_message(connection); - - return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection) -{ - init_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection) -{ - init_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); -} - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection) -{ - init_message(connection); - return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); -} diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_msg.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_msg.h deleted file mode 100644 index be3cc55cb..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/mqtt_msg.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * File: mqtt_msg.h - * Author: Minh Tuan - * - * Created on July 12, 2014, 1:05 PM - */ - -#ifndef MQTT_MSG_H -#define MQTT_MSG_H -#include "user_config.h" -#include "c_types.h" -#ifdef __cplusplus -extern "C" { -#endif - -/* -* Copyright (c) 2014, Stephen Robinson -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. 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. -* 3. Neither the name of the copyright holder nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* 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. -* -*/ -/* 7 6 5 4 3 2 1 0*/ -/*| --- Message Type---- | DUP Flag | QoS Level | Retain | -/* Remaining Length */ - - -enum mqtt_message_type -{ - MQTT_MSG_TYPE_CONNECT = 1, - MQTT_MSG_TYPE_CONNACK = 2, - MQTT_MSG_TYPE_PUBLISH = 3, - MQTT_MSG_TYPE_PUBACK = 4, - MQTT_MSG_TYPE_PUBREC = 5, - MQTT_MSG_TYPE_PUBREL = 6, - MQTT_MSG_TYPE_PUBCOMP = 7, - MQTT_MSG_TYPE_SUBSCRIBE = 8, - MQTT_MSG_TYPE_SUBACK = 9, - MQTT_MSG_TYPE_UNSUBSCRIBE = 10, - MQTT_MSG_TYPE_UNSUBACK = 11, - MQTT_MSG_TYPE_PINGREQ = 12, - MQTT_MSG_TYPE_PINGRESP = 13, - MQTT_MSG_TYPE_DISCONNECT = 14 -}; - -enum mqtt_connect_return_code -{ - CONNECTION_ACCEPTED = 0, - CONNECTION_REFUSE_PROTOCOL, - CONNECTION_REFUSE_ID_REJECTED, - CONNECTION_REFUSE_SERVER_UNAVAILABLE, - CONNECTION_REFUSE_BAD_USERNAME, - CONNECTION_REFUSE_NOT_AUTHORIZED -}; - -typedef struct mqtt_message -{ - uint8_t* data; - uint16_t length; - -} mqtt_message_t; - -typedef struct mqtt_connection -{ - mqtt_message_t message; - - uint16_t message_id; - uint8_t* buffer; - uint16_t buffer_length; - -} mqtt_connection_t; - -typedef struct mqtt_connect_info -{ - char* client_id; - char* username; - char* password; - char* will_topic; - char* will_message; - uint32_t keepalive; - int will_qos; - int will_retain; - int clean_session; - -} mqtt_connect_info_t; - - -static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; } -static inline int ICACHE_FLASH_ATTR mqtt_get_connect_return_code(uint8_t* buffer) { return buffer[3]; } -static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; } -static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; } -static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); } - -void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length); -int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length); -const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length); -const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length); -uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length); - -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection); -mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection); - - -#ifdef __cplusplus -} -#endif - -#endif /* MQTT_MSG_H */ - diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/proto.c b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/proto.c deleted file mode 100644 index 84078b233..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/proto.c +++ /dev/null @@ -1,129 +0,0 @@ -#include "proto.h" -#include "ringbuf.h" -I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize) -{ - parser->buf = buf; - parser->bufSize = bufSize; - parser->dataLen = 0; - parser->callback = completeCallback; - parser->isEsc = 0; - return 0; -} - -I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value) -{ - switch (value) { - case 0x7D: - parser->isEsc = 1; - break; - - case 0x7E: - parser->dataLen = 0; - parser->isEsc = 0; - parser->isBegin = 1; - break; - - case 0x7F: - if (parser->callback != NULL) - parser->callback(); - parser->isBegin = 0; - return 0; - break; - - default: - if (parser->isBegin == 0) break; - - if (parser->isEsc) { - value ^= 0x20; - parser->isEsc = 0; - } - - if (parser->dataLen < parser->bufSize) - parser->buf[parser->dataLen++] = value; - - break; - } - return -1; -} - -I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len) -{ - while (len--) - PROTO_ParseByte(parser, *buf++); - - return 0; -} -I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF* rb, U8 *bufOut, U16* len, U16 maxBufLen) -{ - U8 c; - - PROTO_PARSER proto; - PROTO_Init(&proto, NULL, bufOut, maxBufLen); - while (RINGBUF_Get(rb, &c) == 0) { - if (PROTO_ParseByte(&proto, c) == 0) { - *len = proto.dataLen; - return 0; - } - } - return -1; -} -I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize) -{ - U16 i = 2; - U16 len = *(U16*) packet; - - if (bufSize < 1) return -1; - - *buf++ = 0x7E; - bufSize--; - - while (len--) { - switch (*packet) { - case 0x7D: - case 0x7E: - case 0x7F: - if (bufSize < 2) return -1; - *buf++ = 0x7D; - *buf++ = *packet++ ^ 0x20; - i += 2; - bufSize -= 2; - break; - default: - if (bufSize < 1) return -1; - *buf++ = *packet++; - i++; - bufSize--; - break; - } - } - - if (bufSize < 1) return -1; - *buf++ = 0x7F; - - return i; -} - -I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len) -{ - U16 i = 2; - if (RINGBUF_Put(rb, 0x7E) == -1) return -1; - while (len--) { - switch (*packet) { - case 0x7D: - case 0x7E: - case 0x7F: - if (RINGBUF_Put(rb, 0x7D) == -1) return -1; - if (RINGBUF_Put(rb, *packet++ ^ 0x20) == -1) return -1; - i += 2; - break; - default: - if (RINGBUF_Put(rb, *packet++) == -1) return -1; - i++; - break; - } - } - if (RINGBUF_Put(rb, 0x7F) == -1) return -1; - - return i; -} - diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/proto.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/proto.h deleted file mode 100644 index a405bcb95..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/proto.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * File: proto.h - * Author: ThuHien - * - * Created on November 23, 2012, 8:57 AM - */ - -#ifndef _PROTO_H_ -#define _PROTO_H_ -#include -#include "typedef.h" -#include "ringbuf.h" - -typedef void(PROTO_PARSE_CALLBACK)(); - -typedef struct { - U8 *buf; - U16 bufSize; - U16 dataLen; - U8 isEsc; - U8 isBegin; - PROTO_PARSE_CALLBACK* callback; -} PROTO_PARSER; - -I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize); -I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len); -I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize); -I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len); -I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value); -I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF *rb, U8 *bufOut, U16* len, U16 maxBufLen); -#endif - diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/queue.c b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/queue.c deleted file mode 100644 index 95bbec0cd..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/queue.c +++ /dev/null @@ -1,75 +0,0 @@ -/* str_queue.c -* -* Copyright (c) 2014-2015, Tuan PM -* 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. -* * Neither the name of Redis nor the names of its contributors may be used -* to endorse or promote products derived from this software without -* specific prior written permission. -* -* 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 OWNER 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. -*/ -#include "queue.h" - -#include "user_interface.h" -#include "osapi.h" -#include "os_type.h" -#include "mem.h" -#include "proto.h" - -uint8_t *last_rb_p_r; -uint8_t *last_rb_p_w; -uint32_t last_fill_cnt; - -void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize) -{ - queue->buf = (uint8_t*)os_zalloc(bufferSize); - RINGBUF_Init(&queue->rb, queue->buf, bufferSize); -} -int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len) -{ - uint32_t ret; - - last_rb_p_r = queue->rb.p_r; - last_rb_p_w = queue->rb.p_w; - last_fill_cnt = queue->rb.fill_cnt; - - ret = PROTO_AddRb(&queue->rb, buffer, len); - if (ret == -1) { - // rolling ring buffer back - queue->rb.p_r = last_rb_p_r; - queue->rb.p_w = last_rb_p_w; - queue->rb.fill_cnt = last_fill_cnt; - } - return ret; -} -int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen) -{ - - return PROTO_ParseRb(&queue->rb, buffer, len, maxLen); -} - -BOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue) -{ - if (queue->rb.fill_cnt <= 0) - return TRUE; - return FALSE; -} diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/queue.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/queue.h deleted file mode 100644 index 79107f2d5..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/queue.h +++ /dev/null @@ -1,44 +0,0 @@ -/* str_queue.h -- -* -* Copyright (c) 2014-2015, Tuan PM -* 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. -* * Neither the name of Redis nor the names of its contributors may be used -* to endorse or promote products derived from this software without -* specific prior written permission. -* -* 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 OWNER 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. -*/ - -#ifndef USER_QUEUE_H_ -#define USER_QUEUE_H_ -#include "os_type.h" -#include "ringbuf.h" -typedef struct { - uint8_t *buf; - RINGBUF rb; -} QUEUE; - -void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize); -int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len); -int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen); -bool ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue); -#endif /* USER_QUEUE_H_ */ diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/ringbuf.c b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/ringbuf.c deleted file mode 100644 index fc882fd5c..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/ringbuf.c +++ /dev/null @@ -1,67 +0,0 @@ -/** -* \file -* Ring Buffer library -*/ - -#include "ringbuf.h" - - -/** -* \brief init a RINGBUF object -* \param r pointer to a RINGBUF object -* \param buf pointer to a byte array -* \param size size of buf -* \return 0 if successfull, otherwise failed -*/ -I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size) -{ - if (r == NULL || buf == NULL || size < 2) return -1; - - r->p_o = r->p_r = r->p_w = buf; - r->fill_cnt = 0; - r->size = size; - - return 0; -} -/** -* \brief put a character into ring buffer -* \param r pointer to a ringbuf object -* \param c character to be put -* \return 0 if successfull, otherwise failed -*/ -I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c) -{ - if (r->fill_cnt >= r->size)return -1; // ring buffer is full, this should be atomic operation - - - r->fill_cnt++; // increase filled slots count, this should be atomic operation - - - *r->p_w++ = c; // put character into buffer - - if (r->p_w >= r->p_o + r->size) // rollback if write pointer go pass - r->p_w = r->p_o; // the physical boundary - - return 0; -} -/** -* \brief get a character from ring buffer -* \param r pointer to a ringbuf object -* \param c read character -* \return 0 if successfull, otherwise failed -*/ -I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c) -{ - if (r->fill_cnt <= 0)return -1; // ring buffer is empty, this should be atomic operation - - - r->fill_cnt--; // decrease filled slots count - - - *c = *r->p_r++; // get the character out - - if (r->p_r >= r->p_o + r->size) // rollback if write pointer go pass - r->p_r = r->p_o; // the physical boundary - - return 0; -} diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/ringbuf.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/ringbuf.h deleted file mode 100644 index f1a4f7e8b..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/ringbuf.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _RING_BUF_H_ -#define _RING_BUF_H_ - -#include -#include -#include "typedef.h" - -typedef struct { - U8* p_o; /**< Original pointer */ - U8* volatile p_r; /**< Read pointer */ - U8* volatile p_w; /**< Write pointer */ - volatile I32 fill_cnt; /**< Number of filled slots */ - I32 size; /**< Buffer size */ -} RINGBUF; - -I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size); -I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c); -I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c); -#endif diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/typedef.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/typedef.h deleted file mode 100644 index 887001ace..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/typedef.h +++ /dev/null @@ -1,17 +0,0 @@ -/** -* \file -* Standard Types definition -*/ - -#ifndef _TYPE_DEF_H_ -#define _TYPE_DEF_H_ - -typedef char I8; -typedef unsigned char U8; -typedef short I16; -typedef unsigned short U16; -typedef long I32; -typedef unsigned long U32; -typedef unsigned long long U64; - -#endif diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/utils.c b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/utils.c deleted file mode 100644 index ac4c9272b..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/utils.c +++ /dev/null @@ -1,149 +0,0 @@ -/* -* Copyright (c) 2014, Tuan PM -* Email: tuanpm@live.com -* -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. 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. -* 3. Neither the name of the copyright holder nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* 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. -* -*/ -#include -#include -#include -#include -#include -#include "utils.h" - - -uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str) -{ - uint8_t segs = 0; /* Segment count. */ - uint8_t chcnt = 0; /* Character count within segment. */ - uint8_t accum = 0; /* Accumulator for segment. */ - /* Catch NULL pointer. */ - if (str == 0) - return 0; - /* Process every character in string. */ - - while (*str != '\0') { - /* Segment changeover. */ - - if (*str == '.') { - /* Must have some digits in segment. */ - if (chcnt == 0) - return 0; - /* Limit number of segments. */ - if (++segs == 4) - return 0; - /* Reset segment values and restart loop. */ - chcnt = accum = 0; - str++; - continue; - } - - /* Check numeric. */ - if ((*str < '0') || (*str > '9')) - return 0; - - /* Accumulate and check segment. */ - - if ((accum = accum * 10 + *str - '0') > 255) - return 0; - /* Advance other segment specific stuff and continue loop. */ - - chcnt++; - str++; - } - - /* Check enough segments and enough characters in last segment. */ - - if (segs != 3) - return 0; - if (chcnt == 0) - return 0; - /* Address okay. */ - - return 1; -} -uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip) -{ - - /* The count of the number of bytes processed. */ - int i; - /* A pointer to the next digit to process. */ - const char * start; - - start = str; - for (i = 0; i < 4; i++) { - /* The digit being processed. */ - char c; - /* The value of this byte. */ - int n = 0; - while (1) { - c = * start; - start++; - if (c >= '0' && c <= '9') { - n *= 10; - n += c - '0'; - } - /* We insist on stopping at "." if we are still parsing - the first, second, or third numbers. If we have reached - the end of the numbers, we will allow any character. */ - else if ((i < 3 && c == '.') || i == 3) { - break; - } - else { - return 0; - } - } - if (n >= 256) { - return 0; - } - ((uint8_t*)ip)[i] = n; - } - return 1; - -} -uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s) -{ - uint32_t value = 0, digit; - int8_t c; - - while ((c = *s++)) { - if ('0' <= c && c <= '9') - digit = c - '0'; - else if ('A' <= c && c <= 'F') - digit = c - 'A' + 10; - else if ('a' <= c && c <= 'f') - digit = c - 'a' + 10; - else break; - - value = (value << 4) | digit; - } - - return value; -} - diff --git a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/utils.h b/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/utils.h deleted file mode 100644 index fe2874803..000000000 --- a/lib/esp-mqtt-arduino-1.0.1.02.1/src/mqtt/utils.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _UTILS_H_ -#define _UTILS_H_ - -#include "c_types.h" - -uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s); -uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip); -uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str); -#endif From 0826249cff5c7c4419cf24c452b22a524c7506e5 Mon Sep 17 00:00:00 2001 From: Yuval <38878996+rt400@users.noreply.github.com> Date: Tue, 2 Oct 2018 19:25:18 +0300 Subject: [PATCH 27/66] Create Hebrew Language File --- sonoff/language/he-HE.h | 543 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 543 insertions(+) create mode 100644 sonoff/language/he-HE.h diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h new file mode 100644 index 000000000..be6094233 --- /dev/null +++ b/sonoff/language/he-HE.h @@ -0,0 +1,543 @@ +/* + he-HE.h - localization for Hebrew - Israel for Sonoff-Tasmota + + Copyright (C) 2018 Yuval Mejahez + + 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 . +*/ + +#ifndef _LANGUAGE_HE_HE_H_ +#define _LANGUAGE_HE_HE_H_ + +/*************************** ATTENTION *******************************\ + * + * Due to memory constraints only UTF-8 is supported. + * To save code space keep text as short as possible. + * Time and Date provided by SDK can not be localized (yet). + * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. + * Use online command Prefix to translate cmnd, stat and tele. + * + * Updated until v5.14.0b +\*********************************************************************/ + +//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) + +#define LANGUAGE_LCID 1037 +// HTML (ISO 639-1) Language Code +#define D_HTML_LANGUAGE "he" + +// "2017-03-07T11:08:02" - ISO8601:2004 +#define D_YEAR_MONTH_SEPARATOR "-" +#define D_MONTH_DAY_SEPARATOR "-" +#define D_DATE_TIME_SEPARATOR "T" +#define D_HOUR_MINUTE_SEPARATOR ":" +#define D_MINUTE_SECOND_SEPARATOR ":" + +#define D_DAY3LIST "SunMonTueWedThuFriSat" +#define D_MONTH3LIST "JanFebMarAprMayJunJulAugSepOctNovDec" + +// Non JSON decimal separator +#define D_DECIMAL_SEPARATOR "." + +// Common +#define D_ADMIN "מנהל" +#define D_AIR_QUALITY "איכות אוויר" +#define D_AP "AP" // Access Point +#define D_AS "as" +#define D_AUTO "AUTO" +#define D_BLINK "מהבהב" +#define D_BLINKOFF "כיבוי היבהוב" +#define D_BOOT_COUNT "מונה הפעלה מחדש" +#define D_BRIGHTLIGHT "בהירות" +#define D_BSSID "BSSId" +#define D_BUTTON "לחצן" +#define D_BY "by" // Written by me +#define D_BYTES "בייט" +#define D_CELSIUS "צלזיוס" +#define D_CHANNEL "ערוץ" +#define D_CO2 "Carbon dioxide" +#define D_CODE "קוד" // Button code +#define D_COLDLIGHT "קור" +#define D_COMMAND "פקודה" +#define D_CONNECTED "מחובר" +#define D_COUNT "סופר" +#define D_COUNTER "מונה" +#define D_CURRENT "נוכחי" // As in Voltage and Current +#define D_DATA "נתונים" +#define D_DARKLIGHT "חושך" +#define D_DEBUG "באגים" +#define D_DISABLED "מבוטל" +#define D_DISTANCE "מרחק" +#define D_DNS_SERVER "DNS שרת" +#define D_DONE "סיים" +#define D_DST_TIME "DST" +#define D_ECO2 "eCO2" +#define D_EMULATION "הדמיה" +#define D_ENABLED "מאופשר" +#define D_ERASE "מחיקה" +#define D_ERROR "שגיאה" +#define D_FAHRENHEIT "פרנהייט" +#define D_FAILED "נכשל" +#define D_FALLBACK "חזרה" +#define D_FALLBACK_TOPIC "נושא לחזרה" +#define D_FALSE "שגוי" +#define D_FILE "קובץ" +#define D_FREE_MEMORY "זכרון פנוי" +#define D_FREQUENCY "תדר" +#define D_GAS "גז" +#define D_GATEWAY "שער" +#define D_GROUP "קבוצה" +#define D_HOST "מארח" +#define D_HOSTNAME "שם מארח" +#define D_HUMIDITY "לחות" +#define D_ILLUMINANCE "רמת חשיפה" +#define D_IMMEDIATE "מידי" // Button immediate +#define D_INDEX "אינדקס" +#define D_INFO "מידע" +#define D_INFRARED "אינפרא" +#define D_INITIALIZED "מאותחל" +#define D_IP_ADDRESS "IP כתובת" +#define D_LIGHT "אור" +#define D_LWT "LWT" +#define D_MODULE "מודול" +#define D_MQTT "MQTT" +#define D_MULTI_PRESS "multi-press" +#define D_NOISE "רעש" +#define D_NONE "כלום" +#define D_OFF "כבוי" +#define D_OFFLINE "מנותק" +#define D_OK "אוקיי" +#define D_ON "פועל" +#define D_ONLINE "מחובר" +#define D_PASSWORD "סיסמא" +#define D_PORT "פורט" +#define D_POWER_FACTOR "גורם כוח" +#define D_POWERUSAGE "כוח" +#define D_POWERUSAGE_ACTIVE "כוח פעיל" +#define D_POWERUSAGE_APPARENT "כוח לכאורה" +#define D_POWERUSAGE_REACTIVE "כוח תגובתי" +#define D_PRESSURE "לחץ" +#define D_PRESSUREATSEALEVEL "לחץ ימי" +#define D_PROGRAM_FLASH_SIZE "גודל תוכנית פלאש" +#define D_PROGRAM_SIZE "גודל תוכנית" +#define D_PROJECT "פרויקט" +#define D_RECEIVED "התקבל" +#define D_RESTART "איתחול" +#define D_RESTARTING "הפעלה מחדש" +#define D_RESTART_REASON "סיבת הפעלה מחדש" +#define D_RESTORE "שחזור" +#define D_RETAINED "שמור" +#define D_RULE "חוק" +#define D_SAVE "שמירה" +#define D_SENSOR "חיישן" +#define D_SSID "SSId" +#define D_START "התחלה" +#define D_STD_TIME "STD" +#define D_STOP "עצירה" +#define D_SUBNET_MASK "רשת מסכת משנה" +#define D_SUBSCRIBE_TO "הרשם ל" +#define D_SUCCESSFUL "הצליח" +#define D_SUNRISE "זריחה" +#define D_SUNSET "שקיעה" +#define D_TEMPERATURE "טמפרטורה" +#define D_TO "ל" +#define D_TOGGLE "מתג" +#define D_TOPIC "נושא" +#define D_TRANSMIT "עבר" +#define D_TRUE "נכון" +#define D_TVOC "TVOC" +#define D_UPGRADE "שדרוג" +#define D_UPLOAD "העלאה" +#define D_UPTIME "זמן עליה" +#define D_USER "משתמש" +#define D_UTC_TIME "UTC" +#define D_UV_INDEX "UV אינדקס" +#define D_UV_LEVEL "UV רמת" +#define D_VERSION "גרסה" +#define D_VOLTAGE "מתח" +#define D_WARMLIGHT "חום" +#define D_WEB_SERVER "Web שרת" + +// sonoff.ino +#define D_WARNING_MINIMAL_VERSION "WARNING This version does not support persistent settings" +#define D_LEVEL_10 "level 1-0" +#define D_LEVEL_01 "level 0-1" +#define D_SERIAL_LOGGING_DISABLED "Serial logging disabled" +#define D_SYSLOG_LOGGING_REENABLED "Syslog logging re-enabled" + +#define D_SET_BAUDRATE_TO "Set Baudrate to" +#define D_RECEIVED_TOPIC "Received Topic" +#define D_DATA_SIZE "Data Size" +#define D_ANALOG_INPUT "אנלוגי" + +// support.ino +#define D_OSWATCH "osWatch" +#define D_BLOCKED_LOOP "Blocked Loop" +#define D_WPS_FAILED_WITH_STATUS "WPSconfig FAILED with status" +#define D_ACTIVE_FOR_3_MINUTES "active for 3 minutes" +#define D_FAILED_TO_START "failed to start" +#define D_PATCH_ISSUE_2186 "Patch issue 2186" +#define D_CONNECTING_TO_AP "Connecting to AP" +#define D_IN_MODE "in mode" +#define D_CONNECT_FAILED_NO_IP_ADDRESS "Connect failed as no IP address received" +#define D_CONNECT_FAILED_AP_NOT_REACHED "Connect failed as AP cannot be reached" +#define D_CONNECT_FAILED_WRONG_PASSWORD "Connect failed with AP incorrect password" +#define D_CONNECT_FAILED_AP_TIMEOUT "Connect failed with AP timeout" +#define D_ATTEMPTING_CONNECTION "Attempting connection..." +#define D_CHECKING_CONNECTION "Checking connection..." +#define D_QUERY_DONE "Query done. MQTT services found" +#define D_MQTT_SERVICE_FOUND "MQTT service found on" +#define D_FOUND_AT "found at" +#define D_SYSLOG_HOST_NOT_FOUND "Syslog Host not found" + +// settings.ino +#define D_SAVED_TO_FLASH_AT "Saved to flash at" +#define D_LOADED_FROM_FLASH_AT "Loaded from flash at" +#define D_USE_DEFAULTS "השתמש בהגדרות ברירת המחדל" +#define D_ERASED_SECTOR "סקטור מחוק" + +// xdrv_02_webserver.ino +#define D_NOSCRIPT "JavaScript - כדי להשתמש ב קושחה אסמוטה אנא הפעל" +#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "קושחה מינימלית - בבקשה אנא שדרג" +#define D_WEBSERVER_ACTIVE_ON "Web server active on" +#define D_WITH_IP_ADDRESS "with IP address" +#define D_WEBSERVER_STOPPED "Web server stopped" +#define D_FILE_NOT_FOUND "File Not Found" +#define D_REDIRECTED "Redirected to captive portal" +#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager set AccessPoint and keep Station" +#define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager set AccessPoint" +#define D_TRYING_TO_CONNECT "מנסה לחבר את ההתקן לרשת" + +#define D_RESTART_IN "הפעלה מחדש תןך" +#define D_SECONDS "שניות" +#define D_DEVICE_WILL_RESTART "ההתקן יופעל מחדש בעוד מס' שניות" +#define D_BUTTON_TOGGLE "מצב" +#define D_CONFIGURATION "הגדרות" +#define D_INFORMATION "מידע" +#define D_FIRMWARE_UPGRADE "שדרוג קושחה" +#define D_CONSOLE "קונסול" +#define D_CONFIRM_RESTART "אישור הפעלה מחדש" + +#define D_CONFIGURE_MODULE "הגדרות מודול" +#define D_CONFIGURE_WIFI "WIFI הגדרות" +#define D_CONFIGURE_MQTT "MQTT הגדרות" +#define D_CONFIGURE_DOMOTICZ "Domoticz הגדרות" +#define D_CONFIGURE_LOGGING "הגדרת לוגים" +#define D_CONFIGURE_OTHER "הגדרות שונות" +#define D_CONFIRM_RESET_CONFIGURATION "אישור שינוי הגדרות" +#define D_RESET_CONFIGURATION "אתחול הגדרות" +#define D_BACKUP_CONFIGURATION "גיבוי הגדרות" +#define D_RESTORE_CONFIGURATION "שחזור הגדרות" +#define D_MAIN_MENU "תפריט ראשי" + +#define D_MODULE_PARAMETERS "מודול פרמטרים" +#define D_MODULE_TYPE "סוג מודול" +#define D_GPIO " רגל " +#define D_SERIAL_IN "כניסת סריאל" +#define D_SERIAL_OUT "יציאת סריאל" + +#define D_WIFI_PARAMETERS "Wifi פרמטרים" +#define D_SCAN_FOR_WIFI_NETWORKS "סורק עבור רשתות אלחוטיות" +#define D_SCAN_DONE "סריקה הושלמה" +#define D_NO_NETWORKS_FOUND "לא נמצאו רשתות אלחוטיות" +#define D_REFRESH_TO_SCAN_AGAIN "רענן כדי לסרוק שוב" +#define D_DUPLICATE_ACCESSPOINT "נקודות גישה משוכפלות" +#define D_SKIPPING_LOW_QUALITY "מדלג עקב איכות רשת נמוכה" +#define D_RSSI "RSSI" +#define D_WEP "WEP" +#define D_WPA_PSK "WPA PSK" +#define D_WPA2_PSK "WPA2 PSK" +#define D_AP1_SSID "AP1 SSId" +#define D_AP1_PASSWORD "AP1 Password" +#define D_AP2_SSID "AP2 SSId" +#define D_AP2_PASSWORD "AP2 Password" + +#define D_MQTT_PARAMETERS "MQTT פרמטרים" +#define D_CLIENT "לקוח" +#define D_FULL_TOPIC "זיהוי מלא" + +#define D_LOGGING_PARAMETERS "פרמטרי לוגים" +#define D_SERIAL_LOG_LEVEL "רמת לוג עבור סריאל" +#define D_WEB_LOG_LEVEL "רמת לוג עבור אתר" +#define D_SYS_LOG_LEVEL "Syslog רמת לוג עבור שרת" +#define D_MORE_DEBUG "מיפוי נוסף" +#define D_SYSLOG_HOST "Syslog מארח" +#define D_SYSLOG_PORT "Syslog פורט" +#define D_TELEMETRY_PERIOD "Telemetry period" + +#define D_OTHER_PARAMETERS "פרמטרים שונים" +#define D_WEB_ADMIN_PASSWORD "סיסמת מנהל - אתר" +#define D_MQTT_ENABLE "MQTT אפשר" +#define D_FRIENDLY_NAME "שם ידידותי" +#define D_BELKIN_WEMO "Belkin WeMo" +#define D_HUE_BRIDGE "Hue Bridge" +#define D_SINGLE_DEVICE "התקן בודד" +#define D_MULTI_DEVICE "התקנים" + +#define D_SAVE_CONFIGURATION "שמירת הגדרות" +#define D_CONFIGURATION_SAVED "הגדרות נשמרו" +#define D_CONFIGURATION_RESET "איפוס הגדרות" + +#define D_PROGRAM_VERSION "גירסת תוכנה" +#define D_BUILD_DATE_AND_TIME "Build Date & Time" +#define D_CORE_AND_SDK_VERSION "Core/SDK Version" +#define D_FLASH_WRITE_COUNT "מונה צריבות" +#define D_MAC_ADDRESS "MAC כתובת" +#define D_MQTT_HOST "MQTT מארח" +#define D_MQTT_PORT "MQTT פורט" +#define D_MQTT_CLIENT "MQTT לקוח" +#define D_MQTT_USER "MQTT שם משתמש" +#define D_MQTT_TOPIC "MQTT נושא" +#define D_MQTT_GROUP_TOPIC "MQTT נושא קבוצת" +#define D_MQTT_FULL_TOPIC "MQTT נושא מלא" +#define D_MDNS_DISCOVERY "mDNS זיהוי" +#define D_MDNS_ADVERTISE "mDNS פרסום" +#define D_ESP_CHIP_ID "ESP מס' רכיב" +#define D_FLASH_CHIP_ID "מס' רכיב פלאש" +#define D_FLASH_CHIP_SIZE "גודל זיכרון פלאש" +#define D_FREE_PROGRAM_SPACE "מקום פנוי - תוכנה" + +#define D_UPGRADE_BY_WEBSERVER "שדרוג קושחה" +#define D_OTA_URL "OTA כתובת" +#define D_START_UPGRADE "התחל בשדרוג" +#define D_UPGRADE_BY_FILE_UPLOAD "שדרוג דרך קובץ נכשל" +#define D_UPLOAD_STARTED "העלאה מתחילה" +#define D_UPGRADE_STARTED "שדרוג מתחיל" +#define D_UPLOAD_DONE "העלאה הסתיימה" +#define D_UPLOAD_ERR_1 "לא נבחר קובץ" +#define D_UPLOAD_ERR_2 "אין מספיק מקום" +#define D_UPLOAD_ERR_3 "Magic byte is not 0xE9" +#define D_UPLOAD_ERR_4 "גודל קובץ השדרוג גדול מנפח האחסון של הפלאש" +#define D_UPLOAD_ERR_5 "מאגר העלאה לא תקין" +#define D_UPLOAD_ERR_6 "העלאה נכשלה. אפשר רישום 3" +#define D_UPLOAD_ERR_7 "ההעלאה בוטלה" +#define D_UPLOAD_ERR_8 "קובץ שגוי" +#define D_UPLOAD_ERR_9 "קובץ גדול מדי" +#define D_UPLOAD_ERR_10 "נכשלה RF הפעלת שבב" +#define D_UPLOAD_ERR_11 "נכשלה RF מחיקת שבב" +#define D_UPLOAD_ERR_12 "נכשלה RF כתיבת שבב" +#define D_UPLOAD_ERR_13 "נכשלה RF קידוד קושחת שבב" +#define D_UPLOAD_ERROR_CODE "שגיאת קוד העלאה" + +#define D_ENTER_COMMAND "הקש פקודה" +#define D_ENABLE_WEBLOG_FOR_RESPONSE "Enable weblog 2 if response expected" +#define D_NEED_USER_AND_PASSWORD "Need user=&password=" + +// xdrv_01_mqtt.ino +#define D_FINGERPRINT "Verify TLS fingerprint..." +#define D_TLS_CONNECT_FAILED_TO "TLS Connect failed to" +#define D_RETRY_IN "Retry in" +#define D_VERIFIED "Verified using Fingerprint" +#define D_INSECURE "Insecure connection due to invalid Fingerprint" +#define D_CONNECT_FAILED_TO "Connect failed to" + +// xplg_wemohue.ino +#define D_MULTICAST_DISABLED "Multicast disabled" +#define D_MULTICAST_REJOINED "Multicast (re)joined" +#define D_MULTICAST_JOIN_FAILED "Multicast join failed" +#define D_FAILED_TO_SEND_RESPONSE "Failed to send response" + +#define D_WEMO "WeMo" +#define D_WEMO_BASIC_EVENT "WeMo basic event" +#define D_WEMO_EVENT_SERVICE "WeMo event service" +#define D_WEMO_META_SERVICE "WeMo meta service" +#define D_WEMO_SETUP "WeMo setup" +#define D_RESPONSE_SENT "Response sent" + +#define D_HUE "Hue" +#define D_HUE_BRIDGE_SETUP "Hue setup" +#define D_HUE_API_NOT_IMPLEMENTED "Hue API not implemented" +#define D_HUE_API "Hue API" +#define D_HUE_POST_ARGS "Hue POST args" +#define D_3_RESPONSE_PACKETS_SENT "3 response packets sent" + +// xdrv_07_domoticz.ino +#define D_DOMOTICZ_PARAMETERS "Domoticz parameters" +#define D_DOMOTICZ_IDX "Idx" +#define D_DOMOTICZ_KEY_IDX "Key idx" +#define D_DOMOTICZ_SWITCH_IDX "Switch idx" +#define D_DOMOTICZ_SENSOR_IDX "Sensor idx" + #define D_DOMOTICZ_TEMP "Temp" + #define D_DOMOTICZ_TEMP_HUM "Temp,Hum" + #define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Hum,Baro" + #define D_DOMOTICZ_POWER_ENERGY "Power,Energy" + #define D_DOMOTICZ_ILLUMINANCE "Illuminance" + #define D_DOMOTICZ_COUNT "Count/PM1" + #define D_DOMOTICZ_VOLTAGE "Voltage/PM2.5" + #define D_DOMOTICZ_CURRENT "Current/PM10" + #define D_DOMOTICZ_AIRQUALITY "AirQuality" +#define D_DOMOTICZ_UPDATE_TIMER "Update timer" + +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "הגדרות תזמון" +#define D_TIMER_PARAMETERS "פרמטרים עבור תזמון" +#define D_TIMER_ENABLE "אפשר תזמון" +#define D_TIMER_ARM "חמש" +#define D_TIMER_TIME "זמן" +#define D_TIMER_DAYS "ימים" +#define D_TIMER_REPEAT "חזרות" +#define D_TIMER_OUTPUT "פלט" +#define D_TIMER_ACTION "פעולה" + +// xdrv_10_knx.ino +#define D_CONFIGURE_KNX "Configure KNX" +#define D_KNX_PARAMETERS "KNX Parameters" +#define D_KNX_GENERAL_CONFIG "General" +#define D_KNX_PHYSICAL_ADDRESS "Physical Address" +#define D_KNX_PHYSICAL_ADDRESS_NOTE "( Must be unique on the KNX network )" +#define D_KNX_ENABLE "Enable KNX" +#define D_KNX_GROUP_ADDRESS_TO_WRITE "Data to Send to Group Addresses" +#define D_ADD "Add" +#define D_DELETE "Delete" +#define D_REPLY "Reply" +#define D_KNX_GROUP_ADDRESS_TO_READ "Group Addresses to Receive Data from" +#define D_LOG_KNX "KNX: " +#define D_RECEIVED_FROM "Received from" +#define D_KNX_COMMAND_WRITE "Write" +#define D_KNX_COMMAND_READ "Read" +#define D_KNX_COMMAND_OTHER "Other" +#define D_SENT_TO "sent to" +#define D_KNX_WARNING "The group address ( 0 / 0 / 0 ) is reserved and can not be used." +#define D_KNX_ENHANCEMENT "Communication Enhancement" +#define D_KNX_TX_SLOT "KNX TX" +#define D_KNX_RX_SLOT "KNX RX" + +// xdrv_03_energy.ino +#define D_ENERGY_TODAY "צריכה יומית" +#define D_ENERGY_YESTERDAY "צריכה בעבר" +#define D_ENERGY_TOTAL "צריכה כללית" + +// xsns_05_ds18b20.ino +#define D_SENSOR_BUSY "Sensor busy" +#define D_SENSOR_CRC_ERROR "Sensor CRC error" +#define D_SENSORS_FOUND "Sensors found" + +// xsns_06_dht.ino +#define D_TIMEOUT_WAITING_FOR "Timeout waiting for" +#define D_START_SIGNAL_LOW "start signal low" +#define D_START_SIGNAL_HIGH "start signal high" +#define D_PULSE "pulse" +#define D_CHECKSUM_FAILURE "Checksum failure" + +// xsns_07_sht1x.ino +#define D_SENSOR_DID_NOT_ACK_COMMAND "Sensor did not ACK command" +#define D_SHT1X_FOUND "SHT1X found" + +// xsns_18_pms5003.ino +#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter +#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter +#define D_PARTICALS_BEYOND "Particals" + +// xsns_32_mpu6050.ino +#define D_AX_AXIS "Accel. X-Axis" +#define D_AY_AXIS "Accel. Y-Axis" +#define D_AZ_AXIS "Accel. Z-Axis" +#define D_GX_AXIS "Gyro X-Axis" +#define D_GY_AXIS "Gyro Y-Axis" +#define D_GZ_AXIS "Gyro Z-Axis" + +// sonoff_template.h +#define D_SENSOR_NONE "None" +#define D_SENSOR_DHT11 "DHT11" +#define D_SENSOR_AM2301 "AM2301" +#define D_SENSOR_SI7021 "SI7021" +#define D_SENSOR_DS18X20 "DS18x20" +#define D_SENSOR_I2C_SCL "I2C SCL" +#define D_SENSOR_I2C_SDA "I2C SDA" +#define D_SENSOR_WS2812 "WS2812" +#define D_SENSOR_DFR562 "MP3 Player" +#define D_SENSOR_IRSEND "IRsend" +#define D_SENSOR_SWITCH "מתג" // Suffix "1" +#define D_SENSOR_BUTTON "לחצן" // Suffix "1" +#define D_SENSOR_RELAY "ממסר" // Suffix "1i" +#define D_SENSOR_LED "לד" // Suffix "1i" +#define D_SENSOR_PWM "PWM" // Suffix "1" +#define D_SENSOR_COUNTER "מונה" // Suffix "1" +#define D_SENSOR_IRRECV "IRrecv" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM_RX "PZEM Rx" +#define D_SENSOR_PZEM_TX "PZEM Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" +#define D_SENSOR_SPI_CS "SPI CS" +#define D_SENSOR_SPI_DC "SPI DC" +#define D_SENSOR_BACKLIGHT "BkLight" +#define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" +#define D_SENSOR_SR04_TRIG "SR04 Tri" +#define D_SENSOR_SR04_ECHO "SR04 Ech" +#define D_SENSOR_SDM120_TX "SDM120 Tx" +#define D_SENSOR_SDM120_RX "SDM120 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_TM1638_CLK "TM16 CLK" +#define D_SENSOR_TM1638_DIO "TM16 DIO" +#define D_SENSOR_TM1638_STB "TM16 STB" + +// Units +#define D_UNIT_AMPERE "A" +#define D_UNIT_CENTIMETER "cm" +#define D_UNIT_HOUR "Hr" +#define D_UNIT_KILOOHM "kOhm" +#define D_UNIT_KILOWATTHOUR "kWh" +#define D_UNIT_LUX "lx" +#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3" +#define D_UNIT_MICROMETER "um" +#define D_UNIT_MICROSECOND "us" +#define D_UNIT_MILLIAMPERE "mA" +#define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" +#define D_UNIT_PARTS_PER_DECILITER "ppd" +#define D_UNIT_PARTS_PER_MILLION "ppm" +#define D_UNIT_PRESSURE "hPa" +#define D_UNIT_SECOND "sec" +#define D_UNIT_SECTORS "sectors" +#define D_UNIT_VA "VA" +#define D_UNIT_VAR "VAr" +#define D_UNIT_VOLT "V" +#define D_UNIT_WATT "W" +#define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_HERTZ "Hz" + +// Log message prefix +#define D_LOG_APPLICATION "APP: " // Application +#define D_LOG_BRIDGE "BRG: " // Bridge +#define D_LOG_CONFIG "CFG: " // Settings +#define D_LOG_COMMAND "CMD: " // Command +#define D_LOG_DEBUG "DBG: " // Debug +#define D_LOG_DHT "DHT: " // DHT sensor +#define D_LOG_DOMOTICZ "DOM: " // Domoticz +#define D_LOG_DSB "DSB: " // DS18xB20 sensor +#define D_LOG_HTTP "HTP: " // HTTP webserver +#define D_LOG_I2C "I2C: " // I2C +#define D_LOG_IRR "IRR: " // Infra Red Received +#define D_LOG_LOG "LOG: " // Logging +#define D_LOG_MODULE "MOD: " // Module +#define D_LOG_MDNS "DNS: " // mDNS +#define D_LOG_MQTT "MQT: " // MQTT +#define D_LOG_OTHER "OTH: " // Other +#define D_LOG_RESULT "RSL: " // Result +#define D_LOG_RFR "RFR: " // RF Received +#define D_LOG_SERIAL "SER: " // Serial +#define D_LOG_SHT1 "SHT: " // SHT1x sensor +#define D_LOG_UPLOAD "UPL: " // Upload +#define D_LOG_UPNP "UPP: " // UPnP +#define D_LOG_WIFI "WIF: " // Wifi + +#endif // _LANGUAGE_HE_HE_H_ From ee9f609ed3fd5c39f2fc715c0d8d4c042fe68523 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Tue, 2 Oct 2018 19:33:31 +0200 Subject: [PATCH 28/66] Update README.md Update README to include link and information about newly proposed MQTT library and the availability of pre-compiled binaries for same. --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 524ad49ab..fae7f5d52 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,16 @@ See [RELEASENOTES.md](https://github.com/arendst/Sonoff-Tasmota/blob/development The development codebase is checked hourly for changes and if new commits have been merged and compile successfuly they will be posted at http://thehackbox.org/tasmota/ (this web address can be used for OTA too). It is important to note that these are based on the current development codebase and it is not recommended to flash it to devices used in production or which are hard to reach in the event that you need to manually flash the device if OTA failed. The last compiled commit number is also posted on the same page along with the current build status (if a firmware rebuild is in progress). +The current development codebase also stages a new experimental MQTT library that is not enabled by default. This may be enabled by commenting out: + +#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT + +and uncommenting: + +//#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT + +For those interested in pre-compiled binaries based on this proposed MQTT library these may be downloaded from http://thehackbox.org/mqtt/ (This URL is also OTA friendly) but please do not under any circumstances use binaries from this link on devices used for day to day purposes as the testing of this newly proposed library still needs to follow its course of testing and possible debugging - Only use it on devices that you would normally use for testing purposes as to not inconvenience yourself when having to revert back to previous firmware versions by cable upload. + ### Disclaimer :warning: **DANGER OF ELECTROCUTION** :warning: From 93460c6498652cb5563d71d41ad1d5416719a683 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 3 Oct 2018 10:00:46 +0200 Subject: [PATCH 29/66] Change MQTT timeout Change MQTT_ARDUINOMQTT command timeout from 1 to 10 seconds --- sonoff/_changelog.ino | 1 + sonoff/sonoff_post.h | 12 +++++------- sonoff/xdrv_01_mqtt.ino | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 217b665ff..c0eea6fde 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.2.1.11 20191002 * Remove support for MQTT Client based on esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO * Add support for MQTT Client based on lwmqtt to be selected by #define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT + * Change MQTT_ARDUINOMQTT command timeout from 1 to 10 seconds * * 6.2.1.10 20180930 * Add command RGBWWTable to support color calibration (#3933) diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index 423a75f3c..bc747155e 100755 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -50,11 +50,6 @@ void KNX_CB_Action(message_t const &msg, void *arg); #define MODULE SONOFF_BASIC // [Module] Select default model #endif -#define USE_DHT // Default DHT11 sensor needs no external library -#define USE_ENERGY_SENSOR // Use energy sensors (+14k code) -#define USE_HLW8012 // Use energy sensor for Sonoff Pow and WolfBlitz -#define USE_CSE7766 // Use energy sensor for Sonoff S31 and Pow R2 - /*********************************************************************************************\ * [sonoff-sensors.bin] * Provide an image with useful supported sensors enabled @@ -272,10 +267,13 @@ void KNX_CB_Action(message_t const &msg, void *arg); #endif #ifndef MQTT_MAX_PACKET_SIZE -#define MQTT_MAX_PACKET_SIZE 1000 +#define MQTT_MAX_PACKET_SIZE 1000 // Bytes #endif #ifndef MQTT_KEEPALIVE -#define MQTT_KEEPALIVE 15 +#define MQTT_KEEPALIVE 15 // Seconds +#endif +#ifndef MQTT_TIMEOUT +#define MQTT_TIMEOUT 10000 // milli seconds #endif #ifndef MESSZ diff --git a/sonoff/xdrv_01_mqtt.ino b/sonoff/xdrv_01_mqtt.ino index 42214216a..3a7d16990 100644 --- a/sonoff/xdrv_01_mqtt.ino +++ b/sonoff/xdrv_01_mqtt.ino @@ -500,7 +500,7 @@ void MqttReconnect() #elif (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT) MqttClient.begin(Settings.mqtt_host, Settings.mqtt_port, EspClient); MqttClient.setWill(stopic, mqtt_data, true, 1); - MqttClient.setOptions(MQTT_KEEPALIVE, true, 1000); + MqttClient.setOptions(MQTT_KEEPALIVE, true, MQTT_TIMEOUT); // MqttClient.onMessageAdvanced(MqttMyDataCb); MqttClient.onMessage(MqttMyDataCb); #endif From 1707c73264a1bf40c97abdfa458163bb4ad2fc3a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 3 Oct 2018 13:55:07 +0200 Subject: [PATCH 30/66] Update Hebrew language file Add Hebrew language file (#3960) --- platformio.ini | 15 +++++++++++++++ sonoff/_changelog.ino | 3 ++- sonoff/language/en-GB.h | 4 ++-- sonoff/language/he-HE.h | 12 +++++++++++- sonoff/user_config.h | 1 + 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index c01485f5a..5dfd0a442 100644 --- a/platformio.ini +++ b/platformio.ini @@ -25,6 +25,7 @@ env_default = sonoff ;env_default = sonoff-ES ;env_default = sonoff-FR ;env_default = sonoff-GR +;env_default = sonoff-HE ;env_default = sonoff-HU ;env_default = sonoff-IT ;env_default = sonoff-NL @@ -294,6 +295,20 @@ upload_resetmethod = ${common.upload_resetmethod} upload_speed = ${common.upload_speed} extra_scripts = ${common.extra_scripts} +[env:sonoff-HE] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=he-HE +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + [env:sonoff-HU] platform = ${common.platform} framework = ${common.framework} diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index c0eea6fde..5fb481c67 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -2,7 +2,8 @@ * Remove support for MQTT Client based on esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO * Add support for MQTT Client based on lwmqtt to be selected by #define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT * Change MQTT_ARDUINOMQTT command timeout from 1 to 10 seconds - * + * Add Hebrew language file (#3960) + * * 6.2.1.10 20180930 * Add command RGBWWTable to support color calibration (#3933) * Add support for Michael Haustein ESP Switch diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 21d8edab7..043545d65 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -32,7 +32,7 @@ \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) - +// https://www.science.co.il/language/Locale-codes.php #define LANGUAGE_LCID 2057 // HTML (ISO 639-1) Language Code #define D_HTML_LANGUAGE "en" @@ -169,7 +169,7 @@ #define D_UV_INDEX_4 "Danger" #define D_UV_INDEX_5 "BurnL1/2" #define D_UV_INDEX_6 "BurnL3" -#define D_UV_INDEX_7 "OoR" +#define D_UV_INDEX_7 "OoR" // Out of Range #define D_UV_LEVEL "UV Level" #define D_UV_POWER "UV Power" #define D_VERSION "Version" diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h index be6094233..a8afee86a 100644 --- a/sonoff/language/he-HE.h +++ b/sonoff/language/he-HE.h @@ -1,7 +1,7 @@ /* he-HE.h - localization for Hebrew - Israel for Sonoff-Tasmota - Copyright (C) 2018 Yuval Mejahez + Copyright (C) 2018 Yuval Mejahez 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 @@ -163,7 +163,15 @@ #define D_USER "משתמש" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV אינדקס" +#define D_UV_INDEX_1 "Low" +#define D_UV_INDEX_2 "Mid" +#define D_UV_INDEX_3 "High" +#define D_UV_INDEX_4 "Danger" +#define D_UV_INDEX_5 "BurnL1/2" +#define D_UV_INDEX_6 "BurnL3" +#define D_UV_INDEX_7 "OoR" // Out of Range #define D_UV_LEVEL "UV רמת" +#define D_UV_POWER "UV Power" #define D_VERSION "גרסה" #define D_VOLTAGE "מתח" #define D_WARMLIGHT "חום" @@ -493,6 +501,7 @@ #define D_UNIT_AMPERE "A" #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HOUR "Hr" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" @@ -514,6 +523,7 @@ #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" #define D_UNIT_HERTZ "Hz" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 11b8c1d61..161b84fa1 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -196,6 +196,7 @@ //#define MY_LANGUAGE en-GB // English in Great Britain. Enabled by Default //#define MY_LANGUAGE es-AR // Spanish in Argentina //#define MY_LANGUAGE fr-FR // French in France +//#define MY_LANGUAGE he-HE // Hebrew in Israel //#define MY_LANGUAGE hu-HU // Hungarian in Hungary //#define MY_LANGUAGE it-IT // Italian in Italy //#define MY_LANGUAGE nl-NL // Dutch in the Netherlands From cea848dec4489c13376a00d5573c11129e7c3733 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 3 Oct 2018 19:29:46 +0200 Subject: [PATCH 31/66] Fix XSS-Vulnerability in configuration page Add HTML entity encoding to the SSID of networks that can be found using the "Scan for wifi networks" function of the configuration page. --- sonoff/xdrv_02_webserver.ino | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index 6a939dc24..86472b27c 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -789,6 +789,17 @@ void HandleWifiConfiguration() HandleWifi(false); } +String htmlEscape(String s) +{ + s.replace("&", "&"); + s.replace("<", "<"); + s.replace(">", ">"); + s.replace("\"", """); + s.replace("'", "'"); + s.replace("/", "/"); + return s; +} + void HandleWifi(boolean scan) { if (HttpUser()) { return; } @@ -854,7 +865,7 @@ void HandleWifi(boolean scan) String item = FPSTR(HTTP_LNK_ITEM); String rssiQ; rssiQ += quality; - item.replace(F("{v}"), WiFi.SSID(indices[i])); + item.replace(F("{v}"), htmlEscape(WiFi.SSID(indices[i]))); item.replace(F("{w}"), String(WiFi.channel(indices[i]))); item.replace(F("{r}"), rssiQ); uint8_t auth = WiFi.encryptionType(indices[i]); From dbb7b279056a876a3a13f4bd8ff792546212aa6e Mon Sep 17 00:00:00 2001 From: Frank Maas Date: Thu, 4 Oct 2018 00:19:32 +0200 Subject: [PATCH 32/66] Update _changelog.ino It's not 2019 yet... --- sonoff/_changelog.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 5fb481c67..00c59c3a5 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,4 @@ -/* 6.2.1.11 20191002 +/* 6.2.1.11 20181002 * Remove support for MQTT Client based on esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO * Add support for MQTT Client based on lwmqtt to be selected by #define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT * Change MQTT_ARDUINOMQTT command timeout from 1 to 10 seconds From 4ebcbf084adb4a3b48a88ee1837d4c0f7ad19640 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 4 Oct 2018 08:25:32 +0200 Subject: [PATCH 33/66] Driver update 1.0.0.4 20181003 added - MP3Reset command in case that the player do rare things and needs a reset, the default volume will be set again too - MP3_CMD_RESET_VALUE for the player reset function - MP3_CMD_DAC command to switch off/on the dac outputs cleaned - some comments and added function text header fixed - missing void's in function calls tested - works with MP3Device 1 = USB STick, or MP3Device 2 = SD-Card - DAC looks working too on a headset. Had no amplifier for test --- sonoff/xdrv_14_mp3.ino | 102 ++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 27 deletions(-) diff --git a/sonoff/xdrv_14_mp3.ino b/sonoff/xdrv_14_mp3.ino index d799aa1f0..3bbf32bd0 100644 --- a/sonoff/xdrv_14_mp3.ino +++ b/sonoff/xdrv_14_mp3.ino @@ -19,6 +19,16 @@ -------------------------------------------------------------------------------------------- Version yyyymmdd Action Description -------------------------------------------------------------------------------------------- + 1.0.0.4 20181003 added - MP3Reset command in case that the player do rare things + - and needs a reset, the default volume will be set again too + added - MP3_CMD_RESET_VALUE for the player reset function + cleaned - some comments and added function text header + fixed - missing void's in function calls + added - MP3_CMD_DAC command to switch off/on the dac outputs + tested - works with MP3Device 1 = USB STick, or MP3Device 2 = SD-Card + - after power and/or reset the SD-Card(2) is the default device + - DAC looks working too on a headset. Had no amplifier for test + --- 1.0.0.3 20180915 added - select device for SD-Card or USB Stick, default will be SD-Card tested - works by MP3Device 1 = USB STick, or MP3Device 2 = SD-Card - after power and/or reset the SD-Card(2) is the default device @@ -61,13 +71,20 @@ TasmotaSerial *MP3Player; +/*********************************************************************************************\ + * constants +\*********************************************************************************************/ + #define D_CMND_MP3 "MP3" const char S_JSON_MP3_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_MP3 "%s\":%d}"; const char S_JSON_MP3_COMMAND[] PROGMEM = "{\"" D_CMND_MP3 "%s\"}"; -const char kMP3_Commands[] PROGMEM = "Track|Play|Pause|Stop|Volume|EQ|Device"; +const char kMP3_Commands[] PROGMEM = "Track|Play|Pause|Stop|Volume|EQ|Device|Reset|DAC"; + +/*********************************************************************************************\ + * enumerationsines +\*********************************************************************************************/ -// enumerations enum MP3_Commands { // commands useable in console or rules CMND_MP3_TRACK, // MP3Track 001...255 CMND_MP3_PLAY, // MP3Play, after pause or normal start to play @@ -75,9 +92,17 @@ enum MP3_Commands { // commands useable in conso CMND_MP3_STOP, // MP3Stop, real stop, original version was pause function CMND_MP3_VOLUME, // MP3Volume 0..100 CMND_MP3_EQ, // MP3EQ 0..5 - CMND_MP3_DEVICE }; // sd-card: 02, usb-stick: 01 + CMND_MP3_DEVICE, // sd-card: 02, usb-stick: 01 + CMND_MP3_RESET, // MP3Reset, a fresh and default restart + CMND_MP3_DAC }; // set dac, 1=off, 0=on, DAC is turned on (0) by default -// defines + +/*********************************************************************************************\ + * command defines +\*********************************************************************************************/ + +#define MP3_CMD_RESET_VALUE 0 // mp3 reset command value +// player commands #define MP3_CMD_TRACK 0x03 // specify playback of a track, e.g. MP3Track 003 #define MP3_CMD_PLAY 0x0d // Play, works as a normal play on a real MP3 Player, starts at 001.mp3 file on the selected device #define MP3_CMD_PAUSE 0x0e // Pause, was original designed as stop, see data sheet @@ -85,10 +110,14 @@ enum MP3_Commands { // commands useable in conso #define MP3_CMD_VOLUME 0x06 // specifies the volume and means a console input as 0..100 #define MP3_CMD_EQ 0x07 // specify EQ(0/1/2/3/4/5), 0:Normal, 1:Pop, 2:Rock, 3:Jazz, 4:Classic, 5:Bass #define MP3_CMD_DEVICE 0x09 // specify playback device, USB=1, SD-Card=2, default is 2 also after reset or power down/up +#define MP3_CMD_RESET 0x0C // send a reset command to start fresh +#define MP3_CMD_DAC 0x1A // activate or deactivate the DAC output for an external amplifier, DAC is turned on by default + +/*********************************************************************************************\ + * calculate the checksum + * starts with cmd[1] with a length of 6 bytes +\*********************************************************************************************/ -// calculate the checksum -// starts with cmd[1] with a length of 6 bytes -// uint16_t MP3_Checksum(uint8_t *array) { uint16_t checksum = 0; @@ -96,43 +125,58 @@ uint16_t MP3_Checksum(uint8_t *array) checksum += array[i]; } checksum = checksum^0xffff; - return checksum+1; + return (checksum+1); } -// init player, define serial tx port -// fixed with 9600 baud -// -void MP3PlayerInit() { +/*********************************************************************************************\ + * init player + * define serial tx port fixed with 9600 baud +\*********************************************************************************************/ + +void MP3PlayerInit(void) { MP3Player = new TasmotaSerial(-1, pin[GPIO_MP3_DFR562]); // start serial communication fixed to 9600 baud if (MP3Player->begin(9600)) { MP3Player->flush(); - delay(1000); // set delay - // volume setting - MP3_CMD(MP3_CMD_VOLUME, MP3_VOLUME); // set volume depending on the entry in the user_config.h + delay(1000); + MP3_CMD(MP3_CMD_RESET, MP3_CMD_RESET_VALUE); // reset the player to defaults + delay(3000); + MP3_CMD(MP3_CMD_VOLUME, MP3_VOLUME); // after reset set volume depending on the entry in the user_config.h } + return; } -// create mp3 command payload and send it via serail interface to the MP3 player -// {start byte, version, length, command, feedback, para MSB, para LSB, chks MSB, chks LSB, end byte}; -// {cmd[0] , cmd[1] , cmd[2], cmd[3] , cmd[4] , cmd[5] , cmd[6] , cmd[7] , cmd[8] , cmd[9] }; -// {0x7e , 0xff , 6 , 0 , 0/1 , 0 , 0 , 0 , 0 , 0xef }; -// +/*********************************************************************************************\ + * create the MP3 commands payload, and send it via serial interface to the MP3 player + * data length is 6 = 6 bytes [FF 06 09 00 00 00] but not counting the start, end, and verification. + * {start byte, version, length, command, feedback, para MSB, para LSB, chks MSB, chks LSB, end byte}; + * {cmd[0] , cmd[1] , cmd[2], cmd[3] , cmd[4] , cmd[5] , cmd[6] , cmd[7] , cmd[8] , cmd[9] }; + * {0x7e , 0xff , 6 , 0 , 0/1 , 0 , 0 , 0 , 0 , 0xef }; +\*********************************************************************************************/ + void MP3_CMD(uint8_t mp3cmd,uint16_t val) { + uint8_t i = 0; uint8_t cmd[10] = {0x7e,0xff,6,0,0,0,0,0,0,0xef}; // fill array cmd[3] = mp3cmd; // mp3 command value - //cmd[4] = ; // feedback, yet not use + cmd[4] = 0; // feedback, 1=yes, 0=no, yet not use cmd[5] = val>>8; // data value, shift 8 byte right cmd[6] = val; // data value low byte - uint16_t chks = MP3_Checksum(&cmd[1]); // see calculate the checksum, line 62..72 + uint16_t chks = MP3_Checksum(&cmd[1]); // see calculate the checksum cmd[7] = chks>>8; // checksum. shift 8 byte right cmd[8] = chks; // checksum low byte MP3Player->write(cmd, sizeof(cmd)); // write mp3 data array to player + delay(1000); + if (mp3cmd == MP3_CMD_RESET) { + MP3_CMD(MP3_CMD_VOLUME, MP3_VOLUME); // after reset set volume depending on the entry in the user_config.h + } + return; } -// check the MP3 commands -// -boolean MP3PlayerCmd() { +/*********************************************************************************************\ + * check the MP3 commands +\*********************************************************************************************/ + +boolean MP3PlayerCmd(void) { char command[CMDSZ]; boolean serviced = true; uint8_t disp_len = strlen(D_CMND_MP3); @@ -145,27 +189,31 @@ boolean MP3PlayerCmd() { case CMND_MP3_VOLUME: case CMND_MP3_EQ: case CMND_MP3_DEVICE: + case CMND_MP3_DAC: // play a track, set volume, select EQ, sepcify file device if (XdrvMailbox.data_len > 0) { if (command_code == CMND_MP3_TRACK) { MP3_CMD(MP3_CMD_TRACK, XdrvMailbox.payload); } if (command_code == CMND_MP3_VOLUME) { MP3_CMD(MP3_CMD_VOLUME, XdrvMailbox.payload * 30 / 100); } if (command_code == CMND_MP3_EQ) { MP3_CMD(MP3_CMD_EQ, XdrvMailbox.payload); } if (command_code == CMND_MP3_DEVICE) { MP3_CMD(MP3_CMD_DEVICE, XdrvMailbox.payload); } + if (command_code == CMND_MP3_DAC) { MP3_CMD(MP3_CMD_DAC, XdrvMailbox.payload); } } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_MP3_COMMAND_NVALUE, command, XdrvMailbox.payload); break; case CMND_MP3_PLAY: case CMND_MP3_PAUSE: case CMND_MP3_STOP: + case CMND_MP3_RESET: // play or re-play after pause, pause, stop, if (command_code == CMND_MP3_PLAY) { MP3_CMD(MP3_CMD_PLAY, 0); } if (command_code == CMND_MP3_PAUSE) { MP3_CMD(MP3_CMD_PAUSE, 0); } if (command_code == CMND_MP3_STOP) { MP3_CMD(MP3_CMD_STOP, 0); } + if (command_code == CMND_MP3_RESET) { MP3_CMD(MP3_CMD_RESET, 0); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_MP3_COMMAND, command, XdrvMailbox.payload); break; default: - // else for Unknown command - serviced = false; + // else for Unknown command + serviced = false; break; } } From 52d88439ffe0f4fbc6ccbda235f512cb7045ad62 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 4 Oct 2018 11:01:50 +0200 Subject: [PATCH 34/66] Fix Domoticz exception Fix exception when wrong Domoticz JSON message is received (#3963) --- sonoff/_changelog.ino | 3 ++- sonoff/xdrv_07_domoticz.ino | 21 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 00c59c3a5..2af5885db 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -3,7 +3,8 @@ * Add support for MQTT Client based on lwmqtt to be selected by #define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT * Change MQTT_ARDUINOMQTT command timeout from 1 to 10 seconds * Add Hebrew language file (#3960) - * + * Fix exception when wrong Domoticz JSON message is received (#3963) + * * 6.2.1.10 20180930 * Add command RGBWWTable to support color calibration (#3933) * Add support for Michael Haustein ESP Switch diff --git a/sonoff/xdrv_07_domoticz.ino b/sonoff/xdrv_07_domoticz.ino index a30f79439..7710cad13 100644 --- a/sonoff/xdrv_07_domoticz.ino +++ b/sonoff/xdrv_07_domoticz.ino @@ -150,6 +150,15 @@ void DomoticzMqttSubscribe() "svalue1" : "0", "switchType" : "Dimmer", "unit" : 1 +} + * Fail on this one +{ + "LastUpdate" : "2018-10-02 20:39:45", + "Name" : "Sfeerverlichting", + "Status" : "Off", + "Timers" : "true", + "Type" : "Group", + "idx" : "2" } */ @@ -157,7 +166,7 @@ boolean DomoticzMqttData() { char stemp1[10]; unsigned long idx = 0; - int16_t nvalue; + int16_t nvalue = -1; int16_t found = 0; domoticz_update_flag = 1; @@ -174,7 +183,9 @@ boolean DomoticzMqttData() // return 1; // } idx = domoticz["idx"]; - nvalue = domoticz["nvalue"]; + if (domoticz.containsKey("nvalue")) { + nvalue = domoticz["nvalue"]; + } snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue); AddLog(LOG_LEVEL_DEBUG_MORE); @@ -198,7 +209,11 @@ boolean DomoticzMqttData() found = 1; } else if ((!iscolordimmer && 2 == nvalue) || // gswitch_sSetLevel (iscolordimmer && 15 == nvalue)) { // Color_SetBrightnessLevel - nvalue = domoticz["svalue1"]; + if (domoticz.containsKey("svalue1")) { + nvalue = domoticz["svalue1"]; + } else { + return 1; + } if (light_type && (Settings.light_dimmer == nvalue) && ((power >> i) &1)) { return 1; } From 4ba10206091f0ec873beceea4f84417bfd19adbc Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Thu, 4 Oct 2018 13:41:15 +0200 Subject: [PATCH 35/66] Update de-DE.h --- sonoff/language/de-DE.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 72f63f9c4..f035235c7 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -124,9 +124,9 @@ #define D_PORT "Port" #define D_POWER_FACTOR "Leistungsfaktor" #define D_POWERUSAGE "Leistung" -#define D_POWERUSAGE_ACTIVE "Active Power" -#define D_POWERUSAGE_APPARENT "Apparent Power" -#define D_POWERUSAGE_REACTIVE "Reactive Power" +#define D_POWERUSAGE_ACTIVE "Wirkleistung" +#define D_POWERUSAGE_APPARENT "Scheinleistung" +#define D_POWERUSAGE_REACTIVE "Blindleistung" #define D_PRESSURE "Luftdruck" #define D_PRESSUREATSEALEVEL "Luftdruck auf Meereshöhe" #define D_PROGRAM_FLASH_SIZE "Ges. Flash Speicher" From 4208baddac848a423e35d219e971808b234c11d8 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 5 Oct 2018 17:54:12 +0200 Subject: [PATCH 36/66] Update language files Update language files --- sonoff/language/bg-BG.h | 4 ++++ sonoff/language/cs-CZ.h | 4 ++++ sonoff/language/de-DE.h | 4 ++++ sonoff/language/el-GR.h | 4 ++++ sonoff/language/en-GB.h | 8 ++++++-- sonoff/language/es-AR.h | 4 ++++ sonoff/language/fr-FR.h | 4 ++++ sonoff/language/he-HE.h | 6 +++++- sonoff/language/hu-HU.h | 4 ++++ sonoff/language/it-IT.h | 4 ++++ sonoff/language/nl-NL.h | 4 ++++ sonoff/language/pl-PL.h | 4 ++++ sonoff/language/pt-BR.h | 4 ++++ sonoff/language/pt-PT.h | 4 ++++ sonoff/language/ru-RU.h | 4 ++++ sonoff/language/tr-TR.h | 4 ++++ sonoff/language/uk-UK.h | 5 ++++- sonoff/language/zh-CN.h | 4 ++++ sonoff/language/zh-TW.h | 6 +++++- 19 files changed, 80 insertions(+), 5 deletions(-) diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index d79eb5210..177bc69ab 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV мощност" #define D_VERSION "Версия" #define D_VOLTAGE "Напрежение" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Топла" #define D_WEB_SERVER "Уеб сървър" @@ -496,12 +497,15 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "h" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kΩ" #define D_UNIT_KILOWATTHOUR "kWh" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 570cfd4c8..498287457 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Verze" #define D_VOLTAGE "Napětí" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Teplé světlo" #define D_WEB_SERVER "Web Server" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "hod" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index f035235c7..dec1e4723 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Intensität" #define D_VERSION "Version" #define D_VOLTAGE "Spannung" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "warm" #define D_WEB_SERVER "Web-Server" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "h" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index 23b5a2705..e0a1cca7a 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Έκδοση" #define D_VOLTAGE "Τάση" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Ζεστό" #define D_WEB_SERVER "Web διακομιστής" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Hr" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 043545d65..6478d5bde 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v5.14.0b + * Updated until v6.2.1.11 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Version" #define D_VOLTAGE "Voltage" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Warm" #define D_WEB_SERVER "Web Server" @@ -496,12 +497,16 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" #define D_UNIT_CENTIMETER "cm" +#define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Hr" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" @@ -522,7 +527,6 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" -#define D_UNIT_HERTZ "Hz" #define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 713e166ab..843dd3dd8 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Versión" #define D_VOLTAGE "Tensión" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Cálida" #define D_WEB_SERVER "Servidor Web" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Hr" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index a7adaea39..6f0c2960a 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -174,6 +174,7 @@ #define D_UV_POWER "Puissance UV" #define D_VERSION "Version" #define D_VOLTAGE "Tension" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Chaud" #define D_WEB_SERVER "Serveur web" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "h" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kΩ" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h index a8afee86a..b81cbd355 100644 --- a/sonoff/language/he-HE.h +++ b/sonoff/language/he-HE.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "גרסה" #define D_VOLTAGE "מתח" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "חום" #define D_WEB_SERVER "Web שרת" @@ -496,12 +497,16 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" #define D_UNIT_CENTIMETER "cm" +#define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Hr" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" @@ -522,7 +527,6 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" -#define D_UNIT_HERTZ "Hz" #define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index ee6b8a66a..88ddb273a 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Verzió" #define D_VOLTAGE "Feszültség" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Meleg" #define D_WEB_SERVER "Web Szerver" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "ó" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index b0fe0767a..62deadea5 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Versione" #define D_VOLTAGE "Tensione" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Calda" #define D_WEB_SERVER "Web Server" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Hr" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 70e55cb87..921e3b483 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Versie" #define D_VOLTAGE "Spanning" +#define D_WEIGHT "Gewicht" #define D_WARMLIGHT "Warm" #define D_WEB_SERVER "Webserver" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "h" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 40383fb53..85e141c29 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Wersja" #define D_VOLTAGE "Napięcie" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Nagrzanie" #define D_WEB_SERVER "Web Server" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Godz" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index 49affdf2f..96874a2c0 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Versão" #define D_VOLTAGE "Voltagem" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Luz quente" #define D_WEB_SERVER "Servidor WEB" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "H" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index fd2e98451..51b40d248 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Versão" #define D_VOLTAGE "Voltagem" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Luz Quente" #define D_WEB_SERVER "servidor WEB" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Hr" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index 9c6266693..1bcf140d6 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Версия" #define D_VOLTAGE "Напряжение" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Тепло" #define D_WEB_SERVER "Web сервер" @@ -496,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "А" @@ -503,6 +506,7 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Ч" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "кОм" #define D_UNIT_KILOWATTHOUR "кВт" #define D_UNIT_LUX "лк" diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index 0c411868e..f28764d50 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Versiyon" #define D_VOLTAGE "Voltaj" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Sıcak" #define D_WEB_SERVER "Web Sunucusu" @@ -497,12 +498,15 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "A" #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HOUR "Hr" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index 3a9b44afa..f6a2d39c7 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Версія" #define D_VOLTAGE "Напруга" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "Тепло" #define D_WEB_SERVER "Web сервер" @@ -483,7 +484,6 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" -#define D_SENSOR_SDS0X1 "SDS0X1" #define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" #define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" #define D_SENSOR_SBR_RX "SerBr Rx" @@ -497,6 +497,8 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "А" @@ -504,6 +506,7 @@ #define D_UNIT_HERTZ "Гц" #define D_UNIT_HOUR "Г" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "кОм" #define D_UNIT_KILOWATTHOUR "кВт" #define D_UNIT_LUX "лк" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 59271d201..763601964 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "版本" #define D_VOLTAGE "电压" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "暖" #define D_WEB_SERVER "Web Server" @@ -496,12 +497,15 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "安" #define D_UNIT_CENTIMETER "厘米" #define D_UNIT_HOUR "时" #define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "千欧" #define D_UNIT_KILOWATTHOUR "千瓦时" #define D_UNIT_LUX "勒克斯" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 5b275b925..59791b776 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -174,6 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "版本" #define D_VOLTAGE "電壓" +#define D_WEIGHT "Weight" #define D_WARMLIGHT "暖" #define D_WEB_SERVER "Web Server" @@ -496,13 +497,16 @@ #define D_SENSOR_TM1638_CLK "TM16 CLK" #define D_SENSOR_TM1638_DIO "TM16 DIO" #define D_SENSOR_TM1638_STB "TM16 STB" +#define D_SENSOR_HX711_SCK "HX711 SCK" +#define D_SENSOR_HX711_DAT "HX711 DAT" // Units #define D_UNIT_AMPERE "安" #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" -#define D_UNIT_INCREMENTS "inc" #define D_UNIT_HOUR "時" +#define D_UNIT_INCREMENTS "inc" +#define D_UNIT_KILOGRAM "kg" #define D_UNIT_KILOOHM "千歐" #define D_UNIT_KILOWATTHOUR "千瓦時" #define D_UNIT_LUX "勒克斯" From f8b93ad3ea5ff5940b0c1892dccab7f9f65f88f8 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Fri, 5 Oct 2018 21:59:39 -0300 Subject: [PATCH 37/66] Updated Spanish Translation --- sonoff/language/es-AR.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 843dd3dd8..ddf191b19 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v6.2.0.1 + * Updated until v6.2.1.11 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -174,7 +174,7 @@ #define D_UV_POWER "UV Power" #define D_VERSION "Versión" #define D_VOLTAGE "Tensión" -#define D_WEIGHT "Weight" +#define D_WEIGHT "Peso" #define D_WARMLIGHT "Cálida" #define D_WEB_SERVER "Servidor Web" From d3d40a160907443acc76d590fe60efbddcfb1d59 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 6 Oct 2018 16:46:25 +0200 Subject: [PATCH 38/66] Update cs-CZ language --- sonoff/language/cs-CZ.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 498287457..9d3cbf160 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -124,9 +124,9 @@ #define D_PORT "Port" #define D_POWER_FACTOR "Účiník" #define D_POWERUSAGE "Příkon" -#define D_POWERUSAGE_ACTIVE "Active Power" -#define D_POWERUSAGE_APPARENT "Apparent Power" -#define D_POWERUSAGE_REACTIVE "Reactive Power" +#define D_POWERUSAGE_ACTIVE "Činný příkon" +#define D_POWERUSAGE_APPARENT "Zdánlivý příkon" +#define D_POWERUSAGE_REACTIVE "Jalový příkon" #define D_PRESSURE "Tlak" #define D_PRESSUREATSEALEVEL "Tlak na hladině moře" #define D_PROGRAM_FLASH_SIZE "Velikost paměti flash" @@ -163,18 +163,18 @@ #define D_USER "Uživatel" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV Index" -#define D_UV_INDEX_1 "Low" -#define D_UV_INDEX_2 "Mid" -#define D_UV_INDEX_3 "High" -#define D_UV_INDEX_4 "Danger" -#define D_UV_INDEX_5 "BurnL1/2" -#define D_UV_INDEX_6 "BurnL3" -#define D_UV_INDEX_7 "OoR" +#define D_UV_INDEX_1 "Nízký" +#define D_UV_INDEX_2 "Střední" +#define D_UV_INDEX_3 "Vysoký" +#define D_UV_INDEX_4 "Nebezpečný" +#define D_UV_INDEX_5 "Popál1/2" +#define D_UV_INDEX_6 "Popál3" +#define D_UV_INDEX_7 "MimoRozsah" #define D_UV_LEVEL "úroveň UV" #define D_UV_POWER "UV Power" #define D_VERSION "Verze" #define D_VOLTAGE "Napětí" -#define D_WEIGHT "Weight" +#define D_WEIGHT "Hmotnost" #define D_WARMLIGHT "Teplé světlo" #define D_WEB_SERVER "Web Server" @@ -333,10 +333,10 @@ #define D_UPLOAD_ERR_7 "Nahrávání přerušeno" #define D_UPLOAD_ERR_8 "Špatný soubor" #define D_UPLOAD_ERR_9 "Soubor je příliš velký" -#define D_UPLOAD_ERR_10 "Failed to init RF chip" -#define D_UPLOAD_ERR_11 "Failed to erase RF chip" -#define D_UPLOAD_ERR_12 "Failed to write to RF chip" -#define D_UPLOAD_ERR_13 "Failed to decode RF firmware" +#define D_UPLOAD_ERR_10 "Chyba inicializace RF chipu" +#define D_UPLOAD_ERR_11 "Chyba smazání RF chipu" +#define D_UPLOAD_ERR_12 "Chyba při zápisu do RF chipu" +#define D_UPLOAD_ERR_13 "Chyba dekódování RF firmwaru" #define D_UPLOAD_ERROR_CODE "Chyba nahrávání" #define D_ENTER_COMMAND "Vlož příkaz" @@ -505,8 +505,8 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "hod" -#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOGRAM "kg" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" From 174f2736dccbd5307c6d33bc46e8d73e24786399 Mon Sep 17 00:00:00 2001 From: synekvl <42292671+synekvl@users.noreply.github.com> Date: Sat, 6 Oct 2018 18:46:29 +0200 Subject: [PATCH 39/66] Update cs-CZ.h --- sonoff/language/cs-CZ.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 9d3cbf160..e4fb5c66d 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v6.1.1c + * Updated until v6.2.1.11 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) From 461fed62909b6da85451c1d49aa6827a80a4479b Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 6 Oct 2018 20:48:26 +0200 Subject: [PATCH 40/66] missing "" around UV Index test in json Fixed the missing "" around the UV Index test in json Old one: "VEML6070":{"UvLevel":6212,"UvIndex":8.32,"UvIndexText":Danger,"UvPower":0.208}} New one: "VEML6070":{"UvLevel":6212,"UvIndex":8.32,"UvIndexText":"Danger","UvPower":0.208}} Now it works. I have no mqtt system running so i did not know that this would happen. Possible i have to build up one system. --- sonoff/xsns_11_veml6070.ino | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sonoff/xsns_11_veml6070.ino b/sonoff/xsns_11_veml6070.ino index c06175584..68d25234a 100644 --- a/sonoff/xsns_11_veml6070.ino +++ b/sonoff/xsns_11_veml6070.ino @@ -31,6 +31,9 @@ Version Date Action Description -------------------------------------------------------------------------------------------- + 1.0.0.3 20181006 fixed - missing "" around the UV Index text + - thanks to Lisa she had tested it on here mqtt system. + -- 1.0.0.2 20180928 tests - same as in version 1.0.0.1 cleaned - source code changed - snprintf_P for json and web server output @@ -77,9 +80,9 @@ - show not only the UV Power value in W/m2, possible a @define value to show it as joule value - add a #define to select how many characters are shown benhind the decimal point for the UV Index --- - 1.0.0.0 20180912 started - further development by mike2nl - https://github.com/mike2nl/Sonoff-Tasmota - forked - from arendst/tasmota - https://github.com/arendst/Sonoff-Tasmota - base - code base from arendst too + 1.0.0.0 20180912 started - further development by mike2nl - https://github.com/mike2nl/Sonoff-Tasmota + forked - from arendst/tasmota - https://github.com/arendst/Sonoff-Tasmota + base - code base from arendst too */ @@ -168,11 +171,11 @@ void Veml6070EverySecond(void) { // all = 10..15[ms] if (11 == (uptime %100)) { - Veml6070ModeCmd(1); // on = 1[ms], wakeup the UV sensor + Veml6070ModeCmd(1); // on = 1[ms], wakeup the UV sensor Veml6070Detect(); // 1[ms], check for sensor and init with IT time Veml6070ModeCmd(0); // off = 5[ms], suspend the UV sensor } else { - Veml6070ModeCmd(1); // 1[ms], wakeup the UV sensor + Veml6070ModeCmd(1); // 1[ms], wakeup the UV sensor uvlevel = Veml6070ReadUv(); // 1..2[ms], get UV raw values uvrisk = Veml6070UvRiskLevel(uvlevel); // 0..1[ms], get UV risk level uvpower = Veml6070UvPower(uvrisk); // 2[ms], get UV power in W/m2 @@ -277,10 +280,10 @@ void Veml6070Show(boolean json) dtostrfd(uvpower, 3, str_uvpower); if (json) { #ifdef USE_VEML6070_SHOW_RAW - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_LEVEL "\":%s,\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":%s,\"" D_JSON_UV_POWER "\":%s}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_LEVEL "\":%s,\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"), mqtt_data, veml6070_name, str_uvlevel, str_uvrisk, str_uvrisk_text, str_uvpower); #else - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":%s,\"" D_JSON_UV_POWER "\":%s}"), + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"), mqtt_data, veml6070_name, str_uvrisk, str_uvrisk_text, str_uvpower); #endif // USE_VEML6070_SHOW_RAW #ifdef USE_DOMOTICZ From adc3d4ebaa0be33a9184307c5b6c489395eeb94b Mon Sep 17 00:00:00 2001 From: phelagor Date: Sat, 6 Oct 2018 22:05:15 +0200 Subject: [PATCH 41/66] Added support for CSL Aplic WDP303075 - Added template for Module. - Added support for HLW8012 (HLW_SEL is different to sonoff POW, needs different level to read voltage) --- sonoff/sonoff_template.h | 19 ++++++++++++++++++- sonoff/xnrg_01_hlw8012.ino | 9 +++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index aad498f3b..f997eb555 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -235,6 +235,7 @@ enum SupportedModules { ESP_SWITCH, OBI, TECKIN, + APLIC_WDP303075, MAXMODULE }; /********************************************************************************************/ @@ -409,7 +410,8 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { AILIGHT, // Light Bulbs PHILIPS, WITTY, // Development Devices - WEMOS + WEMOS, + APLIC_WDP303075 }; // Default module settings @@ -1112,6 +1114,21 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On) 0, 0, 0 + }, + { "AplicWDP303075", // Aplic WDP 303075 (ESP8285 - HLW8012 Energy Monitoring) + // https://www.amazon.de/dp/B07CNWVNJ2 + 0, // GPIO00 + 0, // GPIO01 + 0, // GPIO02 + GPIO_KEY1, // GPIO03 Button + GPIO_HLW_CF, // GPIO04 HLW8012 CF (power) + GPIO_HLW_CF1, // GPIO05 HLW8012 CF1 (current/voltage) + 0, 0, 0, 0, 0, 0, // ? + GPIO_HLW_SEL, // GPIO12 HLW8012 CF Sel output (CF) + GPIO_LED1_INV, // GPIO13 LED + GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0= Off, 1 = On ) + 0, // GPIO15 + 0, 0 } }; diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino index 0bcfa9060..5c63b4826 100644 --- a/sonoff/xnrg_01_hlw8012.ino +++ b/sonoff/xnrg_01_hlw8012.ino @@ -33,6 +33,10 @@ #define HLW_IREF 4545 // 4.545A #define HLW_SEL_VOLTAGE 1 + +// HLW8012 based (APLIC_WDP303075) +#define A_HLW_SEL_VOLTAGE 0 + // HJL-01 based (BlitzWolf, Homecube, Gosund, Teckin) #define HJL_PREF 1362 #define HJL_UREF 822 @@ -182,6 +186,11 @@ void HlwSnsInit() hlw_voltage_ratio = HJL_UREF; hlw_current_ratio = HJL_IREF; hlw_ui_flag = HJL_SEL_VOLTAGE; + } else if (APLIC_WDP303075 == Settings.module){ + hlw_power_ratio = HLW_PREF; + hlw_voltage_ratio = HLW_UREF; + hlw_current_ratio = HLW_IREF; + hlw_ui_flag = A_HLW_SEL_VOLTAGE; } else { hlw_power_ratio = HLW_PREF; hlw_voltage_ratio = HLW_UREF; From 5bbec2617fab2520d9acd547f324d3d8fa7fc66f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 7 Oct 2018 12:37:03 +0200 Subject: [PATCH 42/66] 6.2.1.12 - Fixes Shelly1 and CSL 6.2.1.12 20181007 * Fix Shelly1 switchmode 3 and 4 when using pushbutton (#3989) * Add support for CSL Aplic WDP 303075 Power Socket with Energy Monitoring (#3991, #3996) --- sonoff/_changelog.ino | 6 +++- sonoff/sonoff.ino | 8 +++-- sonoff/sonoff_template.h | 61 +++++++++++++++++++------------------- sonoff/sonoff_version.h | 2 +- sonoff/xnrg_01_hlw8012.ino | 46 ++++++++++++++-------------- 5 files changed, 65 insertions(+), 58 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 2af5885db..e04c9c727 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,8 @@ -/* 6.2.1.11 20181002 +/* 6.2.1.12 20181007 + * Fix Shelly1 switchmode 3 and 4 when using pushbutton (#3989) + * Add support for CSL Aplic WDP 303075 Power Socket with Energy Monitoring (#3991, #3996) + * + * 6.2.1.11 20181002 * Remove support for MQTT Client based on esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO * Add support for MQTT Client based on lwmqtt to be selected by #define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT * Change MQTT_ARDUINOMQTT command timeout from 1 to 10 seconds diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index b89ffe138..958c7879b 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -2306,9 +2306,11 @@ void GpioSwitchPinMode(uint8_t index) if (pin[GPIO_SWT1 +index] < 99) { // pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : bitRead(switch_no_pullup, index) ? INPUT : INPUT_PULLUP); - uint8_t no_pullup = 0; - if (bitRead(switch_no_pullup, index)) { - no_pullup = (Settings.switchmode[index] < PUSHBUTTON); + uint8_t no_pullup = bitRead(switch_no_pullup, index); + if (no_pullup) { + if (SHELLY2 == Settings.module) { + no_pullup = (Settings.switchmode[index] < PUSHBUTTON); + } } pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : (no_pullup) ? INPUT : INPUT_PULLUP); } diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index f997eb555..ca352149d 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -135,9 +135,11 @@ enum ProgramSelectablePins { GPIO_SPI_MISO, // SPI MISO library fixed pin GPIO12 GPIO_SPI_MOSI, // SPI MOSI library fixed pin GPIO13 GPIO_SPI_CLK, // SPI Clk library fixed pin GPIO14 - GPIO_HLW_SEL, // HLW8012 Sel output (Sonoff Pow) - GPIO_HLW_CF1, // HLW8012 CF1 voltage / current (Sonoff Pow) - GPIO_HLW_CF, // HLW8012 CF power (Sonoff Pow) + GPIO_NRG_SEL, // HLW8012/HLJ-01 Sel output (1 = Voltage) + GPIO_NRG_SEL_INV, // HLW8012/HLJ-01 Sel output (0 = Voltage) + GPIO_NRG_CF1, // HLW8012/HLJ-01 CF1 voltage / current + GPIO_HLW_CF, // HLW8012 CF power + GPIO_HJL_CF, // HJL-01/BL0937 CF power GPIO_ADC0, // ADC GPIO_DI, // my92x1 PWM input GPIO_DCKI, // my92x1 CLK input @@ -396,6 +398,7 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { SHELLY2, BLITZWOLF_BWSHP2, // Socket Relay Devices with Energy Monitoring TECKIN, + APLIC_WDP303075, NEO_COOLCAM, // Socket Relay Devices OBI, ESP_SWITCH, // Switch Devices @@ -410,8 +413,7 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { AILIGHT, // Light Bulbs PHILIPS, WITTY, // Development Devices - WEMOS, - APLIC_WDP303075 + WEMOS }; // Default module settings @@ -492,10 +494,10 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { { "Sonoff Pow", // Sonoff Pow (ESP8266 - HLW8012) GPIO_KEY1, // GPIO00 Button 0, 0, 0, 0, - GPIO_HLW_SEL, // GPIO05 HLW8012 Sel output + GPIO_NRG_SEL, // GPIO05 HLW8012 Sel output (1 = Voltage) 0, 0, 0, 0, 0, 0, // Flash connection GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) - GPIO_HLW_CF1, // GPIO13 HLW8012 CF1 voltage / current + GPIO_NRG_CF1, // GPIO13 HLW8012 CF1 voltage / current GPIO_HLW_CF, // GPIO14 HLW8012 CF power GPIO_LED1, // GPIO15 Blue Led (0 = On, 1 = Off) 0, 0 @@ -729,8 +731,8 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_KEY1, // GPIO4 Button GPIO_REL1_INV, // GPIO5 Relay (0 = On, 1 = Off) 0, 0, 0, 0, 0, 0, // Flash connection - GPIO_HLW_CF1, // GPIO12 HLW8012 CF1 voltage / current - GPIO_HLW_SEL, // GPIO13 HLW8012 Sel output + GPIO_NRG_CF1, // GPIO12 HLW8012 CF1 voltage / current + GPIO_NRG_SEL, // GPIO13 HLW8012 Sel output (1 = Voltage) GPIO_HLW_CF, // GPIO14 HLW8012 CF power 0, 0, 0 }, @@ -899,10 +901,10 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { // https://www.amazon.com/KMC-Timing-Monitoring-Network-125V-240V/dp/B06XRX2GTQ GPIO_KEY1, // GPIO00 Button 0, 0, 0, - GPIO_HLW_CF, // GPIO04 HLW8012 CF - GPIO_HLW_CF1, // GPIO05 HLW8012 CF1 + GPIO_HLW_CF, // GPIO04 HLW8012 CF power + GPIO_NRG_CF1, // GPIO05 HLW8012 CF1 voltage / current 0, 0, 0, 0, 0, 0, // Flash connection - GPIO_HLW_SEL, // GPIO12 HLW8012 SEL + GPIO_NRG_SEL, // GPIO12 HLW8012 SEL (1 = Voltage) GPIO_LED1_INV, // GPIO13 Green Led GPIO_REL1, // GPIO14 Relay 0, 0, 0 @@ -1030,11 +1032,11 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off) GPIO_USER, // GPIO03 Serial TXD and Optional sensor 0, - GPIO_HLW_CF, // GPIO05 BL0937 or HJL-01 CF power + GPIO_HJL_CF, // GPIO05 BL0937 or HJL-01 CF power 0, 0, 0, 0, 0, 0, // Flash connection - GPIO_HLW_SEL, // GPIO12 BL0937 or HJL-01 Sel output + GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) GPIO_KEY1, // GPIO13 Button - GPIO_HLW_CF1, // GPIO14 BL0937 or HJL-01 CF1 voltage / current + GPIO_NRG_CF1, // GPIO14 BL0937 or HJL-01 CF1 current / voltage GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On) 0, 0 }, @@ -1107,28 +1109,25 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_KEY1, // GPIO01 Serial TXD and Button 0, GPIO_LED2_INV, // GPIO03 Serial RXD and Red Led (0 = On, 1 = Off) - GPIO_HLW_CF, // GPIO04 BL0937 or HJL-01 CF power - GPIO_HLW_CF1, // GPIO05 BL0937 or HJL-01 CF1 voltage / current + GPIO_HJL_CF, // GPIO04 BL0937 or HJL-01 CF power + GPIO_NRG_CF1, // GPIO05 BL0937 or HJL-01 CF1 current / voltage 0, 0, 0, 0, 0, 0, // Flash connection - GPIO_HLW_SEL, // GPIO12 BL0937 or HJL-01 Sel output + GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On) 0, 0, 0 }, - { "AplicWDP303075", // Aplic WDP 303075 (ESP8285 - HLW8012 Energy Monitoring) + { "AplicWDP303075", // Aplic WDP 303075 (ESP8285 - HLW8012 Energy Monitoring) // https://www.amazon.de/dp/B07CNWVNJ2 - 0, // GPIO00 - 0, // GPIO01 - 0, // GPIO02 - GPIO_KEY1, // GPIO03 Button - GPIO_HLW_CF, // GPIO04 HLW8012 CF (power) - GPIO_HLW_CF1, // GPIO05 HLW8012 CF1 (current/voltage) - 0, 0, 0, 0, 0, 0, // ? - GPIO_HLW_SEL, // GPIO12 HLW8012 CF Sel output (CF) - GPIO_LED1_INV, // GPIO13 LED - GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0= Off, 1 = On ) - 0, // GPIO15 - 0, 0 + 0, 0, 0, + GPIO_KEY1, // GPIO03 Button + GPIO_HLW_CF, // GPIO04 HLW8012 CF power + GPIO_NRG_CF1, // GPIO05 HLW8012 CF1 current / voltage + 0, 0, 0, 0, 0, 0, // Flash connection + GPIO_NRG_SEL_INV, // GPIO12 HLW8012 CF Sel output (0 = Voltage) + GPIO_LED1_INV, // GPIO13 LED (0 = On, 1 = Off) + GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0 = Off, 1 = On ) + 0, 0, 0 } }; diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 60a044326..df02100d3 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x0602010B +#define VERSION 0x0602010C #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino index 5c63b4826..0a7a074e7 100644 --- a/sonoff/xnrg_01_hlw8012.ino +++ b/sonoff/xnrg_01_hlw8012.ino @@ -27,26 +27,21 @@ #define XNRG_01 1 -// HLW8012 based (Sonoff Pow, KMC70011, HuaFan) +// Energy model type 0 (GPIO_HLW_CF) - HLW8012 based (Sonoff Pow, KMC70011, HuaFan, AplicWDP303075) #define HLW_PREF 10000 // 1000.0W #define HLW_UREF 2200 // 220.0V #define HLW_IREF 4545 // 4.545A -#define HLW_SEL_VOLTAGE 1 - -// HLW8012 based (APLIC_WDP303075) -#define A_HLW_SEL_VOLTAGE 0 - -// HJL-01 based (BlitzWolf, Homecube, Gosund, Teckin) +// Energy model type 1 (GPIO_HJL_CF) - HJL-01/BL0937 based (BlitzWolf, Homecube, Gosund, Teckin) #define HJL_PREF 1362 #define HJL_UREF 822 #define HJL_IREF 3300 -#define HJL_SEL_VOLTAGE 0 #define HLW_POWER_PROBE_TIME 10 // Number of seconds to probe for power before deciding none used byte hlw_select_ui_flag; byte hlw_ui_flag = 1; +byte hlw_model_type = 0; byte hlw_load_off; byte hlw_cf1_timer; unsigned long hlw_cf_pulse_length; @@ -124,7 +119,7 @@ void HlwEvery200ms() if (hlw_cf1_timer >= 8) { hlw_cf1_timer = 0; hlw_select_ui_flag = (hlw_select_ui_flag) ? 0 : 1; - digitalWrite(pin[GPIO_HLW_SEL], hlw_select_ui_flag); + digitalWrite(pin[GPIO_NRG_SEL], hlw_select_ui_flag); if (hlw_cf1_pulse_counter) { hlw_cf1_pulse_length = hlw_cf1_summed_pulse_length / hlw_cf1_pulse_counter; @@ -181,21 +176,14 @@ void HlwSnsInit() Settings.energy_current_calibration = HLW_IREF_PULSE; } - if ((BLITZWOLF_BWSHP2 == Settings.module) || (TECKIN == Settings.module)) { + if (hlw_model_type) { hlw_power_ratio = HJL_PREF; hlw_voltage_ratio = HJL_UREF; hlw_current_ratio = HJL_IREF; - hlw_ui_flag = HJL_SEL_VOLTAGE; - } else if (APLIC_WDP303075 == Settings.module){ - hlw_power_ratio = HLW_PREF; - hlw_voltage_ratio = HLW_UREF; - hlw_current_ratio = HLW_IREF; - hlw_ui_flag = A_HLW_SEL_VOLTAGE; } else { hlw_power_ratio = HLW_PREF; hlw_voltage_ratio = HLW_UREF; hlw_current_ratio = HLW_IREF; - hlw_ui_flag = HLW_SEL_VOLTAGE; } hlw_cf_pulse_length = 0; @@ -212,10 +200,10 @@ void HlwSnsInit() hlw_select_ui_flag = 0; // Voltage; - pinMode(pin[GPIO_HLW_SEL], OUTPUT); - digitalWrite(pin[GPIO_HLW_SEL], hlw_select_ui_flag); - pinMode(pin[GPIO_HLW_CF1], INPUT_PULLUP); - attachInterrupt(pin[GPIO_HLW_CF1], HlwCf1Interrupt, FALLING); + pinMode(pin[GPIO_NRG_SEL], OUTPUT); + digitalWrite(pin[GPIO_NRG_SEL], hlw_select_ui_flag); + pinMode(pin[GPIO_NRG_CF1], INPUT_PULLUP); + attachInterrupt(pin[GPIO_NRG_CF1], HlwCf1Interrupt, FALLING); pinMode(pin[GPIO_HLW_CF], INPUT_PULLUP); attachInterrupt(pin[GPIO_HLW_CF], HlwCfInterrupt, FALLING); @@ -225,7 +213,21 @@ void HlwSnsInit() void HlwDrvInit() { if (!energy_flg) { - if ((pin[GPIO_HLW_SEL] < 99) && (pin[GPIO_HLW_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)) { // Sonoff Pow or any HLW8012 based device + hlw_model_type = 0; + if (pin[GPIO_HJL_CF] < 99) { + pin[GPIO_HLW_CF] = pin[GPIO_HJL_CF]; + pin[GPIO_HJL_CF] = 99; + hlw_model_type = 1; + } + + hlw_ui_flag = 1; + if (pin[GPIO_NRG_SEL_INV] < 99) { + pin[GPIO_NRG_SEL] = pin[GPIO_NRG_SEL_INV]; + pin[GPIO_NRG_SEL_INV] = 99; + hlw_ui_flag = 0; + } + + if ((pin[GPIO_NRG_SEL] < 99) && (pin[GPIO_NRG_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)) { // HLW8012 or HJL-01 based device energy_flg = XNRG_01; } } From dfce7a280acf4371f6627404e0adbf57f991ec62 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Sun, 7 Oct 2018 14:24:52 -0300 Subject: [PATCH 43/66] Add PWM Freq Limits Config at Compile time PWM_MAX and PWM_MIN are added with explanation comments in order to let a user, who wants to use a Servo, to config these values. Not added at runtime in order to avoid issues with dimmers. --- sonoff/sonoff.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index f891e387a..9a84fabd6 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -80,6 +80,10 @@ typedef unsigned long power_t; // Power (Relay) type //#define PWM_FREQ 1000 // 100..1000 Hz led refresh //#define PWM_FREQ 910 // 100..1000 Hz led refresh (iTead value) #define PWM_FREQ 880 // 100..1000 Hz led refresh (BN-SZ01 value) +#define PWM_MAX 4000 // [PWM_MAX] Maximum frequency - Default: 4000 +#define PWM_MIN 100 // [PWM_MIN] Minimum frequency - Default: 100 + // For Dimmers use double of your mains AC frequecy (100 for 50Hz and 120 for 60Hz) + // For Controlling Servos use 50 and also set PWM_FREQ as 50 (DO NOT USE THESE VALUES FOR DIMMERS) #define DEFAULT_POWER_DELTA 80 // Power change percentage #define MAX_POWER_HOLD 10 // Time in SECONDS to allow max agreed power From efb328de099e6e486494b4f49efbd26dd22f4529 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Sun, 7 Oct 2018 14:27:09 -0300 Subject: [PATCH 44/66] Add PWM Freq Limits Config at Compile time --- sonoff/sonoff.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 958c7879b..89badfbe1 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -914,7 +914,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); } else if (CMND_PWMFREQUENCY == command_code) { - if ((1 == payload) || ((payload >= 100) && (payload <= 4000))) { + if ((1 == payload) || ((payload >= PWM_MIN) && (payload <= PWM_MAX))) { Settings.pwm_frequency = (1 == payload) ? PWM_FREQ : payload; analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c) } From 30154e23352faddbffbf8b9a75212970895cce8b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 8 Oct 2018 10:30:24 +0200 Subject: [PATCH 45/66] 6.2.1.13 Change to ArduinoMqtt 6.2.1.13 20181008 * Change default Mqtt client library from PubSubClient to non-blocking ArduinoMqtt by Joel Gaehwiler --- sonoff/_changelog.ino | 5 ++++- sonoff/sonoff.h | 5 +++-- sonoff/sonoff_version.h | 2 +- sonoff/user_config.h | 4 ++-- sonoff/xdrv_01_mqtt.ino | 23 +++++++++++++---------- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index e04c9c727..2f3a38392 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,7 @@ -/* 6.2.1.12 20181007 +/* 6.2.1.13 20181008 + * Change default Mqtt client library from PubSubClient to non-blocking ArduinoMqtt by Joel Gaehwiler + * + * 6.2.1.12 20181007 * Fix Shelly1 switchmode 3 and 4 when using pushbutton (#3989) * Add support for CSL Aplic WDP 303075 Power Socket with Energy Monitoring (#3991, #3996) * diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 9a84fabd6..2e16b59b0 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -144,8 +144,9 @@ typedef unsigned long power_t; // Power (Relay) type #define NEO_GRBW 6 // Neopixel GRBW leds #define MQTT_PUBSUBCLIENT 1 // Mqtt PubSubClient library -#define MQTT_TASMOTAMQTT 2 // Mqtt TasmotaMqtt library based on esp-mqtt-arduino -#define MQTT_ARDUINOMQTT 3 // Mqtt arduino-mqtt library by Joel Gaehwiler (https://github.com/256dpi/arduino-mqtt) +#define MQTT_TASMOTAMQTT 2 // Mqtt TasmotaMqtt library based on esp-mqtt-arduino - soon obsolete +#define MQTT_ESPMQTTARDUINO 3 // Mqtt esp-mqtt-arduino library by Ingo Randolf - obsolete +#define MQTT_ARDUINOMQTT 4 // Mqtt arduino-mqtt library by Joel Gaehwiler (https://github.com/256dpi/arduino-mqtt) // Sunrise and Sunset DawnType #define DAWN_NORMAL -0.8333 diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index df02100d3..eba7ddc21 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x0602010C +#define VERSION 0x0602010D #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 161b84fa1..0ed7eba35 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -220,11 +220,11 @@ * Select ONE of possible MQTT library types below \*-------------------------------------------------------------------------------------------*/ // Default MQTT driver for both non-TLS and TLS connections. Blocks network if MQTT server is unavailable. -#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library +//#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library // Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support //#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 (core 2.3.0), +14k4 (core 2.4.2 lwip2) code, +4k mem) - non-TLS only // Alternative MQTT driver does not block network when MQTT server is unavailable. TLS should work but needs to be tested. -//#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT // Use arduino-mqtt (lwmqtt) library (+3k3 code, +2k mem) +#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT // Use arduino-mqtt (lwmqtt) library (+3k3 code, +2k mem) // -- MQTT ---------------------------------------- #define MQTT_TELE_RETAIN 0 // Tele messages may send retain flag (0 = off, 1 = on) diff --git a/sonoff/xdrv_01_mqtt.ino b/sonoff/xdrv_01_mqtt.ino index 3a7d16990..3cb76e86d 100644 --- a/sonoff/xdrv_01_mqtt.ino +++ b/sonoff/xdrv_01_mqtt.ino @@ -27,23 +27,26 @@ // Alternative MQTT driver does not block network when MQTT server is unavailable. TLS should work but needs to be tested. //#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT // Use arduino-mqtt (lwmqtt) library (+3k3 code, +2k mem) -#ifdef USE_MQTT_TLS +#if (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) // Obsolete as of v6.2.1.11 +#undef MQTT_LIBRARY_TYPE +#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT +#endif /* -#ifdef MQTT_LIBRARY_TYPE -#undef MQTT_LIBRARY_TYPE -#endif -#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as it only supports TLS -*/ #if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT) #undef MQTT_LIBRARY_TYPE -#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as it only supports TLS +#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT // Obsolete in near future +#endif +*/ + +#ifdef USE_MQTT_TLS + +#if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT) +#undef MQTT_LIBRARY_TYPE #endif -#else - #ifndef MQTT_LIBRARY_TYPE -#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as default +#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as it only supports TLS #endif #endif From 641005ebbc6dbece43a87a75d04b2597cdc466c8 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Mon, 8 Oct 2018 12:01:38 +0200 Subject: [PATCH 46/66] Remove note on new MQTT build --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index fae7f5d52..524ad49ab 100644 --- a/README.md +++ b/README.md @@ -21,16 +21,6 @@ See [RELEASENOTES.md](https://github.com/arendst/Sonoff-Tasmota/blob/development The development codebase is checked hourly for changes and if new commits have been merged and compile successfuly they will be posted at http://thehackbox.org/tasmota/ (this web address can be used for OTA too). It is important to note that these are based on the current development codebase and it is not recommended to flash it to devices used in production or which are hard to reach in the event that you need to manually flash the device if OTA failed. The last compiled commit number is also posted on the same page along with the current build status (if a firmware rebuild is in progress). -The current development codebase also stages a new experimental MQTT library that is not enabled by default. This may be enabled by commenting out: - -#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT - -and uncommenting: - -//#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT - -For those interested in pre-compiled binaries based on this proposed MQTT library these may be downloaded from http://thehackbox.org/mqtt/ (This URL is also OTA friendly) but please do not under any circumstances use binaries from this link on devices used for day to day purposes as the testing of this newly proposed library still needs to follow its course of testing and possible debugging - Only use it on devices that you would normally use for testing purposes as to not inconvenience yourself when having to revert back to previous firmware versions by cable upload. - ### Disclaimer :warning: **DANGER OF ELECTROCUTION** :warning: From ba16e00e3645e4ca7d35addbd721e7df13fe606e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 8 Oct 2018 14:39:36 +0200 Subject: [PATCH 47/66] Add command WebRefresh Add command WebRefresh 1000..10000 to control web page refresh in milliseconds. Default is 2345 --- sonoff/_changelog.ino | 1 + sonoff/i18n.h | 4 ++++ sonoff/settings.h | 17 +++++++---------- sonoff/sonoff.h | 2 +- sonoff/sonoff.ino | 10 ++++++++-- sonoff/xdrv_02_webserver.ino | 16 ++++++++++++---- 6 files changed, 33 insertions(+), 17 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 2f3a38392..b2210c830 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,5 +1,6 @@ /* 6.2.1.13 20181008 * Change default Mqtt client library from PubSubClient to non-blocking ArduinoMqtt by Joel Gaehwiler + * Add command WebRefresh 1000..10000 to control web page refresh in milliseconds. Default is 2345 * * 6.2.1.12 20181007 * Fix Shelly1 switchmode 3 and 4 when using pushbutton (#3989) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index bc161c078..ab1f0a1d2 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -46,6 +46,7 @@ #define D_JSON_COMMAND "Command" #define D_JSON_CONNECT_FAILED "Connect failed" #define D_JSON_COREVERSION "Core" +#define D_JSON_COUNT "Count" #define D_JSON_COUNTER "Counter" #define D_JSON_CURRENT "Current" // As in Voltage and Current #define D_JSON_DATA "Data" @@ -137,6 +138,7 @@ #define D_JSON_VCC "Vcc" #define D_JSON_VERSION "Version" #define D_JSON_VOLTAGE "Voltage" +#define D_JSON_WEIGHT "Weight" #define D_JSON_WIFI "Wifi" #define D_JSON_WRONG "Wrong" #define D_JSON_WRONG_PARAMETERS "Wrong parameters" @@ -187,6 +189,7 @@ #define D_CMND_FREQUENCY_RESOLUTION "FreqRes" #define D_CMND_CURRENT_RESOLUTION "AmpRes" #define D_CMND_ENERGY_RESOLUTION "EnergyRes" +#define D_CMND_WEIGHT_RESOLUTION "WeightRes" #define D_CMND_MODULE "Module" #define D_CMND_MODULES "Modules" #define D_CMND_GPIO "GPIO" @@ -277,6 +280,7 @@ #define D_JSON_WITH_IP_ADDRESS "with IP address" #define D_CMND_WEBPASSWORD "WebPassword" #define D_CMND_WEBLOG "WebLog" +#define D_CMND_WEBREFRESH "WebRefresh" #define D_CMND_WEBSEND "WebSend" #define D_CMND_EMULATION "Emulation" diff --git a/sonoff/settings.h b/sonoff/settings.h index 978b72b24..26f4f2865 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -110,8 +110,7 @@ typedef union { uint32_t spare06 : 1; uint32_t spare07 : 1; uint32_t spare08 : 1; - uint32_t spare09 : 1; - uint32_t spare10 : 1; + uint32_t weight_resolution : 2; uint32_t frequency_resolution : 2; uint32_t axis_resolution : 2; uint32_t current_resolution : 2; @@ -321,20 +320,18 @@ struct SYSCFG { byte free_717[1]; // 717 uint16_t mcp230xx_int_timer; // 718 - uint8_t rgbwwTable[5]; // 71A - byte free_71F[169]; // 71F + byte free_71F[157]; // 71F + uint16_t weight_item; // 7BC Weight of one item in gram * 10 + uint16_t weight_max; // 7BE Total max weight in kilogram + unsigned long weight_reference; // 7C0 Reference weight in gram + unsigned long weight_calibration; // 7C4 unsigned long energy_frequency_calibration; // 7C8 - - byte free_7CC[2]; // 7CC - + uint16_t web_refresh; // 7CC char mems[MAX_RULE_MEMS][10]; // 7CE - // 800 Full - no more free locations - char rules[MAX_RULE_SETS][MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m, 3 x 512 bytes in v5.14.0b - // E00 - FFF free locations } Settings; diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 2e16b59b0..5d41aa18d 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -145,7 +145,7 @@ typedef unsigned long power_t; // Power (Relay) type #define MQTT_PUBSUBCLIENT 1 // Mqtt PubSubClient library #define MQTT_TASMOTAMQTT 2 // Mqtt TasmotaMqtt library based on esp-mqtt-arduino - soon obsolete -#define MQTT_ESPMQTTARDUINO 3 // Mqtt esp-mqtt-arduino library by Ingo Randolf - obsolete +#define MQTT_ESPMQTTARDUINO 3 // Mqtt esp-mqtt-arduino library by Ingo Randolf - obsolete but define is present for debugging purposes #define MQTT_ARDUINOMQTT 4 // Mqtt arduino-mqtt library by Joel Gaehwiler (https://github.com/256dpi/arduino-mqtt) // Sunrise and Sunset DawnType diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 89badfbe1..23ee2a27d 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -77,7 +77,7 @@ enum TasmotaCommands { CMND_BACKLOG, CMND_DELAY, CMND_POWER, CMND_FANSPEED, CMND_STATUS, CMND_STATE, CMND_POWERONSTATE, CMND_PULSETIME, CMND_BLINKTIME, CMND_BLINKCOUNT, CMND_SENSOR, CMND_SAVEDATA, CMND_SETOPTION, CMND_TEMPERATURE_RESOLUTION, CMND_HUMIDITY_RESOLUTION, - CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_FREQUENCY_RESOLUTION, CMND_CURRENT_RESOLUTION, CMND_ENERGY_RESOLUTION, + CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_FREQUENCY_RESOLUTION, CMND_CURRENT_RESOLUTION, CMND_ENERGY_RESOLUTION, CMND_WEIGHT_RESOLUTION, CMND_MODULE, CMND_MODULES, CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE, CMND_COUNTERDEBOUNCE, CMND_BUTTONDEBOUNCE, CMND_SWITCHDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG, CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME, @@ -87,7 +87,7 @@ enum TasmotaCommands { const char kTasmotaCommands[] PROGMEM = D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_FANSPEED "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|" D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SENSOR "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|" - D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_FREQUENCY_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" + D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_FREQUENCY_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_WEIGHT_RESOLUTION "|" D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" D_CMND_COUNTER "|" D_CMND_COUNTERTYPE "|" D_CMND_COUNTERDEBOUNCE "|" D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|" D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" @@ -821,6 +821,12 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.energy_resolution); } + else if (CMND_WEIGHT_RESOLUTION == command_code) { + if ((payload >= 0) && (payload <= 3)) { + Settings.flag2.weight_resolution = payload; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.weight_resolution); + } else if (CMND_MODULE == command_code) { if ((payload > 0) && (payload <= MAXMODULE)) { payload--; diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index 86472b27c..099411eba 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -25,6 +25,8 @@ * Based on source by AlexT (https://github.com/tzapu) \*********************************************************************************************/ +#define HTTP_REFRESH_TIME 2345 // milliseconds + #ifdef USE_RF_FLASH uint8_t *efm8bb1_update = NULL; #endif // USE_RF_FLASH @@ -72,7 +74,7 @@ const char HTTP_HEAD[] PROGMEM = "};" "x.open('GET','ay'+a,true);" "x.send();" - "lt=setTimeout(la,2345);" + "lt=setTimeout(la,{a});" // Settings.web_refresh "}" "function lb(p){" "la('?d='+p);" @@ -147,7 +149,7 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM = "x.open('GET','ax?c2='+id+o,true);" "x.send();" "}" - "lt=setTimeout(l,2345);" + "lt=setTimeout(l,{a});" "return false;" "}" ""; @@ -367,6 +369,7 @@ void ExecuteWebCommand(char* svalue, int source) void StartWebserver(int type, IPAddress ipweb) { + if (!Settings.web_refresh) { Settings.web_refresh = HTTP_REFRESH_TIME; } if (!webserver_state) { if (!WebServer) { WebServer = new ESP8266WebServer((HTTP_MANAGER==type) ? 80 : WEB_PORT); @@ -497,6 +500,7 @@ void ShowPage(String &page, bool auth) return WebServer->requestAuthentication(); } + page.replace(F("{a}"), String(Settings.web_refresh)); page.replace(F("{ha"), my_module.name); page.replace(F("{h}"), Settings.friendlyname[0]); if (HTTP_MANAGER == webserver_state) { @@ -1994,8 +1998,8 @@ int WebSend(char *buffer) /*********************************************************************************************/ -enum WebCommands { CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_WEBSEND, CMND_EMULATION }; -const char kWebCommands[] PROGMEM = D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBSEND "|" D_CMND_EMULATION ; +enum WebCommands { CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_WEBREFRESH, CMND_WEBSEND, CMND_EMULATION }; +const char kWebCommands[] PROGMEM = D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_EMULATION ; const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND ; bool WebCommand() @@ -2028,6 +2032,10 @@ bool WebCommand() if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_ALL)) { Settings.weblog_level = XdrvMailbox.payload; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.weblog_level); } + else if (CMND_WEBREFRESH == command_code) { + if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload <= 10000)) { Settings.web_refresh = XdrvMailbox.payload; } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.web_refresh); + } else if (CMND_WEBSEND == command_code) { if (XdrvMailbox.data_len > 0) { uint8_t result = WebSend(XdrvMailbox.data); From 3bc3e7e3323b30eeb6bfe46a2cd666e7cbf11d28 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Mon, 8 Oct 2018 17:25:42 -0300 Subject: [PATCH 48/66] Add comment for sleep command (datasheet) --- sonoff/support.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/support.ino b/sonoff/support.ino index d2b38bb09..d5cf005ba 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -1298,13 +1298,13 @@ void WiFiSetSleepMode() * See https://github.com/arendst/Sonoff-Tasmota/issues/2559 */ -//#ifdef ARDUINO_ESP8266_RELEASE_2_4_1 +// Sleep explanation: https://github.com/esp8266/Arduino/blob/3f0c601cfe81439ce17e9bd5d28994a7ed144482/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp#L255 #if defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) #else // Enabled in 2.3.0, 2.4.0 and stage if (sleep) { WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times } else { - WiFi.setSleepMode(WIFI_MODEM_SLEEP); // Diable sleep (Esp8288/Arduino core and sdk default) + WiFi.setSleepMode(WIFI_MODEM_SLEEP); // Disable sleep (Esp8288/Arduino core and sdk default) } #endif } From 077b8a79e15be9446c3a7f796e895a87628de0cc Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 10 Oct 2018 16:40:54 +0200 Subject: [PATCH 49/66] 6.2.1.14 Webserver rewrite 6.2.1.14 20181010 * Rewrite Webserver page handler for easier extension (thx to Adrian Scillato) --- sonoff/_changelog.ino | 5 +- sonoff/i18n.h | 1 - sonoff/sonoff.h | 2 +- sonoff/sonoff_version.h | 2 +- ...02_webserver.ino => xdrv_01_webserver.ino} | 466 ++++++++---------- sonoff/{xdrv_01_mqtt.ino => xdrv_02_mqtt.ino} | 103 +++- sonoff/xdrv_07_domoticz.ino | 49 +- sonoff/xdrv_09_timers.ino | 33 +- sonoff/xdrv_11_knx.ino | 18 +- sonoff/xplg_wemohue.ino | 14 + 10 files changed, 389 insertions(+), 304 deletions(-) rename sonoff/{xdrv_02_webserver.ino => xdrv_01_webserver.ino} (84%) rename sonoff/{xdrv_01_mqtt.ino => xdrv_02_mqtt.ino} (86%) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index b2210c830..def41834a 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,7 @@ -/* 6.2.1.13 20181008 +/* 6.2.1.14 20181010 + * Rewrite Webserver page handler for easier extension (thx to Adrian Scillato) + * + * 6.2.1.13 20181008 * Change default Mqtt client library from PubSubClient to non-blocking ArduinoMqtt by Joel Gaehwiler * Add command WebRefresh 1000..10000 to control web page refresh in milliseconds. Default is 2345 * diff --git a/sonoff/i18n.h b/sonoff/i18n.h index ab1f0a1d2..62226f91f 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -539,7 +539,6 @@ const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION; const char S_CONFIGURE_MODULE[] PROGMEM = D_CONFIGURE_MODULE; const char S_CONFIGURE_WIFI[] PROGMEM = D_CONFIGURE_WIFI; const char S_NO_NETWORKS_FOUND[] PROGMEM = D_NO_NETWORKS_FOUND; -const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT; const char S_CONFIGURE_LOGGING[] PROGMEM = D_CONFIGURE_LOGGING; const char S_CONFIGURE_OTHER[] PROGMEM = D_CONFIGURE_OTHER; const char S_SAVE_CONFIGURATION[] PROGMEM = D_SAVE_CONFIGURATION; diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 5d41aa18d..5bc744157 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -214,7 +214,7 @@ enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MA enum XsnsFunctions {FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART, FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR, - FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM}; + FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_HANDLER}; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index eba7ddc21..080c76fa4 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x0602010D +#define VERSION 0x0602010E #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_01_webserver.ino similarity index 84% rename from sonoff/xdrv_02_webserver.ino rename to sonoff/xdrv_01_webserver.ino index 099411eba..50345145f 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -1,5 +1,5 @@ /* - xdrv_02_webserver.ino - webserver for Sonoff-Tasmota + xdrv_01_webserver.ino - webserver for Sonoff-Tasmota Copyright (C) 2018 Theo Arends @@ -193,25 +193,9 @@ const char HTTP_BTN_MENU1[] PROGMEM = const char HTTP_BTN_RSTRT[] PROGMEM = "
"; const char HTTP_BTN_MENU_MODULE[] PROGMEM = - "
"; -#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) -const char HTTP_BTN_MENU_TIMER[] PROGMEM = - "
"; -#endif // USE_TIMERS and USE_TIMERS_WEB -const char HTTP_BTN_MENU_WIFI[] PROGMEM = - "
"; -const char HTTP_BTN_MENU_MQTT[] PROGMEM = - "
" -#ifdef USE_DOMOTICZ - "
" -#endif // USE_DOMOTICZ - ""; + "
" + "
"; const char HTTP_BTN_MENU4[] PROGMEM = -#ifdef USE_KNX -#ifdef USE_KNX_WEB_MENU - "
" -#endif // USE_KNX_WEB_MENU -#endif // USE_KNX "
" "
" "
" @@ -229,34 +213,21 @@ const char HTTP_FORM_LOGIN[] PROGMEM = const char HTTP_BTN_CONF[] PROGMEM = "

"; const char HTTP_FORM_MODULE[] PROGMEM = - "
 " D_MODULE_PARAMETERS " 
" - "" + "
 " D_MODULE_PARAMETERS " " "
" D_MODULE_TYPE " ({mt)

"; const char HTTP_LNK_ITEM[] PROGMEM = "
{v} ({w}) {i} {r}%
"; const char HTTP_LNK_SCAN[] PROGMEM = - "
"; + "
"; const char HTTP_FORM_WIFI[] PROGMEM = - "
 " D_WIFI_PARAMETERS " " - "" + "
 " D_WIFI_PARAMETERS " " "
" D_AP1_SSID " (" STA_SSID1 ")

" "
" D_AP1_PASSWORD "

" "
" D_AP2_SSID " (" STA_SSID2 ")

" "
" D_AP2_PASSWORD "

" "
" D_HOSTNAME " (" WIFI_HOSTNAME ")

"; -const char HTTP_FORM_MQTT[] PROGMEM = - "
 " D_MQTT_PARAMETERS " " - "" - "
" D_HOST " (" MQTT_HOST ")

" - "
" D_PORT " (" STR(MQTT_PORT) ")

" - "
" D_CLIENT " ({m0)

" - "
" D_USER " (" MQTT_USER ")

" - "
" D_PASSWORD "

" - "
" D_TOPIC " = %topic% (" MQTT_TOPIC ")

" - "
" D_FULL_TOPIC " (" MQTT_FULLTOPIC ")

"; const char HTTP_FORM_LOG1[] PROGMEM = - "
 " D_LOGGING_PARAMETERS " " - ""; + "
 " D_LOGGING_PARAMETERS " "; const char HTTP_FORM_LOG2[] PROGMEM = "
{b0 ({b1)

" "
" D_TELEMETRY_PERIOD " (" STR(TELE_PERIOD) ")

"; const char HTTP_FORM_OTHER[] PROGMEM = - "
 " D_OTHER_PARAMETERS " " - "" + "
 " D_OTHER_PARAMETERS " " +// "" "
" D_WEB_ADMIN_PASSWORD "

" "
" D_MQTT_ENABLE "
"; const char HTTP_FORM_OTHER2[] PROGMEM = @@ -283,7 +254,7 @@ const char HTTP_FORM_OTHER3b[] PROGMEM = "
{3{4"; // Different id only used for labels #endif // USE_EMULATION const char HTTP_FORM_END[] PROGMEM = - "
"; + "
"; const char HTTP_FORM_RST[] PROGMEM = "
" "
 " D_RESTORE_CONFIGURATION " "; @@ -383,46 +354,23 @@ void StartWebserver(int type, IPAddress ipweb) WebServer->on("/ay", HandleAjaxStatusRefresh); WebServer->on("/cm", HandleHttpCommand); WebServer->on("/rb", HandleRestart); +// WebServer->on("/fwlink", HandleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. + WebServer->onNotFound(HandleNotFound); #ifndef BE_MINIMAL WebServer->on("/cn", HandleConfiguration); WebServer->on("/md", HandleModuleConfiguration); -#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) - WebServer->on("/tm", HandleTimerConfiguration); -#endif // USE_TIMERS and USE_TIMERS_WEB - WebServer->on("/w1", HandleWifiConfigurationWithScan); - WebServer->on("/w0", HandleWifiConfiguration); - if (Settings.flag.mqtt_enabled) { - WebServer->on("/mq", HandleMqttConfiguration); -#ifdef USE_DOMOTICZ - WebServer->on("/dm", HandleDomoticzConfiguration); -#endif // USE_DOMOTICZ - } -#ifdef USE_KNX -#ifdef USE_KNX_WEB_MENU - WebServer->on("/kn", HandleKNXConfiguration); -#endif // USE_KNX_WEB_MENU -#endif // USE_KNX + WebServer->on("/wi", HandleWifiConfiguration); WebServer->on("/lg", HandleLoggingConfiguration); WebServer->on("/co", HandleOtherConfiguration); WebServer->on("/dl", HandleBackupConfiguration); - WebServer->on("/sv", HandleSaveSettings); WebServer->on("/rs", HandleRestoreConfiguration); WebServer->on("/rt", HandleResetConfiguration); WebServer->on("/in", HandleInformation); #ifdef USE_EMULATION - if (EMUL_WEMO == Settings.flag2.emulation) { - WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); - WebServer->on("/eventservice.xml", HandleUpnpService); - WebServer->on("/metainfoservice.xml", HandleUpnpMetaService); - WebServer->on("/setup.xml", HandleUpnpSetupWemo); - } - if (EMUL_HUE == Settings.flag2.emulation) { - WebServer->on("/description.xml", HandleUpnpSetupHue); - } + HueWemoAddHandlers(); #endif // USE_EMULATION + XdrvCall(FUNC_WEB_ADD_HANDLER); #endif // Not BE_MINIMAL - WebServer->on("/fwlink", HandleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. - WebServer->onNotFound(HandleNotFound); } reset_web_log_flag = 0; WebServer->begin(); // Web server start @@ -697,7 +645,30 @@ boolean HttpUser() return status; } +/*-------------------------------------------------------------------------------------------*/ + #ifndef BE_MINIMAL + +void WaitForRestart(String result) +{ + String page = FPSTR(HTTP_HEAD); + page.replace(F("{v}"), FPSTR(S_SAVE_CONFIGURATION)); + page += FPSTR(HTTP_HEAD_STYLE); + page += F("
" D_CONFIGURATION_SAVED "
"); + page += result; + page += F("
"); + page += FPSTR(HTTP_MSG_RSTRT); + if (HTTP_MANAGER == webserver_state) { + webserver_state = HTTP_ADMIN; + } else { + page += FPSTR(HTTP_BTN_MAIN); + } + ShowPage(page); + + ShowWebSource(SRC_WEBGUI); + restart_flag = 2; +} + void HandleConfiguration() { if (HttpUser()) { return; } @@ -708,29 +679,34 @@ void HandleConfiguration() page.replace(F("{v}"), FPSTR(S_CONFIGURATION)); page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_BTN_MENU_MODULE); -#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) -#ifdef USE_RULES - page += FPSTR(HTTP_BTN_MENU_TIMER); -#else - if (devices_present) { page += FPSTR(HTTP_BTN_MENU_TIMER); } -#endif // USE_RULES -#endif // USE_TIMERS and USE_TIMERS_WEB - page += FPSTR(HTTP_BTN_MENU_WIFI); - if (Settings.flag.mqtt_enabled) { page += FPSTR(HTTP_BTN_MENU_MQTT); } + + mqtt_data[0] = '\0'; + XdrvCall(FUNC_WEB_ADD_BUTTON); + page += String(mqtt_data); + page += FPSTR(HTTP_BTN_MENU4); page += FPSTR(HTTP_BTN_MAIN); ShowPage(page); } +/*-------------------------------------------------------------------------------------------*/ + void HandleModuleConfiguration() { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - char stemp[20]; - uint8_t midx; AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MODULE); + if (WebServer->hasArg("save")) { + ModuleSaveSettings(); + WaitForRestart(""); + return; + } + + char stemp[20]; + uint8_t midx; + String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_MODULE)); page += FPSTR(HTTP_SCRIPT_MODULE1); @@ -783,15 +759,36 @@ void HandleModuleConfiguration() ShowPage(page); } -void HandleWifiConfigurationWithScan() +void ModuleSaveSettings() { - HandleWifi(true); + char tmp[100]; + char stemp[TOPSZ]; + + WebGetArg("g99", tmp, sizeof(tmp)); + byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp); + Settings.last_module = Settings.module; + Settings.module = new_module; + mytmplt cmodule; + memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule)); + String gpios = ""; + for (byte i = 0; i < MAX_GPIO_PIN; i++) { + if (Settings.last_module != new_module) { + Settings.my_gp.io[i] = 0; + } else { + if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) { + snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i); + WebGetArg(stemp, tmp, sizeof(tmp)); + Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp); + gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]); + } + } + } + snprintf_P(stemp, sizeof(stemp), kModules[Settings.module].name); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), stemp, gpios.c_str()); + AddLog(LOG_LEVEL_INFO); } -void HandleWifiConfiguration() -{ - HandleWifi(false); -} +/*-------------------------------------------------------------------------------------------*/ String htmlEscape(String s) { @@ -804,18 +801,25 @@ String htmlEscape(String s) return s; } -void HandleWifi(boolean scan) +void HandleWifiConfiguration() { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI); + if (WebServer->hasArg("save")) { + WifiSaveSettings(); + String result = F("
" D_TRYING_TO_CONNECT "
"); + WaitForRestart(result); + return; + } + String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_WIFI)); page += FPSTR(HTTP_HEAD_STYLE); - if (scan) { + if (WebServer->hasArg("scan")) { #ifdef USE_EMULATION UdpDisconnect(); #endif // USE_EMULATION @@ -901,39 +905,46 @@ void HandleWifi(boolean scan) ShowPage(page, !(HTTP_MANAGER == webserver_state)); } -void HandleMqttConfiguration() +void WifiSaveSettings() { - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT); + char tmp[100]; - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_MQTT)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_MQTT); - char str[sizeof(Settings.mqtt_client)]; - page.replace(F("{m0"), Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client))); - page.replace(F("{m1"), Settings.mqtt_host); - page.replace(F("{m2"), String(Settings.mqtt_port)); - page.replace(F("{m3"), Settings.mqtt_client); - page.replace(F("{m4"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user); - page.replace(F("{m5"), (Settings.mqtt_pwd[0] == '\0')?"0":Settings.mqtt_pwd); - page.replace(F("{m6"), Settings.mqtt_topic); - page.replace(F("{m7"), Settings.mqtt_fulltopic); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WebGetArg("h", tmp, sizeof(tmp)); + strlcpy(Settings.hostname, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp, sizeof(Settings.hostname)); + if (strstr(Settings.hostname,"%")) { + strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname)); + } + WebGetArg("s1", tmp, sizeof(tmp)); + strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? STA_SSID1 : tmp, sizeof(Settings.sta_ssid[0])); + WebGetArg("s2", tmp, sizeof(tmp)); + strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1])); + WebGetArg("p1", tmp, sizeof(tmp)); + strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0])); + WebGetArg("p2", tmp, sizeof(tmp)); + strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1])); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"), + Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]); + AddLog(LOG_LEVEL_INFO); } +/*-------------------------------------------------------------------------------------------*/ + void HandleLoggingConfiguration() { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_LOGGING); + if (WebServer->hasArg("save")) { + LoggingSaveSettings(); + HandleConfiguration(); + return; + } + String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_LOGGING)); page += FPSTR(HTTP_HEAD_STYLE); + page += FPSTR(HTTP_FORM_LOG1); for (byte idx = 0; idx < 3; idx++) { page += FPSTR(HTTP_FORM_LOG2); @@ -973,11 +984,46 @@ void HandleLoggingConfiguration() ShowPage(page); } +void LoggingSaveSettings() +{ + char tmp[100]; + + WebGetArg("ls", tmp, sizeof(tmp)); + Settings.seriallog_level = (!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp); + WebGetArg("lw", tmp, sizeof(tmp)); + Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp); + WebGetArg("ll", tmp, sizeof(tmp)); + Settings.syslog_level = (!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp); + syslog_level = Settings.syslog_level; + syslog_timer = 0; + WebGetArg("lh", tmp, sizeof(tmp)); + strlcpy(Settings.syslog_host, (!strlen(tmp)) ? SYS_LOG_HOST : tmp, sizeof(Settings.syslog_host)); + WebGetArg("lp", tmp, sizeof(tmp)); + Settings.syslog_port = (!strlen(tmp)) ? SYS_LOG_PORT : atoi(tmp); + WebGetArg("lt", tmp, sizeof(tmp)); + Settings.tele_period = (!strlen(tmp)) ? TELE_PERIOD : atoi(tmp); + if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) { + Settings.tele_period = 10; // Do not allow periods < 10 seconds + } + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"), + Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period); + AddLog(LOG_LEVEL_INFO); +} + +/*-------------------------------------------------------------------------------------------*/ + void HandleOtherConfiguration() { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_OTHER); + + if (WebServer->hasArg("save")) { + OtherSaveSettings(); + WaitForRestart(""); + return; + } + char stemp[40]; String page = FPSTR(HTTP_HEAD); @@ -1011,6 +1057,32 @@ void HandleOtherConfiguration() ShowPage(page); } +void OtherSaveSettings() +{ + char tmp[100]; + char stemp[TOPSZ]; + char stemp2[TOPSZ]; + + WebGetArg("p1", tmp, sizeof(tmp)); + strlcpy(Settings.web_password, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.web_password : tmp, sizeof(Settings.web_password)); + Settings.flag.mqtt_enabled = WebServer->hasArg("b1"); +#ifdef USE_EMULATION + WebGetArg("b2", tmp, sizeof(tmp)); + Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp); +#endif // USE_EMULATION + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation); + for (byte i = 0; i < MAX_FRIENDLYNAMES; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("a%d"), i +1); + WebGetArg(stemp, tmp, sizeof(tmp)); + snprintf_P(stemp2, sizeof(stemp2), PSTR(FRIENDLY_NAME"%d"), i +1); + strlcpy(Settings.friendlyname[i], (!strlen(tmp)) ? (i) ? stemp2 : FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[i])); + snprintf_P(log_data, sizeof(log_data), PSTR("%s%s %s"), log_data, (i) ? "," : "", Settings.friendlyname[i]); + } + AddLog(LOG_LEVEL_INFO); +} + +/*-------------------------------------------------------------------------------------------*/ + void HandleBackupConfiguration() { if (HttpUser()) { return; } @@ -1053,171 +1125,7 @@ void HandleBackupConfiguration() Settings.cfg_crc = cfg_crc; // Restore crc in case savedata = 0 to make sure settings will be noted as changed } -void HandleSaveSettings() -{ - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - - char stemp[TOPSZ]; - char stemp2[TOPSZ]; - String result = ""; - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_SAVE_CONFIGURATION); - - char tmp[100]; - WebGetArg("w", tmp, sizeof(tmp)); // Returns "5,1" where 5 is config type and 1 is restart flag - char *p = tmp; - uint8_t what = strtol(p, &p, 10); - p++; // Skip comma - uint8_t restart = strtol(p, &p, 10); - switch (what) { - case 1: - WebGetArg("h", tmp, sizeof(tmp)); - strlcpy(Settings.hostname, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp, sizeof(Settings.hostname)); - if (strstr(Settings.hostname,"%")) { - strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname)); - } - WebGetArg("s1", tmp, sizeof(tmp)); - strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? STA_SSID1 : tmp, sizeof(Settings.sta_ssid[0])); - WebGetArg("s2", tmp, sizeof(tmp)); - strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1])); -// WebGetArg("s1", tmp, sizeof(tmp)); -// strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[0])); -// WebGetArg("s2", tmp, sizeof(tmp)); -// strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[1])); - WebGetArg("p1", tmp, sizeof(tmp)); - strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0])); - WebGetArg("p2", tmp, sizeof(tmp)); - strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1])); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"), - Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]); - AddLog(LOG_LEVEL_INFO); - result += F("
" D_TRYING_TO_CONNECT "
"); - break; - case 2: - WebGetArg("mt", tmp, sizeof(tmp)); - strlcpy(stemp, (!strlen(tmp)) ? MQTT_TOPIC : tmp, sizeof(stemp)); - MakeValidMqtt(0, stemp); - WebGetArg("mf", tmp, sizeof(tmp)); - strlcpy(stemp2, (!strlen(tmp)) ? MQTT_FULLTOPIC : tmp, sizeof(stemp2)); - MakeValidMqtt(1,stemp2); - if ((strcmp(stemp, Settings.mqtt_topic)) || (strcmp(stemp2, Settings.mqtt_fulltopic))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : ""); - MqttPublishPrefixTopic_P(TELE, S_LWT, true); // Offline or remove previous retained topic - } - strlcpy(Settings.mqtt_topic, stemp, sizeof(Settings.mqtt_topic)); - strlcpy(Settings.mqtt_fulltopic, stemp2, sizeof(Settings.mqtt_fulltopic)); - WebGetArg("mh", tmp, sizeof(tmp)); - strlcpy(Settings.mqtt_host, (!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_host)); - WebGetArg("ml", tmp, sizeof(tmp)); - Settings.mqtt_port = (!strlen(tmp)) ? MQTT_PORT : atoi(tmp); - WebGetArg("mc", tmp, sizeof(tmp)); - strlcpy(Settings.mqtt_client, (!strlen(tmp)) ? MQTT_CLIENT_ID : tmp, sizeof(Settings.mqtt_client)); - WebGetArg("mu", tmp, sizeof(tmp)); - strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user)); - WebGetArg("mp", tmp, sizeof(tmp)); - strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? MQTT_PASS : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_pwd)); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_MQTTPASSWORD " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"), - Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_pwd, Settings.mqtt_topic, Settings.mqtt_fulltopic); - AddLog(LOG_LEVEL_INFO); - break; - case 3: - WebGetArg("ls", tmp, sizeof(tmp)); - Settings.seriallog_level = (!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp); - WebGetArg("lw", tmp, sizeof(tmp)); - Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp); - WebGetArg("ll", tmp, sizeof(tmp)); - Settings.syslog_level = (!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp); - syslog_level = Settings.syslog_level; - syslog_timer = 0; - WebGetArg("lh", tmp, sizeof(tmp)); - strlcpy(Settings.syslog_host, (!strlen(tmp)) ? SYS_LOG_HOST : tmp, sizeof(Settings.syslog_host)); - WebGetArg("lp", tmp, sizeof(tmp)); - Settings.syslog_port = (!strlen(tmp)) ? SYS_LOG_PORT : atoi(tmp); - WebGetArg("lt", tmp, sizeof(tmp)); - Settings.tele_period = (!strlen(tmp)) ? TELE_PERIOD : atoi(tmp); - if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) { - Settings.tele_period = 10; // Do not allow periods < 10 seconds - } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"), - Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period); - AddLog(LOG_LEVEL_INFO); - break; -#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) - case 7: - TimerSaveSettings(); - break; -#endif // USE_TIMERS and USE_TIMERS_WEB -#ifdef USE_DOMOTICZ - case 4: - DomoticzSaveSettings(); - break; -#endif // USE_DOMOTICZ - case 5: - WebGetArg("p1", tmp, sizeof(tmp)); - strlcpy(Settings.web_password, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.web_password : tmp, sizeof(Settings.web_password)); - Settings.flag.mqtt_enabled = WebServer->hasArg("b1"); -#ifdef USE_EMULATION - WebGetArg("b2", tmp, sizeof(tmp)); - Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp); -#endif // USE_EMULATION - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation); - for (byte i = 0; i < MAX_FRIENDLYNAMES; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("a%d"), i +1); - WebGetArg(stemp, tmp, sizeof(tmp)); - snprintf_P(stemp2, sizeof(stemp2), PSTR(FRIENDLY_NAME"%d"), i +1); - strlcpy(Settings.friendlyname[i], (!strlen(tmp)) ? (i) ? stemp2 : FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[i])); - snprintf_P(log_data, sizeof(log_data), PSTR("%s%s %s"), log_data, (i) ? "," : "", Settings.friendlyname[i]); - } - AddLog(LOG_LEVEL_INFO); - break; - case 6: - WebGetArg("g99", tmp, sizeof(tmp)); - byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp); - Settings.last_module = Settings.module; - Settings.module = new_module; - mytmplt cmodule; - memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule)); - String gpios = ""; - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if (Settings.last_module != new_module) { - Settings.my_gp.io[i] = 0; - } else { - if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) { - snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]); - } - } - } - snprintf_P(stemp, sizeof(stemp), kModules[Settings.module].name); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), stemp, gpios.c_str()); - AddLog(LOG_LEVEL_INFO); - break; - } - - if (restart) { - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_SAVE_CONFIGURATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += F("
" D_CONFIGURATION_SAVED "
"); - page += result; - page += F("
"); - page += FPSTR(HTTP_MSG_RSTRT); - if (HTTP_MANAGER == webserver_state) { - webserver_state = HTTP_ADMIN; - } else { - page += FPSTR(HTTP_BTN_MAIN); - } - ShowPage(page); - - ShowWebSource(SRC_WEBGUI); - restart_flag = 2; - } else { - HandleConfiguration(); - } -} +/*-------------------------------------------------------------------------------------------*/ void HandleResetConfiguration() { @@ -1259,6 +1167,8 @@ void HandleRestoreConfiguration() upload_file_type = UPL_SETTINGS; } +/*-------------------------------------------------------------------------------------------*/ + void HandleInformation() { if (HttpUser()) { return; } @@ -1376,6 +1286,8 @@ void HandleInformation() } #endif // Not BE_MINIMAL +/*-------------------------------------------------------------------------------------------*/ + void HandleUpgradeFirmware() { if (HttpUser()) { return; } @@ -1669,6 +1581,8 @@ void HandleUploadLoop() delay(0); } +/*-------------------------------------------------------------------------------------------*/ + void HandlePreflightRequest() { WebServer->sendHeader(F("Access-Control-Allow-Origin"), F("*")); @@ -1677,6 +1591,8 @@ void HandlePreflightRequest() WebServer->send(200, FPSTR(HDR_CTYPE_HTML), ""); } +/*-------------------------------------------------------------------------------------------*/ + void HandleHttpCommand() { if (HttpUser()) { return; } @@ -1735,6 +1651,8 @@ void HandleHttpCommand() WebServer->send(200, FPSTR(HDR_CTYPE_JSON), message); } +/*-------------------------------------------------------------------------------------------*/ + void HandleConsole() { if (HttpUser()) { return; } @@ -1808,6 +1726,8 @@ void HandleAjaxConsoleRefresh() WebServer->send(200, FPSTR(HDR_CTYPE_XML), message); } +/*-------------------------------------------------------------------------------------------*/ + void HandleRestart() { if (HttpUser()) { return; } @@ -2061,9 +1981,9 @@ bool WebCommand() * Interface \*********************************************************************************************/ -#define XDRV_02 +#define XDRV_01 -boolean Xdrv02(byte function) +boolean Xdrv01(byte function) { boolean result = false; diff --git a/sonoff/xdrv_01_mqtt.ino b/sonoff/xdrv_02_mqtt.ino similarity index 86% rename from sonoff/xdrv_01_mqtt.ino rename to sonoff/xdrv_02_mqtt.ino index 3cb76e86d..1cd6d9aff 100644 --- a/sonoff/xdrv_01_mqtt.ino +++ b/sonoff/xdrv_02_mqtt.ino @@ -1,5 +1,5 @@ /* - xdrv_01_mqtt.ino - mqtt support for Sonoff-Tasmota + xdrv_02_mqtt.ino - mqtt support for Sonoff-Tasmota Copyright (C) 2018 Theo Arends @@ -782,18 +782,115 @@ bool MqttCommand() return serviced; } +/*********************************************************************************************\ + * Presentation +\*********************************************************************************************/ + +#ifdef USE_WEBSERVER + +#define WEB_HANDLE_MQTT "mq" + +const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT; + +const char HTTP_BTN_MENU_MQTT[] PROGMEM = + "
"; + +const char HTTP_FORM_MQTT[] PROGMEM = + "
 " D_MQTT_PARAMETERS " 
" + "
" D_HOST " (" MQTT_HOST ")

" + "
" D_PORT " (" STR(MQTT_PORT) ")

" + "
" D_CLIENT " ({m0)

" + "
" D_USER " (" MQTT_USER ")

" + "
" D_PASSWORD "

" + "
" D_TOPIC " = %topic% (" MQTT_TOPIC ")

" + "
" D_FULL_TOPIC " (" MQTT_FULLTOPIC ")

"; + +void HandleMqttConfiguration() +{ + if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT); + + if (WebServer->hasArg("save")) { + MqttSaveSettings(); + WaitForRestart(""); + return; + } + + String page = FPSTR(HTTP_HEAD); + page.replace(F("{v}"), FPSTR(S_CONFIGURE_MQTT)); + page += FPSTR(HTTP_HEAD_STYLE); + + page += FPSTR(HTTP_FORM_MQTT); + char str[sizeof(Settings.mqtt_client)]; + page.replace(F("{m0"), Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client))); + page.replace(F("{m1"), Settings.mqtt_host); + page.replace(F("{m2"), String(Settings.mqtt_port)); + page.replace(F("{m3"), Settings.mqtt_client); + page.replace(F("{m4"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user); + page.replace(F("{m5"), (Settings.mqtt_pwd[0] == '\0')?"0":Settings.mqtt_pwd); + page.replace(F("{m6"), Settings.mqtt_topic); + page.replace(F("{m7"), Settings.mqtt_fulltopic); + + page += FPSTR(HTTP_FORM_END); + page += FPSTR(HTTP_BTN_CONF); + ShowPage(page); +} + +void MqttSaveSettings() +{ + char tmp[100]; + char stemp[TOPSZ]; + char stemp2[TOPSZ]; + + WebGetArg("mt", tmp, sizeof(tmp)); + strlcpy(stemp, (!strlen(tmp)) ? MQTT_TOPIC : tmp, sizeof(stemp)); + MakeValidMqtt(0, stemp); + WebGetArg("mf", tmp, sizeof(tmp)); + strlcpy(stemp2, (!strlen(tmp)) ? MQTT_FULLTOPIC : tmp, sizeof(stemp2)); + MakeValidMqtt(1,stemp2); + if ((strcmp(stemp, Settings.mqtt_topic)) || (strcmp(stemp2, Settings.mqtt_fulltopic))) { + snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : ""); + MqttPublishPrefixTopic_P(TELE, S_LWT, true); // Offline or remove previous retained topic + } + strlcpy(Settings.mqtt_topic, stemp, sizeof(Settings.mqtt_topic)); + strlcpy(Settings.mqtt_fulltopic, stemp2, sizeof(Settings.mqtt_fulltopic)); + WebGetArg("mh", tmp, sizeof(tmp)); + strlcpy(Settings.mqtt_host, (!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_host)); + WebGetArg("ml", tmp, sizeof(tmp)); + Settings.mqtt_port = (!strlen(tmp)) ? MQTT_PORT : atoi(tmp); + WebGetArg("mc", tmp, sizeof(tmp)); + strlcpy(Settings.mqtt_client, (!strlen(tmp)) ? MQTT_CLIENT_ID : tmp, sizeof(Settings.mqtt_client)); + WebGetArg("mu", tmp, sizeof(tmp)); + strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user)); + WebGetArg("mp", tmp, sizeof(tmp)); + strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? MQTT_PASS : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_pwd)); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_MQTTPASSWORD " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"), + Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_pwd, Settings.mqtt_topic, Settings.mqtt_fulltopic); + AddLog(LOG_LEVEL_INFO); +} +#endif // USE_WEBSERVER + /*********************************************************************************************\ * Interface \*********************************************************************************************/ -#define XDRV_01 +#define XDRV_02 -boolean Xdrv01(byte function) +boolean Xdrv02(byte function) { boolean result = false; if (Settings.flag.mqtt_enabled) { switch (function) { +#ifdef USE_WEBSERVER + case FUNC_WEB_ADD_BUTTON: + strncat_P(mqtt_data, HTTP_BTN_MENU_MQTT, sizeof(mqtt_data)); + break; + case FUNC_WEB_ADD_HANDLER: + WebServer->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration); + break; +#endif // USE_WEBSERVER case FUNC_LOOP: MqttLoop(); break; diff --git a/sonoff/xdrv_07_domoticz.ino b/sonoff/xdrv_07_domoticz.ino index 7710cad13..d40bae88f 100644 --- a/sonoff/xdrv_07_domoticz.ino +++ b/sonoff/xdrv_07_domoticz.ino @@ -19,22 +19,6 @@ #ifdef USE_DOMOTICZ -#ifdef USE_WEBSERVER -const char HTTP_FORM_DOMOTICZ[] PROGMEM = - "
 " D_DOMOTICZ_PARAMETERS " " - "" - "
"; -const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = - "" - ""; - const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM = - ""; -const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM = - ""; -const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = - ""; -#endif // USE_WEBSERVER - const char DOMOTICZ_MESSAGE[] PROGMEM = "{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"%s\",\"Battery\":%d,\"RSSI\":%d}"; enum DomoticzCommands { CMND_IDX, CMND_KEYIDX, CMND_SWITCHIDX, CMND_SENSORIDX, CMND_UPDATETIMER }; @@ -386,14 +370,39 @@ void DomoticzSensorPowerEnergy(int power, char *energy) \*********************************************************************************************/ #ifdef USE_WEBSERVER + +#define WEB_HANDLE_DOMOTICZ "dm" + const char S_CONFIGURE_DOMOTICZ[] PROGMEM = D_CONFIGURE_DOMOTICZ; +const char HTTP_BTN_MENU_DOMOTICZ[] PROGMEM = + "
"; + +const char HTTP_FORM_DOMOTICZ[] PROGMEM = + "
 " D_DOMOTICZ_PARAMETERS " 
" + "
" D_DOMOTICZ_IDX " {1
" D_DOMOTICZ_KEY_IDX " {1
" D_DOMOTICZ_SWITCH_IDX " {1
" D_DOMOTICZ_SENSOR_IDX " {1 {2
" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")
"; +const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = + "" + ""; + const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM = + ""; +const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM = + ""; +const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = + ""; + void HandleDomoticzConfiguration() { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ); + if (WebServer->hasArg("save")) { + DomoticzSaveSettings(); + WaitForRestart(""); + return; + } + char stemp[32]; String page = FPSTR(HTTP_HEAD); @@ -474,6 +483,14 @@ boolean Xdrv07(byte function) if (Settings.flag.mqtt_enabled) { switch (function) { +#ifdef USE_WEBSERVER + case FUNC_WEB_ADD_BUTTON: + strncat_P(mqtt_data, HTTP_BTN_MENU_DOMOTICZ, sizeof(mqtt_data)); + break; + case FUNC_WEB_ADD_HANDLER: + WebServer->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration); + break; +#endif // USE_WEBSERVER case FUNC_COMMAND: result = DomoticzCommand(); break; diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index 124b41534..338a8ddc0 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -510,6 +510,14 @@ boolean TimerCommand() #ifdef USE_WEBSERVER #ifdef USE_TIMERS_WEB + +#define WEB_HANDLE_TIMER "tm" + +const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER; + +const char HTTP_BTN_MENU_TIMER[] PROGMEM = + "
"; + const char HTTP_TIMER_SCRIPT[] PROGMEM = "var pt=[],ct=99;" "function qs(s){" // Alias to save code space @@ -639,8 +647,7 @@ const char HTTP_TIMER_STYLE[] PROGMEM = #endif ""; const char HTTP_FORM_TIMER[] PROGMEM = - "
 " D_TIMER_PARAMETERS " 
" - "" + "
 " D_TIMER_PARAMETERS " " "
" D_TIMER_ENABLE "


" "requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TIMER); + if (WebServer->hasArg("save")) { + TimerSaveSettings(); + HandleConfiguration(); + return; + } + String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_TIMER)); page += FPSTR(HTTP_TIMER_SCRIPT); @@ -743,6 +754,20 @@ boolean Xdrv09(byte function) case FUNC_PRE_INIT: TimerSetRandomWindows(); break; +#ifdef USE_WEBSERVER +#ifdef USE_TIMERS_WEB + case FUNC_WEB_ADD_BUTTON: +#ifdef USE_RULES + strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data)); +#else + if (devices_present) { strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data)); } +#endif // USE_RULES + break; + case FUNC_WEB_ADD_HANDLER: + WebServer->on("/" WEB_HANDLE_TIMER, HandleTimerConfiguration); + break; +#endif // USE_TIMERS_WEB +#endif // USE_WEBSERVER case FUNC_EVERY_SECOND: TimerEverySecond(); break; diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 88260b23c..6132133ae 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -749,6 +749,9 @@ void KnxSensor(byte sensor_type, float value) #ifdef USE_KNX_WEB_MENU const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX; +const char HTTP_BTN_MENU_KNX[] PROGMEM = + "
"; + const char HTTP_FORM_KNX[] PROGMEM = "
 " D_KNX_PARAMETERS " 
" "
" @@ -784,7 +787,6 @@ const char HTTP_FORM_KNX_ADD_BTN[] PROGMEM = const char HTTP_FORM_KNX_ADD_TABLE_ROW[] PROGMEM = "
" -// ""; ""; const char HTTP_FORM_KNX3[] PROGMEM = @@ -797,10 +799,8 @@ const char HTTP_FORM_KNX4[] PROGMEM = const char HTTP_FORM_KNX_ADD_TABLE_ROW2[] PROGMEM = "" -// ""; ""; - void HandleKNXConfiguration() { if (HttpUser()) { return; } @@ -971,7 +971,7 @@ void HandleKNXConfiguration() } } page += F("
" D_DOMOTICZ_IDX " {1
" D_DOMOTICZ_KEY_IDX " {1
" D_DOMOTICZ_SWITCH_IDX " {1
" D_DOMOTICZ_SENSOR_IDX " {1 {2
" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")
{optex} -> GAfnum / GAarea / GAfdef
GAfnum / GAarea / GAfdef -> {optex}
"); - page += F("
"); + page += F("
"); page += FPSTR(HTTP_BTN_CONF); page.replace( F(""), @@ -1295,6 +1295,16 @@ boolean Xdrv11(byte function) case FUNC_PRE_INIT: KNX_INIT(); break; +#ifdef USE_WEBSERVER +#ifdef USE_KNX_WEB_MENU + case FUNC_WEB_ADD_BUTTON: + strncat_P(mqtt_data, HTTP_BTN_MENU_KNX, sizeof(mqtt_data)); + break; + case FUNC_WEB_ADD_HANDLER: + WebServer->on("/kn", HandleKNXConfiguration); + break; +#endif // USE_KNX_WEB_MENU +#endif // USE_WEBSERVER case FUNC_LOOP: knx.loop(); // Process knx events break; diff --git a/sonoff/xplg_wemohue.ino b/sonoff/xplg_wemohue.ino index f0b20ef59..d43ca90b1 100644 --- a/sonoff/xplg_wemohue.ino +++ b/sonoff/xplg_wemohue.ino @@ -835,4 +835,18 @@ void HandleHueApi(String *path) else if (path->endsWith("/rules")) HueNotImplemented(path); else HueGlobalConfig(path); } + +void HueWemoAddHandlers() +{ + if (EMUL_WEMO == Settings.flag2.emulation) { + WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); + WebServer->on("/eventservice.xml", HandleUpnpService); + WebServer->on("/metainfoservice.xml", HandleUpnpMetaService); + WebServer->on("/setup.xml", HandleUpnpSetupWemo); + } + if (EMUL_HUE == Settings.flag2.emulation) { + WebServer->on("/description.xml", HandleUpnpSetupHue); + } +} + #endif // USE_WEBSERVER && USE_EMULATION From 8aabe10711d9cbfff479d47358d13d684412f797 Mon Sep 17 00:00:00 2001 From: guyelg Date: Wed, 10 Oct 2018 20:25:04 +0300 Subject: [PATCH 50/66] Add support for DS3231-external I2C RTC --- sonoff/xsns_33_ds3231.ino | 191 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 sonoff/xsns_33_ds3231.ino diff --git a/sonoff/xsns_33_ds3231.ino b/sonoff/xsns_33_ds3231.ino new file mode 100644 index 000000000..df18c73db --- /dev/null +++ b/sonoff/xsns_33_ds3231.ino @@ -0,0 +1,191 @@ +/* + xsns_33_ds3231.ino - ds3231 RTC chip, act like sensor support for Sonoff-Tasmota + + Copyright (C) 2018 Guy Elgabsi (guy.elg AT gmail.com) + + 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 . +*/ + +#ifdef USE_I2C +#ifdef USE_DS3231 +/*********************************************************************************************\ + DS3231 - its a accurate RTC that used in the SONOFF for get time when you not have internet connection + This is minimal library that use only for read/write time ! + We store UTC time in the DS3231 , so we can use the standart functions. + HOWTO Use : first time, you must to have internet connection (use your mobile phone or try in other location). + once you have ntp connection , the DS3231 internal clock will be updated automatically. + you can now power off the device, from now and on the time is stored in the module and will + be restored when the is no connection to NTP. + Source: Guy Elgabsi with special thanks to Jack Christensen + + I2C Address: 0x68 + \*********************************************************************************************/ + +//DS3232 I2C Address +#ifndef USE_RTC_ADDR + #define USE_RTC_ADDR 0x68 +#endif + +//DS3232 Register Addresses +#define RTC_SECONDS 0x00 +#define RTC_MINUTES 0x01 +#define RTC_HOURS 0x02 +#define RTC_DAY 0x03 +#define RTC_DATE 0x04 +#define RTC_MONTH 0x05 +#define RTC_YEAR 0x06 +#define RTC_CONTROL 0x0E +#define RTC_STATUS 0x0F +//Control register bits +#define OSF 7 +#define EOSC 7 +#define BBSQW 6 +#define CONV 5 +#define RS2 4 +#define RS1 3 +#define INTCN 2 + +//Other +#define HR1224 6 //Hours register 12 or 24 hour mode (24 hour mode==0) +#define CENTURY 7 //Century bit in Month register +#define DYDT 6 //Day/Date flag bit in alarm Day/Date registers +boolean ds3231ReadStatus = false , ds3231WriteStatus = false; //flag, we want to wriet/write to DS3231 onlu once +boolean DS3231chipDetected; + + +/*----------------------------------------------------------------------* + Detect the DS3231 Chip + ----------------------------------------------------------------------*/ +boolean DS3231Detect() +{ + if (I2cValidRead(USE_RTC_ADDR, RTC_STATUS, 1)) + { + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "DS3231", USE_RTC_ADDR); + AddLog(LOG_LEVEL_INFO); + return true; + } + else + { + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "%s *NOT* " D_FOUND_AT " 0x%x"), "DS3231", USE_RTC_ADDR); + AddLog(LOG_LEVEL_INFO); + return false; + } +} + +/*----------------------------------------------------------------------* + BCD-to-Decimal conversion + ----------------------------------------------------------------------*/ +uint8_t bcd2dec(uint8_t n) +{ + return n - 6 * (n >> 4); +} + +/*----------------------------------------------------------------------* + Decimal-to-BCD conversion + ----------------------------------------------------------------------*/ +uint8_t dec2bcd(uint8_t n) +{ + return n + 6 * (n / 10); +} + +/*----------------------------------------------------------------------* + Read time from DS3231 and return the epoch time (second since 1-1-1970 00:00) + ----------------------------------------------------------------------*/ +uint32_t ReadFromDS3231() +{ + TIME_T tm; + tm.second = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_SECONDS)); + tm.minute = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_MINUTES)); + tm.hour = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_HOURS) & ~_BV(HR1224)); //assumes 24hr clock + tm.day_of_week = I2cRead8(USE_RTC_ADDR, RTC_DAY); + tm.day_of_month = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_DATE)); + tm.month = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_MONTH) & ~_BV(CENTURY)); //don't use the Century bit + tm.year = bcd2dec(I2cRead8(USE_RTC_ADDR, RTC_YEAR)); + return MakeTime(tm); +} +/*----------------------------------------------------------------------* + Get time as TIME_T and set the DS3231 time to this value + ----------------------------------------------------------------------*/ +void SetDS3231Time (uint32_t epoch_time) { + TIME_T tm; + BreakTime(epoch_time, tm); + I2cWrite8(USE_RTC_ADDR, RTC_SECONDS, dec2bcd(tm.second)); + I2cWrite8(USE_RTC_ADDR, RTC_MINUTES, dec2bcd(tm.minute)); + I2cWrite8(USE_RTC_ADDR, RTC_HOURS, dec2bcd(tm.hour)); + I2cWrite8(USE_RTC_ADDR, RTC_DAY, tm.day_of_week); + I2cWrite8(USE_RTC_ADDR, RTC_DATE, dec2bcd(tm.day_of_month)); + I2cWrite8(USE_RTC_ADDR, RTC_MONTH, dec2bcd(tm.month)); + I2cWrite8(USE_RTC_ADDR, RTC_YEAR, dec2bcd(tm.year)); + I2cWrite8(USE_RTC_ADDR, RTC_STATUS, I2cRead8(USE_RTC_ADDR, RTC_STATUS) & ~_BV(OSF)); //clear the Oscillator Stop Flag +} + +/*********************************************************************************************\ + Interface + \*********************************************************************************************/ + +#define XSNS_33 + +boolean Xsns33(byte function) +{ + boolean result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_INIT: + DS3231chipDetected = DS3231Detect(); + result = DS3231chipDetected; + break; + + case FUNC_EVERY_SECOND: + TIME_T tmpTime; + if (!ds3231ReadStatus && DS3231chipDetected && utc_time < 1451602800 ) { // We still did not sync with NTP (time not valid) , so, read time from DS3231 + ntp_force_sync = 1; //force to sync with ntp + utc_time = ReadFromDS3231(); //we read UTC TIME from DS3231 + // from this line, we just copy the function from "void RtcSecond()" at the support.ino ,line 2143 and above + // We need it to set rules etc. + BreakTime(utc_time, tmpTime); + if (utc_time < 1451602800 ) { + ds3231ReadStatus = true; //if time in DS3231 is valid, do not update again + } + RtcTime.year = tmpTime.year + 1970; + daylight_saving_time = RuleToTime(Settings.tflag[1], RtcTime.year); + standard_time = RuleToTime(Settings.tflag[0], RtcTime.year); + snprintf_P(log_data, sizeof(log_data), PSTR("Set time from DS3231 to RTC (" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), + GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str()); + AddLog(LOG_LEVEL_INFO); + if (local_time < 1451602800) { // 2016-01-01 + rules_flag.time_init = 1; + } else { + rules_flag.time_set = 1; + } + result = true; + } + else if (!ds3231WriteStatus && DS3231chipDetected && utc_time > 1451602800 && abs(utc_time - ReadFromDS3231()) > 60) {//if time is valid and is drift from RTC in more that 60 second + snprintf_P(log_data, sizeof(log_data), PSTR("Write Time TO DS3231 from NTP (" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), + GetTime(0).c_str(), GetTime(2).c_str(), GetTime(3).c_str()); + AddLog(LOG_LEVEL_INFO); + SetDS3231Time (utc_time); //update the DS3231 time + ds3231WriteStatus = true; + } + else { + result = false; + } + break; + } + } + return result; +} + +#endif // USE_DS3231 +#endif // USE_I2C From f98b4cf69d5e9f418d250de965bae1759bf3c03b Mon Sep 17 00:00:00 2001 From: guyelg Date: Wed, 10 Oct 2018 20:31:21 +0300 Subject: [PATCH 51/66] add support for DS3231 - I2C RTC --- sonoff/user_config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 0ed7eba35..46a98c4e3 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -322,6 +322,8 @@ #define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module + #define USE_DS3231 // Enable use DS3231 external RTC , usefall when you don't have avaliable WIFI. see docs in the source file (+1k2 code) +// #define USE_RTC_ADDR //you can change the addrsss of the DS3231 RTC, default is 0x68, not mandatory fieled #endif // USE_I2C From 633a45f964d0dbf4d29b7dbc418d5d2a4504f91f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 10 Oct 2018 19:41:08 +0200 Subject: [PATCH 52/66] Revert "6.2.1.14 Webserver rewrite" This reverts commit 077b8a79e15be9446c3a7f796e895a87628de0cc. --- sonoff/_changelog.ino | 5 +- sonoff/i18n.h | 1 + sonoff/sonoff.h | 2 +- sonoff/sonoff_version.h | 2 +- sonoff/{xdrv_02_mqtt.ino => xdrv_01_mqtt.ino} | 103 +--- ...01_webserver.ino => xdrv_02_webserver.ino} | 466 ++++++++++-------- sonoff/xdrv_07_domoticz.ino | 49 +- sonoff/xdrv_09_timers.ino | 33 +- sonoff/xdrv_11_knx.ino | 18 +- sonoff/xplg_wemohue.ino | 14 - 10 files changed, 304 insertions(+), 389 deletions(-) rename sonoff/{xdrv_02_mqtt.ino => xdrv_01_mqtt.ino} (86%) rename sonoff/{xdrv_01_webserver.ino => xdrv_02_webserver.ino} (84%) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index def41834a..b2210c830 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,7 +1,4 @@ -/* 6.2.1.14 20181010 - * Rewrite Webserver page handler for easier extension (thx to Adrian Scillato) - * - * 6.2.1.13 20181008 +/* 6.2.1.13 20181008 * Change default Mqtt client library from PubSubClient to non-blocking ArduinoMqtt by Joel Gaehwiler * Add command WebRefresh 1000..10000 to control web page refresh in milliseconds. Default is 2345 * diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 62226f91f..ab1f0a1d2 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -539,6 +539,7 @@ const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION; const char S_CONFIGURE_MODULE[] PROGMEM = D_CONFIGURE_MODULE; const char S_CONFIGURE_WIFI[] PROGMEM = D_CONFIGURE_WIFI; const char S_NO_NETWORKS_FOUND[] PROGMEM = D_NO_NETWORKS_FOUND; +const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT; const char S_CONFIGURE_LOGGING[] PROGMEM = D_CONFIGURE_LOGGING; const char S_CONFIGURE_OTHER[] PROGMEM = D_CONFIGURE_OTHER; const char S_SAVE_CONFIGURATION[] PROGMEM = D_SAVE_CONFIGURATION; diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 5bc744157..5d41aa18d 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -214,7 +214,7 @@ enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MA enum XsnsFunctions {FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART, FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR, - FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_HANDLER}; + FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM}; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 080c76fa4..eba7ddc21 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x0602010E +#define VERSION 0x0602010D #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/xdrv_02_mqtt.ino b/sonoff/xdrv_01_mqtt.ino similarity index 86% rename from sonoff/xdrv_02_mqtt.ino rename to sonoff/xdrv_01_mqtt.ino index 1cd6d9aff..3cb76e86d 100644 --- a/sonoff/xdrv_02_mqtt.ino +++ b/sonoff/xdrv_01_mqtt.ino @@ -1,5 +1,5 @@ /* - xdrv_02_mqtt.ino - mqtt support for Sonoff-Tasmota + xdrv_01_mqtt.ino - mqtt support for Sonoff-Tasmota Copyright (C) 2018 Theo Arends @@ -782,115 +782,18 @@ bool MqttCommand() return serviced; } -/*********************************************************************************************\ - * Presentation -\*********************************************************************************************/ - -#ifdef USE_WEBSERVER - -#define WEB_HANDLE_MQTT "mq" - -const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT; - -const char HTTP_BTN_MENU_MQTT[] PROGMEM = - "
"; - -const char HTTP_FORM_MQTT[] PROGMEM = - "
 " D_MQTT_PARAMETERS " 
" - "
" D_HOST " (" MQTT_HOST ")

" - "
" D_PORT " (" STR(MQTT_PORT) ")

" - "
" D_CLIENT " ({m0)

" - "
" D_USER " (" MQTT_USER ")

" - "
" D_PASSWORD "

" - "
" D_TOPIC " = %topic% (" MQTT_TOPIC ")

" - "
" D_FULL_TOPIC " (" MQTT_FULLTOPIC ")

"; - -void HandleMqttConfiguration() -{ - if (HttpUser()) { return; } - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT); - - if (WebServer->hasArg("save")) { - MqttSaveSettings(); - WaitForRestart(""); - return; - } - - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_MQTT)); - page += FPSTR(HTTP_HEAD_STYLE); - - page += FPSTR(HTTP_FORM_MQTT); - char str[sizeof(Settings.mqtt_client)]; - page.replace(F("{m0"), Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client))); - page.replace(F("{m1"), Settings.mqtt_host); - page.replace(F("{m2"), String(Settings.mqtt_port)); - page.replace(F("{m3"), Settings.mqtt_client); - page.replace(F("{m4"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user); - page.replace(F("{m5"), (Settings.mqtt_pwd[0] == '\0')?"0":Settings.mqtt_pwd); - page.replace(F("{m6"), Settings.mqtt_topic); - page.replace(F("{m7"), Settings.mqtt_fulltopic); - - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); -} - -void MqttSaveSettings() -{ - char tmp[100]; - char stemp[TOPSZ]; - char stemp2[TOPSZ]; - - WebGetArg("mt", tmp, sizeof(tmp)); - strlcpy(stemp, (!strlen(tmp)) ? MQTT_TOPIC : tmp, sizeof(stemp)); - MakeValidMqtt(0, stemp); - WebGetArg("mf", tmp, sizeof(tmp)); - strlcpy(stemp2, (!strlen(tmp)) ? MQTT_FULLTOPIC : tmp, sizeof(stemp2)); - MakeValidMqtt(1,stemp2); - if ((strcmp(stemp, Settings.mqtt_topic)) || (strcmp(stemp2, Settings.mqtt_fulltopic))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : ""); - MqttPublishPrefixTopic_P(TELE, S_LWT, true); // Offline or remove previous retained topic - } - strlcpy(Settings.mqtt_topic, stemp, sizeof(Settings.mqtt_topic)); - strlcpy(Settings.mqtt_fulltopic, stemp2, sizeof(Settings.mqtt_fulltopic)); - WebGetArg("mh", tmp, sizeof(tmp)); - strlcpy(Settings.mqtt_host, (!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_host)); - WebGetArg("ml", tmp, sizeof(tmp)); - Settings.mqtt_port = (!strlen(tmp)) ? MQTT_PORT : atoi(tmp); - WebGetArg("mc", tmp, sizeof(tmp)); - strlcpy(Settings.mqtt_client, (!strlen(tmp)) ? MQTT_CLIENT_ID : tmp, sizeof(Settings.mqtt_client)); - WebGetArg("mu", tmp, sizeof(tmp)); - strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user)); - WebGetArg("mp", tmp, sizeof(tmp)); - strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? MQTT_PASS : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_pwd)); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_MQTTPASSWORD " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"), - Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_pwd, Settings.mqtt_topic, Settings.mqtt_fulltopic); - AddLog(LOG_LEVEL_INFO); -} -#endif // USE_WEBSERVER - /*********************************************************************************************\ * Interface \*********************************************************************************************/ -#define XDRV_02 +#define XDRV_01 -boolean Xdrv02(byte function) +boolean Xdrv01(byte function) { boolean result = false; if (Settings.flag.mqtt_enabled) { switch (function) { -#ifdef USE_WEBSERVER - case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_MQTT, sizeof(mqtt_data)); - break; - case FUNC_WEB_ADD_HANDLER: - WebServer->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration); - break; -#endif // USE_WEBSERVER case FUNC_LOOP: MqttLoop(); break; diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_02_webserver.ino similarity index 84% rename from sonoff/xdrv_01_webserver.ino rename to sonoff/xdrv_02_webserver.ino index 50345145f..099411eba 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -1,5 +1,5 @@ /* - xdrv_01_webserver.ino - webserver for Sonoff-Tasmota + xdrv_02_webserver.ino - webserver for Sonoff-Tasmota Copyright (C) 2018 Theo Arends @@ -193,9 +193,25 @@ const char HTTP_BTN_MENU1[] PROGMEM = const char HTTP_BTN_RSTRT[] PROGMEM = "
"; const char HTTP_BTN_MENU_MODULE[] PROGMEM = - "
" - "
"; + "
"; +#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) +const char HTTP_BTN_MENU_TIMER[] PROGMEM = + "
"; +#endif // USE_TIMERS and USE_TIMERS_WEB +const char HTTP_BTN_MENU_WIFI[] PROGMEM = + "
"; +const char HTTP_BTN_MENU_MQTT[] PROGMEM = + "
" +#ifdef USE_DOMOTICZ + "
" +#endif // USE_DOMOTICZ + ""; const char HTTP_BTN_MENU4[] PROGMEM = +#ifdef USE_KNX +#ifdef USE_KNX_WEB_MENU + "
" +#endif // USE_KNX_WEB_MENU +#endif // USE_KNX "
" "
" "
" @@ -213,21 +229,34 @@ const char HTTP_FORM_LOGIN[] PROGMEM = const char HTTP_BTN_CONF[] PROGMEM = "

"; const char HTTP_FORM_MODULE[] PROGMEM = - "
 " D_MODULE_PARAMETERS " 
" + "
 " D_MODULE_PARAMETERS " " + "" "
" D_MODULE_TYPE " ({mt)

"; const char HTTP_LNK_ITEM[] PROGMEM = "
{v} ({w}) {i} {r}%
"; const char HTTP_LNK_SCAN[] PROGMEM = - "
"; + "
"; const char HTTP_FORM_WIFI[] PROGMEM = - "
 " D_WIFI_PARAMETERS " " + "
 " D_WIFI_PARAMETERS " " + "" "
" D_AP1_SSID " (" STA_SSID1 ")

" "
" D_AP1_PASSWORD "

" "
" D_AP2_SSID " (" STA_SSID2 ")

" "
" D_AP2_PASSWORD "

" "
" D_HOSTNAME " (" WIFI_HOSTNAME ")

"; +const char HTTP_FORM_MQTT[] PROGMEM = + "
 " D_MQTT_PARAMETERS " " + "" + "
" D_HOST " (" MQTT_HOST ")

" + "
" D_PORT " (" STR(MQTT_PORT) ")

" + "
" D_CLIENT " ({m0)

" + "
" D_USER " (" MQTT_USER ")

" + "
" D_PASSWORD "

" + "
" D_TOPIC " = %topic% (" MQTT_TOPIC ")

" + "
" D_FULL_TOPIC " (" MQTT_FULLTOPIC ")

"; const char HTTP_FORM_LOG1[] PROGMEM = - "
 " D_LOGGING_PARAMETERS " "; + "
 " D_LOGGING_PARAMETERS " " + ""; const char HTTP_FORM_LOG2[] PROGMEM = "
{b0 ({b1)

" "
" D_TELEMETRY_PERIOD " (" STR(TELE_PERIOD) ")

"; const char HTTP_FORM_OTHER[] PROGMEM = - "
 " D_OTHER_PARAMETERS " " -// "" + "
 " D_OTHER_PARAMETERS " " + "" "
" D_WEB_ADMIN_PASSWORD "

" "
" D_MQTT_ENABLE "
"; const char HTTP_FORM_OTHER2[] PROGMEM = @@ -254,7 +283,7 @@ const char HTTP_FORM_OTHER3b[] PROGMEM = "
{3{4"; // Different id only used for labels #endif // USE_EMULATION const char HTTP_FORM_END[] PROGMEM = - "
"; + "
"; const char HTTP_FORM_RST[] PROGMEM = "
" "
 " D_RESTORE_CONFIGURATION " "; @@ -354,23 +383,46 @@ void StartWebserver(int type, IPAddress ipweb) WebServer->on("/ay", HandleAjaxStatusRefresh); WebServer->on("/cm", HandleHttpCommand); WebServer->on("/rb", HandleRestart); -// WebServer->on("/fwlink", HandleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. - WebServer->onNotFound(HandleNotFound); #ifndef BE_MINIMAL WebServer->on("/cn", HandleConfiguration); WebServer->on("/md", HandleModuleConfiguration); - WebServer->on("/wi", HandleWifiConfiguration); +#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) + WebServer->on("/tm", HandleTimerConfiguration); +#endif // USE_TIMERS and USE_TIMERS_WEB + WebServer->on("/w1", HandleWifiConfigurationWithScan); + WebServer->on("/w0", HandleWifiConfiguration); + if (Settings.flag.mqtt_enabled) { + WebServer->on("/mq", HandleMqttConfiguration); +#ifdef USE_DOMOTICZ + WebServer->on("/dm", HandleDomoticzConfiguration); +#endif // USE_DOMOTICZ + } +#ifdef USE_KNX +#ifdef USE_KNX_WEB_MENU + WebServer->on("/kn", HandleKNXConfiguration); +#endif // USE_KNX_WEB_MENU +#endif // USE_KNX WebServer->on("/lg", HandleLoggingConfiguration); WebServer->on("/co", HandleOtherConfiguration); WebServer->on("/dl", HandleBackupConfiguration); + WebServer->on("/sv", HandleSaveSettings); WebServer->on("/rs", HandleRestoreConfiguration); WebServer->on("/rt", HandleResetConfiguration); WebServer->on("/in", HandleInformation); #ifdef USE_EMULATION - HueWemoAddHandlers(); + if (EMUL_WEMO == Settings.flag2.emulation) { + WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); + WebServer->on("/eventservice.xml", HandleUpnpService); + WebServer->on("/metainfoservice.xml", HandleUpnpMetaService); + WebServer->on("/setup.xml", HandleUpnpSetupWemo); + } + if (EMUL_HUE == Settings.flag2.emulation) { + WebServer->on("/description.xml", HandleUpnpSetupHue); + } #endif // USE_EMULATION - XdrvCall(FUNC_WEB_ADD_HANDLER); #endif // Not BE_MINIMAL + WebServer->on("/fwlink", HandleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. + WebServer->onNotFound(HandleNotFound); } reset_web_log_flag = 0; WebServer->begin(); // Web server start @@ -645,30 +697,7 @@ boolean HttpUser() return status; } -/*-------------------------------------------------------------------------------------------*/ - #ifndef BE_MINIMAL - -void WaitForRestart(String result) -{ - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_SAVE_CONFIGURATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += F("
" D_CONFIGURATION_SAVED "
"); - page += result; - page += F("
"); - page += FPSTR(HTTP_MSG_RSTRT); - if (HTTP_MANAGER == webserver_state) { - webserver_state = HTTP_ADMIN; - } else { - page += FPSTR(HTTP_BTN_MAIN); - } - ShowPage(page); - - ShowWebSource(SRC_WEBGUI); - restart_flag = 2; -} - void HandleConfiguration() { if (HttpUser()) { return; } @@ -679,34 +708,29 @@ void HandleConfiguration() page.replace(F("{v}"), FPSTR(S_CONFIGURATION)); page += FPSTR(HTTP_HEAD_STYLE); page += FPSTR(HTTP_BTN_MENU_MODULE); - - mqtt_data[0] = '\0'; - XdrvCall(FUNC_WEB_ADD_BUTTON); - page += String(mqtt_data); - +#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) +#ifdef USE_RULES + page += FPSTR(HTTP_BTN_MENU_TIMER); +#else + if (devices_present) { page += FPSTR(HTTP_BTN_MENU_TIMER); } +#endif // USE_RULES +#endif // USE_TIMERS and USE_TIMERS_WEB + page += FPSTR(HTTP_BTN_MENU_WIFI); + if (Settings.flag.mqtt_enabled) { page += FPSTR(HTTP_BTN_MENU_MQTT); } page += FPSTR(HTTP_BTN_MENU4); page += FPSTR(HTTP_BTN_MAIN); ShowPage(page); } -/*-------------------------------------------------------------------------------------------*/ - void HandleModuleConfiguration() { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } - - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MODULE); - - if (WebServer->hasArg("save")) { - ModuleSaveSettings(); - WaitForRestart(""); - return; - } - char stemp[20]; uint8_t midx; + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MODULE); + String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_MODULE)); page += FPSTR(HTTP_SCRIPT_MODULE1); @@ -759,36 +783,15 @@ void HandleModuleConfiguration() ShowPage(page); } -void ModuleSaveSettings() +void HandleWifiConfigurationWithScan() { - char tmp[100]; - char stemp[TOPSZ]; - - WebGetArg("g99", tmp, sizeof(tmp)); - byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp); - Settings.last_module = Settings.module; - Settings.module = new_module; - mytmplt cmodule; - memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule)); - String gpios = ""; - for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if (Settings.last_module != new_module) { - Settings.my_gp.io[i] = 0; - } else { - if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) { - snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i); - WebGetArg(stemp, tmp, sizeof(tmp)); - Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]); - } - } - } - snprintf_P(stemp, sizeof(stemp), kModules[Settings.module].name); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), stemp, gpios.c_str()); - AddLog(LOG_LEVEL_INFO); + HandleWifi(true); } -/*-------------------------------------------------------------------------------------------*/ +void HandleWifiConfiguration() +{ + HandleWifi(false); +} String htmlEscape(String s) { @@ -801,25 +804,18 @@ String htmlEscape(String s) return s; } -void HandleWifiConfiguration() +void HandleWifi(boolean scan) { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI); - if (WebServer->hasArg("save")) { - WifiSaveSettings(); - String result = F("
" D_TRYING_TO_CONNECT "
"); - WaitForRestart(result); - return; - } - String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_WIFI)); page += FPSTR(HTTP_HEAD_STYLE); - if (WebServer->hasArg("scan")) { + if (scan) { #ifdef USE_EMULATION UdpDisconnect(); #endif // USE_EMULATION @@ -905,46 +901,39 @@ void HandleWifiConfiguration() ShowPage(page, !(HTTP_MANAGER == webserver_state)); } -void WifiSaveSettings() +void HandleMqttConfiguration() { - char tmp[100]; + if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT); - WebGetArg("h", tmp, sizeof(tmp)); - strlcpy(Settings.hostname, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp, sizeof(Settings.hostname)); - if (strstr(Settings.hostname,"%")) { - strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname)); - } - WebGetArg("s1", tmp, sizeof(tmp)); - strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? STA_SSID1 : tmp, sizeof(Settings.sta_ssid[0])); - WebGetArg("s2", tmp, sizeof(tmp)); - strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1])); - WebGetArg("p1", tmp, sizeof(tmp)); - strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0])); - WebGetArg("p2", tmp, sizeof(tmp)); - strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1])); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"), - Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]); - AddLog(LOG_LEVEL_INFO); + String page = FPSTR(HTTP_HEAD); + page.replace(F("{v}"), FPSTR(S_CONFIGURE_MQTT)); + page += FPSTR(HTTP_HEAD_STYLE); + page += FPSTR(HTTP_FORM_MQTT); + char str[sizeof(Settings.mqtt_client)]; + page.replace(F("{m0"), Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client))); + page.replace(F("{m1"), Settings.mqtt_host); + page.replace(F("{m2"), String(Settings.mqtt_port)); + page.replace(F("{m3"), Settings.mqtt_client); + page.replace(F("{m4"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user); + page.replace(F("{m5"), (Settings.mqtt_pwd[0] == '\0')?"0":Settings.mqtt_pwd); + page.replace(F("{m6"), Settings.mqtt_topic); + page.replace(F("{m7"), Settings.mqtt_fulltopic); + page += FPSTR(HTTP_FORM_END); + page += FPSTR(HTTP_BTN_CONF); + ShowPage(page); } -/*-------------------------------------------------------------------------------------------*/ - void HandleLoggingConfiguration() { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_LOGGING); - if (WebServer->hasArg("save")) { - LoggingSaveSettings(); - HandleConfiguration(); - return; - } - String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_LOGGING)); page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_LOG1); for (byte idx = 0; idx < 3; idx++) { page += FPSTR(HTTP_FORM_LOG2); @@ -984,46 +973,11 @@ void HandleLoggingConfiguration() ShowPage(page); } -void LoggingSaveSettings() -{ - char tmp[100]; - - WebGetArg("ls", tmp, sizeof(tmp)); - Settings.seriallog_level = (!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp); - WebGetArg("lw", tmp, sizeof(tmp)); - Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp); - WebGetArg("ll", tmp, sizeof(tmp)); - Settings.syslog_level = (!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp); - syslog_level = Settings.syslog_level; - syslog_timer = 0; - WebGetArg("lh", tmp, sizeof(tmp)); - strlcpy(Settings.syslog_host, (!strlen(tmp)) ? SYS_LOG_HOST : tmp, sizeof(Settings.syslog_host)); - WebGetArg("lp", tmp, sizeof(tmp)); - Settings.syslog_port = (!strlen(tmp)) ? SYS_LOG_PORT : atoi(tmp); - WebGetArg("lt", tmp, sizeof(tmp)); - Settings.tele_period = (!strlen(tmp)) ? TELE_PERIOD : atoi(tmp); - if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) { - Settings.tele_period = 10; // Do not allow periods < 10 seconds - } - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"), - Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period); - AddLog(LOG_LEVEL_INFO); -} - -/*-------------------------------------------------------------------------------------------*/ - void HandleOtherConfiguration() { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_OTHER); - - if (WebServer->hasArg("save")) { - OtherSaveSettings(); - WaitForRestart(""); - return; - } - char stemp[40]; String page = FPSTR(HTTP_HEAD); @@ -1057,32 +1011,6 @@ void HandleOtherConfiguration() ShowPage(page); } -void OtherSaveSettings() -{ - char tmp[100]; - char stemp[TOPSZ]; - char stemp2[TOPSZ]; - - WebGetArg("p1", tmp, sizeof(tmp)); - strlcpy(Settings.web_password, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.web_password : tmp, sizeof(Settings.web_password)); - Settings.flag.mqtt_enabled = WebServer->hasArg("b1"); -#ifdef USE_EMULATION - WebGetArg("b2", tmp, sizeof(tmp)); - Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp); -#endif // USE_EMULATION - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation); - for (byte i = 0; i < MAX_FRIENDLYNAMES; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("a%d"), i +1); - WebGetArg(stemp, tmp, sizeof(tmp)); - snprintf_P(stemp2, sizeof(stemp2), PSTR(FRIENDLY_NAME"%d"), i +1); - strlcpy(Settings.friendlyname[i], (!strlen(tmp)) ? (i) ? stemp2 : FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[i])); - snprintf_P(log_data, sizeof(log_data), PSTR("%s%s %s"), log_data, (i) ? "," : "", Settings.friendlyname[i]); - } - AddLog(LOG_LEVEL_INFO); -} - -/*-------------------------------------------------------------------------------------------*/ - void HandleBackupConfiguration() { if (HttpUser()) { return; } @@ -1125,7 +1053,171 @@ void HandleBackupConfiguration() Settings.cfg_crc = cfg_crc; // Restore crc in case savedata = 0 to make sure settings will be noted as changed } -/*-------------------------------------------------------------------------------------------*/ +void HandleSaveSettings() +{ + if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + + char stemp[TOPSZ]; + char stemp2[TOPSZ]; + String result = ""; + + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_SAVE_CONFIGURATION); + + char tmp[100]; + WebGetArg("w", tmp, sizeof(tmp)); // Returns "5,1" where 5 is config type and 1 is restart flag + char *p = tmp; + uint8_t what = strtol(p, &p, 10); + p++; // Skip comma + uint8_t restart = strtol(p, &p, 10); + switch (what) { + case 1: + WebGetArg("h", tmp, sizeof(tmp)); + strlcpy(Settings.hostname, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp, sizeof(Settings.hostname)); + if (strstr(Settings.hostname,"%")) { + strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname)); + } + WebGetArg("s1", tmp, sizeof(tmp)); + strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? STA_SSID1 : tmp, sizeof(Settings.sta_ssid[0])); + WebGetArg("s2", tmp, sizeof(tmp)); + strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1])); +// WebGetArg("s1", tmp, sizeof(tmp)); +// strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[0])); +// WebGetArg("s2", tmp, sizeof(tmp)); +// strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[1])); + WebGetArg("p1", tmp, sizeof(tmp)); + strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0])); + WebGetArg("p2", tmp, sizeof(tmp)); + strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1])); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"), + Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]); + AddLog(LOG_LEVEL_INFO); + result += F("
" D_TRYING_TO_CONNECT "
"); + break; + case 2: + WebGetArg("mt", tmp, sizeof(tmp)); + strlcpy(stemp, (!strlen(tmp)) ? MQTT_TOPIC : tmp, sizeof(stemp)); + MakeValidMqtt(0, stemp); + WebGetArg("mf", tmp, sizeof(tmp)); + strlcpy(stemp2, (!strlen(tmp)) ? MQTT_FULLTOPIC : tmp, sizeof(stemp2)); + MakeValidMqtt(1,stemp2); + if ((strcmp(stemp, Settings.mqtt_topic)) || (strcmp(stemp2, Settings.mqtt_fulltopic))) { + snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : ""); + MqttPublishPrefixTopic_P(TELE, S_LWT, true); // Offline or remove previous retained topic + } + strlcpy(Settings.mqtt_topic, stemp, sizeof(Settings.mqtt_topic)); + strlcpy(Settings.mqtt_fulltopic, stemp2, sizeof(Settings.mqtt_fulltopic)); + WebGetArg("mh", tmp, sizeof(tmp)); + strlcpy(Settings.mqtt_host, (!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_host)); + WebGetArg("ml", tmp, sizeof(tmp)); + Settings.mqtt_port = (!strlen(tmp)) ? MQTT_PORT : atoi(tmp); + WebGetArg("mc", tmp, sizeof(tmp)); + strlcpy(Settings.mqtt_client, (!strlen(tmp)) ? MQTT_CLIENT_ID : tmp, sizeof(Settings.mqtt_client)); + WebGetArg("mu", tmp, sizeof(tmp)); + strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user)); + WebGetArg("mp", tmp, sizeof(tmp)); + strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? MQTT_PASS : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_pwd)); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_MQTTPASSWORD " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"), + Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_pwd, Settings.mqtt_topic, Settings.mqtt_fulltopic); + AddLog(LOG_LEVEL_INFO); + break; + case 3: + WebGetArg("ls", tmp, sizeof(tmp)); + Settings.seriallog_level = (!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp); + WebGetArg("lw", tmp, sizeof(tmp)); + Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp); + WebGetArg("ll", tmp, sizeof(tmp)); + Settings.syslog_level = (!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp); + syslog_level = Settings.syslog_level; + syslog_timer = 0; + WebGetArg("lh", tmp, sizeof(tmp)); + strlcpy(Settings.syslog_host, (!strlen(tmp)) ? SYS_LOG_HOST : tmp, sizeof(Settings.syslog_host)); + WebGetArg("lp", tmp, sizeof(tmp)); + Settings.syslog_port = (!strlen(tmp)) ? SYS_LOG_PORT : atoi(tmp); + WebGetArg("lt", tmp, sizeof(tmp)); + Settings.tele_period = (!strlen(tmp)) ? TELE_PERIOD : atoi(tmp); + if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) { + Settings.tele_period = 10; // Do not allow periods < 10 seconds + } + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"), + Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period); + AddLog(LOG_LEVEL_INFO); + break; +#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB) + case 7: + TimerSaveSettings(); + break; +#endif // USE_TIMERS and USE_TIMERS_WEB +#ifdef USE_DOMOTICZ + case 4: + DomoticzSaveSettings(); + break; +#endif // USE_DOMOTICZ + case 5: + WebGetArg("p1", tmp, sizeof(tmp)); + strlcpy(Settings.web_password, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.web_password : tmp, sizeof(Settings.web_password)); + Settings.flag.mqtt_enabled = WebServer->hasArg("b1"); +#ifdef USE_EMULATION + WebGetArg("b2", tmp, sizeof(tmp)); + Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp); +#endif // USE_EMULATION + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation); + for (byte i = 0; i < MAX_FRIENDLYNAMES; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("a%d"), i +1); + WebGetArg(stemp, tmp, sizeof(tmp)); + snprintf_P(stemp2, sizeof(stemp2), PSTR(FRIENDLY_NAME"%d"), i +1); + strlcpy(Settings.friendlyname[i], (!strlen(tmp)) ? (i) ? stemp2 : FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[i])); + snprintf_P(log_data, sizeof(log_data), PSTR("%s%s %s"), log_data, (i) ? "," : "", Settings.friendlyname[i]); + } + AddLog(LOG_LEVEL_INFO); + break; + case 6: + WebGetArg("g99", tmp, sizeof(tmp)); + byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp); + Settings.last_module = Settings.module; + Settings.module = new_module; + mytmplt cmodule; + memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule)); + String gpios = ""; + for (byte i = 0; i < MAX_GPIO_PIN; i++) { + if (Settings.last_module != new_module) { + Settings.my_gp.io[i] = 0; + } else { + if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) { + snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i); + WebGetArg(stemp, tmp, sizeof(tmp)); + Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp); + gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]); + } + } + } + snprintf_P(stemp, sizeof(stemp), kModules[Settings.module].name); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), stemp, gpios.c_str()); + AddLog(LOG_LEVEL_INFO); + break; + } + + if (restart) { + String page = FPSTR(HTTP_HEAD); + page.replace(F("{v}"), FPSTR(S_SAVE_CONFIGURATION)); + page += FPSTR(HTTP_HEAD_STYLE); + page += F("
" D_CONFIGURATION_SAVED "
"); + page += result; + page += F("
"); + page += FPSTR(HTTP_MSG_RSTRT); + if (HTTP_MANAGER == webserver_state) { + webserver_state = HTTP_ADMIN; + } else { + page += FPSTR(HTTP_BTN_MAIN); + } + ShowPage(page); + + ShowWebSource(SRC_WEBGUI); + restart_flag = 2; + } else { + HandleConfiguration(); + } +} void HandleResetConfiguration() { @@ -1167,8 +1259,6 @@ void HandleRestoreConfiguration() upload_file_type = UPL_SETTINGS; } -/*-------------------------------------------------------------------------------------------*/ - void HandleInformation() { if (HttpUser()) { return; } @@ -1286,8 +1376,6 @@ void HandleInformation() } #endif // Not BE_MINIMAL -/*-------------------------------------------------------------------------------------------*/ - void HandleUpgradeFirmware() { if (HttpUser()) { return; } @@ -1581,8 +1669,6 @@ void HandleUploadLoop() delay(0); } -/*-------------------------------------------------------------------------------------------*/ - void HandlePreflightRequest() { WebServer->sendHeader(F("Access-Control-Allow-Origin"), F("*")); @@ -1591,8 +1677,6 @@ void HandlePreflightRequest() WebServer->send(200, FPSTR(HDR_CTYPE_HTML), ""); } -/*-------------------------------------------------------------------------------------------*/ - void HandleHttpCommand() { if (HttpUser()) { return; } @@ -1651,8 +1735,6 @@ void HandleHttpCommand() WebServer->send(200, FPSTR(HDR_CTYPE_JSON), message); } -/*-------------------------------------------------------------------------------------------*/ - void HandleConsole() { if (HttpUser()) { return; } @@ -1726,8 +1808,6 @@ void HandleAjaxConsoleRefresh() WebServer->send(200, FPSTR(HDR_CTYPE_XML), message); } -/*-------------------------------------------------------------------------------------------*/ - void HandleRestart() { if (HttpUser()) { return; } @@ -1981,9 +2061,9 @@ bool WebCommand() * Interface \*********************************************************************************************/ -#define XDRV_01 +#define XDRV_02 -boolean Xdrv01(byte function) +boolean Xdrv02(byte function) { boolean result = false; diff --git a/sonoff/xdrv_07_domoticz.ino b/sonoff/xdrv_07_domoticz.ino index d40bae88f..7710cad13 100644 --- a/sonoff/xdrv_07_domoticz.ino +++ b/sonoff/xdrv_07_domoticz.ino @@ -19,6 +19,22 @@ #ifdef USE_DOMOTICZ +#ifdef USE_WEBSERVER +const char HTTP_FORM_DOMOTICZ[] PROGMEM = + "
 " D_DOMOTICZ_PARAMETERS " 
" + "" + "
"; +const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = + "" + ""; + const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM = + ""; +const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM = + ""; +const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = + ""; +#endif // USE_WEBSERVER + const char DOMOTICZ_MESSAGE[] PROGMEM = "{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"%s\",\"Battery\":%d,\"RSSI\":%d}"; enum DomoticzCommands { CMND_IDX, CMND_KEYIDX, CMND_SWITCHIDX, CMND_SENSORIDX, CMND_UPDATETIMER }; @@ -370,39 +386,14 @@ void DomoticzSensorPowerEnergy(int power, char *energy) \*********************************************************************************************/ #ifdef USE_WEBSERVER - -#define WEB_HANDLE_DOMOTICZ "dm" - const char S_CONFIGURE_DOMOTICZ[] PROGMEM = D_CONFIGURE_DOMOTICZ; -const char HTTP_BTN_MENU_DOMOTICZ[] PROGMEM = - "
"; - -const char HTTP_FORM_DOMOTICZ[] PROGMEM = - "
 " D_DOMOTICZ_PARAMETERS " 
" - "
" D_DOMOTICZ_IDX " {1
" D_DOMOTICZ_KEY_IDX " {1
" D_DOMOTICZ_SWITCH_IDX " {1
" D_DOMOTICZ_SENSOR_IDX " {1 {2
" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")
"; -const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = - "" - ""; - const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM = - ""; -const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM = - ""; -const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = - ""; - void HandleDomoticzConfiguration() { if (HttpUser()) { return; } if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ); - if (WebServer->hasArg("save")) { - DomoticzSaveSettings(); - WaitForRestart(""); - return; - } - char stemp[32]; String page = FPSTR(HTTP_HEAD); @@ -483,14 +474,6 @@ boolean Xdrv07(byte function) if (Settings.flag.mqtt_enabled) { switch (function) { -#ifdef USE_WEBSERVER - case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_DOMOTICZ, sizeof(mqtt_data)); - break; - case FUNC_WEB_ADD_HANDLER: - WebServer->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration); - break; -#endif // USE_WEBSERVER case FUNC_COMMAND: result = DomoticzCommand(); break; diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index 338a8ddc0..124b41534 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -510,14 +510,6 @@ boolean TimerCommand() #ifdef USE_WEBSERVER #ifdef USE_TIMERS_WEB - -#define WEB_HANDLE_TIMER "tm" - -const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER; - -const char HTTP_BTN_MENU_TIMER[] PROGMEM = - "
"; - const char HTTP_TIMER_SCRIPT[] PROGMEM = "var pt=[],ct=99;" "function qs(s){" // Alias to save code space @@ -647,7 +639,8 @@ const char HTTP_TIMER_STYLE[] PROGMEM = #endif ""; const char HTTP_FORM_TIMER[] PROGMEM = - "
 " D_TIMER_PARAMETERS " 
" + "
 " D_TIMER_PARAMETERS " " + "" "
" D_TIMER_ENABLE "


" "requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TIMER); - if (WebServer->hasArg("save")) { - TimerSaveSettings(); - HandleConfiguration(); - return; - } - String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_TIMER)); page += FPSTR(HTTP_TIMER_SCRIPT); @@ -754,20 +743,6 @@ boolean Xdrv09(byte function) case FUNC_PRE_INIT: TimerSetRandomWindows(); break; -#ifdef USE_WEBSERVER -#ifdef USE_TIMERS_WEB - case FUNC_WEB_ADD_BUTTON: -#ifdef USE_RULES - strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data)); -#else - if (devices_present) { strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data)); } -#endif // USE_RULES - break; - case FUNC_WEB_ADD_HANDLER: - WebServer->on("/" WEB_HANDLE_TIMER, HandleTimerConfiguration); - break; -#endif // USE_TIMERS_WEB -#endif // USE_WEBSERVER case FUNC_EVERY_SECOND: TimerEverySecond(); break; diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 6132133ae..88260b23c 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -749,9 +749,6 @@ void KnxSensor(byte sensor_type, float value) #ifdef USE_KNX_WEB_MENU const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX; -const char HTTP_BTN_MENU_KNX[] PROGMEM = - "
"; - const char HTTP_FORM_KNX[] PROGMEM = "
 " D_KNX_PARAMETERS " 
" "
" @@ -787,6 +784,7 @@ const char HTTP_FORM_KNX_ADD_BTN[] PROGMEM = const char HTTP_FORM_KNX_ADD_TABLE_ROW[] PROGMEM = "
" +// ""; ""; const char HTTP_FORM_KNX3[] PROGMEM = @@ -799,8 +797,10 @@ const char HTTP_FORM_KNX4[] PROGMEM = const char HTTP_FORM_KNX_ADD_TABLE_ROW2[] PROGMEM = "" +// ""; ""; + void HandleKNXConfiguration() { if (HttpUser()) { return; } @@ -971,7 +971,7 @@ void HandleKNXConfiguration() } } page += F("
" D_DOMOTICZ_IDX " {1
" D_DOMOTICZ_KEY_IDX " {1
" D_DOMOTICZ_SWITCH_IDX " {1
" D_DOMOTICZ_SENSOR_IDX " {1 {2
" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")
{optex} -> GAfnum / GAarea / GAfdef
GAfnum / GAarea / GAfdef -> {optex}
"); - page += F("
"); + page += F("
"); page += FPSTR(HTTP_BTN_CONF); page.replace( F(""), @@ -1295,16 +1295,6 @@ boolean Xdrv11(byte function) case FUNC_PRE_INIT: KNX_INIT(); break; -#ifdef USE_WEBSERVER -#ifdef USE_KNX_WEB_MENU - case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_KNX, sizeof(mqtt_data)); - break; - case FUNC_WEB_ADD_HANDLER: - WebServer->on("/kn", HandleKNXConfiguration); - break; -#endif // USE_KNX_WEB_MENU -#endif // USE_WEBSERVER case FUNC_LOOP: knx.loop(); // Process knx events break; diff --git a/sonoff/xplg_wemohue.ino b/sonoff/xplg_wemohue.ino index d43ca90b1..f0b20ef59 100644 --- a/sonoff/xplg_wemohue.ino +++ b/sonoff/xplg_wemohue.ino @@ -835,18 +835,4 @@ void HandleHueApi(String *path) else if (path->endsWith("/rules")) HueNotImplemented(path); else HueGlobalConfig(path); } - -void HueWemoAddHandlers() -{ - if (EMUL_WEMO == Settings.flag2.emulation) { - WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); - WebServer->on("/eventservice.xml", HandleUpnpService); - WebServer->on("/metainfoservice.xml", HandleUpnpMetaService); - WebServer->on("/setup.xml", HandleUpnpSetupWemo); - } - if (EMUL_HUE == Settings.flag2.emulation) { - WebServer->on("/description.xml", HandleUpnpSetupHue); - } -} - #endif // USE_WEBSERVER && USE_EMULATION From 5684c844aa3b6a6f77a6a1b22d07137cd0c8c469 Mon Sep 17 00:00:00 2001 From: guyelg Date: Wed, 10 Oct 2018 20:54:26 +0300 Subject: [PATCH 53/66] fix address in user_config.h --- sonoff/user_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 46a98c4e3..d2f89d9b9 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -323,7 +323,7 @@ #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module #define USE_DS3231 // Enable use DS3231 external RTC , usefall when you don't have avaliable WIFI. see docs in the source file (+1k2 code) -// #define USE_RTC_ADDR //you can change the addrsss of the DS3231 RTC, default is 0x68, not mandatory fieled +// #define USE_RTC_ADDR 0x68 //you can change the addrsss of the DS3231 RTC, default is 0x68, not mandatory fieled #endif // USE_I2C From 9c77d1d7610e2118927021f09119ac64cb5f88a4 Mon Sep 17 00:00:00 2001 From: guyelg Date: Wed, 10 Oct 2018 21:01:07 +0300 Subject: [PATCH 54/66] disable the sensor by default --- sonoff/user_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index d2f89d9b9..f37f8dc63 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -322,7 +322,7 @@ #define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module - #define USE_DS3231 // Enable use DS3231 external RTC , usefall when you don't have avaliable WIFI. see docs in the source file (+1k2 code) +// #define USE_DS3231 // Enable use DS3231 external RTC , usefall when you don't have avaliable WIFI. see docs in the source file (+1k2 code) // #define USE_RTC_ADDR 0x68 //you can change the addrsss of the DS3231 RTC, default is 0x68, not mandatory fieled #endif // USE_I2C From b3039de1b6b844ff5987e23ebf27ad5a06b6763c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 10 Oct 2018 22:21:44 +0200 Subject: [PATCH 55/66] 6.2.1.14 Rewrite Webserver 6.2.1.14 20181010 * Rewrite Webserver page handler for easier extension (thx to Adrian Scillato) --- sonoff/_changelog.ino | 5 +- sonoff/i18n.h | 1 - sonoff/sonoff.h | 2 +- sonoff/sonoff_version.h | 2 +- sonoff/xdrv_01_webserver.ino | 2003 ++++++++++++++++++++++++++++++++++ sonoff/xdrv_02_mqtt.ino | 903 +++++++++++++++ sonoff/xdrv_07_domoticz.ino | 49 +- sonoff/xdrv_09_timers.ino | 33 +- sonoff/xdrv_11_knx.ino | 18 +- sonoff/xplg_wemohue.ino | 14 + 10 files changed, 3002 insertions(+), 28 deletions(-) create mode 100644 sonoff/xdrv_01_webserver.ino create mode 100644 sonoff/xdrv_02_mqtt.ino diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index b2210c830..def41834a 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,7 @@ -/* 6.2.1.13 20181008 +/* 6.2.1.14 20181010 + * Rewrite Webserver page handler for easier extension (thx to Adrian Scillato) + * + * 6.2.1.13 20181008 * Change default Mqtt client library from PubSubClient to non-blocking ArduinoMqtt by Joel Gaehwiler * Add command WebRefresh 1000..10000 to control web page refresh in milliseconds. Default is 2345 * diff --git a/sonoff/i18n.h b/sonoff/i18n.h index ab1f0a1d2..62226f91f 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -539,7 +539,6 @@ const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION; const char S_CONFIGURE_MODULE[] PROGMEM = D_CONFIGURE_MODULE; const char S_CONFIGURE_WIFI[] PROGMEM = D_CONFIGURE_WIFI; const char S_NO_NETWORKS_FOUND[] PROGMEM = D_NO_NETWORKS_FOUND; -const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT; const char S_CONFIGURE_LOGGING[] PROGMEM = D_CONFIGURE_LOGGING; const char S_CONFIGURE_OTHER[] PROGMEM = D_CONFIGURE_OTHER; const char S_SAVE_CONFIGURATION[] PROGMEM = D_SAVE_CONFIGURATION; diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 5d41aa18d..5bc744157 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -214,7 +214,7 @@ enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MA enum XsnsFunctions {FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART, FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR, - FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM}; + FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_HANDLER}; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index eba7ddc21..080c76fa4 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x0602010D +#define VERSION 0x0602010E #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino new file mode 100644 index 000000000..50345145f --- /dev/null +++ b/sonoff/xdrv_01_webserver.ino @@ -0,0 +1,2003 @@ +/* + xdrv_01_webserver.ino - webserver for Sonoff-Tasmota + + Copyright (C) 2018 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 . +*/ + +#ifdef USE_WEBSERVER +/*********************************************************************************************\ + * Web server and WiFi Manager + * + * Enables configuration and reconfiguration of WiFi credentials using a Captive Portal + * Based on source by AlexT (https://github.com/tzapu) +\*********************************************************************************************/ + +#define HTTP_REFRESH_TIME 2345 // milliseconds + +#ifdef USE_RF_FLASH +uint8_t *efm8bb1_update = NULL; +#endif // USE_RF_FLASH + +enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1 }; + +const char HTTP_HEAD[] PROGMEM = + "" + "" + "" + "" + "{h} - {v}" + + "" + + "" + + "" + "" + "
" +#ifdef BE_MINIMAL + "

" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "

" +#endif + "
" +#ifdef LANGUAGE_MODULE_NAME + "

" D_MODULE " {ha

" +#else + "

{ha " D_MODULE "

" +#endif + "

{h}

"; +const char HTTP_SCRIPT_CONSOL[] PROGMEM = + "var sn=0;" // Scroll position + "var id=0;" // Get most of weblog initially + "function l(p){" // Console log and command service + "var c,o,t;" + "clearTimeout(lt);" + "o='';" + "t=eb('t1');" + "if(p==1){" + "c=eb('c1');" + "o='&c1='+encodeURIComponent(c.value);" + "c.value='';" + "t.scrollTop=sn;" + "}" + "if(t.scrollTop>=sn){" // User scrolled back so no updates + "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) + "x=new XMLHttpRequest();" + "x.onreadystatechange=function(){" + "if(x.readyState==4&&x.status==200){" + "var z,d;" + "d=x.responseXML;" + "id=d.getElementsByTagName('i')[0].childNodes[0].nodeValue;" + "if(d.getElementsByTagName('j')[0].childNodes[0].nodeValue==0){t.value='';}" + "z=d.getElementsByTagName('l')[0].childNodes;" + "if(z.length>0){t.value+=decodeURIComponent(z[0].nodeValue);}" + "t.scrollTop=99999;" + "sn=t.scrollTop;" + "}" + "};" + "x.open('GET','ax?c2='+id+o,true);" + "x.send();" + "}" + "lt=setTimeout(l,{a});" + "return false;" + "}" + ""; +const char HTTP_SCRIPT_MODULE1[] PROGMEM = + "var os;" + "function sk(s,g){" + "var o=os.replace(\"value='\"+s+\"'\",\"selected value='\"+s+\"'\");" + "eb('g'+g).innerHTML=o;" + "}" + "function sl(){" + "var o0=\""; +const char HTTP_SCRIPT_MODULE2[] PROGMEM = + "}1'%d'>%02d %s}2"; // "}1" and "}2" means do not use "}x" in Module name and Sensor name +const char HTTP_SCRIPT_MODULE3[] PROGMEM = + "\";" + "os=o0.replace(/}1/g,\"