diff --git a/README.md b/README.md
index 8915464e1..c85fbe698 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 331e25afb..2d041b532 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 1826ea637..7939e01c4 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 adce6a693..7da899391 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 8704121ab..e6d7685b9 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 c2e918c70..1d4400bc3 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 63c432983..ec8cc5984 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 e120a577b..9f4f17f86 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 000000000..b8b99a318
--- /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 a7a86d017..9f5acdf0c 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 af0811f8b..18c542d93 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 9a236691f..9b3d7f898 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 a8c159ae8..cb751db30 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;
}