From a6cecfcb792f236bdbf7ef30e30674b1d42eb807 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 30 Dec 2019 16:42:53 +0100 Subject: [PATCH] Add support for ADC0 Current Transformer - Bump version to 8.1.0.2 - Add support for ``AdcParam`` parameters to control ADC0 Current Transformer Apparent Power formula by Jodi Dillon (#7100) --- RELEASENOTES.md | 3 +- tasmota/CHANGELOG.md | 4 + tasmota/i18n.h | 28 +++--- tasmota/language/bg-BG.h | 1 + tasmota/language/cs-CZ.h | 1 + tasmota/language/de-DE.h | 1 + tasmota/language/el-GR.h | 1 + tasmota/language/en-GB.h | 1 + tasmota/language/es-ES.h | 1 + tasmota/language/fr-FR.h | 1 + tasmota/language/he-HE.h | 1 + tasmota/language/hu-HU.h | 1 + tasmota/language/it-IT.h | 1 + tasmota/language/ko-KO.h | 1 + tasmota/language/nl-NL.h | 1 + tasmota/language/pl-PL.h | 1 + tasmota/language/pt-BR.h | 1 + tasmota/language/pt-PT.h | 1 + tasmota/language/ru-RU.h | 1 + tasmota/language/sk-SK.h | 1 + tasmota/language/sv-SE.h | 1 + tasmota/language/tr-TR.h | 1 + tasmota/language/uk-UA.h | 1 + tasmota/language/zh-CN.h | 1 + tasmota/language/zh-TW.h | 1 + tasmota/tasmota_template.h | 2 + tasmota/tasmota_version.h | 2 +- tasmota/xdrv_03_energy.ino | 9 +- tasmota/xsns_02_analog.ino | 176 +++++++++++++++++++++++++++++-------- 29 files changed, 190 insertions(+), 56 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a1324e1f1..30f05d21e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -52,7 +52,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ## Changelog -### Version 8.1.0.1 +### Version 8.1.0.2 - Change Lights: simplified gamma correction and 10 bits internal computation - Fix Sonoff Bridge, Sc, L1, iFan03 and CSE7766 serial interface to forced speed, config and disable logging @@ -63,3 +63,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add WifiPower to ``Status 5`` - Add support for DS1624, DS1621 Temperature sensor by Leonid Myravjev - Add Zigbee attribute decoder for Xiaomi Aqara Cube +- Add support for ``AdcParam`` parameters to control ADC0 Current Transformer Apparent Power formula by Jodi Dillon (#7100) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 172afb56a..99aca3e2c 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -1,5 +1,9 @@ ## Unreleased (development) +### 8.1.0.2 20191230 + +- Add support for ``AdcParam`` parameters to control ADC0 Current Transformer Apparent Power formula by Jodi Dillon (#7100) + ### 8.1.0.1 20191225 - Change Lights: simplified gamma correction and 10 bits internal computation diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 9e33de8bb..bb8174e50 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -59,6 +59,7 @@ #define D_JSON_ECO2 "eCO2" #define D_JSON_EMPTY "Empty" #define D_JSON_ENDDST "EndDST" // End Daylight Savings Time +#define D_JSON_ENERGY "Energy" #define D_JSON_ERASE "Erase" #define D_JSON_ERROR "Error" #define D_JSON_EVERY "Every" @@ -613,18 +614,23 @@ static const char kMonthNames[] = D_MONTH3LIST; // xdrv_02_webserver.ino #ifdef USE_WEBSERVER -const char HTTP_SNS_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%s°%c{e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_HUM[] PROGMEM = "{s}%s " D_HUMIDITY "{m}%s%%{e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_PRESSURE[] PROGMEM = "{s}%s " D_PRESSURE "{m}%s %s{e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "{s}%s " D_PRESSUREATSEALEVEL "{m}%s %s{e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_ANALOG[] PROGMEM = "{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_ILLUMINANCE[] PROGMEM = "{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_CO2[] PROGMEM = "{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_CO2EAVG[] PROGMEM = "{s}%s " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_GALLONS[] PROGMEM = "{s}%s " D_TOTAL_USAGE "{m}%s " D_UNIT_GALLONS " {e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_GPM[] PROGMEM = "{s}%s " D_FLOW_RATE "{m}%s " D_UNIT_GALLONS_PER_MIN" {e}"; // {s} = , {m} = , {e} = -const char HTTP_SNS_MOISTURE[] PROGMEM = "{s}%s " D_MOISTURE "{m}%d %%{e}"; // {s} = , {m} = , {e} = +// {s} = , {m} = , {e} = +const char HTTP_SNS_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%s°%c{e}"; +const char HTTP_SNS_HUM[] PROGMEM = "{s}%s " D_HUMIDITY "{m}%s%%{e}"; +const char HTTP_SNS_PRESSURE[] PROGMEM = "{s}%s " D_PRESSURE "{m}%s %s{e}"; +const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "{s}%s " D_PRESSUREATSEALEVEL "{m}%s %s{e}"; +const char HTTP_SNS_ANALOG[] PROGMEM = "{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; +const char HTTP_SNS_ILLUMINANCE[] PROGMEM = "{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; +const char HTTP_SNS_CO2[] PROGMEM = "{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; +const char HTTP_SNS_CO2EAVG[] PROGMEM = "{s}%s " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; +const char HTTP_SNS_GALLONS[] PROGMEM = "{s}%s " D_TOTAL_USAGE "{m}%s " D_UNIT_GALLONS " {e}"; +const char HTTP_SNS_GPM[] PROGMEM = "{s}%s " D_FLOW_RATE "{m}%s " D_UNIT_GALLONS_PER_MIN" {e}"; +const char HTTP_SNS_MOISTURE[] PROGMEM = "{s}%s " D_MOISTURE "{m}%d %%{e}"; +const char HTTP_SNS_VOLTAGE[] PROGMEM = "{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"; +const char HTTP_SNS_CURRENT[] PROGMEM = "{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"; +const char HTTP_SNS_POWER[] PROGMEM = "{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"; +const char HTTP_SNS_ENERGY_TOTAL[] PROGMEM = "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; const char S_MAIN_MENU[] PROGMEM = D_MAIN_MENU; const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION; diff --git a/tasmota/language/bg-BG.h b/tasmota/language/bg-BG.h index 22e99f9f9..cb1efbbf3 100644 --- a/tasmota/language/bg-BG.h +++ b/tasmota/language/bg-BG.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS домейн" #define D_COUNT "Брой" #define D_COUNTER "Брояч" +#define D_CT_POWER "CT Power" #define D_CURRENT "Ток" // As in Voltage and Current #define D_DATA "Данни" #define D_DARKLIGHT "Тъмна" diff --git a/tasmota/language/cs-CZ.h b/tasmota/language/cs-CZ.h index 92ba99b30..fbed64c80 100644 --- a/tasmota/language/cs-CZ.h +++ b/tasmota/language/cs-CZ.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Počítej" #define D_COUNTER "Počítadlo" +#define D_CT_POWER "CT Power" #define D_CURRENT "Proud" // As in Voltage and Current #define D_DATA "Data" #define D_DARKLIGHT "Tmavý" diff --git a/tasmota/language/de-DE.h b/tasmota/language/de-DE.h index 455e22ff6..5e9f43002 100644 --- a/tasmota/language/de-DE.h +++ b/tasmota/language/de-DE.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "zählen" #define D_COUNTER "Zähler" +#define D_CT_POWER "CT Power" #define D_CURRENT "Strom" // As in Voltage and Current #define D_DATA "Daten" #define D_DARKLIGHT "dunkel" diff --git a/tasmota/language/el-GR.h b/tasmota/language/el-GR.h index 15b78fea7..97c2fb063 100644 --- a/tasmota/language/el-GR.h +++ b/tasmota/language/el-GR.h @@ -74,6 +74,7 @@ #define D_COUNT "Μέτρηση" #define D_CORS_DOMAIN "CORS Domain" #define D_COUNTER "Μετρητής" +#define D_CT_POWER "CT Power" #define D_CURRENT "Ένταση" // As in Voltage and Current #define D_DATA "Δεδομένα" #define D_DARKLIGHT "Σκοτεινό" diff --git a/tasmota/language/en-GB.h b/tasmota/language/en-GB.h index 4062a1b84..7f92ac447 100644 --- a/tasmota/language/en-GB.h +++ b/tasmota/language/en-GB.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Count" #define D_COUNTER "Counter" +#define D_CT_POWER "CT Power" #define D_CURRENT "Current" // As in Voltage and Current #define D_DATA "Data" #define D_DARKLIGHT "Dark" diff --git a/tasmota/language/es-ES.h b/tasmota/language/es-ES.h index 111ead8dc..c4ab3d239 100644 --- a/tasmota/language/es-ES.h +++ b/tasmota/language/es-ES.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "Sitio WEB para CORS" #define D_COUNT "Conteo" #define D_COUNTER "Contador" +#define D_CT_POWER "CT Power" #define D_CURRENT "Corriente" // As in Voltage and Current #define D_DATA "Datos" #define D_DARKLIGHT "Oscuro" diff --git a/tasmota/language/fr-FR.h b/tasmota/language/fr-FR.h index c84610379..f9f2d0d87 100644 --- a/tasmota/language/fr-FR.h +++ b/tasmota/language/fr-FR.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "Domaine CORS" #define D_COUNT "Compte" #define D_COUNTER "Compteur" +#define D_CT_POWER "CT Power" #define D_CURRENT "Courant" // As in Voltage and Current #define D_DATA "Donnée" #define D_DARKLIGHT "Sombre" diff --git a/tasmota/language/he-HE.h b/tasmota/language/he-HE.h index d21750fba..1cbab98c9 100644 --- a/tasmota/language/he-HE.h +++ b/tasmota/language/he-HE.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "סופר" #define D_COUNTER "מונה" +#define D_CT_POWER "CT Power" #define D_CURRENT "נוכחי" // As in Voltage and Current #define D_DATA "נתונים" #define D_DARKLIGHT "חושך" diff --git a/tasmota/language/hu-HU.h b/tasmota/language/hu-HU.h index da61d1ffd..b43fda2bb 100644 --- a/tasmota/language/hu-HU.h +++ b/tasmota/language/hu-HU.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Szám" #define D_COUNTER "Számláló" +#define D_CT_POWER "CT Power" #define D_CURRENT "Áramerősség" // As in Voltage and Current #define D_DATA "Adat" #define D_DARKLIGHT "Min. fényerő" diff --git a/tasmota/language/it-IT.h b/tasmota/language/it-IT.h index ca584ec8e..bd5f145a0 100644 --- a/tasmota/language/it-IT.h +++ b/tasmota/language/it-IT.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Conteggio" #define D_COUNTER "Contatore" +#define D_CT_POWER "CT Power" #define D_CURRENT "Corrente" // As in Voltage and Current #define D_DATA "Dati" #define D_DARKLIGHT "Scuro" diff --git a/tasmota/language/ko-KO.h b/tasmota/language/ko-KO.h index b85f60bce..edddc292b 100644 --- a/tasmota/language/ko-KO.h +++ b/tasmota/language/ko-KO.h @@ -74,6 +74,7 @@ #define D_COUNT "횟수" #define D_CORS_DOMAIN "CORS Domain" #define D_COUNTER "Counter" +#define D_CT_POWER "CT Power" #define D_CURRENT "전류" // As in Voltage and Current #define D_DATA "Data" #define D_DARKLIGHT "어둡게" diff --git a/tasmota/language/nl-NL.h b/tasmota/language/nl-NL.h index 1fde4786d..e475e7af8 100644 --- a/tasmota/language/nl-NL.h +++ b/tasmota/language/nl-NL.h @@ -74,6 +74,7 @@ #define D_COUNT "Aantal" #define D_CORS_DOMAIN "CORS Domain" #define D_COUNTER "Teller" +#define D_CT_POWER "CT Power" #define D_CURRENT "Stroom" // As in Voltage and Current #define D_DATA "Data" #define D_DARKLIGHT "Donker" diff --git a/tasmota/language/pl-PL.h b/tasmota/language/pl-PL.h index f8250eda2..0ee1d10a5 100644 --- a/tasmota/language/pl-PL.h +++ b/tasmota/language/pl-PL.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "Domena CORS" #define D_COUNT "Licz" #define D_COUNTER "Licznik" +#define D_CT_POWER "CT Power" #define D_CURRENT "Prąd" // As in Voltage and Current #define D_DATA "Data" #define D_DARKLIGHT "Ciemny" diff --git a/tasmota/language/pt-BR.h b/tasmota/language/pt-BR.h index f5390be86..b5198d81a 100644 --- a/tasmota/language/pt-BR.h +++ b/tasmota/language/pt-BR.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Contagem" #define D_COUNTER "Contador" +#define D_CT_POWER "CT Power" #define D_CURRENT "Corrente" // As in Voltage and Current #define D_DATA "Dados" #define D_DARKLIGHT "Luz escura" diff --git a/tasmota/language/pt-PT.h b/tasmota/language/pt-PT.h index 154bebd70..bae64f156 100644 --- a/tasmota/language/pt-PT.h +++ b/tasmota/language/pt-PT.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Contagem" #define D_COUNTER "Contador" +#define D_CT_POWER "CT Power" #define D_CURRENT "Corrente" // As in Voltage and Current #define D_DATA "Dados" #define D_DARKLIGHT "Luz Escura" diff --git a/tasmota/language/ru-RU.h b/tasmota/language/ru-RU.h index 89567f11f..1d59105e0 100644 --- a/tasmota/language/ru-RU.h +++ b/tasmota/language/ru-RU.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Подсчет" #define D_COUNTER "Счетчик" +#define D_CT_POWER "CT Power" #define D_CURRENT "Ток" // As in Voltage and Current #define D_DATA "Данные" #define D_DARKLIGHT "Темный" diff --git a/tasmota/language/sk-SK.h b/tasmota/language/sk-SK.h index c42130e11..4373b4957 100644 --- a/tasmota/language/sk-SK.h +++ b/tasmota/language/sk-SK.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Počítaj" #define D_COUNTER "Počítadlo" +#define D_CT_POWER "CT Power" #define D_CURRENT "Prúd" // As in Voltage and Current #define D_DATA "Dáta" #define D_FLOW_RATE "Flow rate" diff --git a/tasmota/language/sv-SE.h b/tasmota/language/sv-SE.h index 074c81c8e..e37212998 100644 --- a/tasmota/language/sv-SE.h +++ b/tasmota/language/sv-SE.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Räkna" #define D_COUNTER "Räknare" +#define D_CT_POWER "CT Power" #define D_CURRENT "Ström" // As in Voltage and Current #define D_DATA "Data" #define D_DARKLIGHT "Mörkt" diff --git a/tasmota/language/tr-TR.h b/tasmota/language/tr-TR.h index 04cc270ec..9990f6b03 100644 --- a/tasmota/language/tr-TR.h +++ b/tasmota/language/tr-TR.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "Sayı" #define D_COUNTER "Sayaç" +#define D_CT_POWER "CT Power" #define D_CURRENT "Current" // As in Voltage and Current #define D_DATA "Data" #define D_DARKLIGHT "Karanlık" diff --git a/tasmota/language/uk-UA.h b/tasmota/language/uk-UA.h index af7672973..9b1c9d52f 100644 --- a/tasmota/language/uk-UA.h +++ b/tasmota/language/uk-UA.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "Домен CORS" #define D_COUNT "разів" #define D_COUNTER "Лічильник" +#define D_CT_POWER "CT Power" #define D_CURRENT "Струм" // As in Voltage and Current #define D_DATA "Дані" #define D_DARKLIGHT "Темний" diff --git a/tasmota/language/zh-CN.h b/tasmota/language/zh-CN.h index 4c75b7bb7..c55500e4c 100644 --- a/tasmota/language/zh-CN.h +++ b/tasmota/language/zh-CN.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "数量:" #define D_COUNTER "计数器" +#define D_CT_POWER "CT Power" #define D_CURRENT "电流" // As in Voltage and Current #define D_DATA "数据:" #define D_DARKLIGHT "暗" diff --git a/tasmota/language/zh-TW.h b/tasmota/language/zh-TW.h index f17ba46b7..11c1f77a2 100644 --- a/tasmota/language/zh-TW.h +++ b/tasmota/language/zh-TW.h @@ -74,6 +74,7 @@ #define D_CORS_DOMAIN "CORS Domain" #define D_COUNT "數量:" #define D_COUNTER "Counter" +#define D_CT_POWER "CT Power" #define D_CURRENT "電流" // As in Voltage and Current #define D_DATA "數據:" #define D_DARKLIGHT "Dark" diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 685546b91..24037dcbe 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -312,6 +312,7 @@ enum UserSelectableAdc0 { ADC0_BUTTON, // Button ADC0_BUTTON_INV, ADC0_MOIST, // Moisture + ADC0_CT_POWER, // Current // ADC0_SWITCH, // Switch // ADC0_SWITCH_INV, ADC0_END }; @@ -328,6 +329,7 @@ const char kAdc0Names[] PROGMEM = D_TEMPERATURE "|" D_LIGHT "|" D_SENSOR_BUTTON "|" D_SENSOR_BUTTON "i|" D_MOISTURE "|" + D_CT_POWER "|" // D_SENSOR_SWITCH "|" D_SENSOR_SWITCH "i|" ; diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index 8bc0a50e1..a1dac458d 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -20,7 +20,7 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x08010001; +const uint32_t VERSION = 0x08010002; // Lowest compatible version const uint32_t VERSION_COMPATIBLE = 0x07010006; diff --git a/tasmota/xdrv_03_energy.ino b/tasmota/xdrv_03_energy.ino index 6d8be5c2b..95c73754f 100644 --- a/tasmota/xdrv_03_energy.ino +++ b/tasmota/xdrv_03_energy.ino @@ -1062,15 +1062,12 @@ void EnergyShow(bool json) #ifdef USE_WEBSERVER } else { if (Energy.voltage_available) { - WSContentSend_PD(PSTR("{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"), - EnergyFormat(value_chr, voltage_chr[0], json, Energy.voltage_common)); + WSContentSend_PD(HTTP_SNS_VOLTAGE, EnergyFormat(value_chr, voltage_chr[0], json, Energy.voltage_common)); } if (Energy.current_available) { - WSContentSend_PD(PSTR("{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"), - EnergyFormat(value_chr, current_chr[0], json)); + WSContentSend_PD(HTTP_SNS_CURRENT, EnergyFormat(value_chr, current_chr[0], json)); } - WSContentSend_PD(PSTR("{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"), - EnergyFormat(value_chr, active_power_chr[0], json)); + WSContentSend_PD(HTTP_SNS_POWER, EnergyFormat(value_chr, active_power_chr[0], json)); if (!Energy.type_dc) { if (Energy.current_available && Energy.voltage_available) { WSContentSend_PD(HTTP_ENERGY_SNS1, EnergyFormat(value_chr, apparent_power_chr[0], json), diff --git a/tasmota/xsns_02_analog.ino b/tasmota/xsns_02_analog.ino index 3dd974918..5bfe8c26d 100644 --- a/tasmota/xsns_02_analog.ino +++ b/tasmota/xsns_02_analog.ino @@ -47,8 +47,27 @@ #define ANALOG_LDR_LUX_CALC_SCALAR 12518931 // Experimental #define ANALOG_LDR_LUX_CALC_EXPONENT -1.4050 // Experimental -uint16_t adc_last_value = 0; -float adc_temp = 0; +// CT Based Apparrent Power Measurement Parameters +// 3V3 --- R1 ----v--- R1 --- Gnd +// | +// CT+ CT- +// | +// ADC0 +// Default settings for a 20A/1V Current Transformer. +// Analog peak to peak range is measured and converted to RMS current using ANALOG_CT_MULTIPLIER +#define ANALOG_CT_FLAGS 0 // (uint32_t) reserved for possible future use +#define ANALOG_CT_MULTIPLIER 2146 // (uint32_t) Multiplier*100000 to convert raw ADC peak to peak range 0..1023 to RMS current in Amps. Value of 100000 corresponds to 1 +#define ANALOG_CT_VOLTAGE 2300 // (int) Convert current in Amps to apparrent power in Watts using voltage in Volts*10. Value of 2200 corresponds to 220V + +#define CT_FLAG_ENERGY_RESET (1 << 0) // Reset energy total + +struct { + float temperature = 0; + float current = 0; + float energy = 0; + uint32_t previous_millis = 0; + uint16_t last_value = 0; +} Adc; void AdcInit(void) { @@ -72,6 +91,12 @@ void AdcInit(void) Settings.adc_param2 = 1023; Settings.adc_param3 = 0; } + else if (ADC0_CT_POWER == my_adc0) { + Settings.adc_param_type = ADC0_CT_POWER; + Settings.adc_param1 = ANALOG_CT_FLAGS; //(uint32_t) 0 + Settings.adc_param2 = ANALOG_CT_MULTIPLIER; //(uint32_t) 100000 + Settings.adc_param3 = ANALOG_CT_VOLTAGE; //(int) 10 + } } } @@ -97,9 +122,9 @@ void AdcEvery250ms(void) { if (ADC0_INPUT == my_adc0) { uint16_t new_value = AdcRead(5); - if ((new_value < adc_last_value -10) || (new_value > adc_last_value +10)) { - adc_last_value = new_value; - uint16_t value = adc_last_value / 10; + if ((new_value < Adc.last_value -10) || (new_value > Adc.last_value +10)) { + Adc.last_value = new_value; + uint16_t value = Adc.last_value / 10; Response_P(PSTR("{\"ANALOG\":{\"A0div10\":%d}}"), (value > 99) ? 100 : value); XdrvRulesProcess(); } @@ -120,17 +145,45 @@ uint16_t AdcGetLux(void) } uint16_t AdcGetMoist(void) -// formula for calibration: value, fromLow, fromHigh, toHigh, toLow -// Example: 632, 0, 1023, 100, 0 -// int( ( ( ( - ) / ( - ) ) * ( - ) ) + ) -// double amoist = ((Settings.adc_param2 - (double)adc) / (Settings.adc_param2 - Settings.adc_param1) * 100; -// int((((1023 - ) / ( 1023 - 0 )) * ( 100 - 0 )) + 0 ) - { - int adc = AdcRead(2); - double amoist = ((double)Settings.adc_param2 - (double)adc) / ((double)Settings.adc_param2 - (double)Settings.adc_param1) * 100; - //double amoist = ((1023 - (double)adc) / 1023) * 100; - return (uint16_t)amoist; + // formula for calibration: value, fromLow, fromHigh, toHigh, toLow + // Example: 632, 0, 1023, 100, 0 + // int( ( ( ( - ) / ( - ) ) * ( - ) ) + ) + // double amoist = ((Settings.adc_param2 - (double)adc) / (Settings.adc_param2 - Settings.adc_param1) * 100; + // int((((1023 - ) / ( 1023 - 0 )) * ( 100 - 0 )) + 0 ) + int adc = AdcRead(2); + double amoist = ((double)Settings.adc_param2 - (double)adc) / ((double)Settings.adc_param2 - (double)Settings.adc_param1) * 100; + //double amoist = ((1023 - (double)adc) / 1023) * 100; + return (uint16_t)amoist; +} + +void AdcGetCurrentPower(uint8_t factor) +{ + // factor 1 = 2 samples + // factor 2 = 4 samples + // factor 3 = 8 samples + // factor 4 = 16 samples + // factor 5 = 32 samples + uint8_t samples = 1 << factor; + uint16_t analog = 0; + uint16_t analog_min = 1023; + uint16_t analog_max = 0; + for (uint32_t i = 0; i < samples; i++) { + analog = analogRead(A0); + if (analog < analog_min) { + analog_min = analog; + } + if (analog > analog_max) { + analog_max = analog; + } + delay(1); + } + + Adc.current = (float)(analog_max-analog_min) * ((float)(Settings.adc_param2) / 100000); + float power = Adc.current * (float)(Settings.adc_param3) / 10; + uint32_t current_millis = millis(); + Adc.energy = Adc.energy + ((power * (current_millis - Adc.previous_millis)) / 3600000000); + Adc.previous_millis = current_millis; } void AdcEverySecond(void) @@ -141,7 +194,10 @@ void AdcEverySecond(void) double Rt = (adc * Settings.adc_param1) / (1024.0 * ANALOG_V33 - (double)adc); double BC = (double)Settings.adc_param3 / 10000; double T = BC / (BC / ANALOG_T0 + TaylorLog(Rt / (double)Settings.adc_param2)); - adc_temp = ConvertTemp(TO_CELSIUS(T)); + Adc.temperature = ConvertTemp(TO_CELSIUS(T)); + } + else if (ADC0_CT_POWER == my_adc0) { + AdcGetCurrentPower(5); } } @@ -158,9 +214,10 @@ void AdcShow(bool json) #endif // USE_WEBSERVER } } + else if (ADC0_TEMP == my_adc0) { char temperature[33]; - dtostrfd(adc_temp, Settings.flag2.temperature_resolution, temperature); + dtostrfd(Adc.temperature, Settings.flag2.temperature_resolution, temperature); if (json) { ResponseAppend_P(JSON_SNS_TEMP, "ANALOG", temperature); @@ -171,7 +228,7 @@ void AdcShow(bool json) #endif // USE_DOMOTICZ #ifdef USE_KNX if (0 == tele_period) { - KnxSensor(KNX_TEMPERATURE, adc_temp); + KnxSensor(KNX_TEMPERATURE, Adc.temperature); } #endif // USE_KNX #ifdef USE_WEBSERVER @@ -180,6 +237,7 @@ void AdcShow(bool json) #endif // USE_WEBSERVER } } + else if (ADC0_LIGHT == my_adc0) { uint16_t adc_light = AdcGetLux(); @@ -196,6 +254,7 @@ void AdcShow(bool json) #endif // USE_WEBSERVER } } + else if (ADC0_MOIST == my_adc0) { uint16_t adc_moist = AdcGetMoist(); @@ -207,6 +266,40 @@ void AdcShow(bool json) #endif // USE_WEBSERVER } } + + else if (ADC0_CT_POWER == my_adc0) { + AdcGetCurrentPower(5); + + float voltage = (float)(Settings.adc_param3) / 10; + char voltage_chr[FLOATSZ]; + dtostrfd(voltage, Settings.flag2.voltage_resolution, voltage_chr); + char current_chr[FLOATSZ]; + dtostrfd(Adc.current, Settings.flag2.current_resolution, current_chr); + char power_chr[FLOATSZ]; + dtostrfd(voltage * Adc.current, Settings.flag2.wattage_resolution, power_chr); + char energy_chr[FLOATSZ]; + dtostrfd(Adc.energy, Settings.flag2.energy_resolution, energy_chr); + + if (json) { + ResponseAppend_P(PSTR(",\"ANALOG\":{\"" D_JSON_ENERGY "\":%s,\"" D_JSON_POWERUSAGE "\":%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"), + energy_chr, power_chr, voltage_chr, current_chr); +#ifdef USE_DOMOTICZ + if (0 == tele_period) { + DomoticzSensor(DZ_POWER_ENERGY, power_chr); + DomoticzSensor(DZ_VOLTAGE, voltage_chr); + DomoticzSensor(DZ_CURRENT, current_chr); + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_VOLTAGE, voltage_chr); + WSContentSend_PD(HTTP_SNS_CURRENT, current_chr); + WSContentSend_PD(HTTP_SNS_POWER, power_chr); + WSContentSend_PD(HTTP_SNS_ENERGY_TOTAL, energy_chr); +#endif // USE_WEBSERVER + } + } + } /*********************************************************************************************\ @@ -247,23 +340,31 @@ void CmndAdcs(void) void CmndAdcParam(void) { if (XdrvMailbox.data_len) { - if ((ADC0_TEMP == XdrvMailbox.payload) || (ADC0_LIGHT == XdrvMailbox.payload) || (ADC0_MOIST == XdrvMailbox.payload)) { -// if ((XdrvMailbox.payload == my_adc0) && ((ADC0_TEMP == my_adc0) || (ADC0_LIGHT == my_adc0))) { + if ((ADC0_TEMP == XdrvMailbox.payload) || + (ADC0_LIGHT == XdrvMailbox.payload) || + (ADC0_MOIST == XdrvMailbox.payload) || + (ADC0_CT_POWER == XdrvMailbox.payload)) { if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry char sub_string[XdrvMailbox.data_len +1]; // AdcParam 2, 32000, 10000, 3350 // AdcParam 3, 10000, 12518931, -1.405 Settings.adc_param_type = XdrvMailbox.payload; -// Settings.adc_param_type = my_adc0; Settings.adc_param1 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.adc_param2 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 3), nullptr, 10); if (!ADC0_MOIST == XdrvMailbox.payload) { Settings.adc_param3 = (int)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 4)) * 10000); } + if (ADC0_CT_POWER == XdrvMailbox.payload) { + if ((Settings.adc_param1 & CT_FLAG_ENERGY_RESET) > 0) { + Adc.energy = 0; + Settings.adc_param1 ^= CT_FLAG_ENERGY_RESET; // Cancel energy reset flag + } + } } else { // Set default values based on current adc type // AdcParam 2 // AdcParam 3 // AdcParam 6 + // AdcParam 7 Settings.adc_param_type = 0; AdcInit(); } @@ -271,22 +372,19 @@ void CmndAdcParam(void) } // AdcParam - int value = Settings.adc_param3; - uint8_t precision; - for (precision = 4; precision > 0; precision--) { - if (value % 10) { break; } - value /= 10; - } - char param3[33]; - dtostrfd(((double)Settings.adc_param3)/10000, precision, param3); - if ((ADC0_TEMP == my_adc0) || (ADC0_LIGHT == my_adc0)) { - Response_P(PSTR("{\"" D_CMND_ADCPARAM "\":[%d,%d,%d,%s]}"), - Settings.adc_param_type, Settings.adc_param1, Settings.adc_param2, param3); - } - else if (ADC0_MOIST == my_adc0) { - Response_P(PSTR("{\"" D_CMND_ADCPARAM "\":[%d,%d,%d]}"), - Settings.adc_param_type, Settings.adc_param1, Settings.adc_param2); + Response_P(PSTR("{\"" D_CMND_ADCPARAM "\":[%d,%d,%d"), Settings.adc_param_type, Settings.adc_param1, Settings.adc_param2); + if (ADC0_MOIST != my_adc0) { + int value = Settings.adc_param3; + uint8_t precision; + for (precision = 4; precision > 0; precision--) { + if (value % 10) { break; } + value /= 10; + } + char param3[33]; + dtostrfd(((double)Settings.adc_param3)/10000, precision, param3); + ResponseAppend_P(PSTR(",%s"), param3); } + ResponseAppend_P(PSTR("]}")); } /*********************************************************************************************\ @@ -302,7 +400,11 @@ bool Xsns02(uint8_t function) result = DecodeCommand(kAdcCommands, AdcCommand); break; default: - if ((ADC0_INPUT == my_adc0) || (ADC0_TEMP == my_adc0) || (ADC0_LIGHT == my_adc0) || (ADC0_MOIST == my_adc0)) { + if ((ADC0_INPUT == my_adc0) || + (ADC0_TEMP == my_adc0) || + (ADC0_LIGHT == my_adc0) || + (ADC0_MOIST == my_adc0) || + (ADC0_CT_POWER == my_adc0)) { switch (function) { #ifdef USE_RULES case FUNC_EVERY_250_MSECOND: