5.1.3 20170520
* Add Domoticz Counter
This commit is contained in:
arendst 2017-05-20 14:03:34 +02:00
parent 26d3a8c191
commit 70ccdfe9b9
11 changed files with 167 additions and 107 deletions

View File

@ -1,7 +1,7 @@
## Sonoff-Tasmota ## 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. 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.2** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. Current version is **5.1.3** - 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 **** ### **** ATTENTION Version 5.x.x specific information ****

Binary file not shown.

View File

@ -1,4 +1,7 @@
/* 5.1.2 20170519 /* 5.1.3 20170520
* Add Domoticz Counter
*
* 5.1.2 20170519
* Fix Counter/Timer JSON message and update Counter/Timer on webpage * Fix Counter/Timer JSON message and update Counter/Timer on webpage
* Fix WS2812 Domoticz related regression issues * Fix WS2812 Domoticz related regression issues
* *

View File

@ -197,7 +197,7 @@ struct SYSCFG {
char mqtt_fulltopic[101]; char mqtt_fulltopic[101];
// 5.1.1 // 5.1.1
unsigned long pCounter[4]; unsigned long pCounter[MAX_COUNTERS];
uint16_t pCounterType; uint16_t pCounterType;
uint16_t pCounterDebounce; uint16_t pCounterDebounce;
@ -209,7 +209,7 @@ struct RTCMEM {
uint8_t power; uint8_t power;
unsigned long hlw_kWhtoday; unsigned long hlw_kWhtoday;
unsigned long hlw_kWhtotal; unsigned long hlw_kWhtotal;
unsigned long pCounter[4]; unsigned long pCounter[MAX_COUNTERS];
} rtcMem; } rtcMem;
// See issue https://github.com/esp8266/Arduino/issues/2913 // See issue https://github.com/esp8266/Arduino/issues/2913

View File

@ -642,7 +642,7 @@ void CFG_Delta()
if (sysCfg.version < 0x05010100) { if (sysCfg.version < 0x05010100) {
sysCfg.pCounterType = 0; sysCfg.pCounterType = 0;
sysCfg.pCounterDebounce = 0; sysCfg.pCounterDebounce = 0;
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < MAX_COUNTERS; i++) {
sysCfg.pCounter[i] = 0; sysCfg.pCounter[i] = 0;
rtcMem.pCounter[i] = 0; rtcMem.pCounter[i] = 0;
} }

View File

@ -24,7 +24,7 @@
- Select IDE Tools - Flash size: "1M (no SPIFFS)" - Select IDE Tools - Flash size: "1M (no SPIFFS)"
====================================================*/ ====================================================*/
#define VERSION 0x05010200 // 5.1.2 #define VERSION 0x05010300 // 5.1.3
enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; 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}; enum week_t {Last, First, Second, Third, Fourth};
@ -116,7 +116,7 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
#define MQTT_RETRY_SECS 10 // Minimum seconds to retry MQTT connection #define MQTT_RETRY_SECS 10 // Minimum seconds to retry MQTT connection
#define APP_POWER 0 // Default saved power state Off #define APP_POWER 0 // Default saved power state Off
#define MAX_DEVICE 1 // Max number of devices #define MAX_COUNTERS 4 // Max number of counter sensors
#define MAX_PULSETIMERS 4 // Max number of supported pulse timers #define MAX_PULSETIMERS 4 // Max number of supported pulse timers
#define WS2812_MAX_LEDS 256 // Max number of LEDs #define WS2812_MAX_LEDS 256 // Max number of LEDs
@ -240,7 +240,7 @@ int tele_period = 0; // Tele period timer
String Log[MAX_LOG_LINES]; // Web log buffer String Log[MAX_LOG_LINES]; // Web log buffer
byte logidx = 0; // Index in Web log buffer byte logidx = 0; // Index in Web log buffer
byte logajaxflg = 0; // Reset web console log byte logajaxflg = 0; // Reset web console log
byte Maxdevice = MAX_DEVICE; // Max number of devices supported byte Maxdevice = 0; // Max number of devices supported
int status_update_timer = 0; // Refresh initial status int status_update_timer = 0; // Refresh initial status
uint16_t pulse_timer[MAX_PULSETIMERS] = { 0 }; // Power off timer uint16_t pulse_timer[MAX_PULSETIMERS] = { 0 }; // Power off timer
uint16_t blink_timer = 0; // Power cycle timer uint16_t blink_timer = 0; // Power cycle timer
@ -251,7 +251,6 @@ uint8_t blink_powersave; // Blink start power save state
uint16_t mqtt_cmnd_publish = 0; // ignore flag for publish command uint16_t mqtt_cmnd_publish = 0; // ignore flag for publish command
uint8_t latching_power = 0; // Power state at latching start uint8_t latching_power = 0; // Power state at latching start
uint8_t latching_relay_pulse = 0; // Latching relay pulse timer uint8_t latching_relay_pulse = 0; // Latching relay pulse timer
unsigned long pTimeLast[4]; // Last counter time in milli seconds
#ifdef USE_MQTT_TLS #ifdef USE_MQTT_TLS
WiFiClientSecure espClient; // Wifi Secure Client WiFiClientSecure espClient; // Wifi Secure Client
@ -1211,14 +1210,14 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
} }
snprintf_P(svalue, sizeof(svalue), PSTR("%s}}"),svalue); snprintf_P(svalue, sizeof(svalue), PSTR("%s}}"),svalue);
} }
else if (!strcmp_P(type,PSTR("COUNTER")) && (index > 0) && (index <= 4)) { else if (!strcmp_P(type,PSTR("COUNTER")) && (index > 0) && (index <= MAX_COUNTERS)) {
if ((data_len > 0) && (pin[GPIO_CNTR1 + index -1] < 99)) { if ((data_len > 0) && (pin[GPIO_CNTR1 + index -1] < 99)) {
rtcMem.pCounter[index -1] = payload16; rtcMem.pCounter[index -1] = payload16;
sysCfg.pCounter[index -1] = payload16; sysCfg.pCounter[index -1] = payload16;
} }
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Counter%d\":%d}"), index, rtcMem.pCounter[index -1]); 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)) { else if (!strcmp_P(type,PSTR("COUNTERTYPE")) && (index > 0) && (index <= MAX_COUNTERS)) {
if ((data_len > 0) && (payload >= 0) && (payload <= 1) && (pin[GPIO_CNTR1 + index -1] < 99)) { if ((data_len > 0) && (payload >= 0) && (payload <= 1) && (pin[GPIO_CNTR1 + index -1] < 99)) {
bitWrite(sysCfg.pCounterType, index -1, payload &1); bitWrite(sysCfg.pCounterType, index -1, payload &1);
rtcMem.pCounter[index -1] = 0; rtcMem.pCounter[index -1] = 0;
@ -1799,8 +1798,6 @@ void state_mqttPresent(char* svalue, uint16_t ssvalue)
void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
{ {
char stemp[16];
snprintf_P(svalue, ssvalue, PSTR("%s{\"Time\":\"%s\""), svalue, getDateTime().c_str()); snprintf_P(svalue, ssvalue, PSTR("%s{\"Time\":\"%s\""), svalue, getDateTime().c_str());
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < 4; i++) {
if (pin[GPIO_SWT1 +i] < 99) { if (pin[GPIO_SWT1 +i] < 99) {
@ -1809,17 +1806,7 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
*djson = 1; *djson = 1;
} }
} }
for (byte i = 0; i < 4; i++) { counter_mqttPresent(svalue, ssvalue, djson);
if (pin[GPIO_CNTR1 +i] < 99) {
if (bitRead(sysCfg.pCounterType, i)) {
dtostrf((double)rtcMem.pCounter[i] / 1000, 1, 3, stemp);
} else {
dtostrf(rtcMem.pCounter[i], 1, 0, stemp);
}
snprintf_P(svalue, ssvalue, PSTR("%s, \"Counter%d\":%s"), svalue, i +1, stemp);
*djson = 1;
}
}
#ifndef USE_ADC_VCC #ifndef USE_ADC_VCC
if (pin[GPIO_ADC0] < 99) { if (pin[GPIO_ADC0] < 99) {
snprintf_P(svalue, ssvalue, PSTR("%s, \"AnalogInput0\":%d"), svalue, analogRead(A0)); snprintf_P(svalue, ssvalue, PSTR("%s, \"AnalogInput0\":%d"), svalue, analogRead(A0));

View File

@ -947,70 +947,6 @@ void rtc_init()
tickerRTC.attach(1, rtc_second); 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 * Miscellaneous
\*********************************************************************************************/ \*********************************************************************************************/

View File

@ -250,8 +250,6 @@ const char HTTP_TABLE100[] PROGMEM =
"<table style='width:100%'>"; "<table style='width:100%'>";
const char HTTP_COUNTER[] PROGMEM = const char HTTP_COUNTER[] PROGMEM =
"<br/><div id='t' name='t' style='text-align:center;'></div>"; "<br/><div id='t' name='t' style='text-align:center;'></div>";
const char HTTP_SNS_COUNTER[] PROGMEM =
"<tr><th>Counter%d</th><td>%s%s</td></tr>";
const char HTTP_SNS_TEMP[] PROGMEM = const char HTTP_SNS_TEMP[] PROGMEM =
"<tr><th>%s Temperature</th><td>%s&deg;%c</td></tr>"; "<tr><th>%s Temperature</th><td>%s&deg;%c</td></tr>";
const char HTTP_SNS_HUM[] PROGMEM = const char HTTP_SNS_HUM[] PROGMEM =
@ -450,7 +448,6 @@ void handleRoot()
void handleAjax2() void handleAjax2()
{ {
char svalue[16]; char svalue[16];
char sensor[80];
if (strlen(webServer->arg("o").c_str())) { if (strlen(webServer->arg("o").c_str())) {
do_cmnd_power(atoi(webServer->arg("o").c_str()), 2); do_cmnd_power(atoi(webServer->arg("o").c_str()), 2);
@ -461,17 +458,7 @@ void handleAjax2()
} }
String tpage = ""; String tpage = "";
for (byte i = 0; i < 4; i++) { tpage += counter_webPresent();
if (pin[GPIO_CNTR1 +i] < 99) {
if (bitRead(sysCfg.pCounterType, i)) {
dtostrf((double)rtcMem.pCounter[i] / 1000, 1, 3, svalue);
} else {
dtostrf(rtcMem.pCounter[i], 1, 0, svalue);
}
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_COUNTER, i+1, svalue, (bitRead(sysCfg.pCounterType, i)) ? " Sec" : "");
tpage += sensor;
}
}
if (hlw_flg) { if (hlw_flg) {
tpage += hlw_webPresent(); tpage += hlw_webPresent();
} }

View File

@ -19,7 +19,7 @@
#ifdef USE_DOMOTICZ #ifdef USE_DOMOTICZ
#define DOMOTICZ_MAX_SENSORS 5 #define DOMOTICZ_MAX_SENSORS 6
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
const char HTTP_FORM_DOMOTICZ[] PROGMEM = const char HTTP_FORM_DOMOTICZ[] PROGMEM =
@ -40,7 +40,7 @@ const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM =
#endif // USE_WEBSERVER #endif // USE_WEBSERVER
const char domoticz_sensors[DOMOTICZ_MAX_SENSORS][14] PROGMEM = const char domoticz_sensors[DOMOTICZ_MAX_SENSORS][14] PROGMEM =
{ "Temp", "Temp,Hum", "Temp,Hum,Baro", "Power,Energy", "Illuminance" }; { "Temp", "Temp,Hum", "Temp,Hum,Baro", "Power,Energy", "Illuminance", "Count" };
boolean domoticz_subscribe = false; boolean domoticz_subscribe = false;
int domoticz_update_timer = 0; int domoticz_update_timer = 0;
@ -329,6 +329,13 @@ void domoticz_sensor5(uint16_t lux)
dom_sensor(4, data); dom_sensor(4, data);
} }
void domoticz_sensor6(uint32_t count)
{
char data[16];
snprintf_P(data, sizeof(data), PSTR("%d"), count);
dom_sensor(5, data);
}
/*********************************************************************************************\ /*********************************************************************************************\
* Presentation * Presentation
\*********************************************************************************************/ \*********************************************************************************************/
@ -400,10 +407,11 @@ void domoticz_saveSettings()
sysCfg.domoticz_relay_idx[0], sysCfg.domoticz_relay_idx[1], sysCfg.domoticz_relay_idx[2], sysCfg.domoticz_relay_idx[3], sysCfg.domoticz_relay_idx[0], sysCfg.domoticz_relay_idx[1], sysCfg.domoticz_relay_idx[2], sysCfg.domoticz_relay_idx[3],
sysCfg.domoticz_update_timer); sysCfg.domoticz_update_timer);
addLog(LOG_LEVEL_INFO, log); addLog(LOG_LEVEL_INFO, log);
snprintf_P(log, sizeof(log), PSTR("HTTP: key %d, %d, %d, %d, switch %d, %d, %d, %d, sensor %d, %d, %d, %d, %d"), snprintf_P(log, sizeof(log), PSTR("HTTP: key %d, %d, %d, %d, switch %d, %d, %d, %d, sensor %d, %d, %d, %d, %d, %d"),
sysCfg.domoticz_key_idx[0], sysCfg.domoticz_key_idx[1], sysCfg.domoticz_key_idx[2], sysCfg.domoticz_key_idx[3], sysCfg.domoticz_key_idx[0], sysCfg.domoticz_key_idx[1], sysCfg.domoticz_key_idx[2], sysCfg.domoticz_key_idx[3],
sysCfg.domoticz_switch_idx[0], sysCfg.domoticz_switch_idx[1], sysCfg.domoticz_switch_idx[2], sysCfg.domoticz_switch_idx[3], sysCfg.domoticz_switch_idx[0], sysCfg.domoticz_switch_idx[1], sysCfg.domoticz_switch_idx[2], sysCfg.domoticz_switch_idx[3],
sysCfg.domoticz_sensor_idx[0], sysCfg.domoticz_sensor_idx[1], sysCfg.domoticz_sensor_idx[2], sysCfg.domoticz_sensor_idx[3], sysCfg.domoticz_sensor_idx[4]); sysCfg.domoticz_sensor_idx[0], sysCfg.domoticz_sensor_idx[1], sysCfg.domoticz_sensor_idx[2], sysCfg.domoticz_sensor_idx[3],
sysCfg.domoticz_sensor_idx[4], sysCfg.domoticz_sensor_idx[5]);
addLog(LOG_LEVEL_INFO, log); addLog(LOG_LEVEL_INFO, log);
} }
#endif // USE_WEBSERVER #endif // USE_WEBSERVER

139
sonoff/xsns_counter.ino Normal file
View File

@ -0,0 +1,139 @@
/*
xsns_counter.ino - Counter sensors (water meters, electricity meters etc.) sensor support for Sonoff-Tasmota
Copyright (C) 2017 Maarten Damen 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 <http://www.gnu.org/licenses/>.
*/
/*********************************************************************************************\
* Counter sensors (water meters, electricity meters etc.)
\*********************************************************************************************/
unsigned long pTimeLast[MAX_COUNTERS]; // Last counter time in milli seconds
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 < MAX_COUNTERS; 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 < MAX_COUNTERS; i++) {
if (pin[GPIO_CNTR1 +i] < 99) {
pinMode(pin[GPIO_CNTR1 +i], INPUT_PULLUP);
attachInterrupt(pin[GPIO_CNTR1 +i], counter_callbacks[i], FALLING);
}
}
}
/*********************************************************************************************\
* Presentation
\*********************************************************************************************/
void counter_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
{
char stemp[16];
byte dsxflg = 0;
for (byte i = 0; i < MAX_COUNTERS; i++) {
if (pin[GPIO_CNTR1 +i] < 99) {
if (bitRead(sysCfg.pCounterType, i)) {
dtostrf((double)rtcMem.pCounter[i] / 1000, 1, 3, stemp);
} else {
dsxflg++;
dtostrf(rtcMem.pCounter[i], 1, 0, stemp);
}
snprintf_P(svalue, ssvalue, PSTR("%s, \"Counter%d\":%s"), svalue, i +1, stemp);
*djson = 1;
#ifdef USE_DOMOTICZ
if (1 == dsxflg) {
domoticz_sensor6(rtcMem.pCounter[i]);
dsxflg++;
}
#endif // USE_DOMOTICZ
}
}
}
#ifdef USE_WEBSERVER
const char HTTP_SNS_COUNTER[] PROGMEM =
"<tr><th>Counter%d</th><td>%s%s</td></tr>";
String counter_webPresent()
{
String page = "";
char stemp[16];
char sensor[80];
for (byte i = 0; i < MAX_COUNTERS; i++) {
if (pin[GPIO_CNTR1 +i] < 99) {
if (bitRead(sysCfg.pCounterType, i)) {
dtostrf((double)rtcMem.pCounter[i] / 1000, 1, 3, stemp);
} else {
dtostrf(rtcMem.pCounter[i], 1, 0, stemp);
}
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_COUNTER, i+1, stemp, (bitRead(sysCfg.pCounterType, i)) ? " Sec" : "");
page += sensor;
}
}
return page;
}
#endif // USE_WEBSERVER

View File

@ -201,7 +201,7 @@ void ds18x20_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
svalue, stemp1, i +1, dsbstype, ds18x20_address(i).c_str(), stemp2); svalue, stemp1, i +1, dsbstype, ds18x20_address(i).c_str(), stemp2);
strcpy(stemp1, ", "); strcpy(stemp1, ", ");
#ifdef USE_DOMOTICZ #ifdef USE_DOMOTICZ
if (dsxflg == 1) domoticz_sensor1(stemp2); if (1 == dsxflg) domoticz_sensor1(stemp2);
#endif // USE_DOMOTICZ #endif // USE_DOMOTICZ
} }
} }