From 0a9ec10b0a9a308c2b5a18ab9e4b982468a2a923 Mon Sep 17 00:00:00 2001 From: arendst Date: Sun, 30 Jul 2017 17:55:37 +0200 Subject: [PATCH] v5.5.0 5.5.0 20170730 * Reduce code space by removing the following commands as they are replaced by SetOption alternatives: * SaveState = SetOption0 * ButtonRestrict = SetOption1 * Units = SetOption2 * MQTT = SetOption3 * MQTTResponse = SetOption4 * TempUnit = SetOption8 * Smoothing WS2812 animation poll, invert fade speed and max allowed wakeup time down to 3000 seconds * Fix initial button press detection * Add support for Sonoff RF Bridge 433 using command RfKey * Fix regression from 5.0.7 by increasing message buffer size from 360 to 368 to accomodate 4 x DS18x20 sensors (#637) * Add GroupTopic to Topic test when using ButtonTopic/SwitchTopic to send either ON/OFF or TOGGLE (#642) * Adjust HLW calibration limits to accomodate HuaFan device and add commands HlwPSet, HlwUSet and HlwISet (#654) --- README.md | 10 +-- sonoff/_releasenotes.ino | 17 +++- sonoff/settings.h | 3 + sonoff/settings.ino | 57 +++++++------- sonoff/sonoff.ino | 135 ++++++++++++-------------------- sonoff/sonoff_template.h | 14 ++++ sonoff/user_config.h | 6 +- sonoff/webserver.ino | 21 +++++ sonoff/xdrv_snfbridge.ino | 160 ++++++++++++++++++++++++++++++++++++++ sonoff/xdrv_snfled.ino | 2 +- sonoff/xdrv_snfsc.ino | 2 +- sonoff/xdrv_ws2812.ino | 50 ++++-------- sonoff/xsns_hlw8012.ino | 40 ++++++++-- 13 files changed, 351 insertions(+), 166 deletions(-) create mode 100644 sonoff/xdrv_snfbridge.ino diff --git a/README.md b/README.md index 8915464e157f..c85fbe698710 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **5.4.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. +Current version is **5.5.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. ### **** ATTENTION Version 5.x.x specific information **** @@ -41,17 +41,15 @@ The following devices are supported: - [iTead Sonoff SC](http://sonoff.itead.cc/en/products/residential/sonoff-sc) - [iTead Sonoff Led](http://sonoff.itead.cc/en/products/appliances/sonoff-led) - [iTead Sonoff BN-SZ01 Ceiling Led](http://sonoff.itead.cc/en/products/appliances/bn-sz01) +- [iTead Sonoff RF Bridge 433](http://sonoff.itead.cc/en/products/appliances/sonoff-rf-bridge-433) - [iTead Sonoff Dev](https://www.itead.cc/sonoff-dev.html) - [iTead 1 Channel Switch 5V / 12V](https://www.itead.cc/smart-home/inching-self-locking-wifi-wireless-switch.html) - [iTead Motor Clockwise/Anticlockwise](https://www.itead.cc/smart-home/motor-reversing-wifi-wireless-switch.html) - [Electrodragon IoT Relay Board](http://www.electrodragon.com/product/wifi-iot-relay-board-based-esp8266/) Planned support: -- [iTead Sonoff T1](https://www.itead.cc/smart-home/sonoff-t1.html) -- [iTead Sonoff B1](https://www.itead.cc/smart-home/sonoff-b1.html) - -Optional future support: -- iTead RF Bridge +- [iTead Sonoff T1](http://sonoff.itead.cc/en/products/residential/sonoff-t1) +- [iTead Sonoff B1](http://sonoff.itead.cc/en/products/residential/sonoff-b1) diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 331e25afbef9..2d041b5324bf 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,19 @@ -/* 5.4.0 20170725 +/* 5.5.0 20170730 + * Reduce code space by removing the following commands as they are replaced by SetOption alternatives: + * SaveState = SetOption0 + * ButtonRestrict = SetOption1 + * Units = SetOption2 + * MQTT = SetOption3 + * MQTTResponse = SetOption4 + * TempUnit = SetOption8 + * Smoothing WS2812 animation poll, invert fade speed and max allowed wakeup time down to 3000 seconds + * Fix initial button press detection + * Add support for Sonoff RF Bridge 433 using command RfKey + * Fix regression from 5.0.7 by increasing message buffer size from 360 to 368 to accomodate 4 x DS18x20 sensors (#637) + * Add GroupTopic to Topic test when using ButtonTopic/SwitchTopic to send either ON/OFF or TOGGLE (#642) + * Adjust HLW calibration limits to accomodate HuaFan device and add commands HlwPSet, HlwUSet and HlwISet (#654) + * + * 5.4.0 20170725 * Fix command reset regression introduced in 5.2.0 * Increase polling from 0.1 second to 0.05 second * Add multipress to all buttons diff --git a/sonoff/settings.h b/sonoff/settings.h index 1826ea637277..7939e01c4a07 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -203,6 +203,9 @@ struct SYSCFG { uint16_t pCounterType; uint16_t pCounterDebounce; + // 5.4.1 + uint8_t sfb_code[17][9]; + } sysCfg; struct RTCMEM { diff --git a/sonoff/settings.ino b/sonoff/settings.ino index adce6a6934bb..7da8993911f4 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -17,6 +17,8 @@ along with this program. If not, see . */ +const uint8_t sfb_codeDefault[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; + /*********************************************************************************************\ * RTC memory \*********************************************************************************************/ @@ -269,30 +271,7 @@ void CFG_Load() } snprintf_P(log, sizeof(log), PSTR("Cnfg: Load from flash at %X and count %d"), _cfgLocation, sysCfg.saveFlag); addLog(LOG_LEVEL_DEBUG, log); -/* if (sysCfg.cfg_holder != CFG_HOLDER) { - CFG_Default(); - } -*/ - if (sysCfg.cfg_holder != CFG_HOLDER) { -/* - // Auto upgrade - if ((sysCfg.version < 0x04020000) || (sysCfg.version > VERSION)) { - noInterrupts(); - spi_flash_read((CFG_LOCATION_3) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); - spi_flash_read((CFG_LOCATION_3 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH)); - if (sysCfg.saveFlag < _sysCfgH.saveFlag) - spi_flash_read((CFG_LOCATION_3 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); - interrupts(); - if (sysCfg.cfg_holder != CFG_HOLDER) { - CFG_Default(); - } else { - sysCfg.saveFlag = 0; - } - } else { - CFG_Default(); - } -*/ // Auto upgrade noInterrupts(); spi_flash_read((CFG_LOCATION_3) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); @@ -339,7 +318,7 @@ void CFG_Erase() } } -void CFG_Dump(uint16_t srow, uint16_t mrow) +void CFG_Dump(char* parms) { #define CFG_COLS 16 @@ -348,18 +327,25 @@ void CFG_Dump(uint16_t srow, uint16_t mrow) uint16_t maxrow; uint16_t row; uint16_t col; + char *p; uint8_t *buffer = (uint8_t *) &sysCfg; - row = 0; maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS); - if ((srow > 0) && (srow < maxrow)) { - row = srow; + + uint16_t srow = strtol(parms, &p, 16) / CFG_COLS; + uint16_t mrow = strtol(p, &p, 10); + +// snprintf_P(log, sizeof(log), PSTR("Cnfg: Parms %s, Start row %d, rows %d"), parms, srow, mrow); +// addLog(LOG_LEVEL_DEBUG, log); + + if (0 == mrow) { // Default only 8 lines + mrow = 8; } - if (0 == mrow) { // Default only four lines - mrow = 4; + if (srow > maxrow) { + srow = maxrow - mrow; } - if ((mrow > 0) && (mrow < (maxrow - row))) { - maxrow = row + mrow; + if (mrow < (maxrow - srow)) { + maxrow = srow + mrow; } for (row = srow; row < maxrow; row++) { @@ -525,6 +511,9 @@ void CFG_DefaultSet2() // 5.2.0 sysCfg.param[P_MAX_POWER_RETRY] = MAX_POWER_RETRY; + // 5.4.1 + memcpy_P(sysCfg.sfb_code[0], sfb_codeDefault, 9); + } /********************************************************************************************/ @@ -727,6 +716,12 @@ void CFG_Delta() if (sysCfg.version < 0x05020000) { sysCfg.param[P_MAX_POWER_RETRY] = MAX_POWER_RETRY; } + if (sysCfg.version < 0x05050000) { + for (byte i = 0; i < 17; i++) { + sysCfg.sfb_code[i][0] = 0; + } + memcpy_P(sysCfg.sfb_code[0], sfb_codeDefault, 9); + } sysCfg.version = VERSION; CFG_Save(1); diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 8704121abc37..e6d7685b99bd 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,7 +25,7 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x05040000 // 5.4.0 +#define VERSION 0x05050000 // 5.5.0 enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; enum week_t {Last, First, Second, Third, Fourth}; @@ -159,7 +159,7 @@ enum opt_t {P_HOLD_TIME, P_MAX_POWER_RETRY, P_MAX_PARAM8}; // Index in sysCf #include // MQTT #ifndef MESSZ - #define MESSZ 360 // Max number of characters in JSON message string (4 x DS18x20 sensors) + #define MESSZ 368 // Max number of characters in JSON message string (4 x DS18x20 sensors) #endif #if (MQTT_MAX_PACKET_SIZE -TOPSZ -7) < MESSZ // If the max message size is too small, throw an error at compile time // See pubsubclient.c line 359 @@ -1111,47 +1111,6 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } snprintf_P(svalue, sizeof(svalue), PSTR("{\"SetOption%d\":\"%s\"}"), (ptype) ? index +32 : index, (ptype) ? stemp1 : getStateText(bitRead(sysCfg.flag.data, index))); } - -// To be removed in near future - else if (!strcmp_P(type,PSTR("SAVESTATE"))) { - if ((payload >= 0) && (payload <= 1)) { - sysCfg.flag.savestate = payload; - } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"SaveState\":\"%s\"}"), getStateText(sysCfg.flag.savestate)); - } - else if (!strcmp_P(type,PSTR("BUTTONRESTRICT"))) { - if ((payload >= 0) && (payload <= 1)) { - sysCfg.flag.button_restrict = payload; - } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"ButtonRestrict\":\"%s\"}"), getStateText(sysCfg.flag.button_restrict)); - } - else if (!strcmp_P(type,PSTR("UNITS"))) { - if ((payload >= 0) && (payload <= 1)) { - sysCfg.flag.value_units = payload; - } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Units\":\"%s\"}"), getStateText(sysCfg.flag.value_units)); - } - else if (!strcmp_P(type,PSTR("TEMPUNIT"))) { - if ((payload >= 0) && (payload <= 1)) { - sysCfg.flag.temperature_conversion = payload; - } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"TempUnit\":\"%s\"}"), (sysCfg.flag.temperature_conversion) ? "Fahrenheit" : "Celsius"); - } - else if (!strcmp_P(type,PSTR("MQTT"))) { - if ((payload >= 0) && (payload <= 1)) { - sysCfg.flag.mqtt_enabled = payload; - restartflag = 2; - } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Mqtt\":\"%s\"}"), getStateText(sysCfg.flag.mqtt_enabled)); - } - else if (!strcmp_P(type,PSTR("MQTTRESPONSE"))) { - if ((payload >= 0) && (payload <= 1)) { - sysCfg.flag.mqtt_response = payload; - } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"MqttResponse\":\"%s\"}"), getStateText(sysCfg.flag.mqtt_response)); - } -// Until here - else if (!strcmp_P(type,PSTR("TEMPRES"))) { if ((payload >= 0) && (payload <= 3)) { sysCfg.flag.temperature_resolution = payload; @@ -1567,23 +1526,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) snprintf_P(svalue, sizeof(svalue), PSTR("{\"LedState\":%d}"), sysCfg.ledstate); } else if (!strcmp_P(type,PSTR("CFGDUMP"))) { - uint16_t srow = 0; - uint16_t mrow = 0; - if (data_len > 0) { - srow = payload16; - byte i = 0; - while (isdigit(dataBuf[i])) { - i++; - } - if (i < strlen(dataBuf)) { - mrow = atoi(dataBuf +i); - } - if (0 == mrow) { - mrow = payload16; - srow = 0; - } - } - CFG_Dump(srow, mrow); + CFG_Dump(dataBuf); snprintf_P(svalue, sizeof(svalue), PSTR("{\"CfgDump\":\"Done\"}")); } else if (sysCfg.flag.mqtt_enabled && mqtt_command(grpflg, type, index, dataBuf, data_len, payload, svalue, sizeof(svalue))) { @@ -1592,6 +1535,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) else if (hlw_flg && hlw_command(type, index, dataBuf, data_len, payload, svalue, sizeof(svalue))) { // Serviced } + else if ((SONOFF_BRIDGE == sysCfg.module) && sb_command(type, index, dataBuf, data_len, payload, svalue, sizeof(svalue))) { + // Serviced + } #ifdef USE_I2C else if (i2c_flg && !strcmp_P(type,PSTR("I2CSCAN"))) { i2c_scan(svalue, sizeof(svalue)); @@ -1661,7 +1607,7 @@ boolean send_button_power(byte key, byte device, byte state) if (9 == state) { svalue[0] = '\0'; } else { - if (!strcmp(sysCfg.mqtt_topic, key_topic) && (2 == state)) { + if ((!strcmp(sysCfg.mqtt_topic, key_topic) || !strcmp(sysCfg.mqtt_grptopic, key_topic)) && (2 == state)) { state = ~(power >> (device -1)) & 0x01; } snprintf_P(svalue, sizeof(svalue), PSTR("%s"), getStateText(state)); @@ -1816,8 +1762,8 @@ void publish_status(uint8_t payload) } if ((0 == payload) || (3 == payload)) { - snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusLOG\":{\"Seriallog\":%d, \"Weblog\":%d, \"Syslog\":%d, \"LogHost\":\"%s\", \"SSId1\":\"%s\", \"SSId2\":\"%s\", \"TelePeriod\":%d}}"), - sysCfg.seriallog_level, sysCfg.weblog_level, sysCfg.syslog_level, sysCfg.syslog_host, sysCfg.sta_ssid[0], sysCfg.sta_ssid[1], sysCfg.tele_period); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusLOG\":{\"Seriallog\":%d, \"Weblog\":%d, \"Syslog\":%d, \"LogHost\":\"%s\", \"SSId1\":\"%s\", \"SSId2\":\"%s\", \"TelePeriod\":%d, \"Option\":\"%X\"}}"), + sysCfg.seriallog_level, sysCfg.weblog_level, sysCfg.syslog_level, sysCfg.syslog_host, sysCfg.sta_ssid[0], sysCfg.sta_ssid[1], sysCfg.tele_period, sysCfg.flag.data); mqtt_publish_topic_P(option, PSTR("STATUS3"), svalue); } @@ -2083,6 +2029,7 @@ void button_handler() char log[LOGSZ]; for (byte i = 0; i < Maxdevice; i++) { + button = NOT_PRESSED; butt_present = 0; if (!i && ((SONOFF_DUAL == sysCfg.module) || (CH4 == sysCfg.module))) { @@ -2095,8 +2042,6 @@ void button_handler() holdbutton[i] = (sysCfg.param[P_HOLD_TIME] * (STATES / 10)) -1; } ButtonCode = 0; - } else { - button = NOT_PRESSED; } } else { if ((pin[GPIO_KEY1 +i] < 99) && !blockgpio0) { @@ -2203,8 +2148,8 @@ void button_handler() } } } - lastbutton[i] = button; } + lastbutton[i] = button; } } @@ -2308,7 +2253,6 @@ void stateloop() * Every 0.1 second \*-------------------------------------------------------------------------------------------*/ -// if (0 == (state & 1)) { if (!(state % (STATES/10))) { if (mqtt_cmnd_publish) { @@ -2346,16 +2290,6 @@ void stateloop() } } - if (sfl_flg) { // Sonoff BN-SZ01 or Sonoff Led - sl_animate(); - } - -#ifdef USE_WS2812 - if (pin[GPIO_WS2812] < 99) { - ws2812_animate(); - } -#endif // USE_WS2812 - // Backlog if (blogdelay) { blogdelay--; @@ -2381,6 +2315,16 @@ void stateloop() button_handler(); switch_handler(); + if (sfl_flg) { // Sonoff BN-SZ01 or Sonoff Led + sl_animate(); + } + +#ifdef USE_WS2812 + if (pin[GPIO_WS2812] < 99) { + ws2812_animate(); + } +#endif // USE_WS2812 + /*-------------------------------------------------------------------------------------------*\ * Every 0.2 second \*-------------------------------------------------------------------------------------------*/ @@ -2533,7 +2477,10 @@ void serial() yield(); SerialInByte = Serial.read(); - // Sonoff dual 19200 baud serial interface +/*-------------------------------------------------------------------------------------------*\ + * Sonoff dual 19200 baud serial interface +\*-------------------------------------------------------------------------------------------*/ + if (Hexcode) { Hexcode--; if (Hexcode) { @@ -2541,17 +2488,29 @@ void serial() SerialInByte = 0; } else { if (SerialInByte != 0xA1) { - ButtonCode = 0; // 0xA1 - End of Sonoff dual button code + ButtonCode = 0; // 0xA1 - End of Sonoff dual button code } } } - if (0xA0 == SerialInByte) { // 0xA0 - Start of Sonoff dual button code + if (0xA0 == SerialInByte) { // 0xA0 - Start of Sonoff dual button code SerialInByte = 0; ButtonCode = 0; Hexcode = 3; } - if (SerialInByte > 127) { // binary data... +/*-------------------------------------------------------------------------------------------*\ + * Sonoff bridge 19200 baud serial interface +\*-------------------------------------------------------------------------------------------*/ + + if (sb_serial()) { + SerialInByteCounter = 0; + Serial.flush(); + return; + } + +/*-------------------------------------------------------------------------------------------*/ + + if (SerialInByte > 127) { // binary data... SerialInByteCounter = 0; Serial.flush(); return; @@ -2564,7 +2523,7 @@ void serial() } } - if (SerialInByte == '\x1B') { // Sonoff SC status from ATMEGA328P + if (SerialInByte == '\x1B') { // Sonoff SC status from ATMEGA328P serialInBuf[SerialInByteCounter] = 0; // serial data completed sc_rcvstat(serialInBuf); SerialInByteCounter = 0; @@ -2650,6 +2609,9 @@ void GPIO_init() analogWriteFreq(PWM_FREQ); // Default is 1000 (core_esp8266_wiring_pwm.c) Maxdevice = 1; + if (SONOFF_BRIDGE == sysCfg.module) { + Baudrate = 19200; + } if (SONOFF_DUAL == sysCfg.module) { Maxdevice = 2; Baudrate = 19200; @@ -2675,12 +2637,15 @@ void GPIO_init() pinMode(pin[GPIO_REL1 +i], OUTPUT); Maxdevice++; } - if (pin[GPIO_KEY1 +i] < 99) { - pinMode(pin[GPIO_KEY1 +i], INPUT_PULLUP); - } +// if (pin[GPIO_KEY1 +i] < 99) { +// pinMode(pin[GPIO_KEY1 +i], INPUT_PULLUP); +// } } } for (byte i = 0; i < 4; i++) { + if (pin[GPIO_KEY1 +i] < 99) { + pinMode(pin[GPIO_KEY1 +i], INPUT_PULLUP); + } if (pin[GPIO_LED1 +i] < 99) { pinMode(pin[GPIO_LED1 +i], OUTPUT); digitalWrite(pin[GPIO_LED1 +i], led_inverted[i]); diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index c2e918c70fdc..1d4400bc3709 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -148,6 +148,7 @@ enum module_t { SONOFF_BN, SONOFF_4CHPRO, HUAFAN_SS, + SONOFF_BRIDGE, MAXMODULE }; /********************************************************************************************/ @@ -475,6 +476,19 @@ const mytmplt modules[MAXMODULE] PROGMEM = { GPIO_HLW_SEL, // GPIO13 HLW8012 Sel output GPIO_HLW_CF, // GPIO14 HLW8012 CF power 0, 0, 0 + }, + { "Sonoff Bridge", // Sonoff RF Bridge 433 (ESP8285) + GPIO_KEY1, // GPIO00 Button + GPIO_TXD, // GPIO01 RF bridge control + GPIO_USER, // GPIO02 Optional sensor + GPIO_RXD, // GPIO03 RF bridge control + 0, 0, + 0, 0, 0, // Flash connection + 0, 0, + 0, // Flash connection + 0, + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + 0, 0, 0, 0 } }; diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 63c43298370d..ec8cc5984d7d 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -31,7 +31,7 @@ #define CFG_HOLDER 0x20161209 // [Reset 1] Change this value to load following default configuration parameters #define SAVE_DATA 1 // [SaveData] Save changed parameters to Flash (0 = disable, 1 - 3600 seconds) -#define SAVE_STATE 1 // [SaveState] Save changed power state to Flash (0 = disable, 1 = enable) +#define SAVE_STATE 1 // [SetOption0] Save changed power state to Flash (0 = disable, 1 = enable) // -- Wifi ---------------------------------------- #define WIFI_IP_ADDRESS "0.0.0.0" // [IpAddress1] Set to 0.0.0.0 for using DHCP or IP address @@ -57,7 +57,7 @@ #define OTA_URL "http://domus1:80/api/arduino/" PROJECT ".ino.bin" // [OtaUrl] // -- MQTT ---------------------------------------- -#define MQTT_USE 1 // [Mqtt] Select default MQTT use (0 = Off, 1 = On) +#define MQTT_USE 1 // [SetOption3] Select default MQTT use (0 = Off, 1 = On) // !!! TLS uses a LOT OF MEMORY (20k) so be careful to enable other options at the same time !!! //#define USE_MQTT_TLS // EXPERIMENTAL Use TLS for MQTT connection (+53k code, +20k mem) - Disable by // // Needs Fingerprint, TLS Port, UserId and Password @@ -145,7 +145,7 @@ #define SWITCH_MODE TOGGLE // [SwitchMode] TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD or PUSHBUTTONHOLD_INV (the wall switch state) #define WS2812_LEDS 30 // [Pixels] Number of WS2812 LEDs to start with -#define TEMP_CONVERSION 0 // [TempUnit] Return temperature in (0 = Celsius or 1 = Fahrenheit) +#define TEMP_CONVERSION 0 // [SetOption8] Return temperature in (0 = Celsius or 1 = Fahrenheit) #define TEMP_RESOLUTION 1 // [TempRes] Maximum number of decimals (0 - 3) showing sensor Temperature #define HUMIDITY_RESOLUTION 1 // [HumRes] Maximum number of decimals (0 - 3) showing sensor Humidity #define PRESSURE_RESOLUTION 1 // [PressRes] Maximum number of decimals (0 - 3) showing sensor Pressure diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index e120a577b3aa..9f4f17f86eee 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -437,6 +437,23 @@ void handleRoot() } page += F(""); } + if (SONOFF_BRIDGE == sysCfg.module) { + page += FPSTR(HTTP_TABLE100); + page += F(""); + byte idx = 0; + for (byte i = 0; i < 4; i++) { + if (idx > 0) { + page += F(""); + } + for (byte j = 0; j < 4; j++) { + idx++; + snprintf_P(line, sizeof(line), PSTR(""), + idx, idx); + page += line; + } + } + page += F(""); + } if (HTTP_ADMIN == _httpflag) { page += FPSTR(HTTP_BTN_MENU1); @@ -457,6 +474,10 @@ void handleAjax2() snprintf_P(svalue, sizeof(svalue), PSTR("dimmer %s"), webServer->arg("d").c_str()); do_cmnd(svalue); } + if (strlen(webServer->arg("k").c_str())) { + snprintf_P(svalue, sizeof(svalue), PSTR("rfkey%s"), webServer->arg("k").c_str()); + do_cmnd(svalue); + } String tpage = ""; tpage += counter_webPresent(); diff --git a/sonoff/xdrv_snfbridge.ino b/sonoff/xdrv_snfbridge.ino new file mode 100644 index 000000000000..b8b99a3184ae --- /dev/null +++ b/sonoff/xdrv_snfbridge.ino @@ -0,0 +1,160 @@ +/* + xdrv_snfbridge.ino - sonoff RF bridge 433 support for Sonoff-Tasmota + + Copyright (C) 2017 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 . +*/ + +/*********************************************************************************************\ + Sonoff RF Bridge 433 +\*********************************************************************************************/ + +uint8_t sfb_rcvflg = 0; // Sonoff RF Bridge communication +uint8_t sfb_learnKey = 1; +uint8_t sfb_learnFlg = 0; + +void sb_received() +{ + char svalue[60]; + char log[LOGSZ]; + + svalue[0] = '\0'; + for (byte i = 0; i < SerialInByteCounter; i++) { + snprintf_P(svalue, sizeof(svalue), PSTR("%s%02X "), svalue, serialInBuf[i]); + } + snprintf_P(log, sizeof(log), PSTR("BRDG: Received %s"), svalue); + addLog(LOG_LEVEL_DEBUG, log); + + if (0xA2 == serialInBuf[0]) { // Learn failed + sfb_learnFlg = 0; + snprintf_P(svalue, sizeof(svalue), PSTR("{\"RfKey%d\":\"Learn failed\"}"), sfb_learnKey); + mqtt_publish_topic_P(5, PSTR("RFKEY"), svalue); + } + if (0xA3 == serialInBuf[0]) { // Learn + sfb_learnFlg = 0; + for (uint8_t i = 0; i < 9; i++) { + sysCfg.sfb_code[sfb_learnKey][i] = serialInBuf[i +1]; + } + snprintf_P(svalue, sizeof(svalue), PSTR("{\"RfKey%d\":\"Learned\"}"), sfb_learnKey); + mqtt_publish_topic_P(5, PSTR("RFKEY"), svalue); + } +} + +boolean sb_serial() +{ + if (sfb_rcvflg) { + if (SerialInByte > 0) { + serialInBuf[SerialInByteCounter++] = SerialInByte; + if (0x55 == SerialInByte) { +// serialInBuf[SerialInByteCounter] = 0x55; + sb_received(); + sfb_rcvflg = 0; // 0x55 - End of text + return 1; + } + } + SerialInByte = 0; + } + if (0xAA == SerialInByte) { // 0xAA - Start of text + SerialInByteCounter = 0; + SerialInByte = 0; + sfb_rcvflg = 1; + } + return 0; +} + +void sb_sendAck() +{ + Serial.write(0xAA); // Start of Text + Serial.write(0xA0); // Acknowledge + Serial.write(0x55); // End of Text +} + +void sb_send(uint8_t idx, uint8_t key) +{ + uint8_t code; + + key--; // Support 1 to 16 + Serial.write(0xAA); // Start of Text + Serial.write(0xA5); // Send following code + for (uint8_t i = 0; i < 8; i++) { + Serial.write(sysCfg.sfb_code[idx][i]); + } + if (0 == idx) { + code = (0x10 << (key >> 2)) | (0x01 << (key & 3)); // 11,12,14,18,21,22,24,28,41,42,44,48,81,82,84,88 + } else { + code = sysCfg.sfb_code[idx][8]; + } + Serial.write(code); + Serial.write(0x55); // End of Text + Serial.flush(); +} + +void sb_learn(uint8_t key) +{ + sfb_learnKey = key; + sfb_learnFlg = 1; + Serial.write(0xAA); // Start of Text + Serial.write(0xA1); // Start learning + Serial.write(0x55); // End of Text +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +boolean sb_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) +{ + boolean serviced = true; + char *p; + + if (!strcmp_P(type, PSTR("RFDEFAULT"))) { + if (4 == data_len) { + uint16_t hexcode = strtol(dataBuf, &p, 16); + uint8_t msb = hexcode >> 8; + uint8_t lsb = hexcode & 0xFF; + if ((hexcode > 0) && (hexcode < 0x7FFF) && (msb != 0x55) && (lsb != 0x55)) { + sysCfg.sfb_code[0][6] = msb; + sysCfg.sfb_code[0][7] = lsb; + } + } + snprintf_P(svalue, ssvalue, PSTR("{\"RfDefault\":\"%0X%0X\"}"), sysCfg.sfb_code[0][6], sysCfg.sfb_code[0][7]); + } + else if (!strcmp_P(type, PSTR("RFKEY")) && (index > 0) && (index <= 16)) { + if (!sfb_learnFlg) { + if (2 == payload) { + sb_learn(index); + snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Start learning\"}"), index); + } + else if (3 == payload) { + sysCfg.sfb_code[index][0] = 0; + snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Set to default\"}"), index); + } else { + if ((1 == payload) || (0 == sysCfg.sfb_code[index][0])) { + sb_send(0, index); + snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Default sent\"}"), index); + } else { + sb_send(index, 0); + snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Learned sent\"}"), index); + } + } + } else { + snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Learning active\"}"), sfb_learnKey); + } + } + else { + serviced = false; // Unknown command + } + return serviced; +} diff --git a/sonoff/xdrv_snfled.ino b/sonoff/xdrv_snfled.ino index a7a86d017219..9f5acdf0c675 100644 --- a/sonoff/xdrv_snfled.ino +++ b/sonoff/xdrv_snfled.ino @@ -290,7 +290,7 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le snprintf_P(svalue, ssvalue, PSTR("{\"Speed\":%d}"), sysCfg.led_speed); } else if (!strcmp_P(type,PSTR("WAKEUPDURATION"))) { - if ((payload > 0) && (payload < 3601)) { + if ((payload > 0) && (payload < 3001)) { sysCfg.led_wakeup = payload; sl_wakeupActive = 0; } diff --git a/sonoff/xdrv_snfsc.ino b/sonoff/xdrv_snfsc.ino index af0811f8bee7..18c542d93f37 100644 --- a/sonoff/xdrv_snfsc.ino +++ b/sonoff/xdrv_snfsc.ino @@ -1,7 +1,7 @@ /* xdrv_snfsc.ino - sonoff SC support for Sonoff-Tasmota - Copyright (C) 2017 Heiko Krupp and Theo Arends + Copyright (C) 2017 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 diff --git a/sonoff/xdrv_ws2812.ino b/sonoff/xdrv_ws2812.ino index 9a236691fb81..9b3d7f898ad1 100644 --- a/sonoff/xdrv_ws2812.ino +++ b/sonoff/xdrv_ws2812.ino @@ -76,31 +76,13 @@ uint8_t repeatValues[5] = { 2, // Largest 1 }; // All uint8_t speedValues[6] = { - 0, // None - 18, // Slowest - 14, // Slower - 10, // Slow - 6, // Fast - 2 }; // Fastest -/* -uint8_t ledTable[] = { - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, - 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, - 14, 15, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, - 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, - 33, 33, 34, 35, 36, 36, 37, 38, 39, 40, 40, 41, 42, 43, 44, 45, - 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, - 80, 81, 82, 83, 85, 86, 87, 89, 90, 91, 93, 94, 95, 97, 98, 99, - 101,102,104,105,107,108,110,111,113,114,116,117,119,121,122,124, - 125,127,129,130,132,134,135,137,139,141,142,144,146,148,150,151, - 153,155,157,159,161,163,165,166,168,170,172,174,176,178,180,182, - 184,186,189,191,193,195,197,199,201,204,206,208,210,212,215,217, - 219,221,224,226,228,231,233,235,238,240,243,245,248,250,253,255 }; -*/ + 0, // None + 9 * (STATES / 10), // Slowest + 7 * (STATES / 10), // Slower + 5 * (STATES / 10), // Slow + 3 * (STATES / 10), // Fast + 1 * (STATES / 10) }; // Fastest + uint8_t lany = 0; RgbColor dcolor; RgbColor tcolor; @@ -409,23 +391,24 @@ void ws2812_animate() tcolor = dcolor; } else { if (tcolor != dcolor) { + uint8_t ws_speed = speedValues[sysCfg.ws_speed]; if (tcolor.R < dcolor.R) { - tcolor.R += ((dcolor.R - tcolor.R) >> sysCfg.ws_speed) +1; + tcolor.R += ((dcolor.R - tcolor.R) / ws_speed) +1; } if (tcolor.G < dcolor.G) { - tcolor.G += ((dcolor.G - tcolor.G) >> sysCfg.ws_speed) +1; + tcolor.G += ((dcolor.G - tcolor.G) / ws_speed) +1; } if (tcolor.B < dcolor.B) { - tcolor.B += ((dcolor.B - tcolor.B) >> sysCfg.ws_speed) +1; + tcolor.B += ((dcolor.B - tcolor.B) / ws_speed) +1; } if (tcolor.R > dcolor.R) { - tcolor.R -= ((tcolor.R - dcolor.R) >> sysCfg.ws_speed) +1; + tcolor.R -= ((tcolor.R - dcolor.R) / ws_speed) +1; } if (tcolor.G > dcolor.G) { - tcolor.G -= ((tcolor.G - dcolor.G) >> sysCfg.ws_speed) +1; + tcolor.G -= ((tcolor.G - dcolor.G) / ws_speed) +1; } if (tcolor.B > dcolor.B) { - tcolor.B -= ((tcolor.B - dcolor.B) >> sysCfg.ws_speed) +1; + tcolor.B -= ((tcolor.B - dcolor.B) / ws_speed) +1; } } } @@ -443,8 +426,9 @@ void ws2812_animate() if (wakeupDimmer <= sysCfg.ws_dimmer) { ws2812_setDim(wakeupDimmer); tcolor = dcolor; - } else + } else { sysCfg.ws_scheme = 0; + } } } break; @@ -599,7 +583,7 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_ snprintf_P(svalue, ssvalue, PSTR("{\"Width\":%d}"), sysCfg.ws_width); } else if (!strcmp_P(type,PSTR("WAKEUP"))) { - if ((payload > 0) && (payload < 3601)) { + if ((payload > 0) && (payload < 3001)) { sysCfg.ws_wakeup = payload; if (1 == sysCfg.ws_scheme) { sysCfg.ws_scheme = 0; diff --git a/sonoff/xsns_hlw8012.ino b/sonoff/xsns_hlw8012.ino index a8c159ae812d..cb751db3055f 100644 --- a/sonoff/xsns_hlw8012.ino +++ b/sonoff/xsns_hlw8012.ino @@ -437,6 +437,7 @@ void hlw_margin_chk() boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) { boolean serviced = true; + uint8_t caltext = 0; if (!strcmp_P(type,PSTR("POWERLOW"))) { if ((payload >= 0) && (payload < 3601)) { @@ -501,21 +502,39 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len } else if (!strcmp_P(type,PSTR("HLWPCAL"))) { if ((payload > 0) && (payload < 32001)) { - sysCfg.hlw_pcal = (payload > 9999) ? payload : HLW_PREF_PULSE; // 12530 + sysCfg.hlw_pcal = (payload > 4000) ? payload : HLW_PREF_PULSE; // 12530 } - snprintf_P(svalue, ssvalue, PSTR("(\"HlwPcal\":\"%d%s\"}"), sysCfg.hlw_pcal, (sysCfg.flag.value_units) ? " uS" : ""); + caltext = 1; + } + else if (!strcmp_P(type,PSTR("HLWPSET"))) { + if ((payload > 0) && (payload < 3601) && hlw_cf_plen) { + sysCfg.hlw_pcal = (payload * 10 * hlw_cf_plen) / HLW_PREF; + } + caltext = 1; } else if (!strcmp_P(type,PSTR("HLWUCAL"))) { if ((payload > 0) && (payload < 32001)) { sysCfg.hlw_ucal = (payload > 999) ? payload : HLW_UREF_PULSE; // 1950 } - snprintf_P(svalue, ssvalue, PSTR("{\"HlwUcal\":\"%d%s\"}"), sysCfg.hlw_ucal, (sysCfg.flag.value_units) ? " uS" : ""); + caltext = 2; + } + else if (!strcmp_P(type,PSTR("HLWUSET"))) { + if ((payload > 0) && (payload < 501) && hlw_cf1u_plen) { + sysCfg.hlw_ucal = (payload * 10 * hlw_cf1u_plen) / HLW_UREF; + } + caltext = 2; } else if (!strcmp_P(type,PSTR("HLWICAL"))) { if ((payload > 0) && (payload < 32001)) { - sysCfg.hlw_ical = (payload > 2499) ? payload : HLW_IREF_PULSE; // 3500 + sysCfg.hlw_ical = (payload > 1100) ? payload : HLW_IREF_PULSE; // 3500 } - snprintf_P(svalue, ssvalue, PSTR("{\"HlwIcal\":\"%d%s\"}"), sysCfg.hlw_ical, (sysCfg.flag.value_units) ? " uS" : ""); + caltext = 3; + } + else if (!strcmp_P(type,PSTR("HLWISET"))) { + if ((payload > 0) && (payload < 16001) && hlw_cf1i_plen) { + sysCfg.hlw_ical = (payload * hlw_cf1i_plen) / HLW_IREF; + } + caltext = 3; } #if FEATURE_POWER_LIMIT else if (!strcmp_P(type,PSTR("MAXPOWER"))) { @@ -571,6 +590,17 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len else { serviced = false; } + switch (caltext) { + case 1: + snprintf_P(svalue, ssvalue, PSTR("(\"HlwPcal\":\"%d%s\"}"), sysCfg.hlw_pcal, (sysCfg.flag.value_units) ? " uS" : ""); + break; + case 2: + snprintf_P(svalue, ssvalue, PSTR("{\"HlwUcal\":\"%d%s\"}"), sysCfg.hlw_ucal, (sysCfg.flag.value_units) ? " uS" : ""); + break; + case 3: + snprintf_P(svalue, ssvalue, PSTR("(\"HlwIcal\":\"%d%s\"}"), sysCfg.hlw_ical, (sysCfg.flag.value_units) ? " uS" : ""); + break; + } return serviced; }