diff --git a/README.md b/README.md
index 9fd6e0505..f55adc2c6 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.1.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
+Current version is **5.1.1** - 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 ****
@@ -44,5 +44,9 @@ The following devices are supported:
- [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/)
+Future support
+- [iTead Sonoff 4CH Pro](https://www.itead.cc/sonoff-4ch-pro.html)
+
+
diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin
index f47b5cf84..f2bbac47b 100644
Binary files a/api/arduino/sonoff.ino.bin and b/api/arduino/sonoff.ino.bin differ
diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino
index 449599b52..8cd202877 100644
--- a/sonoff/_releasenotes.ino
+++ b/sonoff/_releasenotes.ino
@@ -1,4 +1,12 @@
-/* 5.1.0 20170513
+/* 5.1.1 20170517
+ * Allow command FullTopic in group mode
+ * Prepare for more use of RTC memory
+ * Add independant WS2812 led string power control (#386, #390)
+ * Add command Counter to control up to four GPIO falling edge interrupt counters or timers (#459)
+ * Add command CounterType to select between pulse counting or pulse timing
+ * Add command CounterDebounce to select global counter debounce time in mSec
+ *
+ * 5.1.0 20170513
* Fix Offline/Removal of retained topic when FullTopic is changed
* Add FullTopic to MQTT Configuration and Information web pages
* Add license model GPLv3 (#188)
diff --git a/sonoff/settings.h b/sonoff/settings.h
index 832a09491..4b719efe1 100644
--- a/sonoff/settings.h
+++ b/sonoff/settings.h
@@ -196,14 +196,20 @@ struct SYSCFG {
// 5.0.4a
char mqtt_fulltopic[101];
+ // 5.1.1
+ unsigned long pCounter[4];
+ uint16_t pCounterType;
+ uint16_t pCounterDebounce;
+
} sysCfg;
struct RTCMEM {
uint16_t valid;
byte osw_flag;
- byte nu1;
+ uint8_t power;
unsigned long hlw_kWhtoday;
unsigned long hlw_kWhtotal;
+ unsigned long pCounter[4];
} rtcMem;
// See issue https://github.com/esp8266/Arduino/issues/2913
diff --git a/sonoff/settings.ino b/sonoff/settings.ino
index e24c74866..5b52b7daa 100644
--- a/sonoff/settings.ino
+++ b/sonoff/settings.ino
@@ -59,6 +59,12 @@ void RTC_Load()
if (rtcMem.valid != RTC_MEM_VALID) {
memset(&rtcMem, 0x00, sizeof(RTCMEM));
rtcMem.valid = RTC_MEM_VALID;
+ rtcMem.power = sysCfg.power;
+ rtcMem.hlw_kWhtoday = sysCfg.hlw_kWhtoday;
+ rtcMem.hlw_kWhtotal = sysCfg.hlw_kWhtotal;
+ for (byte i = 0; i < 4; i++) {
+ rtcMem.pCounter[i] = sysCfg.pCounter[i];
+ }
RTC_Save();
}
_rtcHash = getRtcHash();
@@ -633,6 +639,14 @@ void CFG_Delta()
if (sysCfg.version < 0x05000600) {
sysCfg.mqtt_retry = MQTT_RETRY_SECS;
}
+ if (sysCfg.version < 0x05010100) {
+ sysCfg.pCounterType = 0;
+ sysCfg.pCounterDebounce = 0;
+ for (byte i = 0; i < 4; i++) {
+ sysCfg.pCounter[i] = 0;
+ rtcMem.pCounter[i] = 0;
+ }
+ }
sysCfg.version = VERSION;
}
}
diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino
index 929b8dca2..454db32ae 100644
--- a/sonoff/sonoff.ino
+++ b/sonoff/sonoff.ino
@@ -16,18 +16,15 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-
-/*
- ====================================================
+/*====================================================
Prerequisites:
- Change libraries/PubSubClient/src/PubSubClient.h
#define MQTT_MAX_PACKET_SIZE 512
- Select IDE Tools - Flash size: "1M (no SPIFFS)"
- ====================================================
-*/
+ ====================================================*/
-#define VERSION 0x05010000 // 5.1.0
+#define VERSION 0x05010100 // 5.1.1
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};
@@ -254,6 +251,7 @@ uint8_t blink_powersave; // Blink start power save state
uint16_t mqtt_cmnd_publish = 0; // ignore flag for publish command
uint8_t latching_power = 0; // Power state at latching start
uint8_t latching_relay_pulse = 0; // Latching relay pulse timer
+unsigned long pTimeLast[4]; // Last counter time in milli seconds
#ifdef USE_MQTT_TLS
WiFiClientSecure espClient; // Wifi Secure Client
@@ -706,7 +704,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf,
}
snprintf_P(svalue, ssvalue, PSTR("{\"MqttPassword\":\"%s\"}"), sysCfg.mqtt_pwd);
}
- else if (!grpflg && !strcmp_P(type,PSTR("FULLTOPIC"))) {
+ else if (!strcmp_P(type,PSTR("FULLTOPIC"))) {
if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_fulltopic))) {
for (i = 0; i <= data_len; i++) {
if ((dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) {
@@ -1213,6 +1211,27 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(svalue, sizeof(svalue), PSTR("%s}}"),svalue);
}
+ else if (!strcmp_P(type,PSTR("COUNTER")) && (index > 0) && (index <= 4)) {
+ if ((data_len > 0) && (pin[GPIO_CNTR1 + index -1] < 99)) {
+ rtcMem.pCounter[index -1] = payload16;
+ sysCfg.pCounter[index -1] = payload16;
+ }
+ snprintf_P(svalue, sizeof(svalue), PSTR("{\"Counter%d\":%d}"), index, rtcMem.pCounter[index -1]);
+ }
+ else if (!strcmp_P(type,PSTR("COUNTERTYPE")) && (index > 0) && (index <= 4)) {
+ if ((data_len > 0) && (payload >= 0) && (payload <= 1) && (pin[GPIO_CNTR1 + index -1] < 99)) {
+ bitWrite(sysCfg.pCounterType, index -1, payload &1);
+ rtcMem.pCounter[index -1] = 0;
+ sysCfg.pCounter[index -1] = 0;
+ }
+ snprintf_P(svalue, sizeof(svalue), PSTR("{\"CounterType%d\":%d}"), index, bitRead(sysCfg.pCounterType, index -1));
+ }
+ else if (!strcmp_P(type,PSTR("COUNTERDEBOUNCE"))) {
+ if ((data_len > 0) && (payload16 < 32001) && (pin[GPIO_CNTR1 + index -1] < 99)) {
+ sysCfg.pCounterDebounce = payload16;
+ }
+ snprintf_P(svalue, sizeof(svalue), PSTR("{\"CounterDebounce\":%d}"), sysCfg.pCounterDebounce);
+ }
else if (!strcmp_P(type,PSTR("SLEEP"))) {
if ((data_len > 0) && (payload >= 0) && (payload < 251)) {
if ((!sysCfg.sleep && payload) || (sysCfg.sleep && !payload)) {
@@ -1527,7 +1546,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Command\":\"Unknown\"}"));
type = (char*)topicBuf;
}
- mqtt_publish_topic_P(5, type, svalue);
+ if (svalue[0] != '\0') {
+ mqtt_publish_topic_P(5, type, svalue);
+ }
}
/********************************************************************************************/
@@ -1786,6 +1807,12 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
*djson = 1;
}
}
+ for (byte i = 0; i < 4; i++) {
+ if (pin[GPIO_CNTR1 +i] < 99) {
+ snprintf_P(svalue, ssvalue, PSTR("%s, {\"Counter%d\":%d}"), svalue, i +1, rtcMem.pCounter[i]);
+ *djson = 1;
+ }
+ }
#ifndef USE_ADC_VCC
if (pin[GPIO_ADC0] < 99) {
snprintf_P(svalue, ssvalue, PSTR("%s, \"AnalogInput0\":%d"), svalue, analogRead(A0));
@@ -2187,6 +2214,9 @@ void stateloop()
}
break;
case (STATES/10)*4:
+ if (rtc_midnight_now()) {
+ counter_savestate();
+ }
if (savedatacounter) {
savedatacounter--;
if (savedatacounter <= 0) {
@@ -2221,6 +2251,7 @@ void stateloop()
if (hlw_flg) {
hlw_savestate();
}
+ counter_savestate();
CFG_Save();
restartflag--;
if (restartflag <= 0) {
@@ -2436,7 +2467,8 @@ void GPIO_init()
analogWrite(pin[GPIO_PWM1 +i], sysCfg.pwmvalue[i]);
}
}
-
+ counter_init();
+
if (EXS_RELAY == sysCfg.module) {
setLatchingRelay(0,2);
setLatchingRelay(1,2);
@@ -2469,7 +2501,8 @@ void GPIO_init()
#ifdef USE_WS2812
if (pin[GPIO_WS2812] < 99) {
- ws2812_init();
+ Maxdevice++;
+ ws2812_init(Maxdevice);
}
#endif // USE_WS2812
diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h
index ebad89b65..ece8c1c1c 100644
--- a/sonoff/sonoff_template.h
+++ b/sonoff/sonoff_template.h
@@ -57,6 +57,10 @@ enum upins_t {
GPIO_PWM3, // Red (swapped with Blue from original)
GPIO_PWM4, // Green
GPIO_PWM5, // Blue (swapped with Red from original)
+ GPIO_CNTR1,
+ GPIO_CNTR2,
+ GPIO_CNTR3,
+ GPIO_CNTR4,
GPIO_SENSOR_END };
// Text in webpage Module Parameters and commands GPIOS and GPIO
@@ -98,7 +102,11 @@ const char sensors[GPIO_SENSOR_END][9] PROGMEM = {
"PWM2",
"PWM3",
"PWM4",
- "PWM5"
+ "PWM5",
+ "Counter1",
+ "Counter2",
+ "Counter3",
+ "Counter4"
};
// Programmer selectable GPIO functionality offset by user selectable GPIOs
diff --git a/sonoff/support.ino b/sonoff/support.ino
index abd826b58..01acad6eb 100644
--- a/sonoff/support.ino
+++ b/sonoff/support.ino
@@ -682,6 +682,7 @@ uint32_t dsttime = 0;
uint32_t stdtime = 0;
uint32_t ntptime = 0;
uint32_t midnight = 1451602800;
+uint8_t midnightnow = 0;
String getBuildDateTime()
{
@@ -867,6 +868,15 @@ uint32_t rtc_midnight()
return midnight;
}
+boolean rtc_midnight_now()
+{
+ boolean mnflg = midnightnow;
+ if (mnflg) {
+ midnightnow = 0;
+ }
+ return mnflg;
+}
+
void rtc_second()
{
char log[LOGSZ];
@@ -919,6 +929,7 @@ void rtc_second()
breakTime(loctime, rtcTime);
if (!rtcTime.Hour && !rtcTime.Minute && !rtcTime.Second && rtcTime.Valid) {
midnight = loctime;
+ midnightnow = 1;
}
rtcTime.Year += 1970;
}
@@ -936,6 +947,70 @@ void rtc_init()
tickerRTC.attach(1, rtc_second);
}
+/*********************************************************************************************\
+ * Counter sensors (water meters, electricity meters etc.)
+\*********************************************************************************************/
+
+void counter_update(byte index)
+{
+// char log[LOGSZ];
+
+ unsigned long pTime = millis() - pTimeLast[index -1];
+ if (pTime > sysCfg.pCounterDebounce) {
+ pTimeLast[index -1] = millis();
+ if (bitRead(sysCfg.pCounterType, index -1)) {
+ rtcMem.pCounter[index -1] = pTime;
+ } else {
+ rtcMem.pCounter[index -1]++;
+ }
+
+// snprintf_P(log, sizeof(log), PSTR("CNTR: Interrupt %d"), index);
+// addLog(LOG_LEVEL_DEBUG, log);
+ }
+}
+
+void counter_update1()
+{
+ counter_update(1);
+}
+
+void counter_update2()
+{
+ counter_update(2);
+}
+
+void counter_update3()
+{
+ counter_update(3);
+}
+
+void counter_update4()
+{
+ counter_update(4);
+}
+
+void counter_savestate()
+{
+ for (byte i = 0; i < 4; i++) {
+ if (pin[GPIO_CNTR1 +i] < 99) {
+ sysCfg.pCounter[i] = rtcMem.pCounter[i];
+ }
+ }
+}
+
+void counter_init()
+{
+ typedef void (*function) () ;
+ function counter_callbacks[] = { counter_update1, counter_update2, counter_update3, counter_update4 };
+
+ for (byte i = 0; i < 4; i++) {
+ if (pin[GPIO_CNTR1 +i] < 99) {
+ pinMode(pin[GPIO_CNTR1 +i], INPUT_PULLUP);
+ attachInterrupt(pin[GPIO_CNTR1 +i], counter_callbacks[i], FALLING);
+ }
+ }
+}
+
/*********************************************************************************************\
* Miscellaneous
\*********************************************************************************************/
diff --git a/sonoff/user_config.h b/sonoff/user_config.h
index 6207269e2..10833a396 100644
--- a/sonoff/user_config.h
+++ b/sonoff/user_config.h
@@ -165,7 +165,7 @@
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+8k code, +1k mem) - Disable by //
#define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB)
-// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial TXD) (+1k mem)
+// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem)
// When USE_WS2812_DMA is enabled expect Exceptions on Pow
/*********************************************************************************************\
diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino
index d054b9185..960a7e5ef 100644
--- a/sonoff/webserver.ino
+++ b/sonoff/webserver.ino
@@ -250,6 +250,8 @@ const char HTTP_TABLE100[] PROGMEM =
"";
const char HTTP_COUNTER[] PROGMEM =
"
";
+const char HTTP_SNS_COUNTER[] PROGMEM =
+ "Counter%d | %d |
";
const char HTTP_SNS_TEMP[] PROGMEM =
"%s Temperature | %s°%c |
";
const char HTTP_SNS_HUM[] PROGMEM =
@@ -447,7 +449,7 @@ void handleRoot()
void handleAjax2()
{
- char svalue[16];
+ char svalue[80];
if (strlen(webServer->arg("o").c_str())) {
do_cmnd_power(atoi(webServer->arg("o").c_str()), 2);
@@ -458,6 +460,12 @@ void handleAjax2()
}
String tpage = "";
+ for (byte i = 0; i < 4; i++) {
+ if (pin[GPIO_CNTR1 +i] < 99) {
+ snprintf_P(svalue, sizeof(svalue), HTTP_SNS_COUNTER, i+1, rtcMem.pCounter[i]);
+ tpage += svalue;
+ }
+ }
if (hlw_flg) {
tpage += hlw_webPresent();
}
diff --git a/sonoff/xdrv_wemohue.ino b/sonoff/xdrv_wemohue.ino
index 559eb1588..720f1e138 100644
--- a/sonoff/xdrv_wemohue.ino
+++ b/sonoff/xdrv_wemohue.ino
@@ -346,10 +346,12 @@ void handleUPnPevent()
String request = webServer->arg(0);
if (request.indexOf("State>1 0) {
- do_cmnd_power(1, 1);
+// do_cmnd_power(1, 1);
+ do_cmnd_power(Maxdevice, 1);
}
if (request.indexOf("State>0 0) {
- do_cmnd_power(1, 0);
+// do_cmnd_power(1, 0);
+ do_cmnd_power(Maxdevice, 0);
}
webServer->send(200, F("text/plain"), "");
}
diff --git a/sonoff/xdrv_ws2812.ino b/sonoff/xdrv_ws2812.ino
index 6598c5398..5989984d8 100644
--- a/sonoff/xdrv_ws2812.ino
+++ b/sonoff/xdrv_ws2812.ino
@@ -107,6 +107,7 @@ RgbColor tcolor;
RgbColor lcolor;
uint8_t wakeupDimmer = 0;
+uint8_t ws_bit = 0;
uint16_t wakeupCntr = 0;
unsigned long stripTimerCntr = 0; // Bars and Gradient
@@ -394,7 +395,7 @@ void ws2812_animate()
uint8_t fadeValue;
stripTimerCntr++;
- if (0 == power) { // Power Off
+ if (0 == bitRead(power, ws_bit)) { // Power Off
sleep = sysCfg.sleep;
stripTimerCntr = 0;
tcolor = 0;
@@ -464,7 +465,7 @@ void ws2812_animate()
}
}
- if ((sysCfg.ws_scheme <= 1) || (!(power &1))) {
+ if ((sysCfg.ws_scheme <= 1) || (0 == bitRead(power, ws_bit))) {
if ((lcolor != tcolor) || lany) {
lany = 0;
lcolor = tcolor;
@@ -499,8 +500,9 @@ void ws2812_pixels()
lany = 1;
}
-void ws2812_init()
+void ws2812_init(uint8_t powerbit)
{
+ ws_bit = powerbit -1;
#ifdef USE_WS2812_DMA
#if (USE_WS2812_CTYPE == 1)
strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use.
@@ -544,14 +546,14 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_
if (6 == data_len) {
// ws2812_setColor(0, dataBufUc);
ws2812_setColor(0, dataBuf);
- power = 1;
+ bitSet(power, ws_bit);
}
ws2812_getColor(0, svalue, ssvalue);
}
else if (!strcmp_P(type,PSTR("DIMMER"))) {
if ((data_len > 0) && (payload >= 0) && (payload <= 100)) {
sysCfg.ws_dimmer = payload;
- power = 1;
+ bitSet(power, ws_bit);
#ifdef USE_DOMOTICZ
mqtt_publishDomoticzPowerState(index);
#endif // USE_DOMOTICZ
@@ -599,6 +601,23 @@ 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("UNDOCA"))) { // Theos WS2812 legacy status
+ RgbColor mcolor;
+ char mtopic[TOPSZ];
+ getTopic_P(mtopic, 1, sysCfg.mqtt_topic, type);
+ ws2812_setDim(sysCfg.ws_dimmer);
+ mcolor = dcolor;
+ uint32_t color = (uint32_t)mcolor.R << 16;
+ color += (uint32_t)mcolor.G << 8;
+ color += (uint32_t)mcolor.B;
+ snprintf_P(svalue, ssvalue, PSTR("%s, %s, %d, %d, %d, %06X, %d, 0, %d, %d, %d, %d, %d, %d"),
+ Version, sysCfg.mqtt_topic, bitRead(power, ws_bit), sysCfg.ws_fade, sysCfg.ws_dimmer, color,
+ sysCfg.ws_pixels, sysCfg.ws_wakeup,
+ sysCfg.ws_scheme, sysCfg.ws_speed, sysCfg.ws_width, sysCfg.timezone, sysCfg.ws_ledtable);
+ mqtt_publish(mtopic, svalue);
+// snprintf_P(svalue, ssvalue, PSTR("{\"UndocA\":\"Done\"}"));
+ svalue[0] = '\0';
+ }
else if (!strcmp_P(type,PSTR("WAKEUP"))) {
if ((data_len > 0) && (payload > 0) && (payload < 3601)) {
sysCfg.ws_wakeup = payload;
@@ -614,7 +633,7 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_
if (1 == sysCfg.ws_scheme) {
ws2812_resetWakupState();
}
- power = 1;
+ bitSet(power, ws_bit);
ws2812_resetStripTimer();
}
snprintf_P(svalue, ssvalue, PSTR("{\"Scheme\":%d}"), sysCfg.ws_scheme);
diff --git a/sonoff/xsns_hlw8012.ino b/sonoff/xsns_hlw8012.ino
index dacc79a8d..6d840ba3d 100644
--- a/sonoff/xsns_hlw8012.ino
+++ b/sonoff/xsns_hlw8012.ino
@@ -265,9 +265,6 @@ void hlw_init()
hlw_Ecntr = 0;
hlw_EDcntr = 0;
hlw_kWhtoday = (RTC_Valid()) ? rtcMem.hlw_kWhtoday : 0;
- if (sysCfg.hlw_kWhtotal > rtcMem.hlw_kWhtotal) {
- rtcMem.hlw_kWhtotal = sysCfg.hlw_kWhtotal;
- }
hlw_SELflag = 0; // Voltage;