From d0fa749c306327f4b37c873fd18b986d163c397e Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 15 Sep 2018 15:56:56 +0200 Subject: [PATCH 01/93] MCP230xx - Fix support for setoption4 --- sonoff/xsns_29_mcp230xx.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 058d6c25c..586b8da8e 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -297,7 +297,7 @@ void MCP230xx_CheckForInterrupt(void) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"MCP230XX_INT\":{\"D%i\":%i,\"MS\":%lu}"), mqtt_data, intp+(mcp230xx_port*8), ((mcp230xx_intcap >> intp) & 0x01),millis_since_last_int); snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data); + MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR("MCP230XX_INT")); } if (int_event) { char command[19]; // Theoretical max = 'event MCPINT_D16=1' so 18 + 1 (for the \n) From 98cfb0080382df4f3a8a0cb1a77297fdf70595e6 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 15 Sep 2018 18:59:45 +0200 Subject: [PATCH 02/93] MCP230xx - Fix millisecond counter reset placement --- sonoff/xsns_29_mcp230xx.ino | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 586b8da8e..80aa76b7a 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -280,7 +280,9 @@ void MCP230xx_CheckForInterrupt(void) { if (report_int) { bool int_tele = false; bool int_event = false; - unsigned long millis_since_last_int = millis() - int_millis[intp+(mcp230xx_port*8)]; + unsigned long millis_now = millis(); + unsigned long millis_since_last_int = millis_now - int_millis[intp+(mcp230xx_port*8)]; + int_millis[intp+(mcp230xx_port*8)]=millis_now; switch (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].int_report_mode) { case 0: int_tele=true; @@ -304,7 +306,6 @@ void MCP230xx_CheckForInterrupt(void) { sprintf(command,"event MCPINT_D%i=%i",intp+(mcp230xx_port*8),((mcp230xx_intcap >> intp) & 0x01)); ExecuteCommand(command, SRC_RULE); } - int_millis[intp+(mcp230xx_port*8)]=millis(); } } } From bf7dcb8eec8c898e869b04e7313e1fcd1073726c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 16 Sep 2018 16:09:00 +0200 Subject: [PATCH 03/93] 6.2.1.3 Add SerialSend5 6.2.1.4 20180916 * Add command SerialSend5 to send raw serial data like "A5074100545293" * Update MCP230xx driver * Update Czech translation * Update MP3 driver (#3800) * Add userid/password option to decode-status.py (#3796) * Fix syslog when emulation is selected (#2109, #3784) * Fix Pzem2 compilation error (#3766, #3767) --- sonoff/_changelog.ino | 13 +++++++++++-- sonoff/sonoff.ino | 13 ++++++++----- sonoff/sonoff_version.h | 2 +- sonoff/support.ino | 15 +++++++++++++++ sonoff/user_config.h | 2 +- sonoff/xdrv_06_snfbridge.ino | 19 ++----------------- 6 files changed, 38 insertions(+), 26 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index eed6ffcc7..bd4ee9b7c 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,10 +1,19 @@ -/* 6.2.1.3 20180907 +/* 6.2.1.4 20180916 + * Add command SerialSend5 to send raw serial data like "A5074100545293" + * Update MCP230xx driver + * Update Czech translation + * Update MP3 driver (#3800) + * Add userid/password option to decode-status.py (#3796) + * Fix syslog when emulation is selected (#2109, #3784) + * Fix Pzem2 compilation error (#3766, #3767) + * + * 6.2.1.3 20180907 * Change web Configure Module GPIO drop down list order for better readability * Fix showing Period Power in energy threshold messages * Fix ButtonRetain to not use default topic for clearing retain messages (#3737) * Add sleep to Nova Fitness SDS01X sensor (#2841, #3724, #3749) * Add Analog input AD0 enabled to sonoff-sensors.bin (#3756, #3757) - * Add Support to Xiaomi-Phillips Bulbs + * Add Support for Xiaomi-Philips Bulbs (#3787) * * 6.2.1.2 20180906 * Fix KNX PA exception. Regression from 6.2.1 buffer overflow caused by subStr() (#3700, #3710) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index a55e896c4..4903fe80f 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -969,22 +969,25 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.baudrate * 1200); } - else if ((CMND_SERIALSEND == command_code) && (index > 0) && (index <= 4)) { + else if ((CMND_SERIALSEND == command_code) && (index > 0) && (index <= 5)) { SetSeriallog(LOG_LEVEL_NONE); Settings.flag.mqtt_serial = 1; - Settings.flag.mqtt_serial_raw = (4 == index) ? 1 : 0; + Settings.flag.mqtt_serial_raw = (index > 3) ? 1 : 0; if (data_len > 0) { if (1 == index) { - Serial.printf("%s\n", dataBuf); + Serial.printf("%s\n", dataBuf); // "Hello Tiger\n" } else if (2 == index || 4 == index) { for (int i = 0; i < data_len; i++) { - Serial.write(dataBuf[i]); + Serial.write(dataBuf[i]); // "Hello Tiger" or "A0" } } else if (3 == index) { uint16_t dat_len = data_len; - Serial.printf("%s", Unescape(dataBuf, &dat_len)); + Serial.printf("%s", Unescape(dataBuf, &dat_len)); // "Hello\f" + } + else if (5 == index) { + SerialSendRaw(dataBuf, data_len); // "AA004566" } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); } diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index f068473ab..f5f94dad1 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 0x06020103 +#define VERSION 0x06020104 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/support.ino b/sonoff/support.ino index af93fa148..fb2b5eae3 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -704,6 +704,21 @@ void ClaimSerial() Settings.baudrate = baudrate / 1200; } +void SerialSendRaw(char *codes, int size) +{ + char *p; + char stemp[3]; + uint8_t code; + + while (size > 0) { + snprintf(stemp, sizeof(stemp), codes); + code = strtol(stemp, &p, 16); + Serial.write(code); + size -= 2; + codes += 2; + } +} + uint32_t GetHash(const char *buffer, size_t size) { uint32_t hash = 0; diff --git a/sonoff/user_config.h b/sonoff/user_config.h index a07c87ec3..5a2b909de 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -342,7 +342,7 @@ //#define USE_SDM630 // Add support for Eastron SDM630-Modbus energy meter (+2k code) #define SDM630_SPEED 9600 // SDM630-Modbus RS485 serial speed (default: 9600 baud) //#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop -// #define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max) + #define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max) // Power monitoring sensors ----------------------- #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) diff --git a/sonoff/xdrv_06_snfbridge.ino b/sonoff/xdrv_06_snfbridge.ino index b0518f133..379d29455 100644 --- a/sonoff/xdrv_06_snfbridge.ino +++ b/sonoff/xdrv_06_snfbridge.ino @@ -199,21 +199,6 @@ uint8_t SnfBrUpdateInit() /********************************************************************************************/ -void SonoffBridgeSendRaw(char *codes, int size) -{ - char *p; - char stemp[3]; - uint8_t code; - - while (size > 0) { - snprintf(stemp, sizeof(stemp), codes); - code = strtol(stemp, &p, 16); - Serial.write(code); - size -= 2; - codes += 2; - } -} - void SonoffBridgeReceivedRaw() { // Decoding according to https://github.com/Portisch/RF-Bridge-EFM8BB1 @@ -552,11 +537,11 @@ boolean SonoffBridgeCommand() break; case 192: // 0xC0 - Beep char beep[] = "AAC000C055"; - SonoffBridgeSendRaw(beep, sizeof(beep)); + SerialSendRaw(beep, sizeof(beep)); break; } } else { - SonoffBridgeSendRaw(XdrvMailbox.data, XdrvMailbox.data_len); + SerialSendRaw(XdrvMailbox.data, XdrvMailbox.data_len); sonoff_bridge_receive_raw_flag = 1; } } From 29b3e6ec27ae9395764e19545246f7fb76f254d3 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sun, 16 Sep 2018 21:36:56 +0200 Subject: [PATCH 04/93] MCP230xx - Change address selection from auto to user defined --- sonoff/user_config.h | 3 +- sonoff/xsns_29_mcp230xx.ino | 73 +++++++++++++++---------------------- 2 files changed, 31 insertions(+), 45 deletions(-) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 5a2b909de..20339b5f6 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -294,7 +294,8 @@ // #define USE_SI1145 // Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) #define USE_LM75AD // Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) // #define USE_APDS9960 // Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) -// #define USE_MCP230xx // Enable MCP23008/MCP23017 for GP INPUT ONLY (I2C addresses 0x20 - 0x27) providing command Sensor29 for configuration (+4k7 code) +// #define USE_MCP230xx // Enable MCP23008/MCP23017 - Must define I2C Address in #define USE_MCP230xx_ADDR below - range 0x20 - 0x27 (+4k7 code) +// #define USE_MCP230xx_ADDR 0x20 // Enable MCP23008/MCP23017 I2C Address to use (Must be within range 0x20 through 0x27 - set according to your wired setup) // #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+1k5 code) // #define USE_MCP230xx_DISPLAYOUTPUT // Enable MCP23008/MCP23017 to display state of OUTPUT pins on Web UI (+0k2 code) // #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 80aa76b7a..50798eb8f 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -31,15 +31,6 @@ #define XSNS_29 29 -#define MCP230xx_ADDRESS1 0x20 -#define MCP230xx_ADDRESS2 0x21 -#define MCP230xx_ADDRESS3 0x22 -#define MCP230xx_ADDRESS4 0x23 -#define MCP230xx_ADDRESS5 0x24 -#define MCP230xx_ADDRESS6 0x25 -#define MCP230xx_ADDRESS7 0x26 -#define MCP230xx_ADDRESS8 0x27 - /* Default register locations for MCP23008 - They change for MCP23017 in default bank mode */ @@ -53,8 +44,6 @@ uint8_t MCP230xx_INTCAP = 0x08; uint8_t MCP230xx_GPIO = 0x09; uint8_t mcp230xx_type = 0; -uint8_t mcp230xx_address; -uint8_t mcp230xx_addresses[] = { MCP230xx_ADDRESS1, MCP230xx_ADDRESS2, MCP230xx_ADDRESS3, MCP230xx_ADDRESS4, MCP230xx_ADDRESS5, MCP230xx_ADDRESS6, MCP230xx_ADDRESS7, MCP230xx_ADDRESS8 }; uint8_t mcp230xx_pincount = 0; uint8_t mcp230xx_int_en = 0; uint8_t mcp230xx_int_prio_counter = 0; @@ -131,7 +120,7 @@ const char* IntModeTxt(uint8_t intmo) { } uint8_t MCP230xx_readGPIO(uint8_t port) { - return I2cRead8(mcp230xx_address, MCP230xx_GPIO + port); + return I2cRead8(USE_MCP230xx_ADDR, MCP230xx_GPIO + port); } void MCP230xx_ApplySettings(void) { @@ -178,11 +167,11 @@ void MCP230xx_ApplySettings(void) { } #endif // USE_MCP230xx_OUTPUT } - I2cWrite8(mcp230xx_address, MCP230xx_GPPU+mcp230xx_port, reg_gppu); - I2cWrite8(mcp230xx_address, MCP230xx_GPINTEN+mcp230xx_port, reg_gpinten); - I2cWrite8(mcp230xx_address, MCP230xx_IODIR+mcp230xx_port, reg_iodir); + I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPPU+mcp230xx_port, reg_gppu); + I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPINTEN+mcp230xx_port, reg_gpinten); + I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_IODIR+mcp230xx_port, reg_iodir); #ifdef USE_MCP230xx_OUTPUT - I2cWrite8(mcp230xx_address, MCP230xx_GPIO+mcp230xx_port, reg_portpins); + I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPIO+mcp230xx_port, reg_portpins); #endif // USE_MCP230xx_OUTPUT } for (uint8_t idx=0;idx 0) { - if (I2cValidRead8(&mcp230xx_intcap, mcp230xx_address, MCP230xx_INTCAP+mcp230xx_port)) { + if (I2cValidRead8(&mcp230xx_intcap, USE_MCP230xx_ADDR, MCP230xx_INTCAP+mcp230xx_port)) { for (uint8_t intp = 0; intp < 8; intp++) { if ((intf >> intp) & 0x01) { // we know which pin caused interrupt report_int = 0; @@ -367,7 +352,7 @@ void MCP230xx_SetOutPin(uint8_t pin,uint8_t pinstate) { portpins ^= (1 << (pin-(port*8))); } } - I2cWrite8(mcp230xx_address, MCP230xx_GPIO + port, portpins); + I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPIO + port, portpins); if (Settings.flag.save_state) { // Firmware configured to save last known state in settings Settings.mcp230xx_config[pin].saved_state=portpins>>(pin-(port*8))&1; Settings.mcp230xx_config[pin+pinadd].saved_state=portpins>>(pin+pinadd-(port*8))&1; From bffc820fb05bae7582934d27e76b6fd1bd86206b Mon Sep 17 00:00:00 2001 From: andrethomas Date: Mon, 17 Sep 2018 08:23:39 +0200 Subject: [PATCH 05/93] Update Bug_report.md --- .github/ISSUE_TEMPLATE/Bug_report.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 2616af48f..f97db3ad0 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -4,6 +4,9 @@ about: Create a report to help us improve --- +**IMPORTANT NOTICE** +If you do not complete the template below your it is likely that your issue will not be addressed. When providing information about your issue please be as extensive as possible so that it can be solved by as little as possible responses. + **Describe the bug** _A clear and concise description of what the bug is._ @@ -11,6 +14,7 @@ _A clear and concise description of what the bug is._ _Also, make sure these boxes are checked [x] before submitting your issue - Thank you!_ - [ ] _Searched the problem in issues and in the wiki_ - [ ] _Hardware used_ : +- [ ] _Development/Compiler/Upload tools used_ : - [ ] _Provide the output of command_``status 0`` : ``` STATUS 0 OUTPUT HERE From 2f0cd60cb3a6ee1cab85c1b3b73e9a13d41e1a8a Mon Sep 17 00:00:00 2001 From: andrethomas Date: Mon, 17 Sep 2018 08:26:43 +0200 Subject: [PATCH 06/93] Update Custom.md --- .github/ISSUE_TEMPLATE/Custom.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/Custom.md b/.github/ISSUE_TEMPLATE/Custom.md index 159549128..bc769a38d 100644 --- a/.github/ISSUE_TEMPLATE/Custom.md +++ b/.github/ISSUE_TEMPLATE/Custom.md @@ -4,12 +4,16 @@ about: Users Troubleshooting Help --- +**IMPORTANT NOTICE** +If you do not complete the template below your it is likely that your issue will not be addressed. When providing information about your issue please be as extensive as possible so that it can be solved by as little as possible responses. + Make sure these boxes are checked [x] before submitting your issue - Thank you! - [ ] Searched the problem in issues (https://github.com/arendst/Sonoff-Tasmota/issues) - [ ] Searched the problem in the wiki (https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting) - [ ] Searched the problem in the forum (https://groups.google.com/d/forum/sonoffusers) - [ ] Searched the problem in the chat (https://discord.gg/Ks2Kzd4) +- [ ] Development/Compiler/Upload tools used : - [ ] Hardware used : - [ ] Provide the output of command ``status 0`` : ``` From 3d74ed9964b9b40ba4fc6bce18aa561d25554f58 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 17 Sep 2018 09:08:37 +0200 Subject: [PATCH 07/93] Update Bug_report.md --- .github/ISSUE_TEMPLATE/Bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index f97db3ad0..bf55e130e 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -5,7 +5,7 @@ about: Create a report to help us improve --- **IMPORTANT NOTICE** -If you do not complete the template below your it is likely that your issue will not be addressed. When providing information about your issue please be as extensive as possible so that it can be solved by as little as possible responses. +If you do not complete the template below it is likely that your issue will not be addressed. When providing information about your issue please be as extensive as possible so that it can be solved by as little as possible responses. **Describe the bug** _A clear and concise description of what the bug is._ From de406b7868f0c6a0d7ab75a3270ef9971dec30a8 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 17 Sep 2018 09:11:18 +0200 Subject: [PATCH 08/93] Update Custom.md --- .github/ISSUE_TEMPLATE/Custom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/Custom.md b/.github/ISSUE_TEMPLATE/Custom.md index bc769a38d..77fc7a3e7 100644 --- a/.github/ISSUE_TEMPLATE/Custom.md +++ b/.github/ISSUE_TEMPLATE/Custom.md @@ -5,7 +5,7 @@ about: Users Troubleshooting Help --- **IMPORTANT NOTICE** -If you do not complete the template below your it is likely that your issue will not be addressed. When providing information about your issue please be as extensive as possible so that it can be solved by as little as possible responses. +If you do not complete the template below it is likely that your issue will not be addressed. When providing information about your issue please be as extensive as possible so that it can be solved by as little as possible responses. Make sure these boxes are checked [x] before submitting your issue - Thank you! From ff4f8f75c17aa21db912775d947d31caf9a2616b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 17 Sep 2018 20:32:38 +0200 Subject: [PATCH 09/93] Add uncalibrated energy monitor Add uncalibrated energy monitoring to Shelly2 (#2789) --- sonoff/_changelog.ino | 1 + sonoff/xdrv_03_energy.ino | 4 +- sonoff/xnrg_04_mcp39f501.ino | 301 +++++++++++++++++++++++++++++++++++ 3 files changed, 304 insertions(+), 2 deletions(-) create mode 100644 sonoff/xnrg_04_mcp39f501.ino diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index bd4ee9b7c..fdf73fdc7 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -6,6 +6,7 @@ * Add userid/password option to decode-status.py (#3796) * Fix syslog when emulation is selected (#2109, #3784) * Fix Pzem2 compilation error (#3766, #3767) + * Add uncalibrated energy monitoring to Shelly2 (#2789) * * 6.2.1.3 20180907 * Change web Configure Module GPIO drop down list order for better readability diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index ac26a18da..aa589efab 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -98,6 +98,8 @@ void EnergyUpdateToday() void Energy200ms() { + energy_power_on = (power != 0) | Settings.flag.no_power_on_check; + energy_fifth_second++; if (5 == energy_fifth_second) { energy_fifth_second = 0; @@ -121,8 +123,6 @@ void Energy200ms() } } - energy_power_on = (power &1) | Settings.flag.no_power_on_check; - XnrgCall(FUNC_EVERY_200_MSECOND); if (energy_calc_power_factor) { diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino new file mode 100644 index 000000000..f74111f9d --- /dev/null +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -0,0 +1,301 @@ +/* + xnrg_04_mcp39f501.ino - MCP39F501 energy sensor support 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_ENERGY_SENSOR +#ifdef USE_MCP39F501 +/*********************************************************************************************\ + * MCP39F501 - Energy (Shelly 2) + * + * Based on datasheet from https://www.microchip.com/wwwproducts/en/MCP39F501 + * and https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/7a7f9bb56d4b72770dba8d0f18eaa9d956dd0baf/olimex/user/modules/mod_emtr.c +\*********************************************************************************************/ + +#define XNRG_04 4 + +#define MCP_START_FRAME 0xA5 +#define MCP_ACK_FRAME 0x06 +#define MCP_ERROR_NAK 0x15 +#define MCP_ERROR_CRC 0x51 + +#define MCP_SINGLE_WIRE 0xAB + +#define MCP_SET_ADDRESS 0x41 + +#define MCP_READ 0x4E +#define MCP_READ_16 0x52 +#define MCP_READ_32 0x44 + +#define MCP_WRITE 0x4D +#define MCP_WRITE_16 0x57 +#define MCP_WRITE_32 0x45 + +#define MCP_SAVE_REGISTERS 0x53 + +#define MCP_FLASH_READ 0x42 +#define MCP_FLASH_WRITE 0x50 + +uint32 mcp_system_configuration = 0x03000000; +uint8_t mcp_single_wire_active = 0; + +/*********************************************************************************************\ + * Olimex tools + * https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/7a7f9bb56d4b72770dba8d0f18eaa9d956dd0baf/olimex/user/modules/mod_emtr.c +\*********************************************************************************************/ + + +unsigned long McpExtractInt(uint8_t *data, uint8_t offset, uint8_t size) +{ + unsigned long result = 0; + unsigned long pow = 1; + + for (byte i = 0; i < size; i++) { + result = result + data[offset + i] * pow; + pow = pow * 256; + } + return result; +} + +void McpSetSystemConfiguration(uint16 interval) +{ + uint8_t data[17]; + + data[ 0] = MCP_START_FRAME; + data[ 1] = sizeof(data); + data[ 2] = MCP_SET_ADDRESS; // Set address pointer + data[ 3] = 0x00; // address + data[ 4] = 0x42; // address + data[ 5] = MCP_WRITE_32; // Write 4 bytes + data[ 6] = (mcp_system_configuration >> 24) & 0xFF; // system_configuration + data[ 7] = (mcp_system_configuration >> 16) & 0xFF; // system_configuration + data[ 8] = (mcp_system_configuration >> 8) & 0xFF; // system_configuration + data[ 9] = (mcp_system_configuration >> 0) & 0xFF; // system_configuration + data[10] = MCP_SET_ADDRESS; // Set address pointer + data[11] = 0x00; // address + data[12] = 0x5A; // address + data[13] = MCP_WRITE_16; // Write 2 bytes + data[14] = (interval >> 8) & 0xFF; // interval + data[15] = (interval >> 0) & 0xFF; // interval + uint8_t checksum = 0; + for (byte i = 0; i < sizeof(data) -1; i++) { checksum += (uint8_t)data[i]; } + data[16] = checksum; + + // A5 11 41 00 42 45 03 00 01 00 41 00 5A 57 00 06 7A + AddLogSerial(LOG_LEVEL_DEBUG, data, sizeof(data)); + + for (byte i = 0; i < sizeof(data); i++) { Serial.write(data[i]); } +} + +void McpSingleWireStart() +{ + if ((mcp_system_configuration & (1 << 8)) != 0) { return; } + mcp_system_configuration = mcp_system_configuration | (1 << 8); + McpSetSystemConfiguration(6); // 64 + mcp_single_wire_active = 1; +} + +void McpSingleWireStop() +{ + if ((mcp_system_configuration & (1 << 8)) == 0) { return; } + mcp_system_configuration = mcp_system_configuration & (~(1 << 8)); + McpSetSystemConfiguration(2); // 4 + mcp_single_wire_active = 0; +} + +/********************************************************************************************/ + +unsigned long mcp_current = 0; +unsigned long mcp_voltage = 0; +unsigned long mcp_power = 0; +unsigned long mcp_frequency = 0; + +void McpParseData(uint8_t single_wire) +{ + if (single_wire) { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // AB CD EF 51 06 00 00 B8 08 FC 0D 00 00 0A C4 11 + // Header-- Current---- Volt- Power------ Freq- Ck + + mcp_current = McpExtractInt((uint8_t*)serial_in_buffer, 3, 4); + mcp_voltage = McpExtractInt((uint8_t*)serial_in_buffer, 7, 2); + mcp_power = McpExtractInt((uint8_t*)serial_in_buffer, 9, 4); + mcp_frequency = McpExtractInt((uint8_t*)serial_in_buffer, 13, 2); + } else { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + // 06 19 61 06 00 00 FE 08 9B 0E 00 00 0B 00 00 00 97 0E 00 00 FF 7F 0C C6 35 + // Ak Ln Current---- Volt- ActivePower ReActivePow ApparentPow Factr Frequ Ck + + mcp_current = McpExtractInt((uint8_t*)serial_in_buffer, 2, 4); + mcp_voltage = McpExtractInt((uint8_t*)serial_in_buffer, 6, 2); + mcp_power = McpExtractInt((uint8_t*)serial_in_buffer, 8, 4); + mcp_frequency = McpExtractInt((uint8_t*)serial_in_buffer, 22, 2); + } + + if (energy_power_on) { // Powered on + energy_frequency = (float)mcp_frequency / 1000; + energy_voltage = (float)mcp_voltage / 10; + energy_power = (float)mcp_power / 100; + if (0 == energy_power) { + energy_current = 0; + } else { + energy_current = (float)mcp_current / 10000; + } + } else { // Powered off + energy_frequency = 0; + energy_voltage = 0; + energy_power = 0; + energy_current = 0; + } +} + +bool McpSerialInput() +{ + Settings.flag.mqtt_serial = 0; // Disable possible SerialReceive handling + + serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; + if (MCP_ERROR_CRC == serial_in_buffer[0]) { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: Send " D_CHECKSUM_FAILURE)); + return 1; + } + else if (MCP_ACK_FRAME == serial_in_buffer[0]) { + if ((serial_in_byte_counter > 1) && (serial_in_byte_counter == serial_in_buffer[1])) { + + AddLogSerial(LOG_LEVEL_DEBUG_MORE); + + uint8_t checksum = 0; + for (byte i = 0; i < serial_in_byte_counter -1; i++) { checksum += (uint8_t)serial_in_buffer[i]; } + if (checksum != serial_in_buffer[serial_in_byte_counter -1]) { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); + } else { + if (25 == serial_in_buffer[1]) { McpParseData(0); } + } + return 1; + } + } + else if (MCP_SINGLE_WIRE == serial_in_buffer[0]) { + if (serial_in_byte_counter == 16) { + + AddLogSerial(LOG_LEVEL_DEBUG_MORE); + + uint8_t checksum = 0; + for (byte i = 3; i < serial_in_byte_counter -1; i++) { checksum += (uint8_t)serial_in_buffer[i]; } +// if (~checksum != serial_in_buffer[serial_in_byte_counter -1]) { +// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); +// } else { + McpParseData(1); +// } + return 1; + } + } + else { + return 1; + } + serial_in_byte = 0; // Discard + return 0; +} + +/********************************************************************************************/ + +void McpEverySecond() +{ + if (!mcp_single_wire_active) { + char get_state[] = "A5084100044E1656"; + SerialSendRaw(get_state, sizeof(get_state)); + } + + energy_kWhtoday += (energy_power / 36); + EnergyUpdateToday(); +} + +void McpSnsInit() +{ + digitalWrite(15, 1); // GPIO15 - MCP enable +} + +void McpDrvInit() +{ + if (!energy_flg) { + if (SHELLY2 == Settings.module) { + pinMode(15, OUTPUT); + digitalWrite(15, 0); // GPIO15 - MCP disable - Reset Delta Sigma ADC's + baudrate = 4800; + energy_calc_power_factor = 1; // Calculate power factor from data + energy_flg = XNRG_04; + } + } +} + +boolean McpCommand() +{ + boolean serviced = true; + + if ((CMND_POWERCAL == energy_command_code) || (CMND_VOLTAGECAL == energy_command_code) || (CMND_CURRENTCAL == energy_command_code)) { + + } + else if (CMND_POWERSET == energy_command_code) { + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 3601) && power_cycle) { +// Settings.energy_power_calibration = (XdrvMailbox.payload * power_cycle) / CSE_PREF; + } + } + else if (CMND_VOLTAGESET == energy_command_code) { + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 501) && voltage_cycle) { +// Settings.energy_voltage_calibration = (XdrvMailbox.payload * voltage_cycle) / CSE_UREF; + } + } + else if (CMND_CURRENTSET == energy_command_code) { + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 16001) && current_cycle) { +// Settings.energy_current_calibration = (XdrvMailbox.payload * current_cycle) / 1000; + } + } + else serviced = false; // Unknown command + + return serviced; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +int Xnrg04(byte function) +{ + int result = 0; + + if (FUNC_PRE_INIT == function) { + McpDrvInit(); + } + else if (XNRG_04 == energy_flg) { + switch (function) { + case FUNC_INIT: + McpSnsInit(); + break; + case FUNC_EVERY_SECOND: + McpEverySecond(); + break; + case FUNC_COMMAND: + result = McpCommand(); + break; + case FUNC_SERIAL: + result = McpSerialInput(); + break; + } + } + return result; +} + +#endif // USE_MCP39F501 +#endif // USE_ENERGY_SENSOR From c9f0c184661b7838536448823d3035a157223222 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Thu, 20 Sep 2018 20:44:17 +0200 Subject: [PATCH 10/93] LM75AD - Force function parameters to be C and C++ compliant --- sonoff/xsns_26_lm75ad.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/xsns_26_lm75ad.ino b/sonoff/xsns_26_lm75ad.ino index 092c8d153..1fd0f4448 100644 --- a/sonoff/xsns_26_lm75ad.ino +++ b/sonoff/xsns_26_lm75ad.ino @@ -46,7 +46,7 @@ uint8_t lm75ad_type = 0; uint8_t lm75ad_address; uint8_t lm75ad_addresses[] = { LM75AD_ADDRESS1, LM75AD_ADDRESS2, LM75AD_ADDRESS3, LM75AD_ADDRESS4, LM75AD_ADDRESS5, LM75AD_ADDRESS6, LM75AD_ADDRESS7, LM75AD_ADDRESS8 }; -void LM75ADDetect() +void LM75ADDetect(void) { if (lm75ad_type) { return; } @@ -64,7 +64,7 @@ void LM75ADDetect() } } -float LM75ADGetTemp() { +float LM75ADGetTemp(void) { int16_t sign = 1; uint16_t t = I2cRead16(lm75ad_address, LM75_TEMP_REGISTER); From 363e19d681584f09268f49fd4ed540d421f79753 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Thu, 20 Sep 2018 21:03:33 +0200 Subject: [PATCH 11/93] MCP230xx - Force C/C++ compliance --- sonoff/xsns_29_mcp230xx.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 50798eb8f..1ca59f8ed 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -181,7 +181,7 @@ void MCP230xx_ApplySettings(void) { MCP230xx_CheckForIntCounter(); // update register on whether or not we should be counting interrupts } -void MCP230xx_Detect() +void MCP230xx_Detect(void) { if (mcp230xx_type) { return; From 846d7a911f0571f209109a39585e7abad4e50cac Mon Sep 17 00:00:00 2001 From: andrethomas Date: Thu, 20 Sep 2018 22:56:07 +0200 Subject: [PATCH 12/93] Add driverXX support for FUNC_COMMAND callback --- sonoff/i18n.h | 4 ++++ sonoff/sonoff.ino | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index da47371d8..32cb458f1 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -174,6 +174,7 @@ #define D_CMND_BLINKTIME "BlinkTime" #define D_CMND_BLINKCOUNT "BlinkCount" #define D_CMND_SENSOR "Sensor" +#define D_CMND_DRIVER "Driver" #define D_CMND_SAVEDATA "SaveData" #define D_CMND_SETOPTION "SetOption" #define D_CMND_TEMPERATURE_RESOLUTION "TempRes" @@ -467,6 +468,9 @@ const char S_JSON_COMMAND_INDEX_NVALUE_ACTIVE_NVALUE[] PROGMEM = "{\"%s%d\":\"%d const char S_JSON_SENSOR_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":%d}"; const char S_JSON_SENSOR_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":\"%s\"}"; +const char S_JSON_DRIVER_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":%d}"; +const char S_JSON_DRIVER_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":\"%s\"}"; + const char JSON_SNS_TEMP[] PROGMEM = "%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"; const char JSON_SNS_TEMPHUM[] PROGMEM = "%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s}"; diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 4903fe80f..84293f5bc 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -83,7 +83,7 @@ enum TasmotaCommands { CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME, CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_TIMESTD, CMND_TIMEDST, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE, - CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_SERIALDELIMITER }; + CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_SERIALDELIMITER, CMND_DRIVER }; 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 "|" @@ -93,7 +93,7 @@ const char kTasmotaCommands[] PROGMEM = D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" - D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER; + D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER "|" D_CMND_DRIVER; const uint8_t kIFan02Speed[4][3] = {{6,6,6}, {7,6,6}, {7,7,6}, {7,6,7}}; @@ -690,6 +690,16 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) XsnsCall(FUNC_COMMAND); // if (!XsnsCall(FUNC_COMMAND)) type = NULL; } + else if (CMND_DRIVER == command_code) { + XdrvMailbox.index = index; + XdrvMailbox.data_len = data_len; + XdrvMailbox.payload16 = payload16; + XdrvMailbox.payload = payload; + XdrvMailbox.grpflg = grpflg; + XdrvMailbox.topic = command; + XdrvMailbox.data = dataBuf; + XdrvCall(FUNC_COMMAND); + } else if ((CMND_SETOPTION == command_code) && (index < 82)) { byte ptype; byte pindex; From 415ed97dab55c02fd1a6b4536bfa40befdaa47c4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 21 Sep 2018 11:15:42 +0200 Subject: [PATCH 13/93] 6.2.1.5 Add web authentication Add authentication to HTTP web pages --- sonoff/_changelog.ino | 5 +- sonoff/sonoff_version.h | 2 +- sonoff/xdrv_02_webserver.ino | 107 ++++++++++++++--------------------- sonoff/xdrv_07_domoticz.ino | 6 +- sonoff/xdrv_09_timers.ino | 6 +- sonoff/xdrv_11_knx.ino | 10 ++-- 6 files changed, 56 insertions(+), 80 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index fdf73fdc7..aa6e8bfae 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,7 @@ -/* 6.2.1.4 20180916 +/* 6.2.1.5 20180921 + * Add authentication to HTTP web pages + * + * 6.2.1.4 20180916 * Add command SerialSend5 to send raw serial data like "A5074100545293" * Update MCP230xx driver * Update Czech translation diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index f5f94dad1..43253e40f 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 0x06020104 +#define VERSION 0x06020105 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/xdrv_02_webserver.ino b/sonoff/xdrv_02_webserver.ino index 6cadb952f..5182b7051 100644 --- a/sonoff/xdrv_02_webserver.ino +++ b/sonoff/xdrv_02_webserver.ino @@ -29,8 +29,6 @@ uint8_t *efm8bb1_update = NULL; #endif // USE_RF_FLASH -#define D_TASMOTA_TOKEN "Tasmota-Token" - enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1 }; const char HTTP_HEAD[] PROGMEM = @@ -58,17 +56,13 @@ const char HTTP_HEAD[] PROGMEM = "eb('s1').value=l.innerText||l.textContent;" "eb('p1').focus();" "}" - "function lx(){" - "if(to==1){" - "if(tp<30){" - "tp++;" - "lt=setTimeout(lx,33);" // Wait for token from server - "}else{" - "lt=setTimeout(la,1355);" // Discard action and retry - "}" - "return;" + "function la(p){" + "var a='';" + "if(la.arguments.length==1){" + "a=p;" + "clearTimeout(lt);" "}" - "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) + "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){" @@ -76,32 +70,15 @@ const char HTTP_HEAD[] PROGMEM = "eb('l1').innerHTML=s;" "}" "};" - "x.open('GET','ay'+pc,true);" // Async request - "x.setRequestHeader('" D_TASMOTA_TOKEN "',to);" - "x.send();" // Perform command if available and get updated information - "pc='';" - "lt=setTimeout(la,2345-(tp*33));" - "}" - "function la(p){" - "if(la.arguments.length==1){" - "pc='?'+p;" - "clearTimeout(lt);" - "}else{pc='';}" - "to=1;tp=0;" - "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){to=x.getResponseHeader('" D_TASMOTA_TOKEN "');}else{to=1;}" - "};" - "x.open('GET','az',true);" // Async request - "x.send();" // Get token from server - "lx();" + "x.open('GET','ay'+a,true);" + "x.send();" + "lt=setTimeout(la,2345);" "}" "function lb(p){" - "la('d='+p);" + "la('?d='+p);" "}" "function lc(p){" - "la('c='+p);" + "la('?t='+p);" "}"; const char HTTP_HEAD_STYLE[] PROGMEM = @@ -340,7 +317,7 @@ const char HTTP_END[] PROGMEM = "" ""; -const char HTTP_DEVICE_CONTROL[] PROGMEM = ""; +const char HTTP_DEVICE_CONTROL[] PROGMEM = ""; const char HTTP_DEVICE_STATE[] PROGMEM = "%s%s"; // {c} = %'>
"), idx, idx); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(""), idx, idx); page += mqtt_data; } } @@ -634,34 +616,13 @@ void HandleRoot() } } -void HandleToken() -{ - char token[11]; - - ajax_token = random(2, 0x7FFFFFFF); - snprintf_P(token, sizeof(token), PSTR("%u"), ajax_token); - SetHeader(); - WebServer->sendHeader(FPSTR(HDR_TASMOTA_TOKEN), token); - snprintf_P(token, sizeof(token), PSTR("%u"), random(0x7FFFFFFF)); - WebServer->send(200, FPSTR(HDR_CTYPE_HTML), token); - - const char* header_key[] = { D_TASMOTA_TOKEN }; - WebServer->collectHeaders(header_key, 1); -} - void HandleAjaxStatusRefresh() { + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + char svalue[80]; char tmp[100]; - if (WebServer->header(FPSTR(HDR_TASMOTA_TOKEN)).toInt() != ajax_token) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_FILE_NOT_FOUND)); - SetHeader(); - WebServer->send(404, FPSTR(HDR_CTYPE_PLAIN), mqtt_data); - return; - } - ajax_token = 1; - WebGetArg("o", tmp, sizeof(tmp)); if (strlen(tmp)) { ShowWebSource(SRC_WEBGUI); @@ -736,6 +697,7 @@ boolean HttpUser() void HandleConfiguration() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURATION); String page = FPSTR(HTTP_HEAD); @@ -759,6 +721,7 @@ void HandleConfiguration() void HandleModuleConfiguration() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } char stemp[20]; uint8_t midx; @@ -829,6 +792,7 @@ 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); @@ -925,6 +889,7 @@ void HandleWifi(boolean scan) void HandleMqttConfiguration() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT); String page = FPSTR(HTTP_HEAD); @@ -948,6 +913,7 @@ void HandleMqttConfiguration() void HandleLoggingConfiguration() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_LOGGING); String page = FPSTR(HTTP_HEAD); @@ -995,6 +961,7 @@ void HandleLoggingConfiguration() void HandleOtherConfiguration() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_OTHER); char stemp[40]; @@ -1032,6 +999,7 @@ void HandleOtherConfiguration() void HandleBackupConfiguration() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_BACKUP_CONFIGURATION)); if (!SettingsBufferAlloc()) { return; } @@ -1067,6 +1035,7 @@ void HandleBackupConfiguration() void HandleSaveSettings() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } char stemp[TOPSZ]; char stemp2[TOPSZ]; @@ -1232,6 +1201,7 @@ void HandleSaveSettings() void HandleResetConfiguration() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } char svalue[33]; @@ -1252,6 +1222,7 @@ void HandleResetConfiguration() void HandleRestoreConfiguration() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESTORE_CONFIGURATION); String page = FPSTR(HTTP_HEAD); @@ -1270,6 +1241,7 @@ void HandleRestoreConfiguration() void HandleInformation() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_INFORMATION); char stopic[TOPSZ]; @@ -1386,6 +1358,7 @@ void HandleInformation() void HandleUpgradeFirmware() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_FIRMWARE_UPGRADE); String page = FPSTR(HTTP_HEAD); @@ -1405,6 +1378,7 @@ void HandleUpgradeFirmware() void HandleUpgradeFirmwareStart() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } char svalue[100]; AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_UPGRADE_STARTED)); @@ -1432,6 +1406,7 @@ void HandleUpgradeFirmwareStart() void HandleUploadDone() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_UPLOAD_DONE)); char error[100]; @@ -1684,6 +1659,7 @@ void HandlePreflightRequest() void HandleHttpCommand() { if (HttpUser()) { return; } +// if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } char svalue[INPUT_BUFFER_SIZE]; // Large to serve Backlog AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_COMMAND)); @@ -1741,6 +1717,7 @@ void HandleHttpCommand() void HandleConsole() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONSOLE); String page = FPSTR(HTTP_HEAD); @@ -1756,6 +1733,7 @@ void HandleConsole() void HandleAjaxConsoleRefresh() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } char svalue[INPUT_BUFFER_SIZE]; // Large to serve Backlog byte cflg = 1; byte counter = 0; // Initial start, should never be 0 again @@ -1812,6 +1790,7 @@ void HandleAjaxConsoleRefresh() void HandleRestart() { if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESTART); String page = FPSTR(HTTP_HEAD); diff --git a/sonoff/xdrv_07_domoticz.ino b/sonoff/xdrv_07_domoticz.ino index a7eb7708f..a30f79439 100644 --- a/sonoff/xdrv_07_domoticz.ino +++ b/sonoff/xdrv_07_domoticz.ino @@ -375,10 +375,8 @@ const char S_CONFIGURE_DOMOTICZ[] PROGMEM = D_CONFIGURE_DOMOTICZ; void HandleDomoticzConfiguration() { - if (HTTP_USER == webserver_state) { - HandleRoot(); - return; - } + if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ); char stemp[32]; diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index 0652f3b53..66bf93614 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -676,10 +676,8 @@ const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER; void HandleTimerConfiguration() { - if (HTTP_USER == webserver_state) { - HandleRoot(); - return; - } + if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TIMER); String page = FPSTR(HTTP_HEAD); diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 3897caac7..88260b23c 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -803,15 +803,13 @@ const char HTTP_FORM_KNX_ADD_TABLE_ROW2[] PROGMEM = void HandleKNXConfiguration() { + if (HttpUser()) { return; } + if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_KNX); + char tmp[100]; String stmp; - if (HTTP_USER == webserver_state) { - HandleRoot(); - return; - } - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_KNX); - if ( WebServer->hasArg("save") ) { KNX_Save_Settings(); HandleConfiguration(); From 4065a215f05173230ce3f5c2e8a56f0b5c2984e0 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 21 Sep 2018 15:22:17 +0200 Subject: [PATCH 14/93] Add Shelly2 Energy Monitoring Add energy monitoring to Shelly2 (#2789) --- sonoff/_changelog.ino | 1 + sonoff/i18n.h | 7 +- sonoff/settings.h | 8 +- sonoff/user_config.h | 1 + sonoff/xdrv_03_energy.ino | 8 +- sonoff/xnrg_04_mcp39f501.ino | 594 ++++++++++++++++++++++++++++++----- 6 files changed, 530 insertions(+), 89 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index aa6e8bfae..72293c30d 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,5 +1,6 @@ /* 6.2.1.5 20180921 * Add authentication to HTTP web pages + * Add energy monitoring to Shelly2 (#2789) * * 6.2.1.4 20180916 * Add command SerialSend5 to send raw serial data like "A5074100545293" diff --git a/sonoff/i18n.h b/sonoff/i18n.h index da47371d8..4ea5ab3fe 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -292,6 +292,7 @@ #define D_CMND_VOLTAGESET "VoltageSet" #define D_CMND_CURRENTCAL "CurrentCal" #define D_CMND_CURRENTSET "CurrentSet" +#define D_CMND_FREQUENCYSET "FrequencySet" #define D_CMND_MAXPOWER "MaxPower" #define D_CMND_MAXPOWERHOLD "MaxPowerHold" #define D_CMND_MAXPOWERWINDOW "MaxPowerWindow" @@ -419,7 +420,8 @@ enum UnitNames { UNIT_SECTORS, UNIT_VOLT, UNIT_WATT, - UNIT_WATTHOUR }; + UNIT_WATTHOUR, + UNIT_HERTZ }; const char kUnitNames[] PROGMEM = D_UNIT_AMPERE "|" D_UNIT_HOUR "|" @@ -439,7 +441,8 @@ const char kUnitNames[] PROGMEM = D_UNIT_SECTORS "|" D_UNIT_VOLT "|" D_UNIT_WATT "|" - D_UNIT_WATTHOUR ; + D_UNIT_WATTHOUR "|" + "d" D_UNIT_HERTZ ; const char S_JSON_COMMAND_NVALUE_SPACE_UNIT[] PROGMEM = "{\"%s\":\"%d %s\"}"; const char S_JSON_COMMAND_LVALUE_SPACE_UNIT[] PROGMEM = "{\"%s\":\"%lu %s\"}"; diff --git a/sonoff/settings.h b/sonoff/settings.h index a1fd218ac..7da610891 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -322,9 +322,13 @@ struct SYSCFG { uint16_t mcp230xx_int_timer; // 718 - byte free_71A[180]; // 71A + byte free_71A[174]; // 71A - char mems[MAX_RULE_MEMS][10]; // 7CE + unsigned long energy_frequency_calibration; // 7C8 + + byte free_7CC[2]; // 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 diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 20339b5f6..ef3e66fc2 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -348,6 +348,7 @@ // Power monitoring sensors ----------------------- #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) #define USE_PZEM2 // Add support for PZEM003,014,016,017 Energy monitor (+1k1 code) +#define USE_MCP39F501 // Add support for MCP39F501 Energy monitor as used in Shelly 2 (+3k2 code) // -- Low level interface devices ----------------- #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram) diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index aa589efab..068261971 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -29,14 +29,14 @@ enum EnergyCommands { CMND_POWERDELTA, CMND_POWERLOW, CMND_POWERHIGH, CMND_VOLTAGELOW, CMND_VOLTAGEHIGH, CMND_CURRENTLOW, CMND_CURRENTHIGH, - CMND_POWERCAL, CMND_POWERSET, CMND_VOLTAGECAL, CMND_VOLTAGESET, CMND_CURRENTCAL, CMND_CURRENTSET, + CMND_POWERCAL, CMND_POWERSET, CMND_VOLTAGECAL, CMND_VOLTAGESET, CMND_CURRENTCAL, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_ENERGYRESET, CMND_MAXENERGY, CMND_MAXENERGYSTART, CMND_MAXPOWER, CMND_MAXPOWERHOLD, CMND_MAXPOWERWINDOW, CMND_SAFEPOWER, CMND_SAFEPOWERHOLD, CMND_SAFEPOWERWINDOW }; const char kEnergyCommands[] PROGMEM = D_CMND_POWERDELTA "|" D_CMND_POWERLOW "|" D_CMND_POWERHIGH "|" D_CMND_VOLTAGELOW "|" D_CMND_VOLTAGEHIGH "|" D_CMND_CURRENTLOW "|" D_CMND_CURRENTHIGH "|" - D_CMND_POWERCAL "|" D_CMND_POWERSET "|" D_CMND_VOLTAGECAL "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTCAL "|" D_CMND_CURRENTSET "|" + D_CMND_POWERCAL "|" D_CMND_POWERSET "|" D_CMND_VOLTAGECAL "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTCAL "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" D_CMND_ENERGYRESET "|" D_CMND_MAXENERGY "|" D_CMND_MAXENERGYSTART "|" D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|" D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW ; @@ -451,6 +451,10 @@ boolean EnergyCommand() nvalue = Settings.energy_current_calibration; unit = UNIT_MICROSECOND; } + else if ((CMND_FREQUENCYSET == command_code) && XnrgCall(FUNC_COMMAND)) { // dHz + nvalue = Settings.energy_frequency_calibration; + unit = UNIT_HERTZ; + } #if FEATURE_POWER_LIMIT else if (CMND_MAXPOWER == command_code) { diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index f74111f9d..a9620ce50 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -26,56 +26,383 @@ * and https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/7a7f9bb56d4b72770dba8d0f18eaa9d956dd0baf/olimex/user/modules/mod_emtr.c \*********************************************************************************************/ -#define XNRG_04 4 +#define XNRG_04 4 -#define MCP_START_FRAME 0xA5 -#define MCP_ACK_FRAME 0x06 -#define MCP_ERROR_NAK 0x15 -#define MCP_ERROR_CRC 0x51 +#define MCP_TIMEOUT 4 -#define MCP_SINGLE_WIRE 0xAB +#define MCP_START_FRAME 0xA5 +#define MCP_ACK_FRAME 0x06 +#define MCP_ERROR_NAK 0x15 +#define MCP_ERROR_CRC 0x51 -#define MCP_SET_ADDRESS 0x41 +#define MCP_SINGLE_WIRE 0xAB -#define MCP_READ 0x4E -#define MCP_READ_16 0x52 -#define MCP_READ_32 0x44 +#define MCP_SET_ADDRESS 0x41 -#define MCP_WRITE 0x4D -#define MCP_WRITE_16 0x57 -#define MCP_WRITE_32 0x45 +#define MCP_READ 0x4E +#define MCP_READ_16 0x52 +#define MCP_READ_32 0x44 -#define MCP_SAVE_REGISTERS 0x53 +#define MCP_WRITE 0x4D +#define MCP_WRITE_16 0x57 +#define MCP_WRITE_32 0x45 -#define MCP_FLASH_READ 0x42 -#define MCP_FLASH_WRITE 0x50 +#define MCP_SAVE_REGISTERS 0x53 -uint32 mcp_system_configuration = 0x03000000; +#define MCP_CALIBRATION_BASE 0x0028 +#define MCP_CALIBRATION_LEN 52 + +#define MCP_FREQUENCY_REF_BASE 0x0094 +#define MCP_FREQUENCY_GAIN_BASE 0x00AE +#define MCP_FREQUENCY_LEN 4 + +#define EMTR_OUT_BASE 0x0004 +#define EMTR_OUT_LEN 28 + +#define MCP_FLASH_READ 0x42 +#define MCP_FLASH_WRITE 0x50 + +typedef struct mcp_calibration_registers_type { + uint16_t gain_current_rms; + uint16_t gain_voltage_rms; + uint16_t gain_active_power; + uint16_t gain_reactive_power; + sint32_t offset_current_rms; + sint32_t offset_active_power; + sint32_t offset_reactive_power; + sint16_t dc_offset_current; + sint16_t phase_compensation; + uint16_t apparent_power_divisor; + + uint32_t system_configuration; + uint16_t dio_configuration; + uint32_t range; + + uint32_t calibration_current; + uint16_t calibration_voltage; + uint32_t calibration_active_power; + uint32_t calibration_reactive_power; + uint16_t accumulation_interval; +} mcp_calibration_registers_type; +mcp_calibration_registers_type mcp_calibration_registers; + +typedef struct mcp_calibration_setpoint_type { + uint32_t calibration_current; + uint16_t calibration_voltage; + uint32_t calibration_active_power; + uint32_t calibration_reactive_power; + uint16_t line_frequency_ref; +} mcp_calibration_setpoint_type; +mcp_calibration_setpoint_type mcp_calibration_setpoint; + +typedef struct mcp_frequency_registers_type { + uint16_t line_frequency_ref; + uint16_t gain_line_frequency; +} mcp_frequency_registers_type; +mcp_frequency_registers_type mcp_frequency_registers; + +typedef struct mcp_output_registers_type { + uint32_t current_rms; + uint16_t voltage_rms; + uint32_t active_power; + uint32_t reactive_power; + uint32_t apparent_power; + sint16_t power_factor; + uint16_t line_frequency; + uint16_t thermistor_voltage; + uint16_t event_flag; + uint16_t system_status; +} mcp_output_registers_type; +mcp_output_registers_type mcp_output_registers; + +uint32_t mcp_system_configuration = 0x03000000; +uint16_t mcp_address = 0; uint8_t mcp_single_wire_active = 0; +uint8_t mcp_calibration_active = 0; +uint8_t mcp_init = 0; +uint8_t mcp_timeout = 0; +unsigned long mcp_kWhcounter = 0; /*********************************************************************************************\ * Olimex tools * https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/7a7f9bb56d4b72770dba8d0f18eaa9d956dd0baf/olimex/user/modules/mod_emtr.c \*********************************************************************************************/ +uint8_t McpChecksum(uint8_t *data) +{ + uint8_t checksum = 0; + uint8_t offset = 0; + uint8_t len = data[1] -1; -unsigned long McpExtractInt(uint8_t *data, uint8_t offset, uint8_t size) + if (MCP_SINGLE_WIRE == data[0]) { + offset = 3; + len = 15; + } + for (byte i = offset; i < len; i++) { checksum += data[i]; } + return (MCP_SINGLE_WIRE == data[0]) ? ~checksum : checksum; +} + +unsigned long McpExtractInt(char *data, uint8_t offset, uint8_t size) { unsigned long result = 0; unsigned long pow = 1; for (byte i = 0; i < size; i++) { - result = result + data[offset + i] * pow; + result = result + (uint8_t)data[offset + i] * pow; pow = pow * 256; } return result; } -void McpSetSystemConfiguration(uint16 interval) +void McpSetInt(unsigned long value, uint8_t *data, uint8_t offset, size_t size) { + for (byte i = 0; i < size; i++) { + data[offset + i] = ((value >> (i * 8)) & 0xFF); + } +} + +void AddLogSerialSend(byte loglevel, uint8_t *buffer, int count) +{ + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_SERIAL "Send")); + for (int i = 0; i < count; i++) { + snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, *(buffer++)); + } + AddLog(loglevel); +} + + +void McpSend(uint8_t *data) +{ + if (mcp_timeout) { return; } + mcp_timeout = MCP_TIMEOUT; + + data[0] = MCP_START_FRAME; + data[data[1] -1] = McpChecksum(data); + +// AddLogSerialSend(LOG_LEVEL_DEBUG_MORE, data, data[1]); + + for (byte i = 0; i < data[1]; i++) { + Serial.write(data[i]); + } +} + +uint32_t McpGetRange(uint8_t shift) +{ + return (mcp_calibration_registers.range >> shift) & 0xFF; +} + +void McpSetRange(uint8_t shift, uint32_t range) +{ + uint32_t old_range = McpGetRange(shift); + mcp_calibration_registers.range = mcp_calibration_registers.range ^ (old_range << shift); + mcp_calibration_registers.range = mcp_calibration_registers.range | (range << shift); +} + +bool McpCalibrationCalc(uint8_t range_shift) +{ + uint32_t measured; + uint32_t expected; + uint16_t *gain; + uint32_t new_gain; + + if (range_shift == 0) { + measured = mcp_output_registers.voltage_rms; + expected = mcp_calibration_registers.calibration_voltage; + gain = &(mcp_calibration_registers.gain_voltage_rms); + } else if (range_shift == 8) { + measured = mcp_output_registers.current_rms; + expected = mcp_calibration_registers.calibration_current; + gain = &(mcp_calibration_registers.gain_current_rms); + } else if (range_shift == 16) { + measured = mcp_output_registers.active_power; + expected = mcp_calibration_registers.calibration_active_power; + gain = &(mcp_calibration_registers.gain_active_power); + } else { + return false; + } + + if (measured == 0) { + return false; + } + + uint32_t range = McpGetRange(range_shift); + +calc: + new_gain = (*gain) * expected / measured; + + if (new_gain < 25000) { + range++; + if (measured > 6) { + measured = measured / 2; + goto calc; + } + } + + if (new_gain > 55000) { + range--; + measured = measured * 2; + goto calc; + } + + *gain = new_gain; + McpSetRange(range_shift, range); + + return true; +} + +void McpCalibrationReactivePower() +{ + mcp_calibration_registers.gain_reactive_power = mcp_calibration_registers.gain_reactive_power * mcp_calibration_setpoint.calibration_reactive_power / mcp_output_registers.reactive_power; +} + +void McpCalibrationLineFreqency() +{ + mcp_frequency_registers.gain_line_frequency = mcp_frequency_registers.gain_line_frequency * mcp_frequency_registers.line_frequency_ref / mcp_output_registers.line_frequency; +} + +void McpResetSetpoints() +{ + mcp_calibration_setpoint.calibration_active_power = 0; + mcp_calibration_setpoint.calibration_voltage = 0; + mcp_calibration_setpoint.calibration_current = 0; + mcp_calibration_setpoint.calibration_reactive_power = 0; + mcp_calibration_setpoint.line_frequency_ref = 0; +} + +/********************************************************************************************/ + +void McpGetAddress() +{ + // A5 07 41 00 26 52 65 + uint8_t data[7]; + + data[1] = sizeof(data); + data[2] = MCP_SET_ADDRESS; // Set address pointer + data[3] = 0x00; // address + data[4] = 0x26; // address + data[5] = MCP_READ_16; // Read 2 bytes + + McpSend(data); + + // Receives 06 05 004D 58 +} + +void McpGetCalibration() +{ + if (mcp_calibration_active) { return; } + mcp_calibration_active = 4; + + // A5 08 41 00 28 4E 34 98 + uint8_t data[8]; + + data[1] = sizeof(data); + data[2] = MCP_SET_ADDRESS; // Set address pointer + data[3] = (MCP_CALIBRATION_BASE >> 8) & 0xFF; // address + data[4] = (MCP_CALIBRATION_BASE >> 0) & 0xFF; // address + data[5] = MCP_READ; // Read N bytes + data[6] = MCP_CALIBRATION_LEN; + + McpSend(data); + + // Receives 06 37 C882 B6AD 0781 9273 06000000 00000000 00000000 0000 D3FF 0300 00000003 9204 120C1300 204E0000 9808 E0AB0000 D9940000 0200 24 +} + +void McpSetCalibration() +{ + uint8_t data[7 + MCP_CALIBRATION_LEN + 2 + 1]; + + data[1] = sizeof(data); + data[2] = MCP_SET_ADDRESS; // Set address pointer + data[3] = (MCP_CALIBRATION_BASE >> 8) & 0xFF; // address + data[4] = (MCP_CALIBRATION_BASE >> 0) & 0xFF; // address + + data[5] = MCP_WRITE; // Write N bytes + data[6] = MCP_CALIBRATION_LEN; + + McpSetInt(mcp_calibration_registers.gain_current_rms, data, 0+7, 2); + McpSetInt(mcp_calibration_registers.gain_voltage_rms, data, 2+7, 2); + McpSetInt(mcp_calibration_registers.gain_active_power, data, 4+7, 2); + McpSetInt(mcp_calibration_registers.gain_reactive_power, data, 6+7, 2); + McpSetInt(mcp_calibration_registers.offset_current_rms, data, 8+7, 4); + McpSetInt(mcp_calibration_registers.offset_active_power, data, 12+7, 4); + McpSetInt(mcp_calibration_registers.offset_reactive_power, data, 16+7, 4); + McpSetInt(mcp_calibration_registers.dc_offset_current, data, 20+7, 2); + McpSetInt(mcp_calibration_registers.phase_compensation, data, 22+7, 2); + McpSetInt(mcp_calibration_registers.apparent_power_divisor, data, 24+7, 2); + + McpSetInt(mcp_calibration_registers.system_configuration, data, 26+7, 4); + McpSetInt(mcp_calibration_registers.dio_configuration, data, 30+7, 2); + McpSetInt(mcp_calibration_registers.range, data, 32+7, 4); + + McpSetInt(mcp_calibration_registers.calibration_current, data, 36+7, 4); + McpSetInt(mcp_calibration_registers.calibration_voltage, data, 40+7, 2); + McpSetInt(mcp_calibration_registers.calibration_active_power, data, 42+7, 4); + McpSetInt(mcp_calibration_registers.calibration_reactive_power, data, 46+7, 4); + McpSetInt(mcp_calibration_registers.accumulation_interval, data, 50+7, 2); + + data[MCP_CALIBRATION_LEN+7] = MCP_SAVE_REGISTERS; // Save registers to flash + data[MCP_CALIBRATION_LEN+8] = mcp_address; // Device address + + McpSend(data); +} + +void McpGetFrequency() +{ + if (mcp_calibration_active) { return; } + mcp_calibration_active = 4; + + // A5 0B 41 00 94 52 41 00 AE 52 18 + uint8_t data[11]; + + data[1] = sizeof(data); + data[2] = MCP_SET_ADDRESS; // Set address pointer + data[3] = (MCP_FREQUENCY_REF_BASE >> 8) & 0xFF; // address + data[4] = (MCP_FREQUENCY_REF_BASE >> 0) & 0xFF; // address + + data[5] = MCP_READ_16; // Read register + + data[6] = MCP_SET_ADDRESS; // Set address pointer + data[7] = (MCP_FREQUENCY_GAIN_BASE >> 8) & 0xFF; // address + data[8] = (MCP_FREQUENCY_GAIN_BASE >> 0) & 0xFF; // address + + data[9] = MCP_READ_16; // Read register + + McpSend(data); +} + +void McpSetFrequency() +{ + // A5 11 41 00 94 57 C3 B4 41 00 AE 57 7E 46 53 4D 03 + uint8_t data[17]; + + data[ 1] = sizeof(data); + data[ 2] = MCP_SET_ADDRESS; // Set address pointer + data[ 3] = (MCP_FREQUENCY_REF_BASE >> 8) & 0xFF; // address + data[ 4] = (MCP_FREQUENCY_REF_BASE >> 0) & 0xFF; // address + + data[ 5] = MCP_WRITE_16; // Write register + data[ 6] = (mcp_frequency_registers.line_frequency_ref >> 8) & 0xFF; // line_frequency_ref high + data[ 7] = (mcp_frequency_registers.line_frequency_ref >> 0) & 0xFF; // line_frequency_ref low + + data[ 8] = MCP_SET_ADDRESS; // Set address pointer + data[ 9] = (MCP_FREQUENCY_GAIN_BASE >> 8) & 0xFF; // address + data[10] = (MCP_FREQUENCY_GAIN_BASE >> 0) & 0xFF; // address + + data[11] = MCP_WRITE_16; // Write register + data[12] = (mcp_frequency_registers.gain_line_frequency >> 8) & 0xFF; // gain_line_frequency high + data[13] = (mcp_frequency_registers.gain_line_frequency >> 0) & 0xFF; // gain_line_frequency low + + data[14] = MCP_SAVE_REGISTERS; // Save registers to flash + data[15] = mcp_address; // Device address + + McpSend(data); +} + +void McpSetSystemConfiguration(uint16 interval) +{ + // A5 11 41 00 42 45 03 00 01 00 41 00 5A 57 00 06 7A uint8_t data[17]; - data[ 0] = MCP_START_FRAME; data[ 1] = sizeof(data); data[ 2] = MCP_SET_ADDRESS; // Set address pointer data[ 3] = 0x00; // address @@ -91,14 +418,8 @@ void McpSetSystemConfiguration(uint16 interval) data[13] = MCP_WRITE_16; // Write 2 bytes data[14] = (interval >> 8) & 0xFF; // interval data[15] = (interval >> 0) & 0xFF; // interval - uint8_t checksum = 0; - for (byte i = 0; i < sizeof(data) -1; i++) { checksum += (uint8_t)data[i]; } - data[16] = checksum; - // A5 11 41 00 42 45 03 00 01 00 41 00 5A 57 00 06 7A - AddLogSerial(LOG_LEVEL_DEBUG, data, sizeof(data)); - - for (byte i = 0; i < sizeof(data); i++) { Serial.write(data[i]); } + McpSend(data); } void McpSingleWireStart() @@ -109,9 +430,9 @@ void McpSingleWireStart() mcp_single_wire_active = 1; } -void McpSingleWireStop() +void McpSingleWireStop(uint8_t force) { - if ((mcp_system_configuration & (1 << 8)) == 0) { return; } + if (!force && ((mcp_system_configuration & (1 << 8)) == 0)) { return; } mcp_system_configuration = mcp_system_configuration & (~(1 << 8)); McpSetSystemConfiguration(2); // 4 mcp_single_wire_active = 0; @@ -119,10 +440,69 @@ void McpSingleWireStop() /********************************************************************************************/ -unsigned long mcp_current = 0; -unsigned long mcp_voltage = 0; -unsigned long mcp_power = 0; -unsigned long mcp_frequency = 0; +void McpAddressReceive() +{ + // 06 05 004D 58 + mcp_address = serial_in_buffer[2] * 256 + serial_in_buffer[3]; +} + +void McpParseCalibration() +{ + bool action = false; + + // 06 37 C882 B6AD 0781 9273 06000000 00000000 00000000 0000 D3FF 0300 00000003 9204 120C1300 204E0000 9808 E0AB0000 D9940000 0200 24 + mcp_calibration_registers.gain_current_rms = McpExtractInt(serial_in_buffer, 2, 2); + mcp_calibration_registers.gain_voltage_rms = McpExtractInt(serial_in_buffer, 4, 2); + mcp_calibration_registers.gain_active_power = McpExtractInt(serial_in_buffer, 6, 2); + mcp_calibration_registers.gain_reactive_power = McpExtractInt(serial_in_buffer, 8, 2); + mcp_calibration_registers.offset_current_rms = McpExtractInt(serial_in_buffer, 10, 4); + mcp_calibration_registers.offset_active_power = McpExtractInt(serial_in_buffer, 14, 4); + mcp_calibration_registers.offset_reactive_power = McpExtractInt(serial_in_buffer, 18, 4); + mcp_calibration_registers.dc_offset_current = McpExtractInt(serial_in_buffer, 22, 2); + mcp_calibration_registers.phase_compensation = McpExtractInt(serial_in_buffer, 24, 2); + mcp_calibration_registers.apparent_power_divisor = McpExtractInt(serial_in_buffer, 26, 2); + + mcp_calibration_registers.system_configuration = McpExtractInt(serial_in_buffer, 28, 4); + mcp_calibration_registers.dio_configuration = McpExtractInt(serial_in_buffer, 32, 2); + mcp_calibration_registers.range = McpExtractInt(serial_in_buffer, 34, 4); + + mcp_calibration_registers.calibration_current = McpExtractInt(serial_in_buffer, 38, 4); + mcp_calibration_registers.calibration_voltage = McpExtractInt(serial_in_buffer, 42, 2); + mcp_calibration_registers.calibration_active_power = McpExtractInt(serial_in_buffer, 44, 4); + mcp_calibration_registers.calibration_reactive_power = McpExtractInt(serial_in_buffer, 48, 4); + mcp_calibration_registers.accumulation_interval = McpExtractInt(serial_in_buffer, 52, 2); + + if (mcp_calibration_setpoint.calibration_active_power) { + mcp_calibration_registers.calibration_active_power = mcp_calibration_setpoint.calibration_active_power; + if (McpCalibrationCalc(16)) { action = true; } + } + if (mcp_calibration_setpoint.calibration_voltage) { + mcp_calibration_registers.calibration_voltage = mcp_calibration_setpoint.calibration_voltage; + if (McpCalibrationCalc(0)) { action = true; } + } + if (mcp_calibration_setpoint.calibration_current) { + mcp_calibration_registers.calibration_current = mcp_calibration_setpoint.calibration_current; + if (McpCalibrationCalc(8)) { action = true; } + } + mcp_timeout = 0; + if (action) { McpSetCalibration(); } + McpResetSetpoints(); +} + +void McpParseFrequency() +{ + // 06 07 C350 8000 A0 + mcp_frequency_registers.line_frequency_ref = serial_in_buffer[2] * 256 + serial_in_buffer[3]; + mcp_frequency_registers.gain_line_frequency = serial_in_buffer[4] * 256 + serial_in_buffer[5]; + + if (mcp_calibration_setpoint.line_frequency_ref) { + mcp_frequency_registers.line_frequency_ref = mcp_calibration_setpoint.line_frequency_ref; + McpCalibrationLineFreqency(); + mcp_timeout = 0; + McpSetFrequency(); + } + McpResetSetpoints(); +} void McpParseData(uint8_t single_wire) { @@ -131,29 +511,31 @@ void McpParseData(uint8_t single_wire) // AB CD EF 51 06 00 00 B8 08 FC 0D 00 00 0A C4 11 // Header-- Current---- Volt- Power------ Freq- Ck - mcp_current = McpExtractInt((uint8_t*)serial_in_buffer, 3, 4); - mcp_voltage = McpExtractInt((uint8_t*)serial_in_buffer, 7, 2); - mcp_power = McpExtractInt((uint8_t*)serial_in_buffer, 9, 4); - mcp_frequency = McpExtractInt((uint8_t*)serial_in_buffer, 13, 2); + mcp_output_registers.current_rms = McpExtractInt(serial_in_buffer, 3, 4); + mcp_output_registers.voltage_rms = McpExtractInt(serial_in_buffer, 7, 2); + mcp_output_registers.active_power = McpExtractInt(serial_in_buffer, 9, 4); + mcp_output_registers.line_frequency = McpExtractInt(serial_in_buffer, 13, 2); } else { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // 06 19 61 06 00 00 FE 08 9B 0E 00 00 0B 00 00 00 97 0E 00 00 FF 7F 0C C6 35 + // 06 19 CE 18 00 00 F2 08 3A 38 00 00 66 00 00 00 93 38 00 00 36 7F 9A C6 B7 // Ak Ln Current---- Volt- ActivePower ReActivePow ApparentPow Factr Frequ Ck - mcp_current = McpExtractInt((uint8_t*)serial_in_buffer, 2, 4); - mcp_voltage = McpExtractInt((uint8_t*)serial_in_buffer, 6, 2); - mcp_power = McpExtractInt((uint8_t*)serial_in_buffer, 8, 4); - mcp_frequency = McpExtractInt((uint8_t*)serial_in_buffer, 22, 2); + mcp_output_registers.current_rms = McpExtractInt(serial_in_buffer, 2, 4); + mcp_output_registers.voltage_rms = McpExtractInt(serial_in_buffer, 6, 2); + mcp_output_registers.active_power = McpExtractInt(serial_in_buffer, 8, 4); + mcp_output_registers.reactive_power = McpExtractInt(serial_in_buffer, 12, 4); + mcp_output_registers.line_frequency = McpExtractInt(serial_in_buffer, 22, 2); } if (energy_power_on) { // Powered on - energy_frequency = (float)mcp_frequency / 1000; - energy_voltage = (float)mcp_voltage / 10; - energy_power = (float)mcp_power / 100; + energy_frequency = (float)mcp_output_registers.line_frequency / 1000; + energy_voltage = (float)mcp_output_registers.voltage_rms / 10; + energy_power = (float)mcp_output_registers.active_power / 100; if (0 == energy_power) { energy_current = 0; } else { - energy_current = (float)mcp_current / 10000; + energy_current = (float)mcp_output_registers.current_rms / 10000; } } else { // Powered off energy_frequency = 0; @@ -165,61 +547,85 @@ void McpParseData(uint8_t single_wire) bool McpSerialInput() { - Settings.flag.mqtt_serial = 0; // Disable possible SerialReceive handling - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - if (MCP_ERROR_CRC == serial_in_buffer[0]) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: Send " D_CHECKSUM_FAILURE)); - return 1; + unsigned long start = millis(); + while (millis() - start < 20) { + yield(); + if (Serial.available()) { + serial_in_buffer[serial_in_byte_counter++] = Serial.read(); + start = millis(); + } + } + + AddLogSerial(LOG_LEVEL_DEBUG_MORE); + + if (1 == serial_in_byte_counter) { + if (MCP_ERROR_CRC == serial_in_buffer[0]) { +// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: Send " D_CHECKSUM_FAILURE)); + mcp_timeout = 0; + } + else if (MCP_ERROR_NAK == serial_in_buffer[0]) { +// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: NAck")); + mcp_timeout = 0; + } } else if (MCP_ACK_FRAME == serial_in_buffer[0]) { - if ((serial_in_byte_counter > 1) && (serial_in_byte_counter == serial_in_buffer[1])) { + if (serial_in_byte_counter == serial_in_buffer[1]) { - AddLogSerial(LOG_LEVEL_DEBUG_MORE); - - uint8_t checksum = 0; - for (byte i = 0; i < serial_in_byte_counter -1; i++) { checksum += (uint8_t)serial_in_buffer[i]; } - if (checksum != serial_in_buffer[serial_in_byte_counter -1]) { + if (McpChecksum((uint8_t *)serial_in_buffer) != serial_in_buffer[serial_in_byte_counter -1]) { AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); } else { + if (5 == serial_in_buffer[1]) { McpAddressReceive(); } if (25 == serial_in_buffer[1]) { McpParseData(0); } + if (MCP_CALIBRATION_LEN + 3 == serial_in_buffer[1]) { McpParseCalibration(); } + if (MCP_FREQUENCY_LEN + 3 == serial_in_buffer[1]) { McpParseFrequency(); } } - return 1; + } + mcp_timeout = 0; } else if (MCP_SINGLE_WIRE == serial_in_buffer[0]) { if (serial_in_byte_counter == 16) { - AddLogSerial(LOG_LEVEL_DEBUG_MORE); - - uint8_t checksum = 0; - for (byte i = 3; i < serial_in_byte_counter -1; i++) { checksum += (uint8_t)serial_in_buffer[i]; } -// if (~checksum != serial_in_buffer[serial_in_byte_counter -1]) { -// AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); -// } else { + if (McpChecksum((uint8_t *)serial_in_buffer) != serial_in_buffer[serial_in_byte_counter -1]) { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); + } else { McpParseData(1); -// } - return 1; + } + } + mcp_timeout = 0; } - else { - return 1; - } - serial_in_byte = 0; // Discard - return 0; + return 1; } /********************************************************************************************/ void McpEverySecond() { - if (!mcp_single_wire_active) { - char get_state[] = "A5084100044E1656"; - SerialSendRaw(get_state, sizeof(get_state)); + uint8_t get_state[] = { 0xA5, 0x08, 0x41, 0x00, 0x04, 0x4E, 0x16, 0x00 }; + + if (mcp_timeout) { + mcp_timeout--; + } + else if (mcp_calibration_active) { + mcp_calibration_active--; + } + else if (mcp_init) { + McpSingleWireStop(1); + mcp_init = 0; + } + else if (!mcp_address) { + McpGetAddress(); + } + else if (!mcp_single_wire_active) { + McpSend(get_state); } - energy_kWhtoday += (energy_power / 36); - EnergyUpdateToday(); + if (mcp_output_registers.active_power) { + energy_kWhtoday_delta += ((mcp_output_registers.active_power * 10) / 36); + EnergyUpdateToday(); + } } void McpSnsInit() @@ -235,6 +641,9 @@ void McpDrvInit() digitalWrite(15, 0); // GPIO15 - MCP disable - Reset Delta Sigma ADC's baudrate = 4800; energy_calc_power_factor = 1; // Calculate power factor from data + mcp_timeout = 4; // Wait for initialization + mcp_init = 1; // Execute initial setup + McpResetSetpoints(); energy_flg = XNRG_04; } } @@ -246,20 +655,39 @@ boolean McpCommand() if ((CMND_POWERCAL == energy_command_code) || (CMND_VOLTAGECAL == energy_command_code) || (CMND_CURRENTCAL == energy_command_code)) { + // MCP Debug commands - PowerCal + if (1 == XdrvMailbox.payload) { McpSingleWireStart(); } + if (2 == XdrvMailbox.payload) { McpSingleWireStop(0); } + if (3 == XdrvMailbox.payload) { McpGetAddress(); } + + serviced = false; } else if (CMND_POWERSET == energy_command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 3601) && power_cycle) { -// Settings.energy_power_calibration = (XdrvMailbox.payload * power_cycle) / CSE_PREF; + if (XdrvMailbox.data_len && mcp_output_registers.active_power) { + Settings.energy_power_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * 100); + mcp_calibration_setpoint.calibration_active_power = Settings.energy_power_calibration; + McpGetCalibration(); } } else if (CMND_VOLTAGESET == energy_command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 501) && voltage_cycle) { -// Settings.energy_voltage_calibration = (XdrvMailbox.payload * voltage_cycle) / CSE_UREF; + if (XdrvMailbox.data_len && mcp_output_registers.voltage_rms) { + Settings.energy_voltage_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); + mcp_calibration_setpoint.calibration_voltage = Settings.energy_voltage_calibration; + McpGetCalibration(); } } else if (CMND_CURRENTSET == energy_command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 16001) && current_cycle) { -// Settings.energy_current_calibration = (XdrvMailbox.payload * current_cycle) / 1000; + if (XdrvMailbox.data_len && mcp_output_registers.current_rms) { + Settings.energy_current_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); + mcp_calibration_setpoint.calibration_current = Settings.energy_current_calibration; + McpGetCalibration(); + } + } + else if (CMND_FREQUENCYSET == energy_command_code) { + if (XdrvMailbox.data_len && mcp_output_registers.line_frequency) { + Settings.energy_frequency_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); + mcp_calibration_setpoint.line_frequency_ref = Settings.energy_frequency_calibration; + McpGetFrequency(); } } else serviced = false; // Unknown command From f7a8b1f9234ee628596b0b00d3736753016cae3b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 21 Sep 2018 16:02:56 +0200 Subject: [PATCH 15/93] Shelly2 clean up Shelly2 clean up --- sonoff/i18n.h | 2 +- sonoff/user_config.h | 2 +- sonoff/xdrv_03_energy.ino | 2 +- sonoff/xnrg_04_mcp39f501.ino | 36 ++++++++++-------------------------- 4 files changed, 13 insertions(+), 29 deletions(-) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 4ea5ab3fe..b0a7ec071 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -442,7 +442,7 @@ const char kUnitNames[] PROGMEM = D_UNIT_VOLT "|" D_UNIT_WATT "|" D_UNIT_WATTHOUR "|" - "d" D_UNIT_HERTZ ; + D_UNIT_HERTZ ; const char S_JSON_COMMAND_NVALUE_SPACE_UNIT[] PROGMEM = "{\"%s\":\"%d %s\"}"; const char S_JSON_COMMAND_LVALUE_SPACE_UNIT[] PROGMEM = "{\"%s\":\"%lu %s\"}"; diff --git a/sonoff/user_config.h b/sonoff/user_config.h index ef3e66fc2..438983a66 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -348,7 +348,7 @@ // Power monitoring sensors ----------------------- #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) #define USE_PZEM2 // Add support for PZEM003,014,016,017 Energy monitor (+1k1 code) -#define USE_MCP39F501 // Add support for MCP39F501 Energy monitor as used in Shelly 2 (+3k2 code) +#define USE_MCP39F501 // Add support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code) // -- Low level interface devices ----------------- #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram) diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index 068261971..860183f49 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -451,7 +451,7 @@ boolean EnergyCommand() nvalue = Settings.energy_current_calibration; unit = UNIT_MICROSECOND; } - else if ((CMND_FREQUENCYSET == command_code) && XnrgCall(FUNC_COMMAND)) { // dHz + else if ((CMND_FREQUENCYSET == command_code) && XnrgCall(FUNC_COMMAND)) { // Hz nvalue = Settings.energy_frequency_calibration; unit = UNIT_HERTZ; } diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index a9620ce50..c34846edf 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -56,12 +56,6 @@ #define MCP_FREQUENCY_GAIN_BASE 0x00AE #define MCP_FREQUENCY_LEN 4 -#define EMTR_OUT_BASE 0x0004 -#define EMTR_OUT_LEN 28 - -#define MCP_FLASH_READ 0x42 -#define MCP_FLASH_WRITE 0x50 - typedef struct mcp_calibration_registers_type { uint16_t gain_current_rms; uint16_t gain_voltage_rms; @@ -161,16 +155,6 @@ void McpSetInt(unsigned long value, uint8_t *data, uint8_t offset, size_t size) } } -void AddLogSerialSend(byte loglevel, uint8_t *buffer, int count) -{ - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_SERIAL "Send")); - for (int i = 0; i < count; i++) { - snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, *(buffer++)); - } - AddLog(loglevel); -} - - void McpSend(uint8_t *data) { if (mcp_timeout) { return; } @@ -179,7 +163,7 @@ void McpSend(uint8_t *data) data[0] = MCP_START_FRAME; data[data[1] -1] = McpChecksum(data); -// AddLogSerialSend(LOG_LEVEL_DEBUG_MORE, data, data[1]); +// AddLogSerial(LOG_LEVEL_DEBUG_MORE, data, data[1]); for (byte i = 0; i < data[1]; i++) { Serial.write(data[i]); @@ -252,7 +236,7 @@ calc: void McpCalibrationReactivePower() { - mcp_calibration_registers.gain_reactive_power = mcp_calibration_registers.gain_reactive_power * mcp_calibration_setpoint.calibration_reactive_power / mcp_output_registers.reactive_power; + mcp_calibration_registers.gain_reactive_power = mcp_calibration_registers.gain_reactive_power * mcp_calibration_registers.calibration_reactive_power / mcp_output_registers.reactive_power; } void McpCalibrationLineFreqency() @@ -605,6 +589,11 @@ void McpEverySecond() { uint8_t get_state[] = { 0xA5, 0x08, 0x41, 0x00, 0x04, 0x4E, 0x16, 0x00 }; + if (mcp_output_registers.active_power) { + energy_kWhtoday_delta += ((mcp_output_registers.active_power * 10) / 36); + EnergyUpdateToday(); + } + if (mcp_timeout) { mcp_timeout--; } @@ -621,11 +610,6 @@ void McpEverySecond() else if (!mcp_single_wire_active) { McpSend(get_state); } - - if (mcp_output_registers.active_power) { - energy_kWhtoday_delta += ((mcp_output_registers.active_power * 10) / 36); - EnergyUpdateToday(); - } } void McpSnsInit() @@ -656,9 +640,9 @@ boolean McpCommand() if ((CMND_POWERCAL == energy_command_code) || (CMND_VOLTAGECAL == energy_command_code) || (CMND_CURRENTCAL == energy_command_code)) { // MCP Debug commands - PowerCal - if (1 == XdrvMailbox.payload) { McpSingleWireStart(); } - if (2 == XdrvMailbox.payload) { McpSingleWireStop(0); } - if (3 == XdrvMailbox.payload) { McpGetAddress(); } +// if (1 == XdrvMailbox.payload) { McpSingleWireStart(); } +// if (2 == XdrvMailbox.payload) { McpSingleWireStop(0); } +// if (3 == XdrvMailbox.payload) { McpGetAddress(); } serviced = false; } From 557545cb56d774bfdfdeb32874a779b649a0fa2a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 21 Sep 2018 16:19:31 +0200 Subject: [PATCH 16/93] Cleanup Driver Cleanup Driver --- sonoff/sonoff.ino | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 84293f5bc..b5d752a3b 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -679,7 +679,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, (Settings.save_data > 1) ? stemp1 : GetStateText(Settings.save_data)); } - else if (CMND_SENSOR == command_code) { + else if ((CMND_SENSOR == command_code) || (CMND_DRIVER == command_code)) { XdrvMailbox.index = index; XdrvMailbox.data_len = data_len; XdrvMailbox.payload16 = payload16; @@ -687,18 +687,11 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) XdrvMailbox.grpflg = grpflg; XdrvMailbox.topic = command; XdrvMailbox.data = dataBuf; - XsnsCall(FUNC_COMMAND); -// if (!XsnsCall(FUNC_COMMAND)) type = NULL; - } - else if (CMND_DRIVER == command_code) { - XdrvMailbox.index = index; - XdrvMailbox.data_len = data_len; - XdrvMailbox.payload16 = payload16; - XdrvMailbox.payload = payload; - XdrvMailbox.grpflg = grpflg; - XdrvMailbox.topic = command; - XdrvMailbox.data = dataBuf; - XdrvCall(FUNC_COMMAND); + if (CMND_SENSOR == command_code) { + XsnsCall(FUNC_COMMAND); + } else { + XdrvCall(FUNC_COMMAND); + } } else if ((CMND_SETOPTION == command_code) && (index < 82)) { byte ptype; From 4992b4368916e7a8cdb8a35b08fee75071197379 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Fri, 21 Sep 2018 23:43:58 +0200 Subject: [PATCH 17/93] PCA9685 I2C Hardware PWM - Experimental --- sonoff/user_config.h | 2 + sonoff/xdrv_15_pca9685.ino | 184 +++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 sonoff/xdrv_15_pca9685.ino diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 438983a66..ee374d41c 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -298,6 +298,8 @@ // #define USE_MCP230xx_ADDR 0x20 // Enable MCP23008/MCP23017 I2C Address to use (Must be within range 0x20 through 0x27 - set according to your wired setup) // #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+1k5 code) // #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 MCP23008/MCP23017 I2C Address to use (Must be within range 0x20 through 0x27 - set according to your wired setup) // #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 new file mode 100644 index 000000000..e53b8d17f --- /dev/null +++ b/sonoff/xdrv_15_pca9685.ino @@ -0,0 +1,184 @@ +/* + xdrv_15_pca9685.ino - Support for I2C PCA9685 12bit 16 pin hardware PWM driver + + Copyright (C) 2018 Andre Thomas and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_PCA9685 + +#define XDRV_15 15 + +#define PCA9685_REG_MODE1 0x00 +#define PCA9685_REG_LED0_ON_L 0x06 +#define PCA9685_REG_PRE_SCALE 0xFE + +uint8_t pca9685_detected = 0; +uint16_t pca9685_freq = 50; + +void PCA9685_Detect(void) +{ + if (pca9685_detected) { return; } + + uint8_t buffer; + + if (I2cValidRead8(&buffer, USE_PCA9685_ADDR, PCA9685_REG_MODE1)) { + I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, 0x20); + if (I2cValidRead8(&buffer, USE_PCA9685_ADDR, PCA9685_REG_MODE1)) { + if (0x20 == buffer) { + pca9685_detected = 1; + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "PCA9685", USE_PCA9685_ADDR); + AddLog(LOG_LEVEL_DEBUG); + PCA9685_Reset(); // Reset the controller + } + } + } +} + +void PCA9685_Reset(void) +{ + I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, 0x80); + PCA9685_SetPWMfreq(50); + for (uint8_t pin=0;pin<16;pin++) { + PCA9685_SetPWM(pin,0,false); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"RESET\":\"OK\"}}")); +} + +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 + 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 + I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_PRE_SCALE, pre_scale_osc); // Set the pre-scaler + I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, current_mode1 | 0xA0); // Reset MODE1 register to original state and enable auto increment +} + +void PCA9685_SetPWM_Reg(uint8_t pin, uint16_t on, uint16_t off) { + uint8_t led_reg = PCA9685_REG_LED0_ON_L + 4 * pin; + uint32_t led_data = 0; + I2cWrite8(USE_PCA9685_ADDR, led_reg, on); + I2cWrite8(USE_PCA9685_ADDR, led_reg+1, (on >> 8)); + I2cWrite8(USE_PCA9685_ADDR, led_reg+2, off); + I2cWrite8(USE_PCA9685_ADDR, led_reg+3, (off >> 8)); +} + +void PCA9685_SetPWM(uint8_t pin, uint16_t pwm, bool inverted) { + if (4096 == pwm) { + PCA9685_SetPWM_Reg(pin, 4096, 0); // Special use additional bit causes channel to turn on completely without PWM + } else { + PCA9685_SetPWM_Reg(pin, 0, pwm); + } +} + +bool PCA9685_Command(void) +{ + boolean serviced = true; + boolean validpin = false; + uint8_t paramcount = 0; + if (XdrvMailbox.data_len > 0) { + paramcount=1; + } else { + serviced = false; + return serviced; + } + char sub_string[XdrvMailbox.data_len]; + for (uint8_t ca=0;ca 1) { + 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\"}}")); + return serviced; + } + } else { // No parameter was given for setfreq, so we return current setting + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PWMF\":%i}}"),pca9685_freq); + return serviced; + } + } + if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"PWM")) { + if (paramcount > 1) { + uint8_t pin = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); + if (paramcount > 2) { + if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 3), "ON")) { + PCA9685_SetPWM(pin, 4096, false); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,4096); + serviced = true; + return serviced; + } + if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 3), "OFF")) { + PCA9685_SetPWM(pin, 0, false); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,0); + serviced = true; + return serviced; + } + uint16_t pwm = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); + if ((pin >= 0 && pin <= 15) && (pwm >= 0 && pwm <= 4096)) { + PCA9685_SetPWM(pin, pwm, false); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PIN\":%i,\"PWM\":%i}}"),pin,pwm); + serviced = true; + return serviced; + } + } + } + } + return serviced; +} + +boolean Xdrv15(byte function) +{ + boolean result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_MQTT_DATA: + break; + case FUNC_EVERY_SECOND: + PCA9685_Detect(); + 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; + } + } + return result; +} + +#endif // USE_PCA9685 +#endif // USE_IC2 From 4ff5667c2adeac42078c57d4dec38522d9ab7109 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Sat, 22 Sep 2018 00:17:08 +0200 Subject: [PATCH 18/93] PCA9685 I2C Hardware PWM - Experimental --- 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 ee374d41c..b93e44211 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -299,7 +299,7 @@ // #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+1k5 code) // #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 MCP23008/MCP23017 I2C Address to use (Must be within range 0x20 through 0x27 - set according to your wired setup) +// #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_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) From 20e8d76877123ffd0584e929c35d087e092d410c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 22 Sep 2018 12:04:38 +0200 Subject: [PATCH 19/93] TSL2561 driver fixes Rewrite TSL2561 driver to fix some issues (#3681) --- sonoff/_changelog.ino | 1 + sonoff/xsns_16_tsl2561.ino | 91 ++++++++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 29 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 72293c30d..908fd262a 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.2.1.5 20180921 * Add authentication to HTTP web pages * Add energy monitoring to Shelly2 (#2789) + * Rewrite TSL2561 driver to fix some issues (#3681) * * 6.2.1.4 20180916 * Add command SerialSend5 to send raw serial data like "A5074100545293" diff --git a/sonoff/xsns_16_tsl2561.ino b/sonoff/xsns_16_tsl2561.ino index ac0536c6a..9f785e3e4 100644 --- a/sonoff/xsns_16_tsl2561.ino +++ b/sonoff/xsns_16_tsl2561.ino @@ -31,17 +31,67 @@ Tsl2561 Tsl(Wire); +uint8_t tsl2561_type = 0; +uint8_t tsl2561_valid = 0; +uint32_t tsl2561_milliLux = 0; +char tsl2561_types[] = "TSL2561"; + +bool Tsl2561Read() +{ + if (tsl2561_valid) { tsl2561_valid--; } + + uint8_t id; + bool gain; + Tsl2561::exposure_t exposure; + uint16_t scaledFull, scaledIr; + uint32_t full, ir; + + if (Tsl.available()) { + if (Tsl.on()) { + if (Tsl.id(id) + && Tsl2561Util::autoGain(Tsl, gain, exposure, scaledFull, scaledIr) + && Tsl2561Util::normalizedLuminosity(gain, exposure, full = scaledFull, ir = scaledIr) + && Tsl2561Util::milliLux(full, ir, tsl2561_milliLux, Tsl2561::packageCS(id))) { + } else{ + tsl2561_milliLux = 0; + } + } + } + tsl2561_valid = SENSOR_MAX_MISS; + return true; +} + void Tsl2561Detect() { + if (tsl2561_type) { return; } + if (!Tsl.available()) { Tsl.begin(); if (Tsl.available()) { - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "TSL2561", Tsl.address()); + tsl2561_type = 1; + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, tsl2561_types, Tsl.address()); AddLog(LOG_LEVEL_DEBUG); } } } +void Tsl2561EverySecond() +{ + if (90 == (uptime %100)) { + // 1mS + Tsl2561Detect(); + } + else if (uptime &3) { + // 1mS + if (tsl2561_type) { + if (!Tsl2561Read()) { + AddLogMissed(tsl2561_types, tsl2561_valid); +// if (!tsl2561_valid) { tsl2561_type = 0; } + } + } + } +} + #ifdef USE_WEBSERVER const char HTTP_SNS_TSL2561[] PROGMEM = "%s{s}TSL2561 " D_ILLUMINANCE "{m}%u.%03u " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = @@ -49,37 +99,17 @@ const char HTTP_SNS_TSL2561[] PROGMEM = void Tsl2561Show(boolean json) { - uint8_t id; - bool gain; - Tsl2561::exposure_t exposure; - uint16_t scaledFull, scaledIr; - uint32_t full, ir; - uint32_t milliLux; - - if (Tsl.available()) { - if (Tsl.on()) { - if( Tsl.id(id) - && Tsl2561Util::autoGain(Tsl, gain, exposure, scaledFull, scaledIr) - && Tsl2561Util::normalizedLuminosity(gain, exposure, full = scaledFull, ir = scaledIr) - && Tsl2561Util::milliLux(full, ir, milliLux, Tsl2561::packageCS(id))) { - -// snprintf_P(log_data, sizeof(log_data), PSTR(D_ILLUMINANCE " g:%d, e:%d, f:%u, i:%u -> %u.%03u " D_UNIT_LUX), -// gain, exposure, full, ir, milliLux/1000, milliLux%1000); -// AddLog(LOG_LEVEL_DEBUG); - - if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"TSL2561\":{\"" D_JSON_ILLUMINANCE "\":%u.%03u}"), - mqtt_data, milliLux/1000, milliLux%1000); + if (tsl2561_valid) { + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"TSL2561\":{\"" D_JSON_ILLUMINANCE "\":%u.%03u}"), + mqtt_data, tsl2561_milliLux / 1000, tsl2561_milliLux % 1000); #ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_ILLUMINANCE, (milliLux+500)/1000); + if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, (tsl2561_milliLux + 500) / 1000); } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER - } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TSL2561, mqtt_data, milliLux/1000, milliLux%1000); + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TSL2561, mqtt_data, tsl2561_milliLux / 1000, tsl2561_milliLux % 1000); #endif // USE_WEBSERVER - } - } - Tsl.off(); } } } @@ -96,9 +126,12 @@ boolean Xsns16(byte function) if (i2c_flg) { switch (function) { - case FUNC_PREP_BEFORE_TELEPERIOD: + case FUNC_INIT: Tsl2561Detect(); break; + case FUNC_EVERY_SECOND: + Tsl2561EverySecond(); + break; case FUNC_JSON_APPEND: Tsl2561Show(1); break; From 57e7005b4898aaeb722444182123bff2651d86ca Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 22 Sep 2018 12:18:13 +0200 Subject: [PATCH 20/93] Fix TSL2561 timeslot --- sonoff/xsns_16_tsl2561.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/xsns_16_tsl2561.ino b/sonoff/xsns_16_tsl2561.ino index 9f785e3e4..61308aa20 100644 --- a/sonoff/xsns_16_tsl2561.ino +++ b/sonoff/xsns_16_tsl2561.ino @@ -81,8 +81,8 @@ void Tsl2561EverySecond() // 1mS Tsl2561Detect(); } - else if (uptime &3) { - // 1mS + else if (!(uptime %2)) { // Update every 2 seconds + // ?mS - 4Sec if (tsl2561_type) { if (!Tsl2561Read()) { AddLogMissed(tsl2561_types, tsl2561_valid); From 7a767f104cd2a9e1626bbcd1ee079f541086367f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 22 Sep 2018 15:09:53 +0200 Subject: [PATCH 21/93] 6.2.1.6 Remove some commands 6.2.1.6 20180922 * Removed commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet * Allow decimals as input to commands PowerSet, VoltageSet and CurrentSet * Add support for PCA9685 12bit 16pin hardware PWM driver (#3866) --- sonoff/_changelog.ino | 7 ++++++- sonoff/i18n.h | 3 --- sonoff/sonoff_version.h | 2 +- sonoff/xdrv_03_energy.ino | 35 ++++++++--------------------------- sonoff/xnrg_01_hlw8012.ino | 17 +++++++---------- sonoff/xnrg_02_cse7766.ino | 17 +++++++---------- sonoff/xnrg_04_mcp39f501.ino | 11 +---------- 7 files changed, 30 insertions(+), 62 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 908fd262a..2b954e151 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,9 @@ -/* 6.2.1.5 20180921 +/* 6.2.1.6 20180922 + * Removed commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet + * Allow decimals as input to commands PowerSet, VoltageSet and CurrentSet + * Add support for PCA9685 12bit 16pin hardware PWM driver (#3866) + * + * 6.2.1.5 20180921 * Add authentication to HTTP web pages * Add energy monitoring to Shelly2 (#2789) * Rewrite TSL2561 driver to fix some issues (#3681) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index a45d7687d..80f757447 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -287,11 +287,8 @@ #define D_CMND_CURRENTLOW "CurrentLow" #define D_CMND_CURRENTHIGH "CurrentHigh" #define D_CMND_ENERGYRESET "EnergyReset" -#define D_CMND_POWERCAL "PowerCal" #define D_CMND_POWERSET "PowerSet" -#define D_CMND_VOLTAGECAL "VoltageCal" #define D_CMND_VOLTAGESET "VoltageSet" -#define D_CMND_CURRENTCAL "CurrentCal" #define D_CMND_CURRENTSET "CurrentSet" #define D_CMND_FREQUENCYSET "FrequencySet" #define D_CMND_MAXPOWER "MaxPower" diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 43253e40f..228a48d92 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 0x06020105 +#define VERSION 0x06020106 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index 860183f49..3ccad7df4 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -29,14 +29,14 @@ enum EnergyCommands { CMND_POWERDELTA, CMND_POWERLOW, CMND_POWERHIGH, CMND_VOLTAGELOW, CMND_VOLTAGEHIGH, CMND_CURRENTLOW, CMND_CURRENTHIGH, - CMND_POWERCAL, CMND_POWERSET, CMND_VOLTAGECAL, CMND_VOLTAGESET, CMND_CURRENTCAL, CMND_CURRENTSET, CMND_FREQUENCYSET, + CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_ENERGYRESET, CMND_MAXENERGY, CMND_MAXENERGYSTART, CMND_MAXPOWER, CMND_MAXPOWERHOLD, CMND_MAXPOWERWINDOW, CMND_SAFEPOWER, CMND_SAFEPOWERHOLD, CMND_SAFEPOWERWINDOW }; const char kEnergyCommands[] PROGMEM = D_CMND_POWERDELTA "|" D_CMND_POWERLOW "|" D_CMND_POWERHIGH "|" D_CMND_VOLTAGELOW "|" D_CMND_VOLTAGEHIGH "|" D_CMND_CURRENTLOW "|" D_CMND_CURRENTHIGH "|" - D_CMND_POWERCAL "|" D_CMND_POWERSET "|" D_CMND_VOLTAGECAL "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTCAL "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" + D_CMND_POWERSET "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" D_CMND_ENERGYRESET "|" D_CMND_MAXENERGY "|" D_CMND_MAXENERGYSTART "|" D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|" D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW ; @@ -415,45 +415,21 @@ boolean EnergyCommand() command, energy_total_chr, energy_yesterday_chr, energy_daily_chr); status_flag = 1; } - else if ((CMND_POWERCAL == command_code) && XnrgCall(FUNC_COMMAND)) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 32001)) { - Settings.energy_power_calibration = (XdrvMailbox.payload > 4000) ? XdrvMailbox.payload : HLW_PREF_PULSE; // HLW = 12530, CSE = 5364 - } - nvalue = Settings.energy_power_calibration; - unit = UNIT_MICROSECOND; - } - else if ((CMND_VOLTAGECAL == command_code) && XnrgCall(FUNC_COMMAND)) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 32001)) { - Settings.energy_voltage_calibration = (XdrvMailbox.payload > 999) ? XdrvMailbox.payload : HLW_UREF_PULSE; // HLW = 1950, CSE = 1912 - } - nvalue = Settings.energy_voltage_calibration; - unit = UNIT_MICROSECOND; - } - else if ((CMND_CURRENTCAL == command_code) && XnrgCall(FUNC_COMMAND)) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 32001)) { - Settings.energy_current_calibration = (XdrvMailbox.payload > 1100) ? XdrvMailbox.payload : HLW_IREF_PULSE; // HLW = 3500, CSE = 16140 - } - nvalue = Settings.energy_current_calibration; - unit = UNIT_MICROSECOND; - } else if ((CMND_POWERSET == command_code) && XnrgCall(FUNC_COMMAND)) { // Watt - snprintf_P(command, sizeof(command), PSTR(D_CMND_POWERCAL)); nvalue = Settings.energy_power_calibration; unit = UNIT_MICROSECOND; } else if ((CMND_VOLTAGESET == command_code) && XnrgCall(FUNC_COMMAND)) { // Volt - snprintf_P(command, sizeof(command), PSTR(D_CMND_VOLTAGECAL)); nvalue = Settings.energy_voltage_calibration; unit = UNIT_MICROSECOND; } else if ((CMND_CURRENTSET == command_code) && XnrgCall(FUNC_COMMAND)) { // milliAmpere - snprintf_P(command, sizeof(command), PSTR(D_CMND_CURRENTCAL)); nvalue = Settings.energy_current_calibration; unit = UNIT_MICROSECOND; } else if ((CMND_FREQUENCYSET == command_code) && XnrgCall(FUNC_COMMAND)) { // Hz nvalue = Settings.energy_frequency_calibration; - unit = UNIT_HERTZ; + unit = UNIT_MICROSECOND; } #if FEATURE_POWER_LIMIT @@ -518,6 +494,11 @@ boolean EnergyCommand() else serviced = false; // Unknown command if (serviced && !status_flag) { + + if (UNIT_MICROSECOND == unit) { + snprintf_P(command, sizeof(command), PSTR("%sCal"), command); + } + if (Settings.flag.value_units) { snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_LVALUE_SPACE_UNIT, command, nvalue, GetTextIndexed(sunit, sizeof(sunit), unit, kUnitNames)); } else { diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino index 6ef196fb1..5140d6596 100644 --- a/sonoff/xnrg_01_hlw8012.ino +++ b/sonoff/xnrg_01_hlw8012.ino @@ -227,22 +227,19 @@ boolean HlwCommand() { boolean serviced = true; - if ((CMND_POWERCAL == energy_command_code) || (CMND_VOLTAGECAL == energy_command_code) || (CMND_CURRENTCAL == energy_command_code)) { - - } - else if (CMND_POWERSET == energy_command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 3601) && hlw_cf_pulse_length) { - Settings.energy_power_calibration = (XdrvMailbox.payload * 10 * hlw_cf_pulse_length) / hlw_power_ratio; + if (CMND_POWERSET == energy_command_code) { + if (XdrvMailbox.data_len && hlw_cf_pulse_length) { + Settings.energy_power_calibration = ((unsigned long)(CharToDouble(XdrvMailbox.data) * 10) * hlw_cf_pulse_length) / hlw_power_ratio; } } else if (CMND_VOLTAGESET == energy_command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 501) && hlw_cf1_voltage_pulse_length) { - Settings.energy_voltage_calibration = (XdrvMailbox.payload * 10 * hlw_cf1_voltage_pulse_length) / hlw_voltage_ratio; + if (XdrvMailbox.data_len && hlw_cf1_voltage_pulse_length) { + Settings.energy_voltage_calibration = ((unsigned long)(CharToDouble(XdrvMailbox.data) * 10) * hlw_cf1_voltage_pulse_length) / hlw_voltage_ratio; } } else if (CMND_CURRENTSET == energy_command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 16001) && hlw_cf1_current_pulse_length) { - Settings.energy_current_calibration = (XdrvMailbox.payload * hlw_cf1_current_pulse_length) / hlw_current_ratio; + if (XdrvMailbox.data_len && hlw_cf1_current_pulse_length) { + Settings.energy_current_calibration = ((unsigned long)(CharToDouble(XdrvMailbox.data)) * hlw_cf1_current_pulse_length) / hlw_current_ratio; } } else serviced = false; // Unknown command diff --git a/sonoff/xnrg_02_cse7766.ino b/sonoff/xnrg_02_cse7766.ino index 84535cf96..a433bc4a4 100644 --- a/sonoff/xnrg_02_cse7766.ino +++ b/sonoff/xnrg_02_cse7766.ino @@ -195,22 +195,19 @@ boolean CseCommand() { boolean serviced = true; - if ((CMND_POWERCAL == energy_command_code) || (CMND_VOLTAGECAL == energy_command_code) || (CMND_CURRENTCAL == energy_command_code)) { - - } - else if (CMND_POWERSET == energy_command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 3601) && power_cycle) { - Settings.energy_power_calibration = (XdrvMailbox.payload * power_cycle) / CSE_PREF; + if (CMND_POWERSET == energy_command_code) { + if (XdrvMailbox.data_len && power_cycle) { + Settings.energy_power_calibration = ((unsigned long)CharToDouble(XdrvMailbox.data) * power_cycle) / CSE_PREF; } } else if (CMND_VOLTAGESET == energy_command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 501) && voltage_cycle) { - Settings.energy_voltage_calibration = (XdrvMailbox.payload * voltage_cycle) / CSE_UREF; + if (XdrvMailbox.data_len && voltage_cycle) { + Settings.energy_voltage_calibration = ((unsigned long)CharToDouble(XdrvMailbox.data) * voltage_cycle) / CSE_UREF; } } else if (CMND_CURRENTSET == energy_command_code) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 16001) && current_cycle) { - Settings.energy_current_calibration = (XdrvMailbox.payload * current_cycle) / 1000; + if (XdrvMailbox.data_len && current_cycle) { + Settings.energy_current_calibration = ((unsigned long)CharToDouble(XdrvMailbox.data) * current_cycle) / 1000; } } else serviced = false; // Unknown command diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index c34846edf..05d55a425 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -637,16 +637,7 @@ boolean McpCommand() { boolean serviced = true; - if ((CMND_POWERCAL == energy_command_code) || (CMND_VOLTAGECAL == energy_command_code) || (CMND_CURRENTCAL == energy_command_code)) { - - // MCP Debug commands - PowerCal -// if (1 == XdrvMailbox.payload) { McpSingleWireStart(); } -// if (2 == XdrvMailbox.payload) { McpSingleWireStop(0); } -// if (3 == XdrvMailbox.payload) { McpGetAddress(); } - - serviced = false; - } - else if (CMND_POWERSET == energy_command_code) { + if (CMND_POWERSET == energy_command_code) { if (XdrvMailbox.data_len && mcp_output_registers.active_power) { Settings.energy_power_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * 100); mcp_calibration_setpoint.calibration_active_power = Settings.energy_power_calibration; From 544abec7bf836ce945b2b65770d1895d07017951 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 22 Sep 2018 15:42:18 +0200 Subject: [PATCH 22/93] Set force_update to true for buttons --- sonoff/xdrv_12_home_assistant.ino | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sonoff/xdrv_12_home_assistant.ino b/sonoff/xdrv_12_home_assistant.ino index 5c8a2a7cf..b085947ae 100644 --- a/sonoff/xdrv_12_home_assistant.ino +++ b/sonoff/xdrv_12_home_assistant.ino @@ -19,7 +19,7 @@ #ifdef USE_HOME_ASSISTANT -const char HASS_DISCOVER_SWITCH[] PROGMEM = +const char HASS_DISCOVER_RELAY[] PROGMEM = "{\"name\":\"%s\"," // dualr2 1 "\"command_topic\":\"%s\"," // cmnd/dualr2/POWER2 "\"state_topic\":\"%s\"," // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",") @@ -39,7 +39,8 @@ const char HASS_DISCOVER_BUTTON[] PROGMEM = // "\"optimistic\":\"false\"," // false is Hass default when state_topic is set "\"availability_topic\":\"%s\"," // tele/dualr2/LWT "\"payload_available\":\"" D_ONLINE "\"," // Online - "\"payload_not_available\":\"" D_OFFLINE "\""; // Offline + "\"payload_not_available\":\"" D_OFFLINE "\"," // Offline + "\"force_update\":true"; const char HASS_DISCOVER_LIGHT_DIMMER[] PROGMEM = "%s,\"brightness_command_topic\":\"%s\"," // cmnd/led2/Dimmer @@ -102,7 +103,7 @@ void HAssDiscoverRelay() GetTopic_P(command_topic, CMND, mqtt_topic, value_template); GetTopic_P(state_topic, STAT, mqtt_topic, S_RSLT_RESULT); GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT); - snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_SWITCH, name, command_topic, state_topic, value_template, Settings.state_text[0], Settings.state_text[1], availability_topic); + snprintf_P(mqtt_data, sizeof(mqtt_data), HASS_DISCOVER_RELAY, name, command_topic, state_topic, value_template, Settings.state_text[0], Settings.state_text[1], availability_topic); if (is_light) { char brightness_command_topic[TOPSZ]; From 665a4abc47cbee81eb32cf5bcd23782ee044561b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 22 Sep 2018 16:09:13 +0200 Subject: [PATCH 23/93] Fix Pow R2 and S31 low power * Add power value below 5W to Sonoff Pow R2 and S31 (#3745) * Add force_update to Home Assistant discovery (#3873) --- sonoff/_changelog.ino | 2 ++ sonoff/xnrg_02_cse7766.ino | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 2b954e151..cb72ff407 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -2,6 +2,8 @@ * Removed commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet * Allow decimals as input to commands PowerSet, VoltageSet and CurrentSet * Add support for PCA9685 12bit 16pin hardware PWM driver (#3866) + * Add power value below 5W to Sonoff Pow R2 and S31 (#3745) + * Add force_update to Home Assistant discovery (#3873) * * 6.2.1.5 20180921 * Add authentication to HTTP web pages diff --git a/sonoff/xnrg_02_cse7766.ino b/sonoff/xnrg_02_cse7766.ino index a433bc4a4..8ba1b146e 100644 --- a/sonoff/xnrg_02_cse7766.ino +++ b/sonoff/xnrg_02_cse7766.ino @@ -27,6 +27,8 @@ #define XNRG_02 2 +#define CSE_MAX_INVALID_POWER 128 // Number of invalid power receipts before deciding active power is zero + #define CSE_NOT_CALIBRATED 0xAA #define CSE_PULSES_NOT_INITIALIZED -1 @@ -42,10 +44,12 @@ long power_cycle = 0; unsigned long power_cycle_first = 0; long cf_pulses = 0; long cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; +uint8_t cse_power_invalid = CSE_MAX_INVALID_POWER; void CseReceived() { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + // 55 5A 02 F7 60 00 03 5A 00 40 10 04 8B 9F 51 A6 58 18 72 75 61 AC A1 30 - Power not valid (load below 5W) // 55 5A 02 F7 60 00 03 AB 00 40 10 02 60 5D 51 A6 58 03 E9 EF 71 0B 7A 36 // Hd Id VCal---- Voltage- ICal---- Current- PCal---- Power--- Ad CF--- Ck @@ -89,10 +93,11 @@ void CseReceived() energy_voltage = (float)(Settings.energy_voltage_calibration * CSE_UREF) / (float)voltage_cycle; } if (adjustement & 0x10) { // Power valid + cse_power_invalid = 0; if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range energy_power = 0; } else { - if (0 == power_cycle_first) power_cycle_first = power_cycle; // Skip first incomplete power_cycle + if (0 == power_cycle_first) { power_cycle_first = power_cycle; } // Skip first incomplete power_cycle if (power_cycle_first != power_cycle) { power_cycle_first = -1; energy_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)power_cycle; @@ -101,8 +106,12 @@ void CseReceived() } } } else { - power_cycle_first = 0; - energy_power = 0; // Powered on but no load + if (cse_power_invalid < CSE_MAX_INVALID_POWER) { // Allow measurements down to about 1W + cse_power_invalid++; + } else { + power_cycle_first = 0; + energy_power = 0; // Powered on but no load + } } if (adjustement & 0x20) { // Current valid if (0 == energy_power) { From f05fc71d675101572a9fbd7ac90ead0542537528 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 22 Sep 2018 17:37:49 +0200 Subject: [PATCH 24/93] Fix rule trigger POWER1#STATE Fix rule trigger POWER1#STATE execution after restart and SetOption0 is 0 (#3856) --- sonoff/_changelog.ino | 1 + sonoff/sonoff.h | 2 +- sonoff/sonoff.ino | 6 +++++- sonoff/xdrv_10_rules.ino | 1 + sonoff/xdrv_interface.ino | 8 -------- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index cb72ff407..b220dc4b3 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -4,6 +4,7 @@ * Add support for PCA9685 12bit 16pin hardware PWM driver (#3866) * Add power value below 5W to Sonoff Pow R2 and S31 (#3745) * Add force_update to Home Assistant discovery (#3873) + * Fix rule trigger POWER1#STATE execution after restart and SetOption0 is 0 (#3856) * * 6.2.1.5 20180921 * Add authentication to HTTP web pages diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 80356d475..c3d514f0c 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -203,7 +203,7 @@ enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_R enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX}; 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_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART, FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_RULE_INIT_POWER, FUNC_SHOW_SENSOR, 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.ino b/sonoff/sonoff.ino index b5d752a3b..a405fe47b 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -335,7 +335,8 @@ void SetDevicePower(power_t rpower, int source) } } - XdrvSetPower(rpower); + XdrvMailbox.index = rpower; + XdrvCall(FUNC_SET_POWER); if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) { Serial.write(0xA0); @@ -2613,6 +2614,9 @@ void setup() } } + XdrvMailbox.index = power; + XdrvCall(FUNC_RULE_INIT_POWER); + blink_powersave = power; snprintf_P(log_data, sizeof(log_data), PSTR(D_PROJECT " %s %s (" D_CMND_TOPIC " %s, " D_FALLBACK " %s, " D_CMND_GROUPTOPIC " %s) " D_VERSION " %s-" ARDUINO_ESP8266_RELEASE), diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 930bde7d5..5ef59c037 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -628,6 +628,7 @@ boolean Xdrv10(byte function) case FUNC_EVERY_SECOND: RulesEverySecond(); break; + case FUNC_RULE_INIT_POWER: case FUNC_SET_POWER: RulesSetPower(); break; diff --git a/sonoff/xdrv_interface.ino b/sonoff/xdrv_interface.ino index 43a391076..a88d3b5f8 100644 --- a/sonoff/xdrv_interface.ino +++ b/sonoff/xdrv_interface.ino @@ -153,14 +153,6 @@ boolean XdrvCommand(uint8_t grpflg, char *type, uint16_t index, char *dataBuf, u return XdrvCall(FUNC_COMMAND); } -void XdrvSetPower(power_t mpower) -{ -// XdrvMailbox.valid = 1; - XdrvMailbox.index = mpower; - - XdrvCall(FUNC_SET_POWER); -} - boolean XdrvMqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t sdataBuf) { XdrvMailbox.index = stopicBuf; From 01ce1b0c91a72d46a87c517626038b11497521da Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 23 Sep 2018 13:55:42 +0200 Subject: [PATCH 25/93] Fix Shelly2 monitoring Disable serial logging on Shelly2 as serial is being used by energy monitoring (#3878) --- sonoff/_changelog.ino | 1 + sonoff/sonoff.h | 2 +- sonoff/sonoff.ino | 4 ---- sonoff/xdrv_10_rules.ino | 2 +- sonoff/xnrg_04_mcp39f501.ino | 1 + 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index b220dc4b3..f38b68153 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -5,6 +5,7 @@ * Add power value below 5W to Sonoff Pow R2 and S31 (#3745) * Add force_update to Home Assistant discovery (#3873) * Fix rule trigger POWER1#STATE execution after restart and SetOption0 is 0 (#3856) + * Disable serial logging on Shelly2 as serial is being used by energy monitoring (#3878) * * 6.2.1.5 20180921 * Add authentication to HTTP web pages diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index c3d514f0c..80356d475 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -203,7 +203,7 @@ enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_R enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX}; 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_RULE_INIT_POWER, FUNC_SHOW_SENSOR, + 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}; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index a405fe47b..dc1445fc4 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -2613,10 +2613,6 @@ void setup() SetPulseTimer(i, Settings.pulse_timer[i]); } } - - XdrvMailbox.index = power; - XdrvCall(FUNC_RULE_INIT_POWER); - blink_powersave = power; snprintf_P(log_data, sizeof(log_data), PSTR(D_PROJECT " %s %s (" D_CMND_TOPIC " %s, " D_FALLBACK " %s, " D_CMND_GROUPTOPIC " %s) " D_VERSION " %s-" ARDUINO_ESP8266_RELEASE), diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 5ef59c037..303207c10 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -366,6 +366,7 @@ void RulesEvery50ms() if (Settings.rule_enabled) { // Any rule enabled char json_event[120]; + if (-1 == rules_new_power) { rules_new_power = power; } if (rules_new_power != rules_old_power) { if (rules_old_power != -1) { for (byte i = 0; i < devices_present; i++) { @@ -628,7 +629,6 @@ boolean Xdrv10(byte function) case FUNC_EVERY_SECOND: RulesEverySecond(); break; - case FUNC_RULE_INIT_POWER: case FUNC_SET_POWER: RulesSetPower(); break; diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index 05d55a425..408e0ca26 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -614,6 +614,7 @@ void McpEverySecond() void McpSnsInit() { + SetSeriallog(LOG_LEVEL_NONE); // Free serial interface from logging interference digitalWrite(15, 1); // GPIO15 - MCP enable } From 683c21124114a25f9d0bdfd3a9712a9dc7095fb9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 23 Sep 2018 16:41:22 +0200 Subject: [PATCH 26/93] Fix Shelly2 wrong FrequencySet Fix Shelly2 wrong FrequencySet calculation and add input range checks (#3882) --- sonoff/_changelog.ino | 1 + sonoff/xnrg_04_mcp39f501.ino | 45 +++++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index f38b68153..b7988c69c 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -6,6 +6,7 @@ * Add force_update to Home Assistant discovery (#3873) * Fix rule trigger POWER1#STATE execution after restart and SetOption0 is 0 (#3856) * Disable serial logging on Shelly2 as serial is being used by energy monitoring (#3878) + * Fix Shelly2 wrong FrequencySet calculation and add input range checks (#3882) * * 6.2.1.5 20180921 * Add authentication to HTTP web pages diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index 408e0ca26..3fa12da26 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -239,8 +239,12 @@ void McpCalibrationReactivePower() mcp_calibration_registers.gain_reactive_power = mcp_calibration_registers.gain_reactive_power * mcp_calibration_registers.calibration_reactive_power / mcp_output_registers.reactive_power; } -void McpCalibrationLineFreqency() +void McpCalibrationLineFrequency() { + if ((0xFFFF == mcp_output_registers.line_frequency) || (0 == mcp_frequency_registers.gain_line_frequency)) { // Reset values to 50Hz + mcp_output_registers.line_frequency = 50000; + mcp_frequency_registers.gain_line_frequency = 0x8000; + } mcp_frequency_registers.gain_line_frequency = mcp_frequency_registers.gain_line_frequency * mcp_frequency_registers.line_frequency_ref / mcp_output_registers.line_frequency; } @@ -481,7 +485,7 @@ void McpParseFrequency() if (mcp_calibration_setpoint.line_frequency_ref) { mcp_frequency_registers.line_frequency_ref = mcp_calibration_setpoint.line_frequency_ref; - McpCalibrationLineFreqency(); + McpCalibrationLineFrequency(); mcp_timeout = 0; McpSetFrequency(); } @@ -637,33 +641,46 @@ void McpDrvInit() boolean McpCommand() { boolean serviced = true; + unsigned long value = 0; if (CMND_POWERSET == energy_command_code) { if (XdrvMailbox.data_len && mcp_output_registers.active_power) { - Settings.energy_power_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * 100); - mcp_calibration_setpoint.calibration_active_power = Settings.energy_power_calibration; - McpGetCalibration(); + value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 100); + if ((value > 100) && (value < 200000)) { // Between 1W and 2000W + Settings.energy_power_calibration = value; + mcp_calibration_setpoint.calibration_active_power = value; + McpGetCalibration(); + } } } else if (CMND_VOLTAGESET == energy_command_code) { if (XdrvMailbox.data_len && mcp_output_registers.voltage_rms) { - Settings.energy_voltage_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); - mcp_calibration_setpoint.calibration_voltage = Settings.energy_voltage_calibration; - McpGetCalibration(); + value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); + if ((value > 1000) && (value < 2600)) { // Between 100V and 260V + Settings.energy_voltage_calibration = value; + mcp_calibration_setpoint.calibration_voltage = value; + McpGetCalibration(); + } } } else if (CMND_CURRENTSET == energy_command_code) { if (XdrvMailbox.data_len && mcp_output_registers.current_rms) { - Settings.energy_current_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); - mcp_calibration_setpoint.calibration_current = Settings.energy_current_calibration; - McpGetCalibration(); + value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); + if ((value > 100) && (value < 80000)) { // Between 10mA and 8A + Settings.energy_current_calibration = value; + mcp_calibration_setpoint.calibration_current = value; + McpGetCalibration(); + } } } else if (CMND_FREQUENCYSET == energy_command_code) { if (XdrvMailbox.data_len && mcp_output_registers.line_frequency) { - Settings.energy_frequency_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); - mcp_calibration_setpoint.line_frequency_ref = Settings.energy_frequency_calibration; - McpGetFrequency(); + value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 1000); + if ((value > 45000) && (value < 65000)) { // Between 45Hz and 65Hz + Settings.energy_frequency_calibration = value; + mcp_calibration_setpoint.line_frequency_ref = value; + McpGetFrequency(); + } } } else serviced = false; // Unknown command From 5fa47c3fdce4b8842f095d8be1c8492685176909 Mon Sep 17 00:00:00 2001 From: andrethomas Date: Mon, 24 Sep 2018 00:30:07 +0200 Subject: [PATCH 27/93] MCP230xx - Add missing (void) --- sonoff/xsns_29_mcp230xx.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 1ca59f8ed..9dbaf406a 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -691,7 +691,7 @@ void MCP230xx_OutputTelemetry(void) { #endif // USE_MCP230xx_OUTPUT -void MCP230xx_Interrupt_Counter_Report() { +void MCP230xx_Interrupt_Counter_Report(void) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"MCP230_INTTIMER\": {"), GetDateAndTime(DT_LOCAL).c_str()); for (uint8_t pinx = 0;pinx < mcp230xx_pincount;pinx++) { if (Settings.mcp230xx_config[pinx].int_count_en) { // Counting is enabled for this pin so we add to report From f65d8c0cbf72ad6f68502df771fb0c91a6c3185c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 24 Sep 2018 11:44:40 +0200 Subject: [PATCH 28/93] Fix possible array overflow Fix possible array overflow (#3887 ) --- sonoff/sonoff.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index dc1445fc4..91c1fbb9b 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -462,10 +462,11 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) grpflg = (strstr(topicBuf, Settings.mqtt_grptopic) != NULL); fallback_topic_flag = (strstr(topicBuf, mqtt_client) != NULL); - type = strrchr(topicBuf, '/') +1; // Last part of received topic is always the command (type) + type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type) index = 1; if (type != NULL) { + type++; for (i = 0; i < strlen(type); i++) { type[i] = toupper(type[i]); } From 43c3cf57d596a14c18313e55ef1ab447f377dde4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 24 Sep 2018 18:16:35 +0200 Subject: [PATCH 29/93] Shelly2 Cleanup Cleanup and debug updates --- sonoff/settings.h | 24 +- sonoff/settings.ino | 4 +- sonoff/xdrv_99_debug.ino | 186 ++++++++++---- sonoff/xnrg_04_mcp39f501.ino | 464 +++++++++++++++-------------------- 4 files changed, 349 insertions(+), 329 deletions(-) diff --git a/sonoff/settings.h b/sonoff/settings.h index 7da610891..bf862dd51 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -337,21 +337,21 @@ struct SYSCFG { } Settings; struct RTCRBT { - uint16_t valid; // 000 - uint8_t fast_reboot_count; // 002 - uint8_t free_003[1]; // 003 + uint16_t valid; // 280 (RTC memory offset 100 - sizeof(RTCRBT)) + uint8_t fast_reboot_count; // 282 + uint8_t free_003[1]; // 283 } RtcReboot; struct RTCMEM { - uint16_t valid; // 000 - byte oswatch_blocked_loop; // 002 - uint8_t ota_loader; // 003 - unsigned long energy_kWhtoday; // 004 - unsigned long energy_kWhtotal; // 008 - unsigned long pulse_counter[MAX_COUNTERS]; // 00C - power_t power; // 01C - uint8_t free_020[60]; // 020 - // 05C next free location (64 (=core) + 100 (=tasmota offset) + 92 (=0x5C RTCMEM struct) = 256 bytes (max = 512)) + uint16_t valid; // 290 (RTC memory offset 100) + byte oswatch_blocked_loop; // 292 + uint8_t ota_loader; // 293 + unsigned long energy_kWhtoday; // 294 + unsigned long energy_kWhtotal; // 298 + unsigned long pulse_counter[MAX_COUNTERS]; // 29C + power_t power; // 2AC + uint8_t free_020[60]; // 2B0 + // 2EC - 2FF free locations } RtcSettings; struct TIME_T { diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 5626f862b..0d8fa451a 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -95,7 +95,7 @@ void RtcSettingsSave() void RtcSettingsLoad() { - ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM)); + ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM)); // 0x290 #ifdef DEBUG_THEO AddLog_P(LOG_LEVEL_DEBUG, PSTR("Dump: Load")); RtcSettingsDump(); @@ -145,7 +145,7 @@ void RtcRebootSave() void RtcRebootLoad() { - ESP.rtcUserMemoryRead(100 - sizeof(RTCRBT), (uint32_t*)&RtcReboot, sizeof(RTCRBT)); + ESP.rtcUserMemoryRead(100 - sizeof(RTCRBT), (uint32_t*)&RtcReboot, sizeof(RTCRBT)); // 0x280 if (RtcReboot.valid != RTC_MEM_VALID) { memset(&RtcReboot, 0, sizeof(RTCRBT)); RtcReboot.valid = RTC_MEM_VALID; diff --git a/sonoff/xdrv_99_debug.ino b/sonoff/xdrv_99_debug.ino index 3cd2e69c5..abd209b82 100644 --- a/sonoff/xdrv_99_debug.ino +++ b/sonoff/xdrv_99_debug.ino @@ -35,20 +35,25 @@ * Debug commands \*********************************************************************************************/ -#define D_CMND_CFGDUMP "CfgDump" -#define D_CMND_CFGPOKE "CfgPoke" -#define D_CMND_CFGPEEK "CfgPeek" -#define D_CMND_CFGXOR "CfgXor" +#define D_CMND_CFGDUMP "CfgDump" +#define D_CMND_CFGPOKE "CfgPoke" +#define D_CMND_CFGPEEK "CfgPeek" +#define D_CMND_CFGSHOW "CfgShow" +#define D_CMND_CFGXOR "CfgXor" +#define D_CMND_CPUCHECK "CpuChk" #define D_CMND_EXCEPTION "Exception" -#define D_CMND_CPUCHECK "CpuChk" +#define D_CMND_FREEMEM "FreeMem" +#define D_CMND_RTCDUMP "RtcDump" +#define D_CMND_HELP "Help" -enum DebugCommands { CMND_CFGDUMP, CMND_CFGPEEK, CMND_CFGPOKE, CMND_CFGXOR, CMND_EXCEPTION, CMND_CPUCHECK }; -const char kDebugCommands[] PROGMEM = D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" D_CMND_CFGXOR "|" D_CMND_EXCEPTION "|" D_CMND_CPUCHECK; +enum DebugCommands { CMND_CFGDUMP, CMND_CFGPEEK, CMND_CFGPOKE, CMND_CFGSHOW, CMND_CFGXOR, CMND_CPUCHECK, CMND_EXCEPTION, CMND_FREEMEM, CMND_RTCDUMP, CMND_HELP }; +const char kDebugCommands[] PROGMEM = D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" D_CMND_CFGSHOW "|" D_CMND_CFGXOR "|" D_CMND_CPUCHECK "|" D_CMND_EXCEPTION "|" D_CMND_FREEMEM "|" D_CMND_RTCDUMP "|" D_CMND_HELP; uint32_t CPU_loops = 0; uint32_t CPU_last_millis = 0; uint32_t CPU_last_loop_time = 0; -uint8_t CPU_load_check = CPU_LOAD_CHECK; +uint8_t CPU_load_check = 0; +uint8_t CPU_show_freemem = 0; /*******************************************************************************************/ @@ -117,41 +122,6 @@ Decoding 14 results } } -/*******************************************************************************************/ - -void RtcSettingsDump() -{ - #define CFG_COLS 16 - - uint16_t idx; - uint16_t maxrow; - uint16_t row; - uint16_t col; - - uint8_t *buffer = (uint8_t *) &RtcSettings; - maxrow = ((sizeof(RTCMEM)+CFG_COLS)/CFG_COLS); - - for (row = 0; row < maxrow; row++) { - idx = row * CFG_COLS; - snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx); - for (col = 0; col < CFG_COLS; col++) { - if (!(col%4)) { - snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data); - for (col = 0; col < CFG_COLS; col++) { -// if (!(col%4)) { -// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); -// } - snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); - } - snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data); - AddLog(LOG_LEVEL_INFO); - } -} - #endif // DEBUG_THEO /*******************************************************************************************/ @@ -224,6 +194,68 @@ void DebugFreeMem() /*******************************************************************************************/ +void DebugRtcDump(char* parms) +{ + #define CFG_COLS 16 + + uint16_t idx; + uint16_t maxrow; + uint16_t row; + uint16_t col; + char *p; + + // |<--SDK data (256 bytes)-->|<--User data (512 bytes)-->| + // 000 - 0FF: SDK + // 000 - 01B: SDK rst_info + // 100 - 2FF: User + // 280 - 283: Tasmota RtcReboot (Offset 100 (x 4bytes) - sizeof(RTCRBT) (x 4bytes)) + // 290 - 2EB: Tasmota RtcSettings (Offset 100 (x 4bytes)) + + uint8_t buffer[768]; +// ESP.rtcUserMemoryRead(0, (uint32_t*)&buffer, sizeof(buffer)); + system_rtc_mem_read(0, (uint32_t*)&buffer, sizeof(buffer)); + + maxrow = ((sizeof(buffer)+CFG_COLS)/CFG_COLS); + + uint16_t srow = strtol(parms, &p, 16) / CFG_COLS; + uint16_t mrow = strtol(p, &p, 10); + +// snprintf_P(log_data, sizeof(log_data), PSTR("Cnfg: Parms %s, Start row %d, rows %d"), parms, srow, mrow); +// AddLog(LOG_LEVEL_DEBUG); + + if (0 == mrow) { // Default only 8 lines + mrow = 8; + } + if (srow > maxrow) { + srow = maxrow - mrow; + } + if (mrow < (maxrow - srow)) { + maxrow = srow + mrow; + } + + for (row = srow; row < maxrow; row++) { + idx = row * CFG_COLS; + snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx); + for (col = 0; col < CFG_COLS; col++) { + if (!(col%4)) { + snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data); + for (col = 0; col < CFG_COLS; col++) { +// if (!(col%4)) { +// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data); +// } + snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); + } + snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data); + AddLog(LOG_LEVEL_INFO); + } +} + +/*******************************************************************************************/ + void DebugCfgDump(char* parms) { #define CFG_COLS 16 @@ -322,6 +354,53 @@ void DebugCfgPoke(char* parms) AddLog(LOG_LEVEL_INFO); } +void DebugCfgShow(uint8_t more) +{ + uint8_t *SetAddr; + SetAddr = (uint8_t *)&Settings; + + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: Hostname (%d) [%s]"), (uint8_t *)&Settings.hostname - SetAddr, sizeof(Settings.hostname)-1, Settings.hostname); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: SSids (%d) [%s], [%s]"), (uint8_t *)&Settings.sta_ssid - SetAddr, sizeof(Settings.sta_ssid[0])-1, Settings.sta_ssid[0], Settings.sta_ssid[1]); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: Friendlynames (%d) [%s], [%s], [%s], [%s]"), (uint8_t *)&Settings.friendlyname - SetAddr, sizeof(Settings.friendlyname[0])-1, Settings.friendlyname[0], Settings.friendlyname[1], Settings.friendlyname[2], Settings.friendlyname[3]); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: OTA Url (%d) [%s]"), (uint8_t *)&Settings.ota_url - SetAddr, sizeof(Settings.ota_url)-1, Settings.ota_url); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: StateText (%d) [%s], [%s], [%s], [%s]"), (uint8_t *)&Settings.state_text - SetAddr, sizeof(Settings.state_text[0])-1, Settings.state_text[0], Settings.state_text[1], Settings.state_text[2], Settings.state_text[3]); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: Syslog Host (%d) [%s]"), (uint8_t *)&Settings.syslog_host - SetAddr, sizeof(Settings.syslog_host)-1, Settings.syslog_host); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: NTP Servers (%d) [%s], [%s], [%s]"), (uint8_t *)&Settings.ntp_server - SetAddr, sizeof(Settings.ntp_server[0])-1, Settings.ntp_server[0], Settings.ntp_server[1], Settings.ntp_server[2]); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT Host (%d) [%s]"), (uint8_t *)&Settings.mqtt_host - SetAddr, sizeof(Settings.mqtt_host)-1, Settings.mqtt_host); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT Client (%d) [%s]"), (uint8_t *)&Settings.mqtt_client - SetAddr, sizeof(Settings.mqtt_client)-1, Settings.mqtt_client); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT User (%d) [%s]"), (uint8_t *)&Settings.mqtt_user - SetAddr, sizeof(Settings.mqtt_user)-1, Settings.mqtt_user); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT FullTopic (%d) [%s]"), (uint8_t *)&Settings.mqtt_fulltopic - SetAddr, sizeof(Settings.mqtt_fulltopic)-1, Settings.mqtt_fulltopic); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT Topic (%d) [%s]"), (uint8_t *)&Settings.mqtt_topic - SetAddr, sizeof(Settings.mqtt_topic)-1, Settings.mqtt_topic); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT GroupTopic (%d) [%s]"), (uint8_t *)&Settings.mqtt_grptopic - SetAddr, sizeof(Settings.mqtt_grptopic)-1, Settings.mqtt_grptopic); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT ButtonTopic (%d) [%s]"), (uint8_t *)&Settings.button_topic - SetAddr, sizeof(Settings.button_topic)-1, Settings.button_topic); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT SwitchTopic (%d) [%s]"), (uint8_t *)&Settings.switch_topic - SetAddr, sizeof(Settings.switch_topic)-1, Settings.switch_topic); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT Prefixes (%d) [%s], [%s], [%s]"), (uint8_t *)&Settings.mqtt_prefix - SetAddr, sizeof(Settings.mqtt_prefix[0])-1, Settings.mqtt_prefix[0], Settings.mqtt_prefix[1], Settings.mqtt_prefix[2]); + AddLog(LOG_LEVEL_INFO); + if (17 == more) { + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: AP Passwords (%d) [%s], [%s]"), (uint8_t *)&Settings.sta_pwd - SetAddr, sizeof(Settings.sta_pwd[0])-1, Settings.sta_pwd[0], Settings.sta_pwd[1]); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: MQTT Password (%d) [%s]"), (uint8_t *)&Settings.mqtt_pwd - SetAddr, sizeof(Settings.mqtt_pwd)-1, Settings.mqtt_pwd); + AddLog(LOG_LEVEL_INFO); + snprintf_P(log_data, sizeof(log_data), PSTR("%03X: Web Password (%d) [%s]"), (uint8_t *)&Settings.web_password - SetAddr, sizeof(Settings.web_password)-1, Settings.web_password); + AddLog(LOG_LEVEL_INFO); + } +} + /*******************************************************************************************/ boolean DebugCommand() @@ -333,6 +412,15 @@ boolean DebugCommand() if (-1 == command_code) { serviced = false; // Unknown command } + else if (CMND_HELP == command_code) { + snprintf_P(log_data, sizeof(log_data), kDebugCommands); + AddLog(LOG_LEVEL_INFO); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); + } + else if (CMND_RTCDUMP == command_code) { + DebugRtcDump(XdrvMailbox.data); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); + } else if (CMND_CFGDUMP == command_code) { DebugCfgDump(XdrvMailbox.data); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); @@ -345,6 +433,10 @@ boolean DebugCommand() DebugCfgPoke(XdrvMailbox.data); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); } + else if (CMND_CFGSHOW == command_code) { + DebugCfgShow(XdrvMailbox.payload); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); + } #ifdef USE_WEBSERVER else if (CMND_CFGXOR == command_code) { if (XdrvMailbox.data_len > 0) { @@ -366,6 +458,12 @@ boolean DebugCommand() } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, CPU_load_check); } + else if (CMND_FREEMEM == command_code) { + if (XdrvMailbox.data_len > 0) { + CPU_show_freemem = XdrvMailbox.payload; + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, CPU_show_freemem); + } else serviced = false; // Unknown command return serviced; @@ -392,7 +490,7 @@ boolean Xdrv99(byte function) result = DebugCommand(); break; case FUNC_FREE_MEM: - DebugFreeMem(); + if (CPU_show_freemem) { DebugFreeMem(); } break; } return result; diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index 3fa12da26..abf11b71f 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -56,7 +56,7 @@ #define MCP_FREQUENCY_GAIN_BASE 0x00AE #define MCP_FREQUENCY_LEN 4 -typedef struct mcp_calibration_registers_type { +typedef struct mcp_cal_registers_type { uint16_t gain_current_rms; uint16_t gain_voltage_rms; uint16_t gain_active_power; @@ -77,24 +77,17 @@ typedef struct mcp_calibration_registers_type { uint32_t calibration_active_power; uint32_t calibration_reactive_power; uint16_t accumulation_interval; -} mcp_calibration_registers_type; -mcp_calibration_registers_type mcp_calibration_registers; +} mcp_cal_registers_type; typedef struct mcp_calibration_setpoint_type { uint32_t calibration_current; uint16_t calibration_voltage; uint32_t calibration_active_power; - uint32_t calibration_reactive_power; +// uint32_t calibration_reactive_power; uint16_t line_frequency_ref; } mcp_calibration_setpoint_type; mcp_calibration_setpoint_type mcp_calibration_setpoint; -typedef struct mcp_frequency_registers_type { - uint16_t line_frequency_ref; - uint16_t gain_line_frequency; -} mcp_frequency_registers_type; -mcp_frequency_registers_type mcp_frequency_registers; - typedef struct mcp_output_registers_type { uint32_t current_rms; uint16_t voltage_rms; @@ -103,15 +96,11 @@ typedef struct mcp_output_registers_type { uint32_t apparent_power; sint16_t power_factor; uint16_t line_frequency; - uint16_t thermistor_voltage; - uint16_t event_flag; - uint16_t system_status; } mcp_output_registers_type; mcp_output_registers_type mcp_output_registers; uint32_t mcp_system_configuration = 0x03000000; -uint16_t mcp_address = 0; -uint8_t mcp_single_wire_active = 0; +uint8_t mcp_address = 0; uint8_t mcp_calibration_active = 0; uint8_t mcp_init = 0; uint8_t mcp_timeout = 0; @@ -128,12 +117,8 @@ uint8_t McpChecksum(uint8_t *data) uint8_t offset = 0; uint8_t len = data[1] -1; - if (MCP_SINGLE_WIRE == data[0]) { - offset = 3; - len = 15; - } for (byte i = offset; i < len; i++) { checksum += data[i]; } - return (MCP_SINGLE_WIRE == data[0]) ? ~checksum : checksum; + return checksum; } unsigned long McpExtractInt(char *data, uint8_t offset, uint8_t size) @@ -170,19 +155,83 @@ void McpSend(uint8_t *data) } } -uint32_t McpGetRange(uint8_t shift) +void McpResetSetpoints(void) { - return (mcp_calibration_registers.range >> shift) & 0xFF; + memset(&mcp_calibration_setpoint, 0, sizeof(mcp_calibration_setpoint)); } -void McpSetRange(uint8_t shift, uint32_t range) +/********************************************************************************************/ + +void McpGetAddress(void) { - uint32_t old_range = McpGetRange(shift); - mcp_calibration_registers.range = mcp_calibration_registers.range ^ (old_range << shift); - mcp_calibration_registers.range = mcp_calibration_registers.range | (range << shift); + uint8_t data[] = { MCP_START_FRAME, 7, MCP_SET_ADDRESS, 0x00, 0x26, MCP_READ_16, 0x00 }; + + McpSend(data); } -bool McpCalibrationCalc(uint8_t range_shift) +void McpAddressReceive(void) +{ + // 06 05 004D 58 + mcp_address = serial_in_buffer[3]; +} + +/********************************************************************************************/ + +void McpGetCalibration(void) +{ + if (mcp_calibration_active) { return; } + mcp_calibration_active = 4; + + uint8_t data[] = { MCP_START_FRAME, 8, MCP_SET_ADDRESS, (MCP_CALIBRATION_BASE >> 8) & 0xFF, MCP_CALIBRATION_BASE & 0xFF, MCP_READ, MCP_CALIBRATION_LEN, 0x00 }; + + McpSend(data); +} + +void McpParseCalibration(void) +{ + bool action = false; + mcp_cal_registers_type cal_registers; + + // 06 37 C882 B6AD 0781 9273 06000000 00000000 00000000 0000 D3FF 0300 00000003 9204 120C1300 204E0000 9808 E0AB0000 D9940000 0200 24 + cal_registers.gain_current_rms = McpExtractInt(serial_in_buffer, 2, 2); + cal_registers.gain_voltage_rms = McpExtractInt(serial_in_buffer, 4, 2); + cal_registers.gain_active_power = McpExtractInt(serial_in_buffer, 6, 2); + cal_registers.gain_reactive_power = McpExtractInt(serial_in_buffer, 8, 2); + cal_registers.offset_current_rms = McpExtractInt(serial_in_buffer, 10, 4); + cal_registers.offset_active_power = McpExtractInt(serial_in_buffer, 14, 4); + cal_registers.offset_reactive_power = McpExtractInt(serial_in_buffer, 18, 4); + cal_registers.dc_offset_current = McpExtractInt(serial_in_buffer, 22, 2); + cal_registers.phase_compensation = McpExtractInt(serial_in_buffer, 24, 2); + cal_registers.apparent_power_divisor = McpExtractInt(serial_in_buffer, 26, 2); + + cal_registers.system_configuration = McpExtractInt(serial_in_buffer, 28, 4); + cal_registers.dio_configuration = McpExtractInt(serial_in_buffer, 32, 2); + cal_registers.range = McpExtractInt(serial_in_buffer, 34, 4); + + cal_registers.calibration_current = McpExtractInt(serial_in_buffer, 38, 4); + cal_registers.calibration_voltage = McpExtractInt(serial_in_buffer, 42, 2); + cal_registers.calibration_active_power = McpExtractInt(serial_in_buffer, 44, 4); + cal_registers.calibration_reactive_power = McpExtractInt(serial_in_buffer, 48, 4); + cal_registers.accumulation_interval = McpExtractInt(serial_in_buffer, 52, 2); + + if (mcp_calibration_setpoint.calibration_active_power) { + cal_registers.calibration_active_power = mcp_calibration_setpoint.calibration_active_power; + if (McpCalibrationCalc(&cal_registers, 16)) { action = true; } + } + if (mcp_calibration_setpoint.calibration_voltage) { + cal_registers.calibration_voltage = mcp_calibration_setpoint.calibration_voltage; + if (McpCalibrationCalc(&cal_registers, 0)) { action = true; } + } + if (mcp_calibration_setpoint.calibration_current) { + cal_registers.calibration_current = mcp_calibration_setpoint.calibration_current; + if (McpCalibrationCalc(&cal_registers, 8)) { action = true; } + } + mcp_timeout = 0; + if (action) { McpSetCalibration(&cal_registers); } + McpResetSetpoints(); +} + +bool McpCalibrationCalc(struct mcp_cal_registers_type *cal_registers, uint8_t range_shift) { uint32_t measured; uint32_t expected; @@ -191,16 +240,16 @@ bool McpCalibrationCalc(uint8_t range_shift) if (range_shift == 0) { measured = mcp_output_registers.voltage_rms; - expected = mcp_calibration_registers.calibration_voltage; - gain = &(mcp_calibration_registers.gain_voltage_rms); + expected = cal_registers->calibration_voltage; + gain = &(cal_registers->gain_voltage_rms); } else if (range_shift == 8) { measured = mcp_output_registers.current_rms; - expected = mcp_calibration_registers.calibration_current; - gain = &(mcp_calibration_registers.gain_current_rms); + expected = cal_registers->calibration_current; + gain = &(cal_registers->gain_current_rms); } else if (range_shift == 16) { measured = mcp_output_registers.active_power; - expected = mcp_calibration_registers.calibration_active_power; - gain = &(mcp_calibration_registers.gain_active_power); + expected = cal_registers->calibration_active_power; + gain = &(cal_registers->gain_active_power); } else { return false; } @@ -209,7 +258,7 @@ bool McpCalibrationCalc(uint8_t range_shift) return false; } - uint32_t range = McpGetRange(range_shift); + uint32_t range = (cal_registers->range >> range_shift) & 0xFF; calc: new_gain = (*gain) * expected / measured; @@ -229,104 +278,50 @@ calc: } *gain = new_gain; - McpSetRange(range_shift, range); + uint32_t old_range = (cal_registers->range >> range_shift) & 0xFF; + cal_registers->range = cal_registers->range ^ (old_range << range_shift); + cal_registers->range = cal_registers->range | (range << range_shift); return true; } - -void McpCalibrationReactivePower() +/* +void McpCalibrationReactivePower(void) { - mcp_calibration_registers.gain_reactive_power = mcp_calibration_registers.gain_reactive_power * mcp_calibration_registers.calibration_reactive_power / mcp_output_registers.reactive_power; + cal_registers.gain_reactive_power = cal_registers.gain_reactive_power * cal_registers.calibration_reactive_power / mcp_output_registers.reactive_power; } - -void McpCalibrationLineFrequency() -{ - if ((0xFFFF == mcp_output_registers.line_frequency) || (0 == mcp_frequency_registers.gain_line_frequency)) { // Reset values to 50Hz - mcp_output_registers.line_frequency = 50000; - mcp_frequency_registers.gain_line_frequency = 0x8000; - } - mcp_frequency_registers.gain_line_frequency = mcp_frequency_registers.gain_line_frequency * mcp_frequency_registers.line_frequency_ref / mcp_output_registers.line_frequency; -} - -void McpResetSetpoints() -{ - mcp_calibration_setpoint.calibration_active_power = 0; - mcp_calibration_setpoint.calibration_voltage = 0; - mcp_calibration_setpoint.calibration_current = 0; - mcp_calibration_setpoint.calibration_reactive_power = 0; - mcp_calibration_setpoint.line_frequency_ref = 0; -} - -/********************************************************************************************/ - -void McpGetAddress() -{ - // A5 07 41 00 26 52 65 - uint8_t data[7]; - - data[1] = sizeof(data); - data[2] = MCP_SET_ADDRESS; // Set address pointer - data[3] = 0x00; // address - data[4] = 0x26; // address - data[5] = MCP_READ_16; // Read 2 bytes - - McpSend(data); - - // Receives 06 05 004D 58 -} - -void McpGetCalibration() -{ - if (mcp_calibration_active) { return; } - mcp_calibration_active = 4; - - // A5 08 41 00 28 4E 34 98 - uint8_t data[8]; - - data[1] = sizeof(data); - data[2] = MCP_SET_ADDRESS; // Set address pointer - data[3] = (MCP_CALIBRATION_BASE >> 8) & 0xFF; // address - data[4] = (MCP_CALIBRATION_BASE >> 0) & 0xFF; // address - data[5] = MCP_READ; // Read N bytes - data[6] = MCP_CALIBRATION_LEN; - - McpSend(data); - - // Receives 06 37 C882 B6AD 0781 9273 06000000 00000000 00000000 0000 D3FF 0300 00000003 9204 120C1300 204E0000 9808 E0AB0000 D9940000 0200 24 -} - -void McpSetCalibration() +*/ +void McpSetCalibration(struct mcp_cal_registers_type *cal_registers) { uint8_t data[7 + MCP_CALIBRATION_LEN + 2 + 1]; data[1] = sizeof(data); - data[2] = MCP_SET_ADDRESS; // Set address pointer - data[3] = (MCP_CALIBRATION_BASE >> 8) & 0xFF; // address - data[4] = (MCP_CALIBRATION_BASE >> 0) & 0xFF; // address + data[2] = MCP_SET_ADDRESS; // Set address pointer + data[3] = (MCP_CALIBRATION_BASE >> 8) & 0xFF; // address + data[4] = (MCP_CALIBRATION_BASE >> 0) & 0xFF; // address - data[5] = MCP_WRITE; // Write N bytes + data[5] = MCP_WRITE; // Write N bytes data[6] = MCP_CALIBRATION_LEN; - McpSetInt(mcp_calibration_registers.gain_current_rms, data, 0+7, 2); - McpSetInt(mcp_calibration_registers.gain_voltage_rms, data, 2+7, 2); - McpSetInt(mcp_calibration_registers.gain_active_power, data, 4+7, 2); - McpSetInt(mcp_calibration_registers.gain_reactive_power, data, 6+7, 2); - McpSetInt(mcp_calibration_registers.offset_current_rms, data, 8+7, 4); - McpSetInt(mcp_calibration_registers.offset_active_power, data, 12+7, 4); - McpSetInt(mcp_calibration_registers.offset_reactive_power, data, 16+7, 4); - McpSetInt(mcp_calibration_registers.dc_offset_current, data, 20+7, 2); - McpSetInt(mcp_calibration_registers.phase_compensation, data, 22+7, 2); - McpSetInt(mcp_calibration_registers.apparent_power_divisor, data, 24+7, 2); + McpSetInt(cal_registers->gain_current_rms, data, 0+7, 2); + McpSetInt(cal_registers->gain_voltage_rms, data, 2+7, 2); + McpSetInt(cal_registers->gain_active_power, data, 4+7, 2); + McpSetInt(cal_registers->gain_reactive_power, data, 6+7, 2); + McpSetInt(cal_registers->offset_current_rms, data, 8+7, 4); + McpSetInt(cal_registers->offset_active_power, data, 12+7, 4); + McpSetInt(cal_registers->offset_reactive_power, data, 16+7, 4); + McpSetInt(cal_registers->dc_offset_current, data, 20+7, 2); + McpSetInt(cal_registers->phase_compensation, data, 22+7, 2); + McpSetInt(cal_registers->apparent_power_divisor, data, 24+7, 2); - McpSetInt(mcp_calibration_registers.system_configuration, data, 26+7, 4); - McpSetInt(mcp_calibration_registers.dio_configuration, data, 30+7, 2); - McpSetInt(mcp_calibration_registers.range, data, 32+7, 4); + McpSetInt(cal_registers->system_configuration, data, 26+7, 4); + McpSetInt(cal_registers->dio_configuration, data, 30+7, 2); + McpSetInt(cal_registers->range, data, 32+7, 4); - McpSetInt(mcp_calibration_registers.calibration_current, data, 36+7, 4); - McpSetInt(mcp_calibration_registers.calibration_voltage, data, 40+7, 2); - McpSetInt(mcp_calibration_registers.calibration_active_power, data, 42+7, 4); - McpSetInt(mcp_calibration_registers.calibration_reactive_power, data, 46+7, 4); - McpSetInt(mcp_calibration_registers.accumulation_interval, data, 50+7, 2); + McpSetInt(cal_registers->calibration_current, data, 36+7, 4); + McpSetInt(cal_registers->calibration_voltage, data, 40+7, 2); + McpSetInt(cal_registers->calibration_active_power, data, 42+7, 4); + McpSetInt(cal_registers->calibration_reactive_power, data, 46+7, 4); + McpSetInt(cal_registers->accumulation_interval, data, 50+7, 2); data[MCP_CALIBRATION_LEN+7] = MCP_SAVE_REGISTERS; // Save registers to flash data[MCP_CALIBRATION_LEN+8] = mcp_address; // Device address @@ -334,187 +329,123 @@ void McpSetCalibration() McpSend(data); } -void McpGetFrequency() +/********************************************************************************************/ + +void McpGetFrequency(void) { if (mcp_calibration_active) { return; } mcp_calibration_active = 4; - // A5 0B 41 00 94 52 41 00 AE 52 18 - uint8_t data[11]; - - data[1] = sizeof(data); - data[2] = MCP_SET_ADDRESS; // Set address pointer - data[3] = (MCP_FREQUENCY_REF_BASE >> 8) & 0xFF; // address - data[4] = (MCP_FREQUENCY_REF_BASE >> 0) & 0xFF; // address - - data[5] = MCP_READ_16; // Read register - - data[6] = MCP_SET_ADDRESS; // Set address pointer - data[7] = (MCP_FREQUENCY_GAIN_BASE >> 8) & 0xFF; // address - data[8] = (MCP_FREQUENCY_GAIN_BASE >> 0) & 0xFF; // address - - data[9] = MCP_READ_16; // Read register + uint8_t data[] = { MCP_START_FRAME, 11, MCP_SET_ADDRESS, (MCP_FREQUENCY_REF_BASE >> 8) & 0xFF, MCP_FREQUENCY_REF_BASE & 0xFF, MCP_READ_16, + MCP_SET_ADDRESS, (MCP_FREQUENCY_GAIN_BASE >> 8) & 0xFF, MCP_FREQUENCY_GAIN_BASE & 0xFF, MCP_READ_16, 0x00 }; McpSend(data); } -void McpSetFrequency() +void McpParseFrequency(void) +{ + // 06 07 C350 8000 A0 + uint16_t line_frequency_ref = serial_in_buffer[2] * 256 + serial_in_buffer[3]; + uint16_t gain_line_frequency = serial_in_buffer[4] * 256 + serial_in_buffer[5]; + + if (mcp_calibration_setpoint.line_frequency_ref) { + line_frequency_ref = mcp_calibration_setpoint.line_frequency_ref; + + if ((0xFFFF == mcp_output_registers.line_frequency) || (0 == gain_line_frequency)) { // Reset values to 50Hz + mcp_output_registers.line_frequency = 50000; + gain_line_frequency = 0x8000; + } + gain_line_frequency = gain_line_frequency * line_frequency_ref / mcp_output_registers.line_frequency; + + mcp_timeout = 0; + McpSetFrequency(line_frequency_ref, gain_line_frequency); + } + McpResetSetpoints(); +} + +void McpSetFrequency(uint16_t line_frequency_ref, uint16_t gain_line_frequency) { // A5 11 41 00 94 57 C3 B4 41 00 AE 57 7E 46 53 4D 03 uint8_t data[17]; data[ 1] = sizeof(data); - data[ 2] = MCP_SET_ADDRESS; // Set address pointer + data[ 2] = MCP_SET_ADDRESS; // Set address pointer data[ 3] = (MCP_FREQUENCY_REF_BASE >> 8) & 0xFF; // address data[ 4] = (MCP_FREQUENCY_REF_BASE >> 0) & 0xFF; // address - data[ 5] = MCP_WRITE_16; // Write register - data[ 6] = (mcp_frequency_registers.line_frequency_ref >> 8) & 0xFF; // line_frequency_ref high - data[ 7] = (mcp_frequency_registers.line_frequency_ref >> 0) & 0xFF; // line_frequency_ref low + data[ 5] = MCP_WRITE_16; // Write register + data[ 6] = (line_frequency_ref >> 8) & 0xFF; // line_frequency_ref high + data[ 7] = (line_frequency_ref >> 0) & 0xFF; // line_frequency_ref low - data[ 8] = MCP_SET_ADDRESS; // Set address pointer - data[ 9] = (MCP_FREQUENCY_GAIN_BASE >> 8) & 0xFF; // address - data[10] = (MCP_FREQUENCY_GAIN_BASE >> 0) & 0xFF; // address + data[ 8] = MCP_SET_ADDRESS; // Set address pointer + data[ 9] = (MCP_FREQUENCY_GAIN_BASE >> 8) & 0xFF; // address + data[10] = (MCP_FREQUENCY_GAIN_BASE >> 0) & 0xFF; // address - data[11] = MCP_WRITE_16; // Write register - data[12] = (mcp_frequency_registers.gain_line_frequency >> 8) & 0xFF; // gain_line_frequency high - data[13] = (mcp_frequency_registers.gain_line_frequency >> 0) & 0xFF; // gain_line_frequency low + data[11] = MCP_WRITE_16; // Write register + data[12] = (gain_line_frequency >> 8) & 0xFF; // gain_line_frequency high + data[13] = (gain_line_frequency >> 0) & 0xFF; // gain_line_frequency low - data[14] = MCP_SAVE_REGISTERS; // Save registers to flash - data[15] = mcp_address; // Device address + data[14] = MCP_SAVE_REGISTERS; // Save registers to flash + data[15] = mcp_address; // Device address McpSend(data); } +/********************************************************************************************/ + void McpSetSystemConfiguration(uint16 interval) { // A5 11 41 00 42 45 03 00 01 00 41 00 5A 57 00 06 7A uint8_t data[17]; data[ 1] = sizeof(data); - data[ 2] = MCP_SET_ADDRESS; // Set address pointer - data[ 3] = 0x00; // address - data[ 4] = 0x42; // address - data[ 5] = MCP_WRITE_32; // Write 4 bytes - data[ 6] = (mcp_system_configuration >> 24) & 0xFF; // system_configuration - data[ 7] = (mcp_system_configuration >> 16) & 0xFF; // system_configuration - data[ 8] = (mcp_system_configuration >> 8) & 0xFF; // system_configuration - data[ 9] = (mcp_system_configuration >> 0) & 0xFF; // system_configuration - data[10] = MCP_SET_ADDRESS; // Set address pointer - data[11] = 0x00; // address - data[12] = 0x5A; // address - data[13] = MCP_WRITE_16; // Write 2 bytes - data[14] = (interval >> 8) & 0xFF; // interval - data[15] = (interval >> 0) & 0xFF; // interval + data[ 2] = MCP_SET_ADDRESS; // Set address pointer + data[ 3] = 0x00; // address + data[ 4] = 0x42; // address + data[ 5] = MCP_WRITE_32; // Write 4 bytes + data[ 6] = (mcp_system_configuration >> 24) & 0xFF; // system_configuration + data[ 7] = (mcp_system_configuration >> 16) & 0xFF; // system_configuration + data[ 8] = (mcp_system_configuration >> 8) & 0xFF; // system_configuration + data[ 9] = (mcp_system_configuration >> 0) & 0xFF; // system_configuration + data[10] = MCP_SET_ADDRESS; // Set address pointer + data[11] = 0x00; // address + data[12] = 0x5A; // address + data[13] = MCP_WRITE_16; // Write 2 bytes + data[14] = (interval >> 8) & 0xFF; // interval + data[15] = (interval >> 0) & 0xFF; // interval McpSend(data); } -void McpSingleWireStart() -{ - if ((mcp_system_configuration & (1 << 8)) != 0) { return; } - mcp_system_configuration = mcp_system_configuration | (1 << 8); - McpSetSystemConfiguration(6); // 64 - mcp_single_wire_active = 1; -} - void McpSingleWireStop(uint8_t force) { if (!force && ((mcp_system_configuration & (1 << 8)) == 0)) { return; } mcp_system_configuration = mcp_system_configuration & (~(1 << 8)); McpSetSystemConfiguration(2); // 4 - mcp_single_wire_active = 0; } /********************************************************************************************/ -void McpAddressReceive() +void McpGetData(void) { - // 06 05 004D 58 - mcp_address = serial_in_buffer[2] * 256 + serial_in_buffer[3]; + uint8_t data[] = { MCP_START_FRAME, 8, MCP_SET_ADDRESS, 0x00, 0x04, MCP_READ, 22, 0x00 }; + + McpSend(data); } -void McpParseCalibration() +void McpParseData(void) { - bool action = false; + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + // 06 19 61 06 00 00 FE 08 9B 0E 00 00 0B 00 00 00 97 0E 00 00 FF 7F 0C C6 35 + // 06 19 CE 18 00 00 F2 08 3A 38 00 00 66 00 00 00 93 38 00 00 36 7F 9A C6 B7 + // Ak Ln Current---- Volt- ActivePower ReActivePow ApparentPow Factr Frequ Ck - // 06 37 C882 B6AD 0781 9273 06000000 00000000 00000000 0000 D3FF 0300 00000003 9204 120C1300 204E0000 9808 E0AB0000 D9940000 0200 24 - mcp_calibration_registers.gain_current_rms = McpExtractInt(serial_in_buffer, 2, 2); - mcp_calibration_registers.gain_voltage_rms = McpExtractInt(serial_in_buffer, 4, 2); - mcp_calibration_registers.gain_active_power = McpExtractInt(serial_in_buffer, 6, 2); - mcp_calibration_registers.gain_reactive_power = McpExtractInt(serial_in_buffer, 8, 2); - mcp_calibration_registers.offset_current_rms = McpExtractInt(serial_in_buffer, 10, 4); - mcp_calibration_registers.offset_active_power = McpExtractInt(serial_in_buffer, 14, 4); - mcp_calibration_registers.offset_reactive_power = McpExtractInt(serial_in_buffer, 18, 4); - mcp_calibration_registers.dc_offset_current = McpExtractInt(serial_in_buffer, 22, 2); - mcp_calibration_registers.phase_compensation = McpExtractInt(serial_in_buffer, 24, 2); - mcp_calibration_registers.apparent_power_divisor = McpExtractInt(serial_in_buffer, 26, 2); - - mcp_calibration_registers.system_configuration = McpExtractInt(serial_in_buffer, 28, 4); - mcp_calibration_registers.dio_configuration = McpExtractInt(serial_in_buffer, 32, 2); - mcp_calibration_registers.range = McpExtractInt(serial_in_buffer, 34, 4); - - mcp_calibration_registers.calibration_current = McpExtractInt(serial_in_buffer, 38, 4); - mcp_calibration_registers.calibration_voltage = McpExtractInt(serial_in_buffer, 42, 2); - mcp_calibration_registers.calibration_active_power = McpExtractInt(serial_in_buffer, 44, 4); - mcp_calibration_registers.calibration_reactive_power = McpExtractInt(serial_in_buffer, 48, 4); - mcp_calibration_registers.accumulation_interval = McpExtractInt(serial_in_buffer, 52, 2); - - if (mcp_calibration_setpoint.calibration_active_power) { - mcp_calibration_registers.calibration_active_power = mcp_calibration_setpoint.calibration_active_power; - if (McpCalibrationCalc(16)) { action = true; } - } - if (mcp_calibration_setpoint.calibration_voltage) { - mcp_calibration_registers.calibration_voltage = mcp_calibration_setpoint.calibration_voltage; - if (McpCalibrationCalc(0)) { action = true; } - } - if (mcp_calibration_setpoint.calibration_current) { - mcp_calibration_registers.calibration_current = mcp_calibration_setpoint.calibration_current; - if (McpCalibrationCalc(8)) { action = true; } - } - mcp_timeout = 0; - if (action) { McpSetCalibration(); } - McpResetSetpoints(); -} - -void McpParseFrequency() -{ - // 06 07 C350 8000 A0 - mcp_frequency_registers.line_frequency_ref = serial_in_buffer[2] * 256 + serial_in_buffer[3]; - mcp_frequency_registers.gain_line_frequency = serial_in_buffer[4] * 256 + serial_in_buffer[5]; - - if (mcp_calibration_setpoint.line_frequency_ref) { - mcp_frequency_registers.line_frequency_ref = mcp_calibration_setpoint.line_frequency_ref; - McpCalibrationLineFrequency(); - mcp_timeout = 0; - McpSetFrequency(); - } - McpResetSetpoints(); -} - -void McpParseData(uint8_t single_wire) -{ - if (single_wire) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - // AB CD EF 51 06 00 00 B8 08 FC 0D 00 00 0A C4 11 - // Header-- Current---- Volt- Power------ Freq- Ck - - mcp_output_registers.current_rms = McpExtractInt(serial_in_buffer, 3, 4); - mcp_output_registers.voltage_rms = McpExtractInt(serial_in_buffer, 7, 2); - mcp_output_registers.active_power = McpExtractInt(serial_in_buffer, 9, 4); - mcp_output_registers.line_frequency = McpExtractInt(serial_in_buffer, 13, 2); - } else { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 - // 06 19 61 06 00 00 FE 08 9B 0E 00 00 0B 00 00 00 97 0E 00 00 FF 7F 0C C6 35 - // 06 19 CE 18 00 00 F2 08 3A 38 00 00 66 00 00 00 93 38 00 00 36 7F 9A C6 B7 - // Ak Ln Current---- Volt- ActivePower ReActivePow ApparentPow Factr Frequ Ck - - mcp_output_registers.current_rms = McpExtractInt(serial_in_buffer, 2, 4); - mcp_output_registers.voltage_rms = McpExtractInt(serial_in_buffer, 6, 2); - mcp_output_registers.active_power = McpExtractInt(serial_in_buffer, 8, 4); - mcp_output_registers.reactive_power = McpExtractInt(serial_in_buffer, 12, 4); - mcp_output_registers.line_frequency = McpExtractInt(serial_in_buffer, 22, 2); - } + mcp_output_registers.current_rms = McpExtractInt(serial_in_buffer, 2, 4); + mcp_output_registers.voltage_rms = McpExtractInt(serial_in_buffer, 6, 2); + mcp_output_registers.active_power = McpExtractInt(serial_in_buffer, 8, 4); +// mcp_output_registers.reactive_power = McpExtractInt(serial_in_buffer, 12, 4); +// mcp_output_registers.power_factor = McpExtractInt(serial_in_buffer, 20, 2); + mcp_output_registers.line_frequency = McpExtractInt(serial_in_buffer, 22, 2); if (energy_power_on) { // Powered on energy_frequency = (float)mcp_output_registers.line_frequency / 1000; @@ -533,7 +464,9 @@ void McpParseData(uint8_t single_wire) } } -bool McpSerialInput() +/********************************************************************************************/ + +bool McpSerialInput(void) { serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; unsigned long start = millis(); @@ -564,7 +497,7 @@ bool McpSerialInput() AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); } else { if (5 == serial_in_buffer[1]) { McpAddressReceive(); } - if (25 == serial_in_buffer[1]) { McpParseData(0); } + if (25 == serial_in_buffer[1]) { McpParseData(); } if (MCP_CALIBRATION_LEN + 3 == serial_in_buffer[1]) { McpParseCalibration(); } if (MCP_FREQUENCY_LEN + 3 == serial_in_buffer[1]) { McpParseFrequency(); } } @@ -573,15 +506,6 @@ bool McpSerialInput() mcp_timeout = 0; } else if (MCP_SINGLE_WIRE == serial_in_buffer[0]) { - if (serial_in_byte_counter == 16) { - - if (McpChecksum((uint8_t *)serial_in_buffer) != serial_in_buffer[serial_in_byte_counter -1]) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("MCP: " D_CHECKSUM_FAILURE)); - } else { - McpParseData(1); - } - - } mcp_timeout = 0; } return 1; @@ -589,10 +513,8 @@ bool McpSerialInput() /********************************************************************************************/ -void McpEverySecond() +void McpEverySecond(void) { - uint8_t get_state[] = { 0xA5, 0x08, 0x41, 0x00, 0x04, 0x4E, 0x16, 0x00 }; - if (mcp_output_registers.active_power) { energy_kWhtoday_delta += ((mcp_output_registers.active_power * 10) / 36); EnergyUpdateToday(); @@ -611,18 +533,18 @@ void McpEverySecond() else if (!mcp_address) { McpGetAddress(); } - else if (!mcp_single_wire_active) { - McpSend(get_state); + else { + McpGetData(); } } -void McpSnsInit() +void McpSnsInit(void) { SetSeriallog(LOG_LEVEL_NONE); // Free serial interface from logging interference digitalWrite(15, 1); // GPIO15 - MCP enable } -void McpDrvInit() +void McpDrvInit(void) { if (!energy_flg) { if (SHELLY2 == Settings.module) { @@ -638,7 +560,7 @@ void McpDrvInit() } } -boolean McpCommand() +boolean McpCommand(void) { boolean serviced = true; unsigned long value = 0; From ecd3175257360ac13c46042000c1297acd385242 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Mon, 24 Sep 2018 16:16:14 -0300 Subject: [PATCH 30/93] Prevent Command NtpServer to restart Tasmota #3890 --- sonoff/sonoff.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 91c1fbb9b..2e64b9046 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -1043,7 +1043,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) for (i = 0; i < strlen(Settings.ntp_server[index -1]); i++) { if (Settings.ntp_server[index -1][i] == ',') Settings.ntp_server[index -1][i] = '.'; } - restart_flag = 2; +// restart_flag = 2; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.ntp_server[index -1]); } From 2029440fae58b204e1d23c50e6b74fbb1383388e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 25 Sep 2018 11:35:37 +0200 Subject: [PATCH 31/93] 6.2.1.7 Fix NTPserver change 6.2.1.7 20180925 * Remove restart after ntpserver change and force NTP re-sync (#3890) * Release full Shelly2 support --- sonoff/_changelog.ino | 6 +- sonoff/sonoff.ino | 3 +- sonoff/sonoff_version.h | 2 +- sonoff/xnrg_04_mcp39f501.ino | 213 ++++++++++++++++++----------------- 4 files changed, 116 insertions(+), 108 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index b7988c69c..5aa6e9e13 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,8 @@ -/* 6.2.1.6 20180922 +/* 6.2.1.7 20180925 + * Remove restart after ntpserver change and force NTP re-sync (#3890) + * Release full Shelly2 support + * + * 6.2.1.6 20180922 * Removed commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet * Allow decimals as input to commands PowerSet, VoltageSet and CurrentSet * Add support for PCA9685 12bit 16pin hardware PWM driver (#3866) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 2e64b9046..f0619f362 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -1043,7 +1043,8 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) for (i = 0; i < strlen(Settings.ntp_server[index -1]); i++) { if (Settings.ntp_server[index -1][i] == ',') Settings.ntp_server[index -1][i] = '.'; } -// restart_flag = 2; +// restart_flag = 2; // Issue #3890 + ntp_force_sync = 1; } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.ntp_server[index -1]); } diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 228a48d92..16c554783 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 0x06020106 +#define VERSION 0x06020107 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index abf11b71f..f2ce321bc 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -29,6 +29,13 @@ #define XNRG_04 4 #define MCP_TIMEOUT 4 +#define MCP_CALIBRATION_TIMEOUT 2 + +#define MCP_CALIBRATE_POWER 0x001 +#define MCP_CALIBRATE_VOLTAGE 0x002 +#define MCP_CALIBRATE_CURRENT 0x004 +#define MCP_CALIBRATE_FREQUENCY 0x008 +#define MCP_SINGLE_WIRE_FLAG 0x100 #define MCP_START_FRAME 0xA5 #define MCP_ACK_FRAME 0x06 @@ -79,32 +86,20 @@ typedef struct mcp_cal_registers_type { uint16_t accumulation_interval; } mcp_cal_registers_type; -typedef struct mcp_calibration_setpoint_type { - uint32_t calibration_current; - uint16_t calibration_voltage; - uint32_t calibration_active_power; -// uint32_t calibration_reactive_power; - uint16_t line_frequency_ref; -} mcp_calibration_setpoint_type; -mcp_calibration_setpoint_type mcp_calibration_setpoint; - -typedef struct mcp_output_registers_type { - uint32_t current_rms; - uint16_t voltage_rms; - uint32_t active_power; - uint32_t reactive_power; - uint32_t apparent_power; - sint16_t power_factor; - uint16_t line_frequency; -} mcp_output_registers_type; -mcp_output_registers_type mcp_output_registers; - +unsigned long mcp_kWhcounter = 0; uint32_t mcp_system_configuration = 0x03000000; +uint32_t mcp_active_power; +//uint32_t mcp_reactive_power; +//uint32_t mcp_apparent_power; +uint32_t mcp_current_rms; +uint16_t mcp_voltage_rms; +uint16_t mcp_line_frequency; +//sint16_t mcp_power_factor; uint8_t mcp_address = 0; uint8_t mcp_calibration_active = 0; uint8_t mcp_init = 0; uint8_t mcp_timeout = 0; -unsigned long mcp_kWhcounter = 0; +uint8_t mcp_calibrate = 0; /*********************************************************************************************\ * Olimex tools @@ -155,11 +150,6 @@ void McpSend(uint8_t *data) } } -void McpResetSetpoints(void) -{ - memset(&mcp_calibration_setpoint, 0, sizeof(mcp_calibration_setpoint)); -} - /********************************************************************************************/ void McpGetAddress(void) @@ -180,7 +170,7 @@ void McpAddressReceive(void) void McpGetCalibration(void) { if (mcp_calibration_active) { return; } - mcp_calibration_active = 4; + mcp_calibration_active = MCP_CALIBRATION_TIMEOUT; uint8_t data[] = { MCP_START_FRAME, 8, MCP_SET_ADDRESS, (MCP_CALIBRATION_BASE >> 8) & 0xFF, MCP_CALIBRATION_BASE & 0xFF, MCP_READ, MCP_CALIBRATION_LEN, 0x00 }; @@ -214,21 +204,33 @@ void McpParseCalibration(void) cal_registers.calibration_reactive_power = McpExtractInt(serial_in_buffer, 48, 4); cal_registers.accumulation_interval = McpExtractInt(serial_in_buffer, 52, 2); - if (mcp_calibration_setpoint.calibration_active_power) { - cal_registers.calibration_active_power = mcp_calibration_setpoint.calibration_active_power; + if (mcp_calibrate & MCP_CALIBRATE_POWER) { + cal_registers.calibration_active_power = Settings.energy_power_calibration; if (McpCalibrationCalc(&cal_registers, 16)) { action = true; } } - if (mcp_calibration_setpoint.calibration_voltage) { - cal_registers.calibration_voltage = mcp_calibration_setpoint.calibration_voltage; + if (mcp_calibrate & MCP_CALIBRATE_VOLTAGE) { + cal_registers.calibration_voltage = Settings.energy_voltage_calibration; if (McpCalibrationCalc(&cal_registers, 0)) { action = true; } } - if (mcp_calibration_setpoint.calibration_current) { - cal_registers.calibration_current = mcp_calibration_setpoint.calibration_current; + if (mcp_calibrate & MCP_CALIBRATE_CURRENT) { + cal_registers.calibration_current = Settings.energy_current_calibration; if (McpCalibrationCalc(&cal_registers, 8)) { action = true; } } mcp_timeout = 0; if (action) { McpSetCalibration(&cal_registers); } - McpResetSetpoints(); + + mcp_calibrate = 0; + + Settings.energy_power_calibration = cal_registers.calibration_active_power; + Settings.energy_voltage_calibration = cal_registers.calibration_voltage; + Settings.energy_current_calibration = cal_registers.calibration_current; + + mcp_system_configuration = cal_registers.system_configuration; + + if (mcp_system_configuration & MCP_SINGLE_WIRE_FLAG) { + mcp_system_configuration &= ~MCP_SINGLE_WIRE_FLAG; // Reset SingleWire flag + McpSetSystemConfiguration(2); + } } bool McpCalibrationCalc(struct mcp_cal_registers_type *cal_registers, uint8_t range_shift) @@ -239,15 +241,15 @@ bool McpCalibrationCalc(struct mcp_cal_registers_type *cal_registers, uint8_t ra uint32_t new_gain; if (range_shift == 0) { - measured = mcp_output_registers.voltage_rms; + measured = mcp_voltage_rms; expected = cal_registers->calibration_voltage; gain = &(cal_registers->gain_voltage_rms); } else if (range_shift == 8) { - measured = mcp_output_registers.current_rms; + measured = mcp_current_rms; expected = cal_registers->calibration_current; gain = &(cal_registers->gain_current_rms); } else if (range_shift == 16) { - measured = mcp_output_registers.active_power; + measured = mcp_active_power; expected = cal_registers->calibration_active_power; gain = &(cal_registers->gain_active_power); } else { @@ -287,7 +289,7 @@ calc: /* void McpCalibrationReactivePower(void) { - cal_registers.gain_reactive_power = cal_registers.gain_reactive_power * cal_registers.calibration_reactive_power / mcp_output_registers.reactive_power; + cal_registers.gain_reactive_power = cal_registers.gain_reactive_power * cal_registers.calibration_reactive_power / mcp_reactive_power; } */ void McpSetCalibration(struct mcp_cal_registers_type *cal_registers) @@ -331,10 +333,36 @@ void McpSetCalibration(struct mcp_cal_registers_type *cal_registers) /********************************************************************************************/ +void McpSetSystemConfiguration(uint16 interval) +{ + // A5 11 41 00 42 45 03 00 01 00 41 00 5A 57 00 06 7A + uint8_t data[17]; + + data[ 1] = sizeof(data); + data[ 2] = MCP_SET_ADDRESS; // Set address pointer + data[ 3] = 0x00; // address + data[ 4] = 0x42; // address + data[ 5] = MCP_WRITE_32; // Write 4 bytes + data[ 6] = (mcp_system_configuration >> 24) & 0xFF; // system_configuration + data[ 7] = (mcp_system_configuration >> 16) & 0xFF; // system_configuration + data[ 8] = (mcp_system_configuration >> 8) & 0xFF; // system_configuration + data[ 9] = (mcp_system_configuration >> 0) & 0xFF; // system_configuration + data[10] = MCP_SET_ADDRESS; // Set address pointer + data[11] = 0x00; // address + data[12] = 0x5A; // address + data[13] = MCP_WRITE_16; // Write 2 bytes + data[14] = (interval >> 8) & 0xFF; // interval + data[15] = (interval >> 0) & 0xFF; // interval + + McpSend(data); +} + +/********************************************************************************************/ + void McpGetFrequency(void) { if (mcp_calibration_active) { return; } - mcp_calibration_active = 4; + mcp_calibration_active = MCP_CALIBRATION_TIMEOUT; uint8_t data[] = { MCP_START_FRAME, 11, MCP_SET_ADDRESS, (MCP_FREQUENCY_REF_BASE >> 8) & 0xFF, MCP_FREQUENCY_REF_BASE & 0xFF, MCP_READ_16, MCP_SET_ADDRESS, (MCP_FREQUENCY_GAIN_BASE >> 8) & 0xFF, MCP_FREQUENCY_GAIN_BASE & 0xFF, MCP_READ_16, 0x00 }; @@ -348,19 +376,22 @@ void McpParseFrequency(void) uint16_t line_frequency_ref = serial_in_buffer[2] * 256 + serial_in_buffer[3]; uint16_t gain_line_frequency = serial_in_buffer[4] * 256 + serial_in_buffer[5]; - if (mcp_calibration_setpoint.line_frequency_ref) { - line_frequency_ref = mcp_calibration_setpoint.line_frequency_ref; + if (mcp_calibrate & MCP_CALIBRATE_FREQUENCY) { + line_frequency_ref = Settings.energy_frequency_calibration; - if ((0xFFFF == mcp_output_registers.line_frequency) || (0 == gain_line_frequency)) { // Reset values to 50Hz - mcp_output_registers.line_frequency = 50000; + if ((0xFFFF == mcp_line_frequency) || (0 == gain_line_frequency)) { // Reset values to 50Hz + mcp_line_frequency = 50000; gain_line_frequency = 0x8000; } - gain_line_frequency = gain_line_frequency * line_frequency_ref / mcp_output_registers.line_frequency; + gain_line_frequency = gain_line_frequency * line_frequency_ref / mcp_line_frequency; mcp_timeout = 0; McpSetFrequency(line_frequency_ref, gain_line_frequency); } - McpResetSetpoints(); + + Settings.energy_frequency_calibration = line_frequency_ref; + + mcp_calibrate = 0; } void McpSetFrequency(uint16_t line_frequency_ref, uint16_t gain_line_frequency) @@ -393,39 +424,6 @@ void McpSetFrequency(uint16_t line_frequency_ref, uint16_t gain_line_frequency) /********************************************************************************************/ -void McpSetSystemConfiguration(uint16 interval) -{ - // A5 11 41 00 42 45 03 00 01 00 41 00 5A 57 00 06 7A - uint8_t data[17]; - - data[ 1] = sizeof(data); - data[ 2] = MCP_SET_ADDRESS; // Set address pointer - data[ 3] = 0x00; // address - data[ 4] = 0x42; // address - data[ 5] = MCP_WRITE_32; // Write 4 bytes - data[ 6] = (mcp_system_configuration >> 24) & 0xFF; // system_configuration - data[ 7] = (mcp_system_configuration >> 16) & 0xFF; // system_configuration - data[ 8] = (mcp_system_configuration >> 8) & 0xFF; // system_configuration - data[ 9] = (mcp_system_configuration >> 0) & 0xFF; // system_configuration - data[10] = MCP_SET_ADDRESS; // Set address pointer - data[11] = 0x00; // address - data[12] = 0x5A; // address - data[13] = MCP_WRITE_16; // Write 2 bytes - data[14] = (interval >> 8) & 0xFF; // interval - data[15] = (interval >> 0) & 0xFF; // interval - - McpSend(data); -} - -void McpSingleWireStop(uint8_t force) -{ - if (!force && ((mcp_system_configuration & (1 << 8)) == 0)) { return; } - mcp_system_configuration = mcp_system_configuration & (~(1 << 8)); - McpSetSystemConfiguration(2); // 4 -} - -/********************************************************************************************/ - void McpGetData(void) { uint8_t data[] = { MCP_START_FRAME, 8, MCP_SET_ADDRESS, 0x00, 0x04, MCP_READ, 22, 0x00 }; @@ -440,21 +438,21 @@ void McpParseData(void) // 06 19 CE 18 00 00 F2 08 3A 38 00 00 66 00 00 00 93 38 00 00 36 7F 9A C6 B7 // Ak Ln Current---- Volt- ActivePower ReActivePow ApparentPow Factr Frequ Ck - mcp_output_registers.current_rms = McpExtractInt(serial_in_buffer, 2, 4); - mcp_output_registers.voltage_rms = McpExtractInt(serial_in_buffer, 6, 2); - mcp_output_registers.active_power = McpExtractInt(serial_in_buffer, 8, 4); -// mcp_output_registers.reactive_power = McpExtractInt(serial_in_buffer, 12, 4); -// mcp_output_registers.power_factor = McpExtractInt(serial_in_buffer, 20, 2); - mcp_output_registers.line_frequency = McpExtractInt(serial_in_buffer, 22, 2); + mcp_current_rms = McpExtractInt(serial_in_buffer, 2, 4); + mcp_voltage_rms = McpExtractInt(serial_in_buffer, 6, 2); + mcp_active_power = McpExtractInt(serial_in_buffer, 8, 4); +// mcp_reactive_power = McpExtractInt(serial_in_buffer, 12, 4); +// mcp_power_factor = McpExtractInt(serial_in_buffer, 20, 2); + mcp_line_frequency = McpExtractInt(serial_in_buffer, 22, 2); if (energy_power_on) { // Powered on - energy_frequency = (float)mcp_output_registers.line_frequency / 1000; - energy_voltage = (float)mcp_output_registers.voltage_rms / 10; - energy_power = (float)mcp_output_registers.active_power / 100; + energy_frequency = (float)mcp_line_frequency / 1000; + energy_voltage = (float)mcp_voltage_rms / 10; + energy_power = (float)mcp_active_power / 100; if (0 == energy_power) { energy_current = 0; } else { - energy_current = (float)mcp_output_registers.current_rms / 10000; + energy_current = (float)mcp_current_rms / 10000; } } else { // Powered off energy_frequency = 0; @@ -515,8 +513,8 @@ bool McpSerialInput(void) void McpEverySecond(void) { - if (mcp_output_registers.active_power) { - energy_kWhtoday_delta += ((mcp_output_registers.active_power * 10) / 36); + if (mcp_active_power) { + energy_kWhtoday_delta += ((mcp_active_power * 10) / 36); EnergyUpdateToday(); } @@ -527,14 +525,19 @@ void McpEverySecond(void) mcp_calibration_active--; } else if (mcp_init) { - McpSingleWireStop(1); - mcp_init = 0; + if (2 == mcp_init) { + McpGetCalibration(); // Get calibration parameters and disable SingleWire mode if enabled + } + else if (1 == mcp_init) { + McpGetFrequency(); // Get calibration parameter + } + mcp_init--; } else if (!mcp_address) { - McpGetAddress(); + McpGetAddress(); // Get device address for future calibration changes } else { - McpGetData(); + McpGetData(); // Get energy data } } @@ -551,10 +554,10 @@ void McpDrvInit(void) pinMode(15, OUTPUT); digitalWrite(15, 0); // GPIO15 - MCP disable - Reset Delta Sigma ADC's baudrate = 4800; + mcp_calibrate = 0; + mcp_timeout = 2; // Initial wait + mcp_init = 2; // Initial setup steps energy_calc_power_factor = 1; // Calculate power factor from data - mcp_timeout = 4; // Wait for initialization - mcp_init = 1; // Execute initial setup - McpResetSetpoints(); energy_flg = XNRG_04; } } @@ -566,41 +569,41 @@ boolean McpCommand(void) unsigned long value = 0; if (CMND_POWERSET == energy_command_code) { - if (XdrvMailbox.data_len && mcp_output_registers.active_power) { + if (XdrvMailbox.data_len && mcp_active_power) { value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 100); if ((value > 100) && (value < 200000)) { // Between 1W and 2000W Settings.energy_power_calibration = value; - mcp_calibration_setpoint.calibration_active_power = value; + mcp_calibrate |= MCP_CALIBRATE_POWER; McpGetCalibration(); } } } else if (CMND_VOLTAGESET == energy_command_code) { - if (XdrvMailbox.data_len && mcp_output_registers.voltage_rms) { + if (XdrvMailbox.data_len && mcp_voltage_rms) { value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); if ((value > 1000) && (value < 2600)) { // Between 100V and 260V Settings.energy_voltage_calibration = value; - mcp_calibration_setpoint.calibration_voltage = value; + mcp_calibrate |= MCP_CALIBRATE_VOLTAGE; McpGetCalibration(); } } } else if (CMND_CURRENTSET == energy_command_code) { - if (XdrvMailbox.data_len && mcp_output_registers.current_rms) { + if (XdrvMailbox.data_len && mcp_current_rms) { value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10); if ((value > 100) && (value < 80000)) { // Between 10mA and 8A Settings.energy_current_calibration = value; - mcp_calibration_setpoint.calibration_current = value; + mcp_calibrate |= MCP_CALIBRATE_CURRENT; McpGetCalibration(); } } } else if (CMND_FREQUENCYSET == energy_command_code) { - if (XdrvMailbox.data_len && mcp_output_registers.line_frequency) { + if (XdrvMailbox.data_len && mcp_line_frequency) { value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 1000); if ((value > 45000) && (value < 65000)) { // Between 45Hz and 65Hz Settings.energy_frequency_calibration = value; - mcp_calibration_setpoint.line_frequency_ref = value; + mcp_calibrate |= MCP_CALIBRATE_FREQUENCY; McpGetFrequency(); } } From ec421e614477115c99c67275bfafa5ecf33a8eb4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 25 Sep 2018 14:08:36 +0200 Subject: [PATCH 32/93] Released decode-config.py Released tools/decode-config.py by Norbert Richter to decode configuration data. --- sonoff/_changelog.ino | 1 + tools/decode-config.py | 1924 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1925 insertions(+) create mode 100644 tools/decode-config.py diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 5aa6e9e13..333a524a6 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.2.1.7 20180925 * Remove restart after ntpserver change and force NTP re-sync (#3890) * Release full Shelly2 support + * Released tools/decode-config.py by Norbert Richter to decode configuration data. See file for information * * 6.2.1.6 20180922 * Removed commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet diff --git a/tools/decode-config.py b/tools/decode-config.py new file mode 100644 index 000000000..299f152c4 --- /dev/null +++ b/tools/decode-config.py @@ -0,0 +1,1924 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" + decode-config.py - Decode configuration of Sonoff-Tasmota device + + Copyright (C) 2018 Norbert Richter + + 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 . + +Requirements: + - Python + - pip 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. + + For help execute command with argument -h + + +Usage: + decode-config.py [-h] [-f ] [-d ] + [-u ] [-p ] [--format ] + [--sort ] [--raw] [--unhide-pw] [-o ] + [-c ] [-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 + allows: key=value, flag=true, stuff=[a,b,c] (for details, see syntax at + https://goo.gl/R74nmi). If an arg is specified in more than one place, then + commandline values override config file values which override defaults. + + optional arguments: + -h, --help show this help message and exit + -c , --config + Config file, can be used instead of command parameter + (defaults to None) + + source: + -f , --file + file to retrieve Tasmota configuration from (default: + None) + -d , --device + device to retrieve configuration from (default: None) + -u , --username + for -d usage: http access username (default: admin) + -p , --password + for -d usage: http access password (default: None) + + output: + --format output format ("json" or "text", default: "json") + --sort sort result - can be "none" or "name" (default: + "name") + --raw output raw values (default: processed) + --unhide-pw unhide passwords (default: hide) + -o , --output-file + file to store decrypted raw binary configuration to + (default: None) + + info: + -V, --version show program's version number and exit + + Note: 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 +try: + import pycurl +except ImportError: + print("module not found. Try 'pip pycurl' to install it") + sys.exit(9) +try: + import urllib2 +except ImportError: + print("module not found. Try 'pip urllib2' to install it") + sys.exit(9) + + +VER = '1.5.0008' +PROG='{} v{} by Norbert Richter'.format(os.path.basename(sys.argv[0]),VER) + +CONFIG_FILE_XOR = 0x5A + + +args = {} +DEFAULTS = { + 'DEFAULT': + { + 'configfile': None, + }, + 'source': + { + 'device': None, + 'username': 'admin', + 'password': None, + 'tasmotafile': None, + }, + 'output': + { + 'format': 'json', + 'sort': 'name', + 'raw': False, + 'unhide-pw': False, + 'outputfile': None, + }, +} + + +""" +Settings dictionary describes the config file fields definition: + + Each setting name has a tuple containing the following items: + + (format, baseaddr, datadef, ) + + where + + format + Define the data interpretation. + For details see struct module format string + https://docs.python.org/2.7/library/struct.html#format-strings + + baseaddr + The address (starting from 0) within config data + + datadef + Define the field interpretation different from simple + standard types (like char, byte, int) e. g. lists or bit fields + Can be None, a single integer, a list or a dictionary + None: + None must be given if the field contains a simple value + desrcibed by the prefix + n: + Same as [n] below + [n]: + 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 + 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': ('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)) + + # it's a single value + return length + +def ConvertFieldValue(value, fielddef): + """ + Convert field value based on field desc + + @param value: + original value read from binary data + @param fielddef + field definition (contains possible conversion defiinition) + + @return: (und)converted value + """ + if not args.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) + return value + + +def GetField(dobj, fieldname, fielddef): + """ + Get field value from definition + + @param dobj: + uncrypted binary config data + @param fieldname: + name of the field + @param fielddef: + see Settings desc above + + @return: read field value + """ + + result = None + + if fielddef[2] 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] ): + # 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]) + length = GetFieldLength(subfielddef) + if length != 0: + result.append(GetField(dobj, fieldname, subfielddef)) + 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); + 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 + 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 = s #unicode(s, errors='replace') + result = ConvertFieldValue(result, fielddef) + + return result + + +def DeEncrypt(obj): + """ + Decrpt/Encrypt binary config data + + @param obj: + binary config data + + @return: decrypted configuration (if obj contains encrypted data) + encrypted configuration (if obj contains decrypted data) + """ + dobj = obj[0:2] + for i in range(2, len(obj)): + dobj += chr( (ord(obj[i]) ^ (CONFIG_FILE_XOR +i)) & 0xff ) + return dobj + + +def Decode(obj): + """ + Decodes (already decrypted) binary data stream + + @param obj: + binary config data + """ + # get header data + cfg_size = GetField(obj, 'cfg_size', Setting_6_2_1['cfg_size']) + version = GetField(obj, 'version', Setting_6_2_1['version']) + + # search setting definition + setting = None + for cfg in Settings: + if version >= cfg[0] and cfg_size == cfg[1]: + template = cfg + break + + setting = template[2] + # if we did not found a mathching setting + if setting is None: + exit(2, "Can't handle Tasmota configuration data for version 0x{:x} with {} bytes".format(version, cfg_size) ) + + if GetField(obj, 'cfg_crc', setting['cfg_crc']) != GetSettingsCrc(obj): + exit(3, 'Data crc error' ) + + config = {} + config['version_template'] = '0x{:x}'.format(template[0]) + for name in setting: + config[name] = GetField(obj, name, setting[name]) + + if args.sort == 'name': + config = collections.OrderedDict(sorted(config.items())) + + if args.format == 'json': + print json.dumps(config, sort_keys=args.sort=='name') + else: + for key,value in config.items(): + print '{} = {}'.format(key, repr(value)) + + + +if __name__ == "__main__": + parser = configargparse.ArgumentParser(description='Decode configuration of Sonoff-Tasmota device.', + epilog='Note: Either argument -d or -f must be given.') + + source = parser.add_argument_group('source') + source.add_argument('-f', '--file', + metavar='', + dest='tasmotafile', + default=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='device to retrieve configuration from (default: {})'.format(DEFAULTS['source']['device']) ) + source.add_argument('-u', '--username', + metavar='', + dest='username', + default=DEFAULTS['source']['username'], + help='for -d usage: http access username (default: {})'.format(DEFAULTS['source']['username'])) + source.add_argument('-p', '--password', + metavar='', + dest='password', + default=DEFAULTS['source']['password'], + help='for -d usage: 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('--sort', + metavar='', + dest='sort', + choices=['none', 'name'], + default=DEFAULTS['output']['sort'], + help='sort result - can be "none" or "name" (default: "{}")'.format(DEFAULTS['output']['sort']) ) + 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') ) + 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') ) + 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'])) + + 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 (defaults to {})'.format(DEFAULTS['DEFAULT']['configfile']) ) + + info = parser.add_argument_group('info') + info.add_argument('-V', '--version', action='version', version=PROG) + + args = parser.parse_args() + + configobj = None + + 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() + c.setopt(c.URL, url) + c.setopt(c.VERBOSE, 0) + if args.username is not None and args.password is not None: + c.setopt(c.HTTPAUTH, c.HTTPAUTH_BASIC) + c.setopt(c.USERPWD, args.username + ':' + args.password) + c.setopt(c.WRITEDATA, buffer) + try: + c.perform() + except Exception, e: + exit(e[0], e[1]) + response = c.getinfo(c.RESPONSE_CODE) + c.close() + if response>=400: + exit(response, 'HTTP returns {}'.format(response) ) + + configobj = buffer.getvalue() + + 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)) + try: + tasmotafile = open(args.tasmotafile, "rb") + configobj = tasmotafile.read() + tasmotafile.close() + except Exception, e: + exit(e[0], e[1]) + + 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() + + Decode(cfg) + + else: + exit(4, "Could not read configuration data from {} '{}'".format('device' if args.device is not None else 'file', args.device if args.device is not None else args.tasmotafile) ) \ No newline at end of file From 977ee779b06b7c90d97fef335788fd826e742e24 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:30:01 +0200 Subject: [PATCH 33/93] Added VEML6070 defines Added define for Rset for the VEML6070 sensor and to show or show-not the raw value --- sonoff/user_config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index b93e44211..846c86097 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -283,6 +283,8 @@ // #define USE_BME680 // Enable support for BME680 sensor using Bosch BME680 library (+4k code) #define USE_BH1750 // Enable BH1750 sensor (I2C address 0x23 or 0x5C) (+0k5 code) // #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+0k5 code) +// #define USE_VEML6070_RSET 270000 // VEML6070, Rset in Ohm used on PCB board, default 270K = 270000ohm, range for this sensor: 220K ... 1Meg +// #define USE_VEML6070_SHOW_RAW // VEML6070, shows the raw value of UV-A // #define USE_ADS1115 // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) based on Adafruit ADS1x15 library (no library needed) (+0k7 code) // #define USE_ADS1115_I2CDEV // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) using library i2cdevlib-Core and i2cdevlib-ADS1115 (+2k code) // #define USE_INA219 // Enable INA219 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+1k code) From 2ba0b1be7324f5ccec0aed308b5b0a98b50c8aca Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:32:24 +0200 Subject: [PATCH 34/93] driver cahnge Added a lot of new calculation for more precission and more output so as UV Index plus a text behind the value and UV Power in W/m2 --- sonoff/xsns_11_veml6070.ino | 234 ++++++++++++++++++++++++++++++++---- 1 file changed, 211 insertions(+), 23 deletions(-) diff --git a/sonoff/xsns_11_veml6070.ino b/sonoff/xsns_11_veml6070.ino index 557f615f3..be7d3daa0 100644 --- a/sonoff/xsns_11_veml6070.ino +++ b/sonoff/xsns_11_veml6070.ino @@ -15,25 +15,136 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . + + ----------------------------------------------------- + Some words to the meaning of the UV Risk Level: + ----------------------------------------------------- + D_UV_INDEX_1 = "Low" = sun->fun + D_UV_INDEX_2 = "Mid" = sun->glases advised + D_UV_INDEX_3 = "High" = sun->glases a must + D_UV_INDEX_4 = "Danger" = sun->skin burns Level 1 + D_UV_INDEX_5 = "BurnL1/2" = sun->skin burns level 1..2 + D_UV_INDEX_6 = "BurnL3" = sun->skin burns with level 3 + D_UV_INDEX_7 = "OoR" = out of range or unknown + + -------------------------------------------------------------------------------------------- + Version Date Action Description + -------------------------------------------------------------------------------------------- + + 1.0.0.1 20180925 tests - all tests are done with 1x sonoff sv, 2x Wemos D1 (not the mini) + - 3 different VEMl6070 sensors from 3 different online shops + - all the last three test where good and all looks working so far + - all tests are done at high noon with blue sky and a leaned UV light source + sience - a special Thank You to my friend the professor. He works in the aerospace industrie. Thank You R.G.T. + - all calculations are based on the very good work of Karel Vanicek. Thank You Karel + - more information about UV Index and the irradiation power calculation can be found on the internet + info - all calculations are based on the effective irradiation from Karel Vanicek + - all this was not possible without the work of @arendst. He has done really a lot of basic work/code. Thank You Theo + cleaned - source code a little bit + added - missing void in function calls: void name(void) + added - UV Risk level now defined as UV Index, 0.00 based on NASA standard with text behind the value + added - UV Power level now named as UV Power, used W/m2 because official standards + added - automatic fill of the uv-risk compare table based on the coefficient calculation + added - suspend and wakeup mode for the uv seonsor + - current drain in wake-up-ed mode was around 180uA incl. I2C bus + - current drain in suspend mode was around 70..80uA incl. I2C bus + changed - 2x the power calculation about some incorrent data sheet values + changed - float to double calculation because a rare effect on uv compare map filling + - in that case @andrethomas was a big help too (while(work){output=lot_of_fun};) + added - USE_VEML6070_RSET + - in user_config as possible input, different resistor values depending on PCB types + added - USE_VEML6070_SHOW_RAW + - in user_config, show or show-NOT the uv raw value + added - lots of #defines for automatic calulations to get the best possible values + added - error messages for LOG_LEVEL_DEBUG + added - lots of information in one of the last postings in: https://github.com/arendst/Sonoff-Tasmota/issues/3844 + debugging - without the softly hit ;-) from @andrethomas about Serial.print i would never done it. Thank You Andre + safety - personal, please read this: http://www.segurancaetrabalho.com.br/download/uv_index_karel_vanicek.pdf + next - possible i will add the calculation for LAT and LONG coordinates for much more precission + - 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 + */ #ifdef USE_I2C #ifdef USE_VEML6070 /*********************************************************************************************\ - * VEML6070 - Ultra Violet Light Intensity + * VEML6070 - Ultra Violet Light Intensity (UV-A, 100% output by 255nm) * * I2C Address: 0x38 and 0x39 \*********************************************************************************************/ -#define VEML6070_ADDR_H 0x39 -#define VEML6070_ADDR_L 0x38 +#define VEML6070_ADDR_H 0x39 // on some PCB boards the address can be changed by a solder point, +#define VEML6070_ADDR_L 0x38 // to have no address conflicts with other I2C sensors and/or hardware -#define VEML6070_INTEGRATION_TIME 3 // 500msec integration time +#define VEML6070_INTEGRATION_TIME 3 // IT_4 = 500msec integration time, because the precission is 4 times higher then IT_0.5 +#define VEML6070_ENABLE 1 // +#define VEML6070_DISABLE 0 // +#define VEML6070_RSET_DEFAULT 270000 // 270K default resistor value 270000 ohm, range from 220K..1Meg +#define VEML6070_UV_MAX_INDEX 15 // normal 11, internal on weather laboratories and NASA it's 15 so far the sensor is linear +#define VEML6070_UV_MAX_DEFAULT 11 // 11 = public default table values +#define VEML6070_POWER_COEFFCIENT 0.025 // based on calculations from Karel Vanicek and reorder by hand +#define VEML6070_TABLE_COEFFCIENT 32.86270591 // calculated by hand with help from a friend of mine, a professor which works in aero space things + // (resistor, differences, power coefficients and official UV index calculations (LAT & LONG will be added later) +/********************************************************************************************/ + +// globals uint8_t veml6070_address; uint8_t veml6070_type = 0; -uint16_t Veml6070ReadUv() +/********************************************************************************************/ + +void Veml6070Detect(void) +{ + if (veml6070_type) { + return; + } + + uint8_t itime = VEML6070_INTEGRATION_TIME; + veml6070_address = VEML6070_ADDR_L; + Wire.beginTransmission(veml6070_address); + Wire.write((itime << 2) | 0x02); + uint8_t status = Wire.endTransmission(); + + if (!status) { + veml6070_type = 1; + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070", veml6070_address); + AddLog(LOG_LEVEL_DEBUG); + } +} + +/********************************************************************************************/ + +void Veml6070ModeCmd(boolean mode_cmd) +{ + uint8_t itime = VEML6070_INTEGRATION_TIME; + uint8_t opmode = 0; + + if (mode_cmd) { + opmode = VEML6070_ENABLE; + } else { + opmode = VEML6070_DISABLE; + } + + veml6070_address = VEML6070_ADDR_L; + Wire.beginTransmission(veml6070_address); + Wire.write((opmode << 0) | 0x02 | (itime << 2)); + uint8_t status = Wire.endTransmission(); + + if (!status) { + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070 opmode", veml6070_address); + AddLog(LOG_LEVEL_DEBUG); + } +} + +/********************************************************************************************/ + +uint16_t Veml6070ReadUv(void) { if (Wire.requestFrom(VEML6070_ADDR_H, 1) != 1) { return -1; @@ -50,45 +161,122 @@ uint16_t Veml6070ReadUv() /********************************************************************************************/ -void Veml6070Detect() +double Veml6070UvRiskLevel(uint16_t uv_level) { - if (veml6070_type) { - return; - } + double risk = 0; + double uv_risk_map[VEML6070_UV_MAX_INDEX] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + // fill the uv-risk compare table based on the coefficient calculation + for (uint8_t i = 0; i < VEML6070_UV_MAX_INDEX; i++) { +#ifdef USE_VEML6070_RSET + if ( (USE_VEML6070_RSET >= 220000) && (USE_VEML6070_RSET <= 1000000) ) { + uv_risk_map[i] = ( (USE_VEML6070_RSET / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT) * (i+1); + } else { + uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT) * (i+1); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "VEML6070 resistor error %d"), USE_VEML6070_RSET); + AddLog(LOG_LEVEL_DEBUG); + } +#else + uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT) * (i+1); +#endif + } - uint8_t itime = VEML6070_INTEGRATION_TIME; - - veml6070_address = VEML6070_ADDR_L; - Wire.beginTransmission(veml6070_address); - Wire.write((itime << 2) | 0x02); - uint8_t status = Wire.endTransmission(); - if (!status) { - veml6070_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070", veml6070_address); + // get the uv-risk level + if (uv_level < uv_risk_map[VEML6070_UV_MAX_INDEX-1]) { + return ( uv_level / uv_risk_map[0] ); + } else { + return ( risk = 99 ); // out of range = much to high - it must be outerspace or sensor damaged + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "VEML6070 out of range %d"), risk); AddLog(LOG_LEVEL_DEBUG); } } +/********************************************************************************************/ + +double Veml6070UvPower(double uvrisk) +{ + // based on calculations for effective irradiation from Karel Vanicek + return ( VEML6070_POWER_COEFFCIENT * uvrisk ); +} + +/********************************************************************************************/ + #ifdef USE_WEBSERVER -const char HTTP_SNS_ULTRAVIOLET[] PROGMEM = - "%s{s}VEML6070 " D_UV_LEVEL "{m}%d{e}"; // {s} = , {m} = , {e} = + // {s} = , {m} = , {e} = +#ifdef USE_VEML6070_SHOW_RAW + const char HTTP_SNS_UV_LEVEL[] PROGMEM = "%s{s}VEML6070 " D_UV_LEVEL "{m}%d " D_UNIT_INCREMENTS "{e}"; +#endif // USE_VEML6070_SHOW_RAW + // different uv index level texts + const char HTTP_SNS_UV_INDEX1[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_1 "{e}"; + const char HTTP_SNS_UV_INDEX2[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_2 "{e}"; + const char HTTP_SNS_UV_INDEX3[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_3 "{e}"; + const char HTTP_SNS_UV_INDEX4[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_4 "{e}"; + const char HTTP_SNS_UV_INDEX5[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_5 "{e}"; + const char HTTP_SNS_UV_INDEX6[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_6 "{e}"; + const char HTTP_SNS_UV_INDEX7[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_7 "{e}"; + const char HTTP_SNS_UV_POWER[] PROGMEM = "%s{s}VEML6070 " D_UV_POWER "{m}%s " D_UNIT_WATT_METER_QUADRAT "{e}"; #endif // USE_WEBSERVER +/********************************************************************************************/ + void Veml6070Show(boolean json) { if (veml6070_type) { + // wakeup the sensor + Veml6070ModeCmd(1); + + // get values from functions uint16_t uvlevel = Veml6070ReadUv(); + double uvrisk = Veml6070UvRiskLevel(uvlevel); + double uvpower = Veml6070UvPower(uvrisk); + char str_uvrisk[10]; + char str_uvpower[5]; + + // convert double values to string + dtostrfd(uvrisk, 2, str_uvrisk); + dtostrfd(uvpower, 3, str_uvpower); if (json) { +#ifdef USE_VEML6070_SHOW_RAW snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_LEVEL "\":%d}"), mqtt_data, uvlevel); +#endif // USE_VEML6070_SHOW_RAW + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_INDEX "\":%s}"), mqtt_data, str_uvrisk); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_POWER "\":%s}"), mqtt_data, str_uvpower); #ifdef USE_DOMOTICZ - if (0 == tele_period) DomoticzSensor(DZ_ILLUMINANCE, uvlevel); + if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, uvlevel) }; #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ULTRAVIOLET, mqtt_data, uvlevel); +#ifdef USE_VEML6070_SHOW_RAW + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_LEVEL, mqtt_data, uvlevel); +#endif // USE_VEML6070_SHOW_RAW + if ( (uvrisk >= 0) && (uvrisk <= 2.9) ) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX1, mqtt_data, str_uvrisk); + } + else if ( (uvrisk >= 3.0) && (uvrisk <= 5.9) ) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX2, mqtt_data, str_uvrisk); + } + else if ( (uvrisk >= 6.0) && (uvrisk <= 7.9) ) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX3, mqtt_data, str_uvrisk); + } + else if ( (uvrisk >= 8.0) && (uvrisk <= 10.9) ) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX4, mqtt_data, str_uvrisk); + } + else if ( (uvrisk >= 11.0) && (uvrisk <= 12.9) ) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX5, mqtt_data, str_uvrisk); + } + else if ( (uvrisk >= 13.0) && (uvrisk <= 15.9) ) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX6, mqtt_data, str_uvrisk); + } else { + // else for Unknown or Out Of Range error = 99 + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX7, mqtt_data, str_uvrisk); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_POWER, mqtt_data, str_uvpower); #endif // USE_WEBSERVER } + // suspend the sensor + Veml6070ModeCmd(0); + // delay(2000); // used while messaurment of current drain } } @@ -105,7 +293,7 @@ boolean Xsns11(byte function) if (i2c_flg) { switch (function) { case FUNC_PREP_BEFORE_TELEPERIOD: - Veml6070Detect(); + Veml6070Detect(); // detect and init the sensor break; case FUNC_JSON_APPEND: Veml6070Show(1); From af5ee5a883384b243dc73f0e400e1577f137bfba Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:37:08 +0200 Subject: [PATCH 35/93] Added defines for text Added defines for uv text and one unit define --- sonoff/language/bg-BG.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index 266714fe4..a3ab3d539 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -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" #define D_UV_LEVEL "Ниво на ултравиолетово излъчване" +#define D_UV_POWER "UV Power" #define D_VERSION "Версия" #define D_VOLTAGE "Напрежение" #define D_WARMLIGHT "Топла" @@ -514,6 +522,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From ee7acd849b67e8fbbebabbe9e702ce8e6b2ab0b0 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:40:55 +0200 Subject: [PATCH 36/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/cs-CZ.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index e90797725..3886c1b4d 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -163,7 +163,15 @@ #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_LEVEL "úroveň UV" +#define D_UV_POWER "UV Power" #define D_VERSION "Verze" #define D_VOLTAGE "Napětí" #define D_WARMLIGHT "Teplé světlo" @@ -514,6 +522,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From 1738f68247f31f41caded85aef4b5f3633365e53 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:42:28 +0200 Subject: [PATCH 37/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/de-DE.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index a6e62c557..9bb14bfa5 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -163,7 +163,14 @@ #define D_USER "Benutzer" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV-Index" +#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_LEVEL "UV-Level" +#define D_UV_POWER "UV Power" #define D_VERSION "Version" #define D_VOLTAGE "Spannung" #define D_WARMLIGHT "warm" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From ef6cd4530d27e662be5d2046c4afe1a4cea477d8 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:44:04 +0200 Subject: [PATCH 38/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/el-GR.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index 715b2a7cf..1b666ae1e 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -163,7 +163,14 @@ #define D_USER "Χρήστης" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV Index" +#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_LEVEL "Επίπεδο UV" +#define D_UV_POWER "UV Power" #define D_VERSION "Έκδοση" #define D_VOLTAGE "Τάση" #define D_WARMLIGHT "Ζεστό" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From c18a3cd7e0a140faf2158793de7fd02049629745 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:45:27 +0200 Subject: [PATCH 39/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/en-GB.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 9ac6c1fad..5f6f0d764 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -163,7 +163,14 @@ #define D_USER "User" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV Index" +#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_LEVEL "UV Level" +#define D_UV_POWER "UV Power" #define D_VERSION "Version" #define D_VOLTAGE "Voltage" #define D_WARMLIGHT "Warm" @@ -514,6 +521,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 From 89e04dafb099652649c245caf2ef8657a488166a Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:46:43 +0200 Subject: [PATCH 40/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/es-AR.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 7d0408080..dafa99900 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -163,7 +163,14 @@ #define D_USER "Usuario" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Índice UV" +#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_LEVEL "Nivel UV" +#define D_UV_POWER "UV Power" #define D_VERSION "Versión" #define D_VOLTAGE "Tensión" #define D_WARMLIGHT "Cálida" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From 651bdf03c0ee556f66b5a6d4535ee692ff66c802 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:49:51 +0200 Subject: [PATCH 41/93] Update fr-FR.h Added some new text UV defines and one unit define W/m2 --- sonoff/language/fr-FR.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 7e6ea07b9..8cbf0ce7d 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -163,7 +163,14 @@ #define D_USER "Utilisateur" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Indice UV" +#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_LEVEL "Niveau UV" +#define D_UV_POWER "UV Power" #define D_VERSION "Version" #define D_VOLTAGE "Tension" #define D_WARMLIGHT "Chaud" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From e3f1d4ad9ae4256b25f321e2e12e1d20a55c6095 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:50:05 +0200 Subject: [PATCH 42/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/hu-HU.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index ef2c28f80..3c9f23334 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -163,7 +163,14 @@ #define D_USER "Felhasználó" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV Index" +#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_LEVEL "UV Szint" +#define D_UV_POWER "UV Power" #define D_VERSION "Verzió" #define D_VOLTAGE "Feszültség" #define D_WARMLIGHT "Meleg" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From 9182d02d0cf601ccfe0987fbbf2bcc7d1d8c8710 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:50:18 +0200 Subject: [PATCH 43/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/it-IT.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index ac818a9f2..b44f612f3 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -163,7 +163,14 @@ #define D_USER "Utente" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Indice UV" +#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_LEVEL "Livello UV" +#define D_UV_POWER "UV Power" #define D_VERSION "Versione" #define D_VOLTAGE "Tensione" #define D_WARMLIGHT "Calda" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From 4c900eb0b720b2c2c8f69c4a392788a5568bb510 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:52:41 +0200 Subject: [PATCH 44/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/nl-NL.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 273699477..4946dd94f 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -163,7 +163,14 @@ #define D_USER "Gebruiker" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV-index" +#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_LEVEL "UV niveau" +#define D_UV_POWER "UV Power" #define D_VERSION "Versie" #define D_VOLTAGE "Spanning" #define D_WARMLIGHT "Warm" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From f7c16f53881d18df0b4134195757ee00b4a4806a Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:53:03 +0200 Subject: [PATCH 45/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/pl-PL.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 199f7cce9..fa118b1b1 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -163,7 +163,14 @@ #define D_USER "Użytkownik" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV Index" +#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_LEVEL "Poziom UV" +#define D_UV_POWER "UV Power" #define D_VERSION "Wersja" #define D_VOLTAGE "Napięcie" #define D_WARMLIGHT "Nagrzanie" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From a6cf1cde4fd1323d43fec33a789aefa3f0d05607 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:53:25 +0200 Subject: [PATCH 46/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/pt-BR.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index 8770b9a4a..bf1318864 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -163,7 +163,14 @@ #define D_USER "Usuário" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Índice UV" +#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_LEVEL "Nível UV" +#define D_UV_POWER "UV Power" #define D_VERSION "Versão" #define D_VOLTAGE "Voltagem" #define D_WARMLIGHT "Luz quente" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "W/h" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From 78df649fcae70e9c1e463ff41151d27fd0d9904a Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:56:38 +0200 Subject: [PATCH 47/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/pt-PT.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index 0b7715583..a3b67c366 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -163,7 +163,14 @@ #define D_USER "Utilizador" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Indíce UV" +#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_LEVEL "Nível UV" +#define D_UV_POWER "UV Power" #define D_VERSION "Versão" #define D_VOLTAGE "Voltagem" #define D_WARMLIGHT "Luz Quente" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From c8f51b68fdaf424a0392c7534a9d68072d983d34 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:57:01 +0200 Subject: [PATCH 48/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/ru-RU.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index e61cbb9c1..a4e48067d 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -163,7 +163,14 @@ #define D_USER "Пользователь" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV Index" +#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_LEVEL "УФ уровень" +#define D_UV_POWER "UV Power" #define D_VERSION "Версия" #define D_VOLTAGE "Напряжение" #define D_WARMLIGHT "Тепло" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "В" #define D_UNIT_WATT "Вт" #define D_UNIT_WATTHOUR "ВтЧ" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From 56e9e92655359c179377248676f6ba7f91c0462b Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 14:57:17 +0200 Subject: [PATCH 49/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/tr-TR.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index 086c236aa..62cec3eb0 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -163,7 +163,14 @@ #define D_USER "Kullanıcı" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV Indeksi" +#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_LEVEL "UV Seviyesi" +#define D_UV_POWER "UV Power" #define D_VERSION "Versiyon" #define D_VOLTAGE "Voltaj" #define D_WARMLIGHT "Sıcak" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "V" #define D_UNIT_WATT "W" #define D_UNIT_WATTHOUR "Wh" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" #define D_UNIT_HERTZ "Hz" // Log message prefix From cf952f66377026cbcf6c6eba344e4476eb7389ee Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 15:00:34 +0200 Subject: [PATCH 50/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/uk-UK.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index 19094d574..7dccdb7db 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -163,7 +163,14 @@ #define D_USER "Користувач" #define D_UTC_TIME "UTC" #define D_UV_INDEX "УФ індекс" +#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_LEVEL "УФ рівень" +#define D_UV_POWER "UV Power" #define D_VERSION "Версія" #define D_VOLTAGE "Напруга" #define D_WARMLIGHT "Тепло" @@ -515,6 +522,7 @@ #define D_UNIT_VOLT "В" #define D_UNIT_WATT "Вт" #define D_UNIT_WATTHOUR "ВтГод" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From 044363dc00eccd9c6c0b6d58cf5c6b693509a6b1 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 15:00:57 +0200 Subject: [PATCH 51/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/zh-CN.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index ea15b6ccb..820cde18c 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -163,7 +163,14 @@ #define D_USER "用户名" #define D_UTC_TIME "UTC" #define D_UV_INDEX "紫外线指数" +#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_LEVEL "紫外线水平" +#define D_UV_POWER "UV Power" #define D_VERSION "版本" #define D_VOLTAGE "电压" #define D_WARMLIGHT "暖" @@ -514,6 +521,7 @@ #define D_UNIT_WATT "瓦" #define D_UNIT_WATTHOUR "瓦时" #define D_UNIT_HERTZ "赫兹" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From 13e0bcbd26c00e91866d8203ac5573626074eb0f Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 15:01:16 +0200 Subject: [PATCH 52/93] Added some text defines Added some new text UV defines and one unit define W/m2 --- sonoff/language/zh-TW.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index f4f439c8b..14052d9f3 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -163,7 +163,14 @@ #define D_USER "用戶名" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV Index" +#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_LEVEL "紫外線等級" +#define D_UV_POWER "UV Power" #define D_VERSION "版本" #define D_VOLTAGE "電壓" #define D_WARMLIGHT "暖" @@ -514,6 +521,7 @@ #define D_UNIT_VOLT "伏" #define D_UNIT_WATT "瓦" #define D_UNIT_WATTHOUR "瓦時" +#define D_UNIT_WATT_METER_QUADRAT "W/m²" // Log message prefix #define D_LOG_APPLICATION "APP: " // Application From 40052a343ffe94ad1ac4f077700acdb42eadb941 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 25 Sep 2018 15:35:49 +0200 Subject: [PATCH 53/93] Add image sonoff-display Add define USE_DISPLAYS for selecting image sonoff-display --- platformio.ini | 15 +++++++++++++++ sonoff/_changelog.ino | 1 + sonoff/sonoff_post.h | 26 +++++++++++++++++++++++++- sonoff/user_config.h | 3 ++- 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index d333fd187..c01485f5a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,6 +16,7 @@ env_default = sonoff ;env_default = sonoff-classic ;env_default = sonoff-knx ;env_default = sonoff-sensors +;env_default = sonoff-display ;env_default = sonoff-BG ;env_default = sonoff-BR ;env_default = sonoff-CN @@ -167,6 +168,20 @@ upload_resetmethod = ${common.upload_resetmethod} upload_speed = ${common.upload_speed} extra_scripts = ${common.extra_scripts} +[env:sonoff-display] +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} -DUSE_DISPLAYS +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-BG] platform = ${common.platform} framework = ${common.framework} diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 333a524a6..f2525b2a7 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -2,6 +2,7 @@ * Remove restart after ntpserver change and force NTP re-sync (#3890) * Release full Shelly2 support * Released tools/decode-config.py by Norbert Richter to decode configuration data. See file for information + * Add define USE_DISPLAYS for selecting image sonoff-display * * 6.2.1.6 20180922 * Removed commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index 8622d0818..423a75f3c 100755 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -51,7 +51,7 @@ void KNX_CB_Action(message_t const &msg, void *arg); #endif #define USE_DHT // Default DHT11 sensor needs no external library -#define USE_ENERGY_SENSOR // Use energy sensors +#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 @@ -167,6 +167,30 @@ void KNX_CB_Action(message_t const &msg, void *arg); #undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem) #endif // USE_KNX_NO_EMULATION +/*********************************************************************************************\ + * [sonoff-display.bin] + * Provide an image with display drivers enabled +\*********************************************************************************************/ + +#ifdef USE_DISPLAYS + +#undef USE_ENERGY_SENSOR // Disable energy sensors (-14k code) +#undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem) + +#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) + #define USE_DISPLAY // Add I2C Display Support (+2k code) + #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 + #define USE_DISPLAY_LCD // [DisplayModel 1] Enable Lcd display (I2C addresses 0x27 and 0x3F) (+6k code) + #define USE_DISPLAY_SSD1306 // [DisplayModel 2] Enable SSD1306 Oled 128x64 display (I2C addresses 0x3C and 0x3D) (+16k code) + #define USE_DISPLAY_MATRIX // [DisplayModel 3] Enable 8x8 Matrix display (I2C adresseses see below) (+11k code) + +#define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC) + #define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code) + +#undef USE_ARILUX_RF // Remove support for Arilux RF remote controller (-0k8 code, 252 iram (non 2.3.0)) +#undef USE_RF_FLASH // Remove support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (-3k code) +#endif // USE_DISPLAYS + /*********************************************************************************************\ * Mandatory define for DS18x20 if changed by above image selections \*********************************************************************************************/ diff --git a/sonoff/user_config.h b/sonoff/user_config.h index b93e44211..f86350334 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -321,7 +321,7 @@ #endif // USE_I2C // -- SPI sensors --------------------------------- -//#define USE_SPI // SPI using library TasmotaTFT +//#define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC) #ifdef USE_SPI #ifndef USE_DISPLAY @@ -384,6 +384,7 @@ //#define USE_CLASSIC // Create sonoff-classic with initial configuration tools WPS, SmartConfig and WifiManager //#define USE_SENSORS // Create sonoff-sensors with useful sensors enabled //#define USE_KNX_NO_EMULATION // Create sonoff-knx with KNX but without Emulation +//#define USE_DISPLAYS // Create sonoff-display with display drivers enabled //#define BE_MINIMAL // Create sonoff-minimal as intermediate firmware for OTA-MAGIC /*********************************************************************************************\ From e9d6a5bc4677197a56a4885886ef11ebf2a43ebb Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:19:49 +0200 Subject: [PATCH 54/93] added define Forgot to add #define D_JSON_UV_POWER "UvPower" --- sonoff/i18n.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 80f757447..1c628b7b7 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -132,6 +132,7 @@ #define D_JSON_UTC_TIME "UTC" #define D_JSON_UVINDEX "UvIndex" #define D_JSON_UV_LEVEL "UvLevel" +#define D_JSON_UV_POWER "UvPower" #define D_JSON_VCC "Vcc" #define D_JSON_VERSION "Version" #define D_JSON_VOLTAGE "Voltage" From baf81daaa2c896fa3f6fa7ba6a89b49ff9053f31 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:23:38 +0200 Subject: [PATCH 55/93] added text forgot the #define D_UNIT_INCREMENTS "inc" --- sonoff/language/bg-BG.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index a3ab3d539..ff7801984 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -502,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "h" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kΩ" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" From e6ae87fd829c25dcb337777aaa6f3331ff99edd3 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:24:44 +0200 Subject: [PATCH 56/93] added text forgot the #define D_UNIT_INCREMENTS "inc" --- sonoff/language/cs-CZ.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 3886c1b4d..570cfd4c8 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -502,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "hod" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" From abd5cb23fe7ac46816d107b5ea2c2be463a05383 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:27:10 +0200 Subject: [PATCH 57/93] Added text forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/de-DE.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 9bb14bfa5..6e90ae409 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -163,6 +163,7 @@ #define D_USER "Benutzer" #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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "h" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" From a7d59f03fa1cb0be7721e8ad4351523858ea44cd Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:28:34 +0200 Subject: [PATCH 58/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/en-GB.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 5f6f0d764..21d8edab7 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -163,6 +163,7 @@ #define D_USER "User" #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" @@ -500,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" From b15a29c046edd5d75351c2900fc84e6fb0f4f1bf Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:29:27 +0200 Subject: [PATCH 59/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/el-GR.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index 1b666ae1e..23b5a2705 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -163,6 +163,7 @@ #define D_USER "Χρήστης" #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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #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" From 3fd8b8f7f8a1b1cf4badbdef3af616216c10ad42 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:32:17 +0200 Subject: [PATCH 60/93] Added text #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/es-AR.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index dafa99900..b67e6e79f 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -163,6 +163,7 @@ #define D_USER "Usuario" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Índice 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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #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" From cdc7b90652601a73052a55b1167f92fdf9c68beb Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:32:36 +0200 Subject: [PATCH 61/93] Added text #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/fr-FR.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 8cbf0ce7d..c4c913fec 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -163,6 +163,7 @@ #define D_USER "Utilisateur" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Indice 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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "h" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kΩ" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" From 9ad0bc149f43c3ac45a239c686f557f2308b1ff4 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:32:46 +0200 Subject: [PATCH 62/93] Added text #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/hu-HU.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 3c9f23334..ee6b8a66a 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -163,6 +163,7 @@ #define D_USER "Felhasználó" #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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "ó" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" From a1d5032993d65e463934632746f73a80dc35761b Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:35:17 +0200 Subject: [PATCH 63/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/it-IT.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index b44f612f3..b0fe0767a 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -163,6 +163,7 @@ #define D_USER "Utente" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Indice 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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #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" From 55db6530ec61d9cc7a5d6613ebfbc6e2d166362b Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:35:29 +0200 Subject: [PATCH 64/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/nl-NL.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 4946dd94f..70e55cb87 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -163,6 +163,7 @@ #define D_USER "Gebruiker" #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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "h" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" From a7495af9edb5c6f148d9f913ac6df6e27eee8682 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:35:48 +0200 Subject: [PATCH 65/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/pl-PL.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index fa118b1b1..40383fb53 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -163,6 +163,7 @@ #define D_USER "Użytkownik" #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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Godz" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" From 6b070e08cf046ec95ca7e6f2ff3b443aeb19d4f8 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:38:04 +0200 Subject: [PATCH 66/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/pt-BR.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index bf1318864..49affdf2f 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -163,6 +163,7 @@ #define D_USER "Usuário" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Índice 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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "H" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "kOhm" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" From dc937ed792a0e27ef773632fa0565c91b382353b Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:38:27 +0200 Subject: [PATCH 67/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/pt-PT.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index a3b67c366..fd2e98451 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -163,6 +163,7 @@ #define D_USER "Utilizador" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Indíce 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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #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" From 65dbf4c709a0a3042ed28247f90aa7168fecfaed Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:38:40 +0200 Subject: [PATCH 68/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/ru-RU.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index a4e48067d..9c6266693 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -163,6 +163,7 @@ #define D_USER "Пользователь" #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" @@ -501,6 +502,7 @@ #define D_UNIT_CENTIMETER "cm" #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "Ч" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "кОм" #define D_UNIT_KILOWATTHOUR "кВт" #define D_UNIT_LUX "лк" From e719cfbf43a63e66d07e08ad3db8be28c7ece159 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:41:51 +0200 Subject: [PATCH 69/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/tr-TR.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index 62cec3eb0..0c411868e 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -163,6 +163,7 @@ #define D_USER "Kullanıcı" #define D_UTC_TIME "UTC" #define D_UV_INDEX "UV Indeksi" +#define D_UV_INDEX_1 "Low" #define D_UV_INDEX_2 "Mid" #define D_UV_INDEX_3 "High" #define D_UV_INDEX_4 "Danger" @@ -501,6 +502,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" From 85692d6f386f7aca47e9ab8d83c8ab54cfd39d0b Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:42:01 +0200 Subject: [PATCH 70/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/zh-CN.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 820cde18c..59271d201 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -163,6 +163,7 @@ #define D_USER "用户名" #define D_UTC_TIME "UTC" #define D_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" @@ -500,6 +501,7 @@ #define D_UNIT_AMPERE "安" #define D_UNIT_CENTIMETER "厘米" #define D_UNIT_HOUR "时" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "千欧" #define D_UNIT_KILOWATTHOUR "千瓦时" #define D_UNIT_LUX "勒克斯" From a47467704e235e87370605074eaa7c9461a0b517 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:42:07 +0200 Subject: [PATCH 71/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/uk-UK.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index 7dccdb7db..3a9b44afa 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -163,6 +163,7 @@ #define D_USER "Користувач" #define D_UTC_TIME "UTC" #define D_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" @@ -502,6 +503,7 @@ #define D_UNIT_CENTIMETER "cм" #define D_UNIT_HERTZ "Гц" #define D_UNIT_HOUR "Г" +#define D_UNIT_INCREMENTS "inc" #define D_UNIT_KILOOHM "кОм" #define D_UNIT_KILOWATTHOUR "кВт" #define D_UNIT_LUX "лк" From 63dbd6d0c94b597be723467a83c4b19cbeb17055 Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 25 Sep 2018 16:42:09 +0200 Subject: [PATCH 72/93] Added text Forgot the #define D_UNIT_INCREMENTS "inc" and #define D_UV_INDEX_1 "Low" --- sonoff/language/zh-TW.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 14052d9f3..5b275b925 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -163,6 +163,7 @@ #define D_USER "用戶名" #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" @@ -500,6 +501,7 @@ #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_KILOOHM "千歐" #define D_UNIT_KILOWATTHOUR "千瓦時" From eb53605fc1ee76f3fd893b0728ef8b9117183060 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 25 Sep 2018 17:03:22 +0200 Subject: [PATCH 73/93] Fix VEML6070 compile errors --- sonoff/i18n.h | 2 +- sonoff/user_config.h | 6 +++--- sonoff/xsns_11_veml6070.ino | 30 +++++++++++++++--------------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 1c628b7b7..c8d3e219f 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -130,7 +130,7 @@ #define D_JSON_TYPE "Type" #define D_JSON_UPTIME "Uptime" #define D_JSON_UTC_TIME "UTC" -#define D_JSON_UVINDEX "UvIndex" +#define D_JSON_UV_INDEX "UvIndex" #define D_JSON_UV_LEVEL "UvLevel" #define D_JSON_UV_POWER "UvPower" #define D_JSON_VCC "Vcc" diff --git a/sonoff/user_config.h b/sonoff/user_config.h index b864d7aa6..eceadc68d 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -282,9 +282,9 @@ #define USE_BMP // Enable BMP085/BMP180/BMP280/BME280 sensor (I2C address 0x76 or 0x77) (+4k code) // #define USE_BME680 // Enable support for BME680 sensor using Bosch BME680 library (+4k code) #define USE_BH1750 // Enable BH1750 sensor (I2C address 0x23 or 0x5C) (+0k5 code) -// #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+0k5 code) -// #define USE_VEML6070_RSET 270000 // VEML6070, Rset in Ohm used on PCB board, default 270K = 270000ohm, range for this sensor: 220K ... 1Meg -// #define USE_VEML6070_SHOW_RAW // VEML6070, shows the raw value of UV-A +// #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+1k5 code) + #define USE_VEML6070_RSET 270000 // VEML6070, Rset in Ohm used on PCB board, default 270K = 270000ohm, range for this sensor: 220K ... 1Meg + #define USE_VEML6070_SHOW_RAW // VEML6070, shows the raw value of UV-A // #define USE_ADS1115 // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) based on Adafruit ADS1x15 library (no library needed) (+0k7 code) // #define USE_ADS1115_I2CDEV // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) using library i2cdevlib-Core and i2cdevlib-ADS1115 (+2k code) // #define USE_INA219 // Enable INA219 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+1k code) diff --git a/sonoff/xsns_11_veml6070.ino b/sonoff/xsns_11_veml6070.ino index be7d3daa0..f60c0f00f 100644 --- a/sonoff/xsns_11_veml6070.ino +++ b/sonoff/xsns_11_veml6070.ino @@ -30,7 +30,7 @@ -------------------------------------------------------------------------------------------- Version Date Action Description -------------------------------------------------------------------------------------------- - + 1.0.0.1 20180925 tests - all tests are done with 1x sonoff sv, 2x Wemos D1 (not the mini) - 3 different VEMl6070 sensors from 3 different online shops - all the last three test where good and all looks working so far @@ -43,7 +43,7 @@ cleaned - source code a little bit added - missing void in function calls: void name(void) added - UV Risk level now defined as UV Index, 0.00 based on NASA standard with text behind the value - added - UV Power level now named as UV Power, used W/m2 because official standards + added - UV Power level now named as UV Power, used W/m2 because official standards added - automatic fill of the uv-risk compare table based on the coefficient calculation added - suspend and wakeup mode for the uv seonsor - current drain in wake-up-ed mode was around 180uA incl. I2C bus @@ -51,7 +51,7 @@ changed - 2x the power calculation about some incorrent data sheet values changed - float to double calculation because a rare effect on uv compare map filling - in that case @andrethomas was a big help too (while(work){output=lot_of_fun};) - added - USE_VEML6070_RSET + added - USE_VEML6070_RSET - in user_config as possible input, different resistor values depending on PCB types added - USE_VEML6070_SHOW_RAW - in user_config, show or show-NOT the uv raw value @@ -62,12 +62,12 @@ safety - personal, please read this: http://www.segurancaetrabalho.com.br/download/uv_index_karel_vanicek.pdf next - possible i will add the calculation for LAT and LONG coordinates for much more precission - 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 + - 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 - + */ #ifdef USE_I2C @@ -87,8 +87,8 @@ #define VEML6070_RSET_DEFAULT 270000 // 270K default resistor value 270000 ohm, range from 220K..1Meg #define VEML6070_UV_MAX_INDEX 15 // normal 11, internal on weather laboratories and NASA it's 15 so far the sensor is linear #define VEML6070_UV_MAX_DEFAULT 11 // 11 = public default table values -#define VEML6070_POWER_COEFFCIENT 0.025 // based on calculations from Karel Vanicek and reorder by hand -#define VEML6070_TABLE_COEFFCIENT 32.86270591 // calculated by hand with help from a friend of mine, a professor which works in aero space things +#define VEML6070_POWER_COEFFCIENT 0.025 // based on calculations from Karel Vanicek and reorder by hand +#define VEML6070_TABLE_COEFFCIENT 32.86270591 // calculated by hand with help from a friend of mine, a professor which works in aero space things // (resistor, differences, power coefficients and official UV index calculations (LAT & LONG will be added later) /********************************************************************************************/ @@ -110,7 +110,7 @@ void Veml6070Detect(void) Wire.beginTransmission(veml6070_address); Wire.write((itime << 2) | 0x02); uint8_t status = Wire.endTransmission(); - + if (!status) { veml6070_type = 1; snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070", veml6070_address); @@ -130,7 +130,7 @@ void Veml6070ModeCmd(boolean mode_cmd) } else { opmode = VEML6070_DISABLE; } - + veml6070_address = VEML6070_ADDR_L; Wire.beginTransmission(veml6070_address); Wire.write((opmode << 0) | 0x02 | (itime << 2)); @@ -165,7 +165,7 @@ double Veml6070UvRiskLevel(uint16_t uv_level) { double risk = 0; double uv_risk_map[VEML6070_UV_MAX_INDEX] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - + // fill the uv-risk compare table based on the coefficient calculation for (uint8_t i = 0; i < VEML6070_UV_MAX_INDEX; i++) { #ifdef USE_VEML6070_RSET @@ -179,7 +179,7 @@ double Veml6070UvRiskLevel(uint16_t uv_level) #else uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT) * (i+1); #endif - } + } // get the uv-risk level if (uv_level < uv_risk_map[VEML6070_UV_MAX_INDEX-1]) { @@ -223,8 +223,8 @@ void Veml6070Show(boolean json) { if (veml6070_type) { // wakeup the sensor - Veml6070ModeCmd(1); - + Veml6070ModeCmd(1); + // get values from functions uint16_t uvlevel = Veml6070ReadUv(); double uvrisk = Veml6070UvRiskLevel(uvlevel); @@ -243,7 +243,7 @@ void Veml6070Show(boolean json) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_INDEX "\":%s}"), mqtt_data, str_uvrisk); snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_POWER "\":%s}"), mqtt_data, str_uvpower); #ifdef USE_DOMOTICZ - if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, uvlevel) }; + if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, uvlevel); }; #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { @@ -270,7 +270,7 @@ void Veml6070Show(boolean json) } else { // else for Unknown or Out Of Range error = 99 snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX7, mqtt_data, str_uvrisk); - } + } snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_POWER, mqtt_data, str_uvpower); #endif // USE_WEBSERVER } From b78626fd480e2b8254e39afd0ca7832e8087623e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 25 Sep 2018 17:08:16 +0200 Subject: [PATCH 74/93] Updated with Shelly --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3f695f666..498cd2f80 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ See [Community](https://groups.google.com/d/forum/sonoffusers) for forum.
See [Chat](https://discord.gg/Ks2Kzd4) for more user experience. The following devices are supported: -- [iTead Sonoff Basic](https://www.itead.cc/smart-home/sonoff-wifi-wireless-switch-1.html) +- [iTead Sonoff Basic (R2)](https://www.itead.cc/smart-home/sonoff-wifi-wireless-switch-1.html) - [iTead Sonoff RF](https://www.itead.cc/smart-home/sonoff-rf.html) - [iTead Sonoff SV](https://www.itead.cc/smart-home/sonoff-sv.html) - [iTead Sonoff TH10/TH16 with temperature sensor](https://www.itead.cc/smart-home/sonoff-th.html) @@ -90,10 +90,15 @@ The following devices are supported: - [MagicHome PWM LED controller](https://github.com/arendst/Sonoff-Tasmota/wiki/MagicHome-LED-strip-controller) - AriLux AL-LC01, AL-LC06 and AL-LC11 PWM LED controller - [Supla device - Espablo-inCan mod. for electrical Installation box](https://forum.supla.org/viewtopic.php?f=33&t=2188) -- [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) +- [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/) -- Xiaomi-Phillips Bulbs -- Wemos D1 mini, NodeMcu and Ledunia +- [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) +- [Allterco Shelly 1](https://shelly.cloud/shelly1-open-source/) +- [Allterco Shelly 2 with Energy Monitoring](https://shelly.cloud/shelly2/) +- NodeMcu and Ledunia +- [KS-602 based switches like GresaTek, Jesiya, NewRice, Lyasi etc](https://ucexperiment.wordpress.com/2017/11/14/reprogramming-a-lyasi-wifi-wall-switch-with-esp8285/) ### Contribute You can contribute to Sonoff-Tasmota by From 71964e0aa46e945b7fa7d958cf926fa276d69339 Mon Sep 17 00:00:00 2001 From: localhost61 Date: Wed, 26 Sep 2018 00:59:00 +0200 Subject: [PATCH 75/93] Update French localization --- sonoff/language/fr-FR.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index c4c913fec..9a479177a 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.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.1.7 + * Updated until v6.2.1.7 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -65,7 +65,7 @@ #define D_BY "par" // Written by me #define D_BYTES "Bytes" #define D_CELSIUS "Celsius" -#define D_CHANNEL "Channel" +#define D_CHANNEL "Canal" #define D_CO2 "Dioxyde de carbone" #define D_CODE "code" // Button code #define D_COLDLIGHT "Froid" @@ -163,15 +163,15 @@ #define D_USER "Utilisateur" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Indice 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" +#define D_UV_INDEX_1 "Faible" +#define D_UV_INDEX_2 "Modéré" +#define D_UV_INDEX_3 "Élevé" +#define D_UV_INDEX_4 "Très élevé" +#define D_UV_INDEX_5 "Brûlure niv.1/2" +#define D_UV_INDEX_6 "Brûlure niv.3" +#define D_UV_INDEX_7 "Extrême" #define D_UV_LEVEL "Niveau UV" -#define D_UV_POWER "UV Power" +#define D_UV_POWER "Puissance UV" #define D_VERSION "Version" #define D_VOLTAGE "Tension" #define D_WARMLIGHT "Chaud" From 6798eb585441e6cbceb241878dfc65a2f0dee59d Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Tue, 25 Sep 2018 21:00:56 -0300 Subject: [PATCH 76/93] Updated Spanish Translation --- sonoff/language/es-AR.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index b67e6e79f..713e166ab 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -163,13 +163,13 @@ #define D_USER "Usuario" #define D_UTC_TIME "UTC" #define D_UV_INDEX "Índice 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" +#define D_UV_INDEX_1 "Bajo" +#define D_UV_INDEX_2 "Medio" +#define D_UV_INDEX_3 "Alto" +#define D_UV_INDEX_4 "Peligroso" +#define D_UV_INDEX_5 "Quemaduras 1 a 2 grad" +#define D_UV_INDEX_6 "Quemaduras 3 grad" +#define D_UV_INDEX_7 "Fuera de Rango" #define D_UV_LEVEL "Nivel UV" #define D_UV_POWER "UV Power" #define D_VERSION "Versión" From 8ff696b34b19cc2fcefcf2bce64ab6cb701a90b8 Mon Sep 17 00:00:00 2001 From: localhost61 Date: Wed, 26 Sep 2018 02:37:27 +0200 Subject: [PATCH 77/93] Correct the OoR translation (thanks Adrian ;-) ) --- sonoff/language/fr-FR.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 9a479177a..a7adaea39 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -169,7 +169,7 @@ #define D_UV_INDEX_4 "Très élevé" #define D_UV_INDEX_5 "Brûlure niv.1/2" #define D_UV_INDEX_6 "Brûlure niv.3" -#define D_UV_INDEX_7 "Extrême" +#define D_UV_INDEX_7 "Hors échelle" #define D_UV_LEVEL "Niveau UV" #define D_UV_POWER "Puissance UV" #define D_VERSION "Version" @@ -184,7 +184,7 @@ #define D_SERIAL_LOGGING_DISABLED "Journalisation série désactivée" #define D_SYSLOG_LOGGING_REENABLED "Jounalisation syslog réactivée" -#define D_SET_BAUDRATE_TO "Définir baudrate à" +#define D_SET_BAUDRATE_TO "Définir le débit à" #define D_RECEIVED_TOPIC "Topic reçu" // Terme MQTT #define D_DATA_SIZE "Taille données" #define D_ANALOG_INPUT "Analogique" From bac33345a05e57fc3fb17f8c0f82ac2f406151a8 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 26 Sep 2018 10:13:44 +0200 Subject: [PATCH 78/93] 6.2.1.8 Extent status JSON 6.2.1.8 20180926 * Change status JSON message providing more switch and retain information --- sonoff/_changelog.ino | 5 ++++- sonoff/sonoff.ino | 9 +++++++-- sonoff/sonoff_version.h | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index f2525b2a7..a442bf59e 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,7 @@ -/* 6.2.1.7 20180925 +/* 6.2.1.8 20180926 + * Change status JSON message providing more switch and retain information + * + * 6.2.1.7 20180925 * Remove restart after ntpserver change and force NTP re-sync (#3890) * Release full Shelly2 support * Released tools/decode-config.py by Norbert Richter to decode configuration data. See file for information diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index f0619f362..5bcf5fa7c 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -1412,6 +1412,7 @@ void PublishStatus(uint8_t payload) { uint8_t option = STAT; char stemp[MAX_FRIENDLYNAMES * (sizeof(Settings.friendlyname[0]) +MAX_FRIENDLYNAMES)]; + char stemp2[MAX_SWITCHES * 3]; // Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) option++; // TELE @@ -1426,8 +1427,12 @@ void PublishStatus(uint8_t payload) for (byte i = 0; i < maxfn; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%s%s\"%s\"" ), stemp, (i > 0 ? "," : ""), Settings.friendlyname[i]); } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"), - Settings.module +1, stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_power_retain); + stemp2[0] = '\0'; + for (byte i = 0; i < MAX_SWITCHES; i++) { + snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\"" D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"), + Settings.module +1, stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.switch_topic, stemp2, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_switch_retain, Settings.flag.mqtt_sensor_retain, Settings.flag.mqtt_power_retain); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS)); } diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 16c554783..915ce52d2 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 0x06020107 +#define VERSION 0x06020108 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" From 6939d6eead78d72dc2ffc104f8a6578711c5afe1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 26 Sep 2018 11:56:58 +0200 Subject: [PATCH 79/93] Fix Shelly Ghost and Rule sensors * Change pinmode for no-pullup defined switches to pullup when configured as switchmode PUSHBUTTON (=3 and up) (#3896) * Add delay after restart before processing rule sensor data (#3811) --- sonoff/_changelog.ino | 2 ++ sonoff/sonoff.ino | 18 ++++++++++++++++-- sonoff/sonoff_template.h | 22 ++++++++++++++++++++-- sonoff/xdrv_10_rules.ino | 2 +- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index a442bf59e..06ebd36c1 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,5 +1,7 @@ /* 6.2.1.8 20180926 * Change status JSON message providing more switch and retain information + * Change pinmode for no-pullup defined switches to pullup when configured as switchmode PUSHBUTTON (=3 and up) (#3896) + * Add delay after restart before processing rule sensor data (#3811) * * 6.2.1.7 20180925 * Remove restart after ntpserver change and force NTP re-sync (#3890) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 5bcf5fa7c..6b354bb24 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -147,6 +147,7 @@ uint16_t blink_counter = 0; // Number of blink cycles uint16_t seriallog_timer = 0; // Timer to disable Seriallog uint16_t syslog_timer = 0; // Timer to re-enable syslog_level uint16_t holdbutton[MAX_KEYS] = { 0 }; // Timer for button hold +uint16_t switch_no_pullup = 0; // Switch pull-up bitmask flags int16_t save_data_counter; // Counter and flag for config save to Flash RulesBitfield rules_flag; // Rule state flags (16 bits) uint8_t serial_local = 0; // Handle serial locally; @@ -1119,6 +1120,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) else if ((CMND_SWITCHMODE == command_code) && (index > 0) && (index <= MAX_SWITCHES)) { if ((payload >= 0) && (payload < MAX_SWITCH_OPTION)) { Settings.switchmode[index -1] = payload; + GpioSwitchPinMode(index -1); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, index, Settings.switchmode[index-1]); } @@ -2296,11 +2298,23 @@ void SerialInput() /********************************************************************************************/ +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); + } + pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : (no_pullup) ? INPUT : INPUT_PULLUP); + } +} + void GpioInit() { uint8_t mpin; uint8_t key_no_pullup = 0; - uint16_t switch_no_pullup = 0; mytmplt def_module; if (!Settings.module || (Settings.module >= MAXMODULE)) { @@ -2457,7 +2471,7 @@ void GpioInit() for (byte i = 0; i < MAX_SWITCHES; i++) { lastwallswitch[i] = 1; // Init global to virtual switch state; if (pin[GPIO_SWT1 +i] < 99) { - pinMode(pin[GPIO_SWT1 +i], (16 == pin[GPIO_SWT1 +i]) ? INPUT_PULLDOWN_16 : bitRead(switch_no_pullup, i) ? INPUT : INPUT_PULLUP); + GpioSwitchPinMode(i); lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // Set global now so doesn't change the saved power state on first switch check } virtualswitch[i] = lastwallswitch[i]; diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 781b1004d..f5e332531 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -399,9 +399,9 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { HUAFAN_SS, KMC_70011, AILIGHT, - WEMOS, + PHILIPS, WITTY, - PHILIPS + WEMOS }; // Default module settings @@ -1060,6 +1060,24 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { /* Optionals + { "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 + // https://www.aliexpress.com/item/Wifi-LED-RGB-Controler-DC12V-MIni-Wifi-RGB-RGBW-LED-Controller-for-RGB-RGBW-LED-Strip/32673444047.html + GPIO_USER, // GPIO00 Optional Button + GPIO_USER, // GPIO01 Serial RXD and Optional sensor + 0, + GPIO_USER, // GPIO03 Serial TXD and Optional sensor0 + GPIO_ARIRFRCV, // GPIO04 RF receiver input + GPIO_PWM2, // GPIO05 RGB LED Green + 0, 0, 0, 0, 0, 0, // Flash connection + GPIO_PWM3, // GPIO12 RGB LED Blue + GPIO_PWM4, // GPIO13 RGBW LED White + GPIO_PWM1, // GPIO14 RGB LED Red + GPIO_LED2_INV, // GPIO15 RF receiver control + 0, 0 + } + { "Xenon 3CH", // Xenon 3CH (ESP8266) - (#1128) 0, 0, 0, GPIO_KEY2, // GPIO03 Serial TXD and Optional sensor diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 303207c10..060bf085f 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -425,7 +425,7 @@ void RulesEvery50ms() void RulesEvery100ms() { - if (Settings.rule_enabled) { // Any rule enabled + if (Settings.rule_enabled && (uptime > 4)) { // Any rule enabled and allow 4 seconds start-up time for sensors (#3811) mqtt_data[0] = '\0'; int tele_period_save = tele_period; tele_period = 2; // Do not allow HA updates during next function call From 76d203d5aaed61bf4769aaa51bce6f30953b23c0 Mon Sep 17 00:00:00 2001 From: Norbert Richter Date: Wed, 26 Sep 2018 15:18:01 +0200 Subject: [PATCH 80/93] 'decode-config.py' version bugfixes & json output enhancements - add new arguments '--json-indent' and '--json-compact' - fix poblem with invalid string chars when having garbadge in flash - fix errors using configs for Tasmota < v6.2.1 - fix setting definition for v5.13.1/v5.14.0 --- tools/decode-config.py | 127 +++++++++++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 44 deletions(-) diff --git a/tools/decode-config.py b/tools/decode-config.py index 299f152c4..dc51e0f42 100644 --- a/tools/decode-config.py +++ b/tools/decode-config.py @@ -21,7 +21,7 @@ Requirements: - Python - - pip json pycurl urllib2 configargparse + - pip install json pycurl urllib2 configargparse Instructions: Execute command with option -d to retrieve config data from device or @@ -31,10 +31,11 @@ Instructions: Usage: - decode-config.py [-h] [-f ] [-d ] - [-u ] [-p ] [--format ] - [--sort ] [--raw] [--unhide-pw] [-o ] - [-c ] [-V] + decode-config.py [-h] [-f ] [-d ] [-u ] + [-p ] [--format ] + [--json-indent ] [--json-compact] + [--sort ] [--raw] [--unhide-pw] [-o ] + [-c ] [-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 @@ -46,21 +47,27 @@ Usage: -h, --help show this help message and exit -c , --config Config file, can be used instead of command parameter - (defaults to None) + (default: None) source: -f , --file file to retrieve Tasmota configuration from (default: None) - -d , --device - device to retrieve configuration from (default: None) + -d , --device + hostname or IP address to retrieve Tasmota + configuration from (default: None) -u , --username - for -d usage: http access username (default: admin) + host http access username (default: admin) -p , --password - for -d usage: 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") + --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) @@ -72,7 +79,7 @@ Usage: info: -V, --version show program's version number and exit - Note: Either argument -d or -f must be given. + Either argument -d or -f must be given. Examples: @@ -113,7 +120,7 @@ except ImportError: sys.exit(9) -VER = '1.5.0008' +VER = '1.5.0009' PROG='{} v{} by Norbert Richter'.format(os.path.basename(sys.argv[0]),VER) CONFIG_FILE_XOR = 0x5A @@ -135,6 +142,8 @@ DEFAULTS = { 'output': { 'format': 'json', + 'jsonindent': None, + 'jsoncompact': False, 'sort': 'name', 'raw': False, 'unhide-pw': False, @@ -940,7 +949,7 @@ Setting_5_14_0 = { 'knx_CB_addr': ('3: + 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 @@ -1685,7 +1696,7 @@ def ConvertFieldValue(value, fielddef): return value -def GetField(dobj, fieldname, fielddef): +def GetField(dobj, fieldname, fielddef, raw=False): """ Get field value from definition @@ -1695,6 +1706,8 @@ def GetField(dobj, fieldname, fielddef): name of the field @param fielddef: see Settings desc above + @param raw + return raw values (True) or converted values (False) @return: read field value """ @@ -1715,13 +1728,13 @@ def GetField(dobj, fieldname, fielddef): subfielddef = (fielddef[0], addr, None, None if len(fielddef)<4 else fielddef[3]) length = GetFieldLength(subfielddef) if length != 0: - result.append(GetField(dobj, fieldname, subfielddef)) + 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); + d['base'] = ConvertFieldValue(value, fielddef, raw); union = fielddef[2] i = 0 for l in union: @@ -1738,8 +1751,8 @@ def GetField(dobj, fieldname, fielddef): if ord(result[:1])==0x00 or ord(result[:1])==0xff: result = '' s = str(result).split('\0')[0] - result = s #unicode(s, errors='replace') - result = ConvertFieldValue(result, fielddef) + result = unicode(s, errors='replace') + result = ConvertFieldValue(result, fielddef, raw) return result @@ -1762,40 +1775,52 @@ def DeEncrypt(obj): def Decode(obj): """ - Decodes (already decrypted) binary data stream + Decodes binary data stream @param obj: - binary config data + binary config data (decrypted) """ # get header data - cfg_size = GetField(obj, 'cfg_size', Setting_6_2_1['cfg_size']) - version = GetField(obj, 'version', Setting_6_2_1['version']) + version = GetField(obj, 'version', Setting_6_2_1['version'], raw=True) # search setting definition - setting = None + template = None for cfg in Settings: - if version >= cfg[0] and cfg_size == cfg[1]: + if version >= cfg[0]: template = cfg break - setting = template[2] # if we did not found a mathching setting - if setting is None: - exit(2, "Can't handle Tasmota configuration data for version 0x{:x} with {} bytes".format(version, cfg_size) ) + if template is None: + exit(2, "Can't handle Tasmota configuration data for version 0x{:x}".format(version) ) - if GetField(obj, 'cfg_crc', setting['cfg_crc']) != GetSettingsCrc(obj): + 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) ) + + # check crc if exists + if 'cfg_crc' in setting: + cfg_crc = GetField(obj, 'cfg_crc', setting['cfg_crc'], raw=True) + else: + cfg_crc = GetSettingsCrc(obj) + if cfg_crc != GetSettingsCrc(obj): exit(3, 'Data crc error' ) config = {} config['version_template'] = '0x{:x}'.format(template[0]) for name in setting: - config[name] = GetField(obj, name, setting[name]) + config[name] = GetField(obj, name, setting[name], 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') + 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)) @@ -1804,7 +1829,7 @@ def Decode(obj): if __name__ == "__main__": parser = configargparse.ArgumentParser(description='Decode configuration of Sonoff-Tasmota device.', - epilog='Note: Either argument -d or -f must be given.') + epilog='Either argument -d or -f must be given.') source = parser.add_argument_group('source') source.add_argument('-f', '--file', @@ -1813,20 +1838,20 @@ if __name__ == "__main__": default=DEFAULTS['source']['tasmotafile'], help='file to retrieve Tasmota configuration from (default: {})'.format(DEFAULTS['source']['tasmotafile'])) source.add_argument('-d', '--device', - metavar='', + metavar='', dest='device', default=DEFAULTS['source']['device'], - help='device to retrieve 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='for -d usage: 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='for -d usage: 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', @@ -1835,6 +1860,17 @@ if __name__ == "__main__": 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']) ) + 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', @@ -1862,7 +1898,7 @@ if __name__ == "__main__": dest='configfile', default=DEFAULTS['DEFAULT']['configfile'], is_config_file=True, - help='Config file, can be used instead of command parameter (defaults to {})'.format(DEFAULTS['DEFAULT']['configfile']) ) + help='Config file, can be used instead of command parameter (default: {})'.format(DEFAULTS['DEFAULT']['configfile']) ) info = parser.add_argument_group('info') info.add_argument('-V', '--version', action='version', version=PROG) @@ -1921,4 +1957,7 @@ if __name__ == "__main__": Decode(cfg) else: - exit(4, "Could not read configuration data from {} '{}'".format('device' if args.device is not None else 'file', args.device if args.device is not None else args.tasmotafile) ) \ No newline at end of file + exit(4, "Could not read configuration data from {} '{}'".format('device' if args.device is not None else 'file', \ + args.device if args.device is not None else args.tasmotafile) ) + + sys.exit(0) From 8022bca19cd49f63f8bfc7bf7fcb5b3d4b940090 Mon Sep 17 00:00:00 2001 From: znanev <20048364+znanev@users.noreply.github.com> Date: Wed, 26 Sep 2018 18:27:23 +0100 Subject: [PATCH 81/93] Update Bulgarian language file --- sonoff/language/bg-BG.h | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index ff7801984..d79eb5210 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.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.8 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -82,7 +82,7 @@ #define D_DNS_SERVER "DNS Сървър" #define D_DONE "Изпълнено" #define D_DST_TIME "DST" -#define D_ECO2 "eCO2" +#define D_ECO2 "eCO₂" #define D_EMULATION "Емулация" #define D_ENABLED "Активиран" #define D_ERASE "Изтриване" @@ -163,15 +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" -#define D_UV_LEVEL "Ниво на ултравиолетово излъчване" -#define D_UV_POWER "UV Power" +#define D_UV_INDEX_1 "Нисък" +#define D_UV_INDEX_2 "Среден" +#define D_UV_INDEX_3 "Висок" +#define D_UV_INDEX_4 "Много висок" +#define D_UV_INDEX_5 "Изгаряне 1/2 степен" +#define D_UV_INDEX_6 "Изгаряне 3-та степен" +#define D_UV_INDEX_7 "Извън обхват" +#define D_UV_LEVEL "UV ниво" +#define D_UV_POWER "UV мощност" #define D_VERSION "Версия" #define D_VOLTAGE "Напрежение" #define D_WARMLIGHT "Топла" @@ -181,8 +181,8 @@ #define D_WARNING_MINIMAL_VERSION "ПРЕДУПРЕЖДЕНИЕ Тази версия не поддържа постоянни настройки" #define D_LEVEL_10 "ниво 1-0" #define D_LEVEL_01 "ниво 0-1" -#define D_SERIAL_LOGGING_DISABLED "Серийния логинг изключен" -#define D_SYSLOG_LOGGING_REENABLED "Системния логинг активиран" +#define D_SERIAL_LOGGING_DISABLED "Серийният лог изключен" +#define D_SYSLOG_LOGGING_REENABLED "Системният лог активиран" #define D_SET_BAUDRATE_TO "Задаване скорост на предаване (Baudrate)" #define D_RECEIVED_TOPIC "Получен топик" @@ -194,7 +194,7 @@ #define D_BLOCKED_LOOP "Блокиран цикъл" #define D_WPS_FAILED_WITH_STATUS "WPS конфигурацията е НЕУСПЕШНА със статус" #define D_ACTIVE_FOR_3_MINUTES "активно в течение на 3 минути" -#define D_FAILED_TO_START "неуспешно стартиране" +#define D_FAILED_TO_START "Неуспешно стартиране" #define D_PATCH_ISSUE_2186 "Проблем с патч 2186" #define D_CONNECTING_TO_AP "Свързване към точка за достъп" #define D_IN_MODE "в режим" @@ -241,7 +241,7 @@ #define D_CONFIGURE_WIFI "Конфигурация на WiFi" #define D_CONFIGURE_MQTT "Конфигурация на MQTT" #define D_CONFIGURE_DOMOTICZ "Конфигурация на Domoticz" -#define D_CONFIGURE_LOGGING "Конфигурация на логинга" +#define D_CONFIGURE_LOGGING "Конфигурация на лога" #define D_CONFIGURE_OTHER "Драги конфигурации" #define D_CONFIRM_RESET_CONFIGURATION "Потвърдете изчистването" #define D_RESET_CONFIGURATION "Изчистване на конфигурацията" @@ -275,7 +275,7 @@ #define D_CLIENT "Клиент" #define D_FULL_TOPIC "Пълен топик" -#define D_LOGGING_PARAMETERS "Параметри на логинга" +#define D_LOGGING_PARAMETERS "Параметри на лога" #define D_SERIAL_LOG_LEVEL "Степен на серийния лог" #define D_WEB_LOG_LEVEL "Степен на Уеб лога" #define D_SYS_LOG_LEVEL "Степен на системния лог" @@ -379,13 +379,13 @@ #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" + #define D_DOMOTICZ_POWER_ENERGY "Мощност,Енергия" + #define D_DOMOTICZ_ILLUMINANCE "Осветеност" + #define D_DOMOTICZ_COUNT "Брояч/PM1" + #define D_DOMOTICZ_VOLTAGE "Напрежение/PM2,5" + #define D_DOMOTICZ_CURRENT "Ток/PM10" + #define D_DOMOTICZ_AIRQUALITY "Качество на въздуха" +#define D_DOMOTICZ_UPDATE_TIMER "Период на опресняване" // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Конфигуриране на таймер" @@ -464,7 +464,7 @@ #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_DFR562 "MP3 плейър" #define D_SENSOR_IRSEND "IRsend" #define D_SENSOR_SWITCH "Ключ" // Suffix "1" #define D_SENSOR_BUTTON "Бутон" // Suffix "1" @@ -506,7 +506,7 @@ #define D_UNIT_KILOOHM "kΩ" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LUX "lx" -#define D_UNIT_MICROGRAM_PER_CUBIC_METER "µg/m3" +#define D_UNIT_MICROGRAM_PER_CUBIC_METER "µg/m³" #define D_UNIT_MICROMETER "µm" #define D_UNIT_MICROSECOND "µs" #define D_UNIT_MILLIAMPERE "mA" From 9acbcc805f206dbbab0dde03d7666f6505e79e7b Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 26 Sep 2018 20:35:39 +0200 Subject: [PATCH 82/93] Fix logic for forced light discovery --- 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..c4e5d833b 100644 --- a/sonoff/xdrv_12_home_assistant.ino +++ b/sonoff/xdrv_12_home_assistant.ino @@ -76,7 +76,7 @@ void HAssDiscoverRelay() for (int i = 1; i <= MAX_RELAYS; i++) { is_light = ((i == devices_present) && (light_type)); - is_topic_light = Settings.flag.hass_light; + is_topic_light = Settings.flag.hass_light || is_light; mqtt_data[0] = '\0'; // Clear retained message From 3bb8b2fe261d5c22dcce4f75dc017302bc2e0d92 Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Wed, 26 Sep 2018 22:10:32 +0200 Subject: [PATCH 83/93] Update de-DE.h --- sonoff/language/de-DE.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 6e90ae409..07dcc9bfd 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -163,15 +163,15 @@ #define D_USER "Benutzer" #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_LEVEL "UV-Level" -#define D_UV_POWER "UV Power" +#define D_UV_INDEX_1 "Niedrig" +#define D_UV_INDEX_2 "Mittel" +#define D_UV_INDEX_3 "Hoch" +#define D_UV_INDEX_4 "Intensiv" +#define D_UV_INDEX_5 "Gefährlich" +#define D_UV_INDEX_6 "Schädlich" +#define D_UV_INDEX_7 "Messwert!" +#define D_UV_LEVEL "UV-Index" +#define D_UV_POWER "UV Intensität" #define D_VERSION "Version" #define D_VOLTAGE "Spannung" #define D_WARMLIGHT "warm" From 86b3ccf6099b85a7bd71961d737e2fd9b82a2210 Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Wed, 26 Sep 2018 22:20:19 +0200 Subject: [PATCH 84/93] Update de-DE.h --- sonoff/language/de-DE.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 07dcc9bfd..72f63f9c4 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -170,7 +170,7 @@ #define D_UV_INDEX_5 "Gefährlich" #define D_UV_INDEX_6 "Schädlich" #define D_UV_INDEX_7 "Messwert!" -#define D_UV_LEVEL "UV-Index" +#define D_UV_LEVEL "UV-Level" #define D_UV_POWER "UV Intensität" #define D_VERSION "Version" #define D_VOLTAGE "Spannung" From a67efa0ab2c36e4c94de31c13e93d6ccbfc382aa Mon Sep 17 00:00:00 2001 From: Adrian Scillato <35405447+ascillato@users.noreply.github.com> Date: Wed, 26 Sep 2018 23:02:55 -0300 Subject: [PATCH 85/93] Added new triggers for rules on boot time To make it possible to trigger a rule at boot time with the state of the switches or relays (in order to take decisions), 2 new trigger types has been added: * SWITCH1#BOOT to be used like: ON SWITCH1#BOOT DO ... %value% ENDON ON SWITCH1#BOOT=0 DO .... ENDON ON SWITCH1#BOOT=1 DO .... ENDON and * POWER1#BOOT to be used like: ON POWER1#BOOT DO ... %value% ENDON ON POWER1#BOOT=0 DO .... ENDON ON POWER1#BOOT=1 DO .... ENDON --- sonoff/xdrv_10_rules.ino | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 060bf085f..b13dfc771 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -376,6 +376,25 @@ void RulesEvery50ms() RulesProcessEvent(json_event); } } + } else { + // Boot time POWER OUTPUTS (Relays) Status + for (byte i = 0; i < devices_present; i++) { + uint8_t new_state = (rules_new_power >> i) &1; + snprintf_P(json_event, sizeof(json_event), PSTR("{\"Power%d\":{\"Boot\":%d}}"), i +1, new_state); + RulesProcessEvent(json_event); + } + // Boot time SWITCHES Status + for (byte i = 0; i < MAX_SWITCHES; i++) { +#ifdef USE_TM1638 + if ((pin[GPIO_SWT1 +i] < 99) || ((pin[GPIO_TM16CLK] < 99) && (pin[GPIO_TM16DIO] < 99) && (pin[GPIO_TM16STB] < 99))) { +#else + if (pin[GPIO_SWT1 +i] < 99) { +#endif // USE_TM1638 + boolean swm = ((FOLLOW_INV == Settings.switchmode[i]) || (PUSHBUTTON_INV == Settings.switchmode[i]) || (PUSHBUTTONHOLD_INV == Settings.switchmode[i])); + snprintf_P(json_event, sizeof(json_event), PSTR("{\"" D_JSON_SWITCH "%d\":{\"Boot\":%d}}"), i +1, (swm ^ lastwallswitch[i])); + RulesProcessEvent(json_event); + } + } } rules_old_power = rules_new_power; } From 1a4458528e1f1269062d03ad45055779e8895959 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 27 Sep 2018 18:36:42 +0200 Subject: [PATCH 86/93] Add Neo Coolcam support Add support for Neo Coolcam Wifi Smart Power Plug --- sonoff/_changelog.ino | 3 +++ sonoff/sonoff_template.h | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 06ebd36c1..ebf1b83cb 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -2,6 +2,9 @@ * Change status JSON message providing more switch and retain information * Change pinmode for no-pullup defined switches to pullup when configured as switchmode PUSHBUTTON (=3 and up) (#3896) * Add delay after restart before processing rule sensor data (#3811) + * Fix Home Assistant forced light discovery (#3908) + * Add rule triggers SWITCH1#BOOT and POWER1#BOOT (#3904, #3910) + * Add support for Neo Coolcam Wifi Smart Power Plug * * 6.2.1.7 20180925 * Remove restart after ntpserver change and force NTP re-sync (#3890) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index f5e332531..8374fa09d 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -231,6 +231,7 @@ enum SupportedModules { SHELLY1, SHELLY2, PHILIPS, + NEO_COOLCAM, MAXMODULE }; /********************************************************************************************/ @@ -390,6 +391,7 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { SHELLY1, SHELLY2, BLITZWOLF_BWSHP2, + NEO_COOLCAM, H801, MAGICHOME, ARILUX_LC01, @@ -1054,6 +1056,16 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0, GPIO_PWM1, // GPIO15 light intensity 0, 0 + }, + { "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) + 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 } }; From 1a0d630da214a180b77096f7f4129dc701562a4d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 28 Sep 2018 11:48:55 +0200 Subject: [PATCH 87/93] Removed debug code Removed unavailable debug code (#3917) --- sonoff/settings.ino | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 0d8fa451a..95e6ce367 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -86,20 +86,12 @@ void RtcSettingsSave() RtcSettings.valid = RTC_MEM_VALID; ESP.rtcUserMemoryWrite(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM)); rtc_settings_crc = GetRtcSettingsCrc(); -#ifdef DEBUG_THEO - AddLog_P(LOG_LEVEL_DEBUG, PSTR("Dump: Save")); - RtcSettingsDump(); -#endif // DEBUG_THEO } } void RtcSettingsLoad() { ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM)); // 0x290 -#ifdef DEBUG_THEO - AddLog_P(LOG_LEVEL_DEBUG, PSTR("Dump: Load")); - RtcSettingsDump(); -#endif // DEBUG_THEO if (RtcSettings.valid != RTC_MEM_VALID) { memset(&RtcSettings, 0, sizeof(RTCMEM)); RtcSettings.valid = RTC_MEM_VALID; From 4b7c797fb76cf8e6ee1a5680b5af430705fbbf65 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 28 Sep 2018 15:48:42 +0200 Subject: [PATCH 88/93] 6.2.1.9 Apparent/Reactive Power 6.2.1.9 20180928 * Add Apparent Power and Reactive Power to Energy Monitoring devices (#251) --- sonoff/_changelog.ino | 5 +- sonoff/sonoff_version.h | 2 +- sonoff/support.ino | 26 +++++++ sonoff/xdrv_03_energy.ino | 146 +++++++++++++++++++++-------------- sonoff/xnrg_01_hlw8012.ino | 7 +- sonoff/xnrg_02_cse7766.ino | 15 ++-- sonoff/xnrg_03_pzem004t.ino | 3 +- sonoff/xnrg_04_mcp39f501.ino | 7 +- sonoff/xnrg_05_pzem2.ino | 6 +- 9 files changed, 137 insertions(+), 80 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index ebf1b83cb..abf4572f6 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,7 @@ -/* 6.2.1.8 20180926 +/* 6.2.1.9 20180928 + * Add Apparent Power and Reactive Power to Energy Monitoring devices (#251) + * + * 6.2.1.8 20180926 * Change status JSON message providing more switch and retain information * Change pinmode for no-pullup defined switches to pullup when configured as switchmode PUSHBUTTON (=3 and up) (#3896) * Add delay after restart before processing rule sensor data (#3811) diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 915ce52d2..4f2b5c0ec 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 0x06020108 +#define VERSION 0x06020109 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/support.ino b/sonoff/support.ino index fb2b5eae3..fc73e726e 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -494,6 +494,32 @@ double FastPrecisePow(double a, double b) return r * u.d; } +uint32_t SqrtInt(uint32_t num) +{ + if (num <= 1) { + return num; + } + + uint32_t x = num / 2; + uint32_t y; + do { + y = (x + num / x) / 2; + if (y >= x) { + return x; + } + x = y; + } while (true); +} + +uint32_t RoundSqrtInt(uint32_t num) +{ + uint32_t s = SqrtInt(4 * num); + if (s & 1) { + s++; + } + return s / 2; +} + char* GetTextIndexed(char* destination, size_t destination_size, uint16_t index, const char* haystack) { // Returns empty string if not found diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index 3ccad7df4..13ab1cb62 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -41,23 +41,25 @@ const char kEnergyCommands[] PROGMEM = D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|" D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW ; -float energy_voltage = 0; // 123.1 V -float energy_current = 0; // 123.123 A -float energy_power = 0; // 123.1 W -float energy_power_factor = NAN; // 0.12 -int energy_calc_power_factor = 0; // Do not calculate power factor from data -float energy_frequency = NAN; // 123.1 Hz -float energy_start = 0; // 12345.12345 kWh total previous +float energy_voltage = 0; // 123.1 V +float energy_current = 0; // 123.123 A +float energy_active_power = 0; // 123.1 W +float energy_apparent_power = NAN; // 123.1 VA +float energy_reactive_power = NAN; // 123.1 VAr +float energy_power_factor = NAN; // 0.12 +float energy_frequency = NAN; // 123.1 Hz +float energy_start = 0; // 12345.12345 kWh total previous -float energy_daily = 0; // 123.123 kWh -float energy_total = 0; // 12345.12345 kWh +float energy_daily = 0; // 123.123 kWh +float energy_total = 0; // 12345.12345 kWh unsigned long energy_kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to energy_kWhtoday (HLW and CSE only) -unsigned long energy_kWhtoday; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily -unsigned long energy_period = 0; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily +unsigned long energy_kWhtoday; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily +unsigned long energy_period = 0; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily float energy_power_last[3] = { 0 }; uint8_t energy_power_delta = 0; +bool energy_type_dc = false; bool energy_power_on = true; byte energy_min_power_flag = 0; @@ -124,15 +126,6 @@ void Energy200ms() } XnrgCall(FUNC_EVERY_200_MSECOND); - - if (energy_calc_power_factor) { - float power_factor = 0; - if (energy_voltage && energy_current && energy_power) { - power_factor = energy_power / (energy_voltage * energy_current); - if (power_factor > 1) power_factor = 1; - } - energy_power_factor = power_factor; - } } void EnergySaveState() @@ -178,21 +171,21 @@ void EnergyMarginCheck() } if (Settings.energy_power_delta) { - float delta = abs(energy_power_last[0] - energy_power); + float delta = abs(energy_power_last[0] - energy_active_power); // Any delta compared to minimal delta - float min_power = (energy_power_last[0] > energy_power) ? energy_power : energy_power_last[0]; + float min_power = (energy_power_last[0] > energy_active_power) ? energy_active_power : energy_power_last[0]; if (((delta / min_power) * 100) > Settings.energy_power_delta) { energy_power_delta = 1; - energy_power_last[1] = energy_power; // We only want one report so reset history - energy_power_last[2] = energy_power; + energy_power_last[1] = energy_active_power; // We only want one report so reset history + energy_power_last[2] = energy_active_power; } } energy_power_last[0] = energy_power_last[1]; // Shift in history every second allowing power changes to settle for up to three seconds energy_power_last[1] = energy_power_last[2]; - energy_power_last[2] = energy_power; + energy_power_last[2] = energy_active_power; if (energy_power_on && (Settings.energy_min_power || Settings.energy_max_power || Settings.energy_min_voltage || Settings.energy_max_voltage || Settings.energy_min_current || Settings.energy_max_current)) { - energy_power_u = (uint16_t)(energy_power); + energy_power_u = (uint16_t)(energy_active_power); energy_voltage_u = (uint16_t)(energy_voltage); energy_current_u = (uint16_t)(energy_current * 1000); @@ -235,7 +228,7 @@ void EnergyMarginCheck() #if FEATURE_POWER_LIMIT // Max Power if (Settings.energy_max_power_limit) { - if (energy_power > Settings.energy_max_power_limit) { + if (energy_active_power > Settings.energy_max_power_limit) { if (!energy_mplh_counter) { energy_mplh_counter = Settings.energy_max_power_limit_hold; } else { @@ -535,6 +528,8 @@ const char HTTP_ENERGY_SNS1[] PROGMEM = "%s" "{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"; const char HTTP_ENERGY_SNS2[] PROGMEM = "%s" + "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}" + "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}" "{s}" D_POWER_FACTOR "{m}%s{e}"; const char HTTP_ENERGY_SNS3[] PROGMEM = "%s" @@ -548,27 +543,64 @@ const char HTTP_ENERGY_SNS4[] PROGMEM = "%s" void EnergyShow(boolean json) { - char energy_total_chr[10]; + char voltage_chr[10]; + char current_chr[10]; + char active_power_chr[10]; + char apparent_power_chr[10]; + char reactive_power_chr[10]; + char power_factor_chr[10]; + char frequency_chr[10]; char energy_daily_chr[10]; char energy_period_chr[10]; - char energy_power_chr[10]; - char energy_voltage_chr[10]; - char energy_current_chr[10]; - char energy_frequency_chr[10]; - char energy_power_factor_chr[10]; char energy_yesterday_chr[10]; + char energy_total_chr[10]; + char speriod[20]; - char spfactor[20]; char sfrequency[20]; bool show_energy_period = (0 == tele_period); - dtostrfd(energy_power, Settings.flag2.wattage_resolution, energy_power_chr); - dtostrfd(energy_voltage, Settings.flag2.voltage_resolution, energy_voltage_chr); - dtostrfd(energy_current, Settings.flag2.current_resolution, energy_current_chr); - dtostrfd(energy_total, Settings.flag2.energy_resolution, energy_total_chr); + if (!energy_type_dc) { + float apparent_power = energy_apparent_power; + if (isnan(apparent_power)) { + apparent_power = energy_voltage * energy_current; + } + if (apparent_power < energy_active_power) { // Should be impossible + energy_active_power = apparent_power; + } + + float power_factor = energy_power_factor; + if (isnan(power_factor)) { + power_factor = (energy_active_power && apparent_power) ? energy_active_power / apparent_power : 0; + if (power_factor > 1) power_factor = 1; + } + + float reactive_power = energy_reactive_power; + if (isnan(reactive_power)) { + reactive_power = 0; + uint32_t difference = ((uint32_t)(apparent_power * 100) - (uint32_t)(energy_active_power * 100)) / 10; + if ((energy_current > 0.005) && ((difference > 15) || (difference > (uint32_t)(apparent_power * 100 / 1000)))) { + // calculating reactive power only if current is greater than 0.005A and + // difference between active and apparent power is greater than 1.5W or 1% + reactive_power = (float)(RoundSqrtInt((uint32_t)(apparent_power * apparent_power * 100) - (uint32_t)(energy_active_power * energy_active_power * 100))) / 10; + } + } + + dtostrfd(apparent_power, Settings.flag2.wattage_resolution, apparent_power_chr); + dtostrfd(reactive_power, Settings.flag2.wattage_resolution, reactive_power_chr); + dtostrfd(power_factor, 2, power_factor_chr); + if (!isnan(energy_frequency)) { + dtostrfd(energy_frequency, Settings.flag2.frequency_resolution, frequency_chr); + snprintf_P(sfrequency, sizeof(sfrequency), PSTR(",\"" D_JSON_FREQUENCY "\":%s"), frequency_chr); + } + } + + dtostrfd(energy_voltage, Settings.flag2.voltage_resolution, voltage_chr); + dtostrfd(energy_current, Settings.flag2.current_resolution, current_chr); + dtostrfd(energy_active_power, Settings.flag2.wattage_resolution, active_power_chr); dtostrfd(energy_daily, Settings.flag2.energy_resolution, energy_daily_chr); dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr); + dtostrfd(energy_total, Settings.flag2.energy_resolution, energy_total_chr); float energy = 0; if (show_energy_period) { @@ -577,34 +609,30 @@ void EnergyShow(boolean json) dtostrfd(energy, Settings.flag2.wattage_resolution, energy_period_chr); snprintf_P(speriod, sizeof(speriod), PSTR(",\"" D_JSON_PERIOD "\":%s"), energy_period_chr); } - if (!isnan(energy_frequency)) { - dtostrfd(energy_frequency, Settings.flag2.frequency_resolution, energy_frequency_chr); - snprintf_P(sfrequency, sizeof(sfrequency), PSTR(",\"" D_JSON_FREQUENCY "\":%s"), energy_frequency_chr); - } - if (!isnan(energy_power_factor)) { - dtostrfd(energy_power_factor, 2, energy_power_factor_chr); - snprintf_P(spfactor, sizeof(spfactor), PSTR(",\"" D_JSON_POWERFACTOR "\":%s"), energy_power_factor_chr); - } if (json) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s%s,\"" - D_JSON_POWERUSAGE "\":%s%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s%s}"), - mqtt_data, energy_total_chr, energy_yesterday_chr, energy_daily_chr, (show_energy_period) ? speriod : "", - energy_power_chr, (!isnan(energy_power_factor)) ? spfactor : "", energy_voltage_chr, energy_current_chr, (!isnan(energy_frequency)) ? sfrequency : ""); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s%s,\"" D_JSON_POWERUSAGE "\":%s"), + mqtt_data, energy_total_chr, energy_yesterday_chr, energy_daily_chr, (show_energy_period) ? speriod : "", active_power_chr); + if (!energy_type_dc) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s%s"), + mqtt_data, apparent_power_chr, reactive_power_chr, power_factor_chr, (!isnan(energy_frequency)) ? sfrequency : ""); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"), mqtt_data, voltage_chr, current_chr); + #ifdef USE_DOMOTICZ if (show_energy_period) { // Only send if telemetry dtostrfd(energy_total * 1000, 1, energy_total_chr); - DomoticzSensorPowerEnergy((int)energy_power, energy_total_chr); // PowerUsage, EnergyToday - DomoticzSensor(DZ_VOLTAGE, energy_voltage_chr); // Voltage - DomoticzSensor(DZ_CURRENT, energy_current_chr); // Current + DomoticzSensorPowerEnergy((int)energy_active_power, energy_total_chr); // PowerUsage, EnergyToday + DomoticzSensor(DZ_VOLTAGE, voltage_chr); // Voltage + DomoticzSensor(DZ_CURRENT, current_chr); // Current } #endif // USE_DOMOTICZ #ifdef USE_KNX if (show_energy_period) { KnxSensor(KNX_ENERGY_VOLTAGE, energy_voltage); KnxSensor(KNX_ENERGY_CURRENT, energy_current); - KnxSensor(KNX_ENERGY_POWER, energy_power); - if (!isnan(energy_power_factor)) { KnxSensor(KNX_ENERGY_POWERFACTOR, energy_power_factor); } + KnxSensor(KNX_ENERGY_POWER, energy_active_power); + if (!energy_type_dc) { KnxSensor(KNX_ENERGY_POWERFACTOR, power_factor); } KnxSensor(KNX_ENERGY_DAILY, energy_daily); KnxSensor(KNX_ENERGY_TOTAL, energy_total); KnxSensor(KNX_ENERGY_START, energy_start); @@ -612,9 +640,11 @@ void EnergyShow(boolean json) #endif // USE_KNX #ifdef USE_WEBSERVER } else { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS1, mqtt_data, energy_voltage_chr, energy_current_chr, energy_power_chr); - if (!isnan(energy_power_factor)) { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS2, mqtt_data, energy_power_factor_chr); } - if (!isnan(energy_frequency)) { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS3, mqtt_data, energy_frequency_chr); } + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS1, mqtt_data, voltage_chr, current_chr, active_power_chr); + if (!energy_type_dc) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS2, mqtt_data, apparent_power_chr, reactive_power_chr, power_factor_chr); + if (!isnan(energy_frequency)) { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS3, mqtt_data, frequency_chr); } + } snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS4, mqtt_data, energy_daily_chr, energy_yesterday_chr, energy_total_chr); #endif // USE_WEBSERVER } diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino index 5140d6596..025ccff44 100644 --- a/sonoff/xnrg_01_hlw8012.ino +++ b/sonoff/xnrg_01_hlw8012.ino @@ -111,9 +111,9 @@ void HlwEvery200ms() if (hlw_cf_pulse_length && energy_power_on && !hlw_load_off) { hlw_w = (hlw_power_ratio * Settings.energy_power_calibration) / hlw_cf_pulse_length; - energy_power = (float)hlw_w / 10; + energy_active_power = (float)hlw_w / 10; } else { - energy_power = 0; + energy_active_power = 0; } hlw_cf1_timer++; @@ -142,7 +142,7 @@ void HlwEvery200ms() hlw_cf1_current_pulse_length = hlw_cf1_pulse_length; hlw_cf1_current_max_pulse_counter = hlw_cf1_pulse_counter; - if (hlw_cf1_current_pulse_length && energy_power) { // No current if no power being consumed + if (hlw_cf1_current_pulse_length && energy_active_power) { // No current if no power being consumed hlw_i = (hlw_current_ratio * Settings.energy_current_calibration) / hlw_cf1_current_pulse_length; energy_current = (float)hlw_i / 1000; } else { @@ -217,7 +217,6 @@ 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 - energy_calc_power_factor = 1; // Calculate power factor from data energy_flg = XNRG_01; } } diff --git a/sonoff/xnrg_02_cse7766.ino b/sonoff/xnrg_02_cse7766.ino index 8ba1b146e..1be231192 100644 --- a/sonoff/xnrg_02_cse7766.ino +++ b/sonoff/xnrg_02_cse7766.ino @@ -95,14 +95,14 @@ void CseReceived() if (adjustement & 0x10) { // Power valid cse_power_invalid = 0; if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range - energy_power = 0; + energy_active_power = 0; } else { if (0 == power_cycle_first) { power_cycle_first = power_cycle; } // Skip first incomplete power_cycle if (power_cycle_first != power_cycle) { power_cycle_first = -1; - energy_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)power_cycle; + energy_active_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)power_cycle; } else { - energy_power = 0; + energy_active_power = 0; } } } else { @@ -110,11 +110,11 @@ void CseReceived() cse_power_invalid++; } else { power_cycle_first = 0; - energy_power = 0; // Powered on but no load + energy_active_power = 0; // Powered on but no load } } if (adjustement & 0x20) { // Current valid - if (0 == energy_power) { + if (0 == energy_active_power) { energy_current = 0; } else { energy_current = (float)Settings.energy_current_calibration / (float)current_cycle; @@ -123,7 +123,7 @@ void CseReceived() } else { // Powered off power_cycle_first = 0; energy_voltage = 0; - energy_power = 0; + energy_active_power = 0; energy_current = 0; } } @@ -180,7 +180,7 @@ void CseEverySecond() } else { cf_frequency = cf_pulses - cf_pulses_last_time; } - if (cf_frequency && energy_power) { + if (cf_frequency && energy_active_power) { cf_pulses_last_time = cf_pulses; energy_kWhtoday_delta += (cf_frequency * Settings.energy_power_calibration) / 36; EnergyUpdateToday(); @@ -194,7 +194,6 @@ void CseDrvInit() if ((SONOFF_S31 == Settings.module) || (SONOFF_POW_R2 == Settings.module)) { // Sonoff S31 or Sonoff Pow R2 baudrate = 4800; serial_config = SERIAL_8E1; - energy_calc_power_factor = 1; // Calculate power factor from data energy_flg = XNRG_02; } } diff --git a/sonoff/xnrg_03_pzem004t.ino b/sonoff/xnrg_03_pzem004t.ino index 03581862c..3dfbc3879 100644 --- a/sonoff/xnrg_03_pzem004t.ino +++ b/sonoff/xnrg_03_pzem004t.ino @@ -177,7 +177,7 @@ void PzemEvery200ms() energy_current = value; break; case 3: // Power as 20W - energy_power = value; + energy_active_power = value; break; case 4: // Total energy as 99999Wh if (!energy_start || (value < energy_start)) energy_start = value; // Init after restart and hanlde roll-over if any @@ -215,7 +215,6 @@ void PzemDrvInit() { if (!energy_flg) { if ((pin[GPIO_PZEM_RX] < 99) && (pin[GPIO_PZEM_TX] < 99)) { // Any device with a Pzem004T - energy_calc_power_factor = 1; // Calculate power factor from data energy_flg = XNRG_03; } } diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino index f2ce321bc..d962ef204 100644 --- a/sonoff/xnrg_04_mcp39f501.ino +++ b/sonoff/xnrg_04_mcp39f501.ino @@ -448,8 +448,8 @@ void McpParseData(void) if (energy_power_on) { // Powered on energy_frequency = (float)mcp_line_frequency / 1000; energy_voltage = (float)mcp_voltage_rms / 10; - energy_power = (float)mcp_active_power / 100; - if (0 == energy_power) { + energy_active_power = (float)mcp_active_power / 100; + if (0 == energy_active_power) { energy_current = 0; } else { energy_current = (float)mcp_current_rms / 10000; @@ -457,7 +457,7 @@ void McpParseData(void) } else { // Powered off energy_frequency = 0; energy_voltage = 0; - energy_power = 0; + energy_active_power = 0; energy_current = 0; } } @@ -557,7 +557,6 @@ void McpDrvInit(void) mcp_calibrate = 0; mcp_timeout = 2; // Initial wait mcp_init = 2; // Initial setup steps - energy_calc_power_factor = 1; // Calculate power factor from data energy_flg = XNRG_04; } } diff --git a/sonoff/xnrg_05_pzem2.ino b/sonoff/xnrg_05_pzem2.ino index b7e1eab42..bb0f4864d 100644 --- a/sonoff/xnrg_05_pzem2.ino +++ b/sonoff/xnrg_05_pzem2.ino @@ -141,12 +141,13 @@ void Pzem2Every200ms() float energy = 0; if (PZEM2_TYPES_003_017 == pzem2_type) { + energy_type_dc = true; // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // FE 04 10 27 10 00 64 03 E8 00 00 00 00 00 00 00 00 00 00 HH LL = PZEM-017 // Id Cc Sz Volt- Curre Power------ Energy----- HiAlm LoAlm Crc-- energy_voltage = (float)((buffer[3] << 8) + buffer[4]) / 100.0; // 655.00 V energy_current = (float)((buffer[5] << 8) + buffer[6]) / 100.0; // 655.00 A - energy_power = (float)((uint32_t)buffer[9] << 24 + (uint32_t)buffer[10] << 16 + (uint32_t)buffer[7] << 8 + buffer[8]) / 10.0; // 429496729.0 W + energy_active_power = (float)((uint32_t)buffer[9] << 24 + (uint32_t)buffer[10] << 16 + (uint32_t)buffer[7] << 8 + buffer[8]) / 10.0; // 429496729.0 W energy = (float)((uint32_t)buffer[13] << 24 + (uint32_t)buffer[14] << 16 + (uint32_t)buffer[11] << 8 + buffer[12]); // 4294967295 Wh if (!energy_start || (energy < energy_start)) { energy_start = energy; } // Init after restart and hanlde roll-over if any energy_kWhtoday += (energy - energy_start) * 100; @@ -154,12 +155,13 @@ void Pzem2Every200ms() EnergyUpdateToday(); } else if (PZEM2_TYPES_014_016 == pzem2_type) { // PZEM-014,016 + energy_type_dc = false; // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // FE 04 14 08 98 03 E8 00 00 08 98 00 00 00 00 00 00 01 F4 00 64 00 00 HH LL = PZEM-014 // Id Cc Sz Volt- Current---- Power------ Energy----- Frequ PFact Alarm Crc-- energy_voltage = (float)((buffer[3] << 8) + buffer[4]) / 10.0; // 6553.0 V energy_current = (float)((uint32_t)buffer[7] << 24 + (uint32_t)buffer[8] << 16 + (uint32_t)buffer[5] << 8 + buffer[6]) / 1000.0; // 4294967.000 A - energy_power = (float)((uint32_t)buffer[11] << 24 + (uint32_t)buffer[12] << 16 + (uint32_t)buffer[9] << 8 + buffer[10]) / 10.0; // 429496729.0 W + energy_active_power = (float)((uint32_t)buffer[11] << 24 + (uint32_t)buffer[12] << 16 + (uint32_t)buffer[9] << 8 + buffer[10]) / 10.0; // 429496729.0 W energy_frequency = (float)((buffer[17] << 8) + buffer[18]) / 10.0; // 50.0 Hz energy_power_factor = (float)((buffer[19] << 8) + buffer[20]) / 100.0; // 1.00 energy = (float)((uint32_t)buffer[15] << 24 + (uint32_t)buffer[16] << 16 + (uint32_t)buffer[13] << 8 + buffer[14]); // 4294967295 Wh From f05a471e48bb0ae891df61cdde1679abab0f0f4c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 28 Sep 2018 17:02:55 +0200 Subject: [PATCH 89/93] Fix KNX compile error --- sonoff/xdrv_03_energy.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index 13ab1cb62..341fc71b5 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -560,6 +560,8 @@ void EnergyShow(boolean json) bool show_energy_period = (0 == tele_period); + float power_factor = energy_power_factor; + if (!energy_type_dc) { float apparent_power = energy_apparent_power; if (isnan(apparent_power)) { @@ -569,7 +571,6 @@ void EnergyShow(boolean json) energy_active_power = apparent_power; } - float power_factor = energy_power_factor; if (isnan(power_factor)) { power_factor = (energy_active_power && apparent_power) ? energy_active_power / apparent_power : 0; if (power_factor > 1) power_factor = 1; From 8f95f07b518010a6c3bf37a2ac34a02b5309fd5e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 28 Sep 2018 17:26:08 +0200 Subject: [PATCH 90/93] Add RF to MagicHome / LC10 Add RF Receiver control to module MagicHome to be used on Arilux LC10 (#3792) --- sonoff/_changelog.ino | 1 + sonoff/sonoff_template.h | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index abf4572f6..efd0944b7 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,5 +1,6 @@ /* 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) * * 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 8374fa09d..d083675d3 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -855,6 +855,7 @@ 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, @@ -869,6 +870,22 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 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_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 + 0, 0 + }, { "Luani HVIO", // ESP8266_HVIO // https://luani.de/projekte/esp8266-hvio/ 0, // GPIO00 Flash jumper From 36d6ae080368aac0987cc8279a365a29ff7a1cb5 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 28 Sep 2018 17:26:13 +0200 Subject: [PATCH 91/93] Added D_JSON_UV_INDEX_TEXT Added D_JSON_UV_INDEX_TEXT for more info on json output --- sonoff/i18n.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index c8d3e219f..2090f4793 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -131,6 +131,7 @@ #define D_JSON_UPTIME "Uptime" #define D_JSON_UTC_TIME "UTC" #define D_JSON_UV_INDEX "UvIndex" +#define D_JSON_UV_INDEX_TEXT "UvIndexText" #define D_JSON_UV_LEVEL "UvLevel" #define D_JSON_UV_POWER "UvPower" #define D_JSON_VCC "Vcc" From e8a56755d90226bf6e2f1840657dbcfb9d6106ff Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 28 Sep 2018 17:34:25 +0200 Subject: [PATCH 92/93] Updated the driver Updated the driver and changed a lot. - Starting with switch(function) and the end of it. - Changed the json output code a lot to more visibility and a better way of working. - Changed the web sever outout so that we need less code. In #ifdef USE_DOMOTICZ i have changed nothing because i don't have a domotica system. Therefor someone with a stable running system can build it further or we can work together on it. Dirver version changed to v1.0.0.2 Theo, i hope the if (11 == (uptime %100)) { .. part is ok. Please have a look on it. --- sonoff/xsns_11_veml6070.ino | 225 ++++++++++++++++++++---------------- 1 file changed, 123 insertions(+), 102 deletions(-) diff --git a/sonoff/xsns_11_veml6070.ino b/sonoff/xsns_11_veml6070.ino index f60c0f00f..de4d903bd 100644 --- a/sonoff/xsns_11_veml6070.ino +++ b/sonoff/xsns_11_veml6070.ino @@ -31,6 +31,19 @@ Version Date Action Description -------------------------------------------------------------------------------------------- + 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 + - much more compressed and more professional code + added - uv_risk_text to json and web server output + changed - switch (function) to be 100% compatible + - added Veml6070EverySecond in thought of compatibile + added - Veml6070UvTableInit to do this only once to spare time + debugging - @Adrian helped me out in case of a %s%s in mqtt_data. Thank You Adrian + next - possible i will add the calculation for LAT and LONG coordinates for much more precission (TBD) + - show not only the UV Power value in W/m2, possible a @define value to show it as joule value (TBD) + - add a #define to select how many characters are shown benhind the decimal point for the UV Index (TBD) + --- 1.0.0.1 20180925 tests - all tests are done with 1x sonoff sv, 2x Wemos D1 (not the mini) - 3 different VEMl6070 sensors from 3 different online shops - all the last three test where good and all looks working so far @@ -80,7 +93,6 @@ #define VEML6070_ADDR_H 0x39 // on some PCB boards the address can be changed by a solder point, #define VEML6070_ADDR_L 0x38 // to have no address conflicts with other I2C sensors and/or hardware - #define VEML6070_INTEGRATION_TIME 3 // IT_4 = 500msec integration time, because the precission is 4 times higher then IT_0.5 #define VEML6070_ENABLE 1 // #define VEML6070_DISABLE 0 // @@ -94,8 +106,18 @@ /********************************************************************************************/ // globals -uint8_t veml6070_address; -uint8_t veml6070_type = 0; +const char kVemlTypes[] PROGMEM = "VEML6070"; // in preperation of veml6075 +double uv_risk_map[VEML6070_UV_MAX_INDEX] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +double uvrisk = 0; +double uvpower = 0; +uint16_t uvlevel = 0; +uint8_t veml6070_addr_low = VEML6070_ADDR_L; +uint8_t veml6070_addr_high = VEML6070_ADDR_H; +uint8_t itime = VEML6070_INTEGRATION_TIME; +uint8_t veml6070_type = 0; +uint8_t veml6070_valid = 0; +char veml6070_name[9]; +char str_uvrisk_text[10]; /********************************************************************************************/ @@ -104,40 +126,72 @@ void Veml6070Detect(void) if (veml6070_type) { return; } - - uint8_t itime = VEML6070_INTEGRATION_TIME; - veml6070_address = VEML6070_ADDR_L; - Wire.beginTransmission(veml6070_address); + // init the UV sensor + Wire.beginTransmission(VEML6070_ADDR_L); Wire.write((itime << 2) | 0x02); uint8_t status = Wire.endTransmission(); - + // action on status if (!status) { - veml6070_type = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070", veml6070_address); + veml6070_type = 1; + uint8_t veml_model = 0; + GetTextIndexed(veml6070_name, sizeof(veml6070_name), veml_model, kVemlTypes); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070", VEML6070_ADDR_L); AddLog(LOG_LEVEL_DEBUG); } } /********************************************************************************************/ +void Veml6070UvTableInit(void) +{ + // fill the uv-risk compare table once, based on the coefficient calculation + for (uint8_t i = 0; i < VEML6070_UV_MAX_INDEX; i++) { +#ifdef USE_VEML6070_RSET + if ( (USE_VEML6070_RSET >= 220000) && (USE_VEML6070_RSET <= 1000000) ) { + uv_risk_map[i] = ( (USE_VEML6070_RSET / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT ) * (i+1); + } else { + uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT ) * (i+1); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "VEML6070 resistor error %d"), USE_VEML6070_RSET); + AddLog(LOG_LEVEL_DEBUG); + } +#else + uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT ) * (i+1); + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "VEML6070 resistor default used %d"), VEML6070_RSET_DEFAULT); + AddLog(LOG_LEVEL_DEBUG); +#endif + } +} + +/********************************************************************************************/ + +void Veml6070EverySecond(void) +{ + // all = 10..15[ms] + if (11 == (uptime %100)) { + 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 + 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 + Veml6070ModeCmd(0); // off = 5[ms], suspend the UV sensor + } +} + +/********************************************************************************************/ + void Veml6070ModeCmd(boolean mode_cmd) { - uint8_t itime = VEML6070_INTEGRATION_TIME; - uint8_t opmode = 0; - - if (mode_cmd) { - opmode = VEML6070_ENABLE; - } else { - opmode = VEML6070_DISABLE; - } - - veml6070_address = VEML6070_ADDR_L; - Wire.beginTransmission(veml6070_address); - Wire.write((opmode << 0) | 0x02 | (itime << 2)); + // mode_cmd 1 = on = 1[ms] + // mode_cmd 0 = off = 2[ms] + Wire.beginTransmission(VEML6070_ADDR_L); + Wire.write((mode_cmd << 0) | 0x02 | (itime << 2)); uint8_t status = Wire.endTransmission(); - + // action on status if (!status) { - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070 opmode", veml6070_address); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070 mode_cmd", VEML6070_ADDR_L); AddLog(LOG_LEVEL_DEBUG); } } @@ -146,17 +200,20 @@ void Veml6070ModeCmd(boolean mode_cmd) uint16_t Veml6070ReadUv(void) { + uint16_t uv_raw = 0; + // read high byte if (Wire.requestFrom(VEML6070_ADDR_H, 1) != 1) { return -1; } - uint16_t uvi = Wire.read(); - uvi <<= 8; + uv_raw = Wire.read(); + uv_raw <<= 8; + // read low byte if (Wire.requestFrom(VEML6070_ADDR_L, 1) != 1) { return -1; } - uvi |= Wire.read(); - - return uvi; + uv_raw |= Wire.read(); + // high and low done + return uv_raw; } /********************************************************************************************/ @@ -164,28 +221,21 @@ uint16_t Veml6070ReadUv(void) double Veml6070UvRiskLevel(uint16_t uv_level) { double risk = 0; - double uv_risk_map[VEML6070_UV_MAX_INDEX] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - - // fill the uv-risk compare table based on the coefficient calculation - for (uint8_t i = 0; i < VEML6070_UV_MAX_INDEX; i++) { -#ifdef USE_VEML6070_RSET - if ( (USE_VEML6070_RSET >= 220000) && (USE_VEML6070_RSET <= 1000000) ) { - uv_risk_map[i] = ( (USE_VEML6070_RSET / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT) * (i+1); - } else { - uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT) * (i+1); - snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "VEML6070 resistor error %d"), USE_VEML6070_RSET); - AddLog(LOG_LEVEL_DEBUG); - } -#else - uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT) * (i+1); -#endif - } - - // get the uv-risk level if (uv_level < uv_risk_map[VEML6070_UV_MAX_INDEX-1]) { - return ( uv_level / uv_risk_map[0] ); + risk = (double)uv_level / uv_risk_map[0]; + // generate uv-risk string + if ( (risk >= 0) && (risk <= 2.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_1); } + else if ( (risk >= 3.0) && (risk <= 5.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_2); } + else if ( (risk >= 6.0) && (risk <= 7.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_3); } + else if ( (risk >= 8.0) && (risk <= 10.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_4); } + else if ( (risk >= 11.0) && (risk <= 12.9) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_5); } + else if ( (risk >= 13.0) && (risk <= 25.0) ) { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_6); } + else { snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_7); } + return risk; } else { - return ( risk = 99 ); // out of range = much to high - it must be outerspace or sensor damaged + // out of range and much to high - it must be outerspace or sensor damaged + snprintf_P(str_uvrisk_text, sizeof(str_uvrisk_text), D_UV_INDEX_7); + return ( risk = 99 ); snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "VEML6070 out of range %d"), risk); AddLog(LOG_LEVEL_DEBUG); } @@ -196,25 +246,21 @@ double Veml6070UvRiskLevel(uint16_t uv_level) double Veml6070UvPower(double uvrisk) { // based on calculations for effective irradiation from Karel Vanicek - return ( VEML6070_POWER_COEFFCIENT * uvrisk ); + double power = 0; + return ( power = VEML6070_POWER_COEFFCIENT * uvrisk ); } /********************************************************************************************/ +// normaly in i18n.h, Line 520 .. 525 #ifdef USE_WEBSERVER // {s} = , {m} = , {e} = #ifdef USE_VEML6070_SHOW_RAW - const char HTTP_SNS_UV_LEVEL[] PROGMEM = "%s{s}VEML6070 " D_UV_LEVEL "{m}%d " D_UNIT_INCREMENTS "{e}"; + const char HTTP_SNS_UV_LEVEL[] PROGMEM = "%s{s}VEML6070 " D_UV_LEVEL "{m}%s " D_UNIT_INCREMENTS "{e}"; #endif // USE_VEML6070_SHOW_RAW // different uv index level texts - const char HTTP_SNS_UV_INDEX1[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_1 "{e}"; - const char HTTP_SNS_UV_INDEX2[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_2 "{e}"; - const char HTTP_SNS_UV_INDEX3[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_3 "{e}"; - const char HTTP_SNS_UV_INDEX4[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_4 "{e}"; - const char HTTP_SNS_UV_INDEX5[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_5 "{e}"; - const char HTTP_SNS_UV_INDEX6[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_6 "{e}"; - const char HTTP_SNS_UV_INDEX7[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX "{m}%s " D_UV_INDEX_7 "{e}"; - const char HTTP_SNS_UV_POWER[] PROGMEM = "%s{s}VEML6070 " D_UV_POWER "{m}%s " D_UNIT_WATT_METER_QUADRAT "{e}"; + const char HTTP_SNS_UV_INDEX[] PROGMEM = "%s{s}VEML6070 " D_UV_INDEX " {m}%s %s{e}"; + const char HTTP_SNS_UV_POWER[] PROGMEM = "%s{s}VEML6070 " D_UV_POWER "{m}%s " D_UNIT_WATT_METER_QUADRAT "{e}"; #endif // USE_WEBSERVER /********************************************************************************************/ @@ -222,61 +268,33 @@ double Veml6070UvPower(double uvrisk) void Veml6070Show(boolean json) { if (veml6070_type) { - // wakeup the sensor - Veml6070ModeCmd(1); - - // get values from functions - uint16_t uvlevel = Veml6070ReadUv(); - double uvrisk = Veml6070UvRiskLevel(uvlevel); - double uvpower = Veml6070UvPower(uvrisk); - char str_uvrisk[10]; - char str_uvpower[5]; - + char str_uvlevel[6]; // e.g. 99999 inc = UVLevel + char str_uvrisk[6]; // e.g. 25.99 text = UvIndex + char str_uvpower[6]; // e.g. 0.399 W/m² = UvPower // convert double values to string + dtostrfd((double)uvlevel, 0, str_uvlevel); dtostrfd(uvrisk, 2, str_uvrisk); dtostrfd(uvpower, 3, str_uvpower); - if (json) { #ifdef USE_VEML6070_SHOW_RAW - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_LEVEL "\":%d}"), mqtt_data, uvlevel); + 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}"), + mqtt_data, veml6070_name, str_uvrisk, str_uvrisk_text, str_uvpower); #endif // USE_VEML6070_SHOW_RAW - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_INDEX "\":%s}"), mqtt_data, str_uvrisk); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_POWER "\":%s}"), mqtt_data, str_uvpower); #ifdef USE_DOMOTICZ - if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, uvlevel); }; + if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, uvlevel); } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { #ifdef USE_VEML6070_SHOW_RAW - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_LEVEL, mqtt_data, uvlevel); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_LEVEL, mqtt_data, str_uvlevel); #endif // USE_VEML6070_SHOW_RAW - if ( (uvrisk >= 0) && (uvrisk <= 2.9) ) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX1, mqtt_data, str_uvrisk); - } - else if ( (uvrisk >= 3.0) && (uvrisk <= 5.9) ) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX2, mqtt_data, str_uvrisk); - } - else if ( (uvrisk >= 6.0) && (uvrisk <= 7.9) ) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX3, mqtt_data, str_uvrisk); - } - else if ( (uvrisk >= 8.0) && (uvrisk <= 10.9) ) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX4, mqtt_data, str_uvrisk); - } - else if ( (uvrisk >= 11.0) && (uvrisk <= 12.9) ) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX5, mqtt_data, str_uvrisk); - } - else if ( (uvrisk >= 13.0) && (uvrisk <= 15.9) ) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX6, mqtt_data, str_uvrisk); - } else { - // else for Unknown or Out Of Range error = 99 - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX7, mqtt_data, str_uvrisk); - } + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX, mqtt_data, str_uvrisk, str_uvrisk_text); snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_POWER, mqtt_data, str_uvpower); #endif // USE_WEBSERVER } - // suspend the sensor - Veml6070ModeCmd(0); - // delay(2000); // used while messaurment of current drain } } @@ -292,8 +310,12 @@ boolean Xsns11(byte function) if (i2c_flg) { switch (function) { - case FUNC_PREP_BEFORE_TELEPERIOD: - Veml6070Detect(); // detect and init the sensor + case FUNC_INIT: + Veml6070Detect(); // 1[ms], detect and init the sensor + Veml6070UvTableInit(); // 1[ms], initalize the UV compare table only once + break; + case FUNC_EVERY_SECOND: + Veml6070EverySecond(); // 10..15[ms], tested with OLED display, do all the actions needed to get all sensor values break; case FUNC_JSON_APPEND: Veml6070Show(1); @@ -310,4 +332,3 @@ boolean Xsns11(byte function) #endif // USE_VEML6070 #endif // USE_I2C - From 41e6939a8150595520261718053eb9b13a96d058 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 28 Sep 2018 17:38:06 +0200 Subject: [PATCH 93/93] outline corrections of // comments --- sonoff/xsns_11_veml6070.ino | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sonoff/xsns_11_veml6070.ino b/sonoff/xsns_11_veml6070.ino index de4d903bd..c06175584 100644 --- a/sonoff/xsns_11_veml6070.ino +++ b/sonoff/xsns_11_veml6070.ino @@ -133,8 +133,8 @@ void Veml6070Detect(void) // action on status if (!status) { veml6070_type = 1; - uint8_t veml_model = 0; - GetTextIndexed(veml6070_name, sizeof(veml6070_name), veml_model, kVemlTypes); + uint8_t veml_model = 0; + GetTextIndexed(veml6070_name, sizeof(veml6070_name), veml_model, kVemlTypes); snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070", VEML6070_ADDR_L); AddLog(LOG_LEVEL_DEBUG); } @@ -168,13 +168,13 @@ 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 - uvlevel = Veml6070ReadUv(); // 1..2[ms], get UV raw values - uvrisk = Veml6070UvRiskLevel(uvlevel); // 0..1[ms], get UV risk level + 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 Veml6070ModeCmd(0); // off = 5[ms], suspend the UV sensor } @@ -312,9 +312,9 @@ boolean Xsns11(byte function) switch (function) { case FUNC_INIT: Veml6070Detect(); // 1[ms], detect and init the sensor - Veml6070UvTableInit(); // 1[ms], initalize the UV compare table only once + Veml6070UvTableInit(); // 1[ms], initalize the UV compare table only once break; - case FUNC_EVERY_SECOND: + case FUNC_EVERY_SECOND: Veml6070EverySecond(); // 10..15[ms], tested with OLED display, do all the actions needed to get all sensor values break; case FUNC_JSON_APPEND: