mirror of
https://github.com/arendst/Tasmota.git
synced 2025-04-24 06:47:17 +00:00
commit
aa45f164f0
13
README.md
13
README.md
@ -59,7 +59,7 @@ See [Community](https://groups.google.com/d/forum/sonoffusers) for forum.<br />
|
||||
See [Chat](https://discord.gg/Ks2Kzd4) for more user experience.
|
||||
|
||||
The following devices are supported:
|
||||
- [iTead Sonoff Basic](https://www.itead.cc/smart-home/sonoff-wifi-wireless-switch-1.html)
|
||||
- [iTead Sonoff Basic (R2)](https://www.itead.cc/smart-home/sonoff-wifi-wireless-switch-1.html)
|
||||
- [iTead Sonoff RF](https://www.itead.cc/smart-home/sonoff-rf.html)
|
||||
- [iTead Sonoff SV](https://www.itead.cc/smart-home/sonoff-sv.html)<img src="https://github.com/arendst/arendst.github.io/blob/master/media/sonoff_th.jpg" width="250" align="right" />
|
||||
- [iTead Sonoff TH10/TH16 with temperature sensor](https://www.itead.cc/smart-home/sonoff-th.html)
|
||||
@ -90,10 +90,15 @@ The following devices are supported:
|
||||
- [MagicHome PWM LED controller](https://github.com/arendst/Sonoff-Tasmota/wiki/MagicHome-LED-strip-controller)
|
||||
- AriLux AL-LC01, AL-LC06 and AL-LC11 PWM LED controller
|
||||
- [Supla device - Espablo-inCan mod. for electrical Installation box](https://forum.supla.org/viewtopic.php?f=33&t=2188)
|
||||
- [BlitzWolf BW-SHP2 Smart Socket with Energy Monitoring](https://www.banggood.com/BlitzWolf-BW-SHP2-Smart-WIFI-Socket-EU-Plug-220V-16A-Work-with-Amazon-Alexa-Google-Assistant-p-1292899.html)
|
||||
- [BlitzWolf BW-SHP2 Smart Socket with Energy Monitoring](https://www.banggood.com/BlitzWolf-BW-SHP2-Smart-WIFI-Socket-EU-Plug-220V-16A-Work-with-Amazon-Alexa-Google-Assistant-p-1292899.html)<img src="https://github.com/arendst/arendst.github.io/blob/master/media/shelly2_small_250a.png" width="250" align="right" />
|
||||
- [Luani HVIO board](https://luani.de/projekte/esp8266-hvio/)
|
||||
- Xiaomi-Phillips Bulbs
|
||||
- Wemos D1 mini, NodeMcu and Ledunia
|
||||
- [Wemos D1 mini](https://wiki.wemos.cc/products:d1:d1_mini)
|
||||
- [HuaFan Smart Socket](HuaFan-Smart-Socket)
|
||||
- [Hyleton-313 Smart Plug](Hyleton-313-Smart-Plug)
|
||||
- [Allterco Shelly 1](https://shelly.cloud/shelly1-open-source/)
|
||||
- [Allterco Shelly 2 with Energy Monitoring](https://shelly.cloud/shelly2/)
|
||||
- NodeMcu and Ledunia
|
||||
- [KS-602 based switches like GresaTek, Jesiya, NewRice, Lyasi etc](https://ucexperiment.wordpress.com/2017/11/14/reprogramming-a-lyasi-wifi-wall-switch-with-esp8285/)
|
||||
|
||||
### Contribute
|
||||
You can contribute to Sonoff-Tasmota by
|
||||
|
@ -16,6 +16,7 @@ env_default = sonoff
|
||||
;env_default = sonoff-classic
|
||||
;env_default = sonoff-knx
|
||||
;env_default = sonoff-sensors
|
||||
;env_default = sonoff-display
|
||||
;env_default = sonoff-BG
|
||||
;env_default = sonoff-BR
|
||||
;env_default = sonoff-CN
|
||||
@ -167,6 +168,20 @@ upload_resetmethod = ${common.upload_resetmethod}
|
||||
upload_speed = ${common.upload_speed}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
|
||||
[env:sonoff-display]
|
||||
platform = ${common.platform}
|
||||
framework = ${common.framework}
|
||||
board = ${common.board}
|
||||
board_build.flash_mode = ${common.board_build.flash_mode}
|
||||
board_build.f_cpu = ${common.board_build.f_cpu}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} -DUSE_DISPLAYS
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_port = ${common.upload_port}
|
||||
upload_resetmethod = ${common.upload_resetmethod}
|
||||
upload_speed = ${common.upload_speed}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
|
||||
[env:sonoff-BG]
|
||||
platform = ${common.platform}
|
||||
framework = ${common.framework}
|
||||
|
@ -1,7 +1,19 @@
|
||||
/* 6.2.1.7 20180925
|
||||
/* 6.2.1.9 20180928
|
||||
* Add Apparent Power and Reactive Power to Energy Monitoring devices (#251)
|
||||
*
|
||||
* 6.2.1.8 20180926
|
||||
* Change status JSON message providing more switch and retain information
|
||||
* Change pinmode for no-pullup defined switches to pullup when configured as switchmode PUSHBUTTON (=3 and up) (#3896)
|
||||
* Add delay after restart before processing rule sensor data (#3811)
|
||||
* Fix Home Assistant forced light discovery (#3908)
|
||||
* Add rule triggers SWITCH1#BOOT and POWER1#BOOT (#3904, #3910)
|
||||
* Add support for Neo Coolcam Wifi Smart Power Plug
|
||||
*
|
||||
* 6.2.1.7 20180925
|
||||
* Remove restart after ntpserver change and force NTP re-sync (#3890)
|
||||
* Release full Shelly2 support
|
||||
* Released tools/decode-config.py by Norbert Richter to decode configuration data. See file for information
|
||||
* Add define USE_DISPLAYS for selecting image sonoff-display
|
||||
*
|
||||
* 6.2.1.6 20180922
|
||||
* Removed commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet
|
||||
|
@ -130,7 +130,7 @@
|
||||
#define D_JSON_TYPE "Type"
|
||||
#define D_JSON_UPTIME "Uptime"
|
||||
#define D_JSON_UTC_TIME "UTC"
|
||||
#define D_JSON_UVINDEX "UvIndex"
|
||||
#define D_JSON_UV_INDEX "UvIndex"
|
||||
#define D_JSON_UV_LEVEL "UvLevel"
|
||||
#define D_JSON_UV_POWER "UvPower"
|
||||
#define D_JSON_VCC "Vcc"
|
||||
|
@ -28,7 +28,7 @@
|
||||
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
|
||||
* Use online command Prefix to translate cmnd, stat and tele.
|
||||
*
|
||||
* Updated until v6.2.0.1
|
||||
* Updated until v6.2.1.8
|
||||
\*********************************************************************/
|
||||
|
||||
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
|
||||
@ -82,7 +82,7 @@
|
||||
#define D_DNS_SERVER "DNS Сървър"
|
||||
#define D_DONE "Изпълнено"
|
||||
#define D_DST_TIME "DST"
|
||||
#define D_ECO2 "eCO2"
|
||||
#define D_ECO2 "eCO₂"
|
||||
#define D_EMULATION "Емулация"
|
||||
#define D_ENABLED "Активиран"
|
||||
#define D_ERASE "Изтриване"
|
||||
@ -163,15 +163,15 @@
|
||||
#define D_USER "Потребител"
|
||||
#define D_UTC_TIME "UTC"
|
||||
#define D_UV_INDEX "UV индекс"
|
||||
#define D_UV_INDEX_1 "Low"
|
||||
#define D_UV_INDEX_2 "Mid"
|
||||
#define D_UV_INDEX_3 "High"
|
||||
#define D_UV_INDEX_4 "Danger"
|
||||
#define D_UV_INDEX_5 "BurnL1/2"
|
||||
#define D_UV_INDEX_6 "BurnL3"
|
||||
#define D_UV_INDEX_7 "OoR"
|
||||
#define D_UV_LEVEL "Ниво на ултравиолетово излъчване"
|
||||
#define D_UV_POWER "UV Power"
|
||||
#define D_UV_INDEX_1 "Нисък"
|
||||
#define D_UV_INDEX_2 "Среден"
|
||||
#define D_UV_INDEX_3 "Висок"
|
||||
#define D_UV_INDEX_4 "Много висок"
|
||||
#define D_UV_INDEX_5 "Изгаряне 1/2 степен"
|
||||
#define D_UV_INDEX_6 "Изгаряне 3-та степен"
|
||||
#define D_UV_INDEX_7 "Извън обхват"
|
||||
#define D_UV_LEVEL "UV ниво"
|
||||
#define D_UV_POWER "UV мощност"
|
||||
#define D_VERSION "Версия"
|
||||
#define D_VOLTAGE "Напрежение"
|
||||
#define D_WARMLIGHT "Топла"
|
||||
@ -181,8 +181,8 @@
|
||||
#define D_WARNING_MINIMAL_VERSION "ПРЕДУПРЕЖДЕНИЕ Тази версия не поддържа постоянни настройки"
|
||||
#define D_LEVEL_10 "ниво 1-0"
|
||||
#define D_LEVEL_01 "ниво 0-1"
|
||||
#define D_SERIAL_LOGGING_DISABLED "Серийния логинг изключен"
|
||||
#define D_SYSLOG_LOGGING_REENABLED "Системния логинг активиран"
|
||||
#define D_SERIAL_LOGGING_DISABLED "Серийният лог изключен"
|
||||
#define D_SYSLOG_LOGGING_REENABLED "Системният лог активиран"
|
||||
|
||||
#define D_SET_BAUDRATE_TO "Задаване скорост на предаване (Baudrate)"
|
||||
#define D_RECEIVED_TOPIC "Получен топик"
|
||||
@ -194,7 +194,7 @@
|
||||
#define D_BLOCKED_LOOP "Блокиран цикъл"
|
||||
#define D_WPS_FAILED_WITH_STATUS "WPS конфигурацията е НЕУСПЕШНА със статус"
|
||||
#define D_ACTIVE_FOR_3_MINUTES "активно в течение на 3 минути"
|
||||
#define D_FAILED_TO_START "неуспешно стартиране"
|
||||
#define D_FAILED_TO_START "Неуспешно стартиране"
|
||||
#define D_PATCH_ISSUE_2186 "Проблем с патч 2186"
|
||||
#define D_CONNECTING_TO_AP "Свързване към точка за достъп"
|
||||
#define D_IN_MODE "в режим"
|
||||
@ -241,7 +241,7 @@
|
||||
#define D_CONFIGURE_WIFI "Конфигурация на WiFi"
|
||||
#define D_CONFIGURE_MQTT "Конфигурация на MQTT"
|
||||
#define D_CONFIGURE_DOMOTICZ "Конфигурация на Domoticz"
|
||||
#define D_CONFIGURE_LOGGING "Конфигурация на логинга"
|
||||
#define D_CONFIGURE_LOGGING "Конфигурация на лога"
|
||||
#define D_CONFIGURE_OTHER "Драги конфигурации"
|
||||
#define D_CONFIRM_RESET_CONFIGURATION "Потвърдете изчистването"
|
||||
#define D_RESET_CONFIGURATION "Изчистване на конфигурацията"
|
||||
@ -275,7 +275,7 @@
|
||||
#define D_CLIENT "Клиент"
|
||||
#define D_FULL_TOPIC "Пълен топик"
|
||||
|
||||
#define D_LOGGING_PARAMETERS "Параметри на логинга"
|
||||
#define D_LOGGING_PARAMETERS "Параметри на лога"
|
||||
#define D_SERIAL_LOG_LEVEL "Степен на серийния лог"
|
||||
#define D_WEB_LOG_LEVEL "Степен на Уеб лога"
|
||||
#define D_SYS_LOG_LEVEL "Степен на системния лог"
|
||||
@ -379,13 +379,13 @@
|
||||
#define D_DOMOTICZ_TEMP "Temp"
|
||||
#define D_DOMOTICZ_TEMP_HUM "Temp,Hum"
|
||||
#define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Hum,Baro"
|
||||
#define D_DOMOTICZ_POWER_ENERGY "Power,Energy"
|
||||
#define D_DOMOTICZ_ILLUMINANCE "Illuminance"
|
||||
#define D_DOMOTICZ_COUNT "Count/PM1"
|
||||
#define D_DOMOTICZ_VOLTAGE "Voltage/PM2,5"
|
||||
#define D_DOMOTICZ_CURRENT "Current/PM10"
|
||||
#define D_DOMOTICZ_AIRQUALITY "AirQuality"
|
||||
#define D_DOMOTICZ_UPDATE_TIMER "Update timer"
|
||||
#define D_DOMOTICZ_POWER_ENERGY "Мощност,Енергия"
|
||||
#define D_DOMOTICZ_ILLUMINANCE "Осветеност"
|
||||
#define D_DOMOTICZ_COUNT "Брояч/PM1"
|
||||
#define D_DOMOTICZ_VOLTAGE "Напрежение/PM2,5"
|
||||
#define D_DOMOTICZ_CURRENT "Ток/PM10"
|
||||
#define D_DOMOTICZ_AIRQUALITY "Качество на въздуха"
|
||||
#define D_DOMOTICZ_UPDATE_TIMER "Период на опресняване"
|
||||
|
||||
// xdrv_09_timers.ino
|
||||
#define D_CONFIGURE_TIMER "Конфигуриране на таймер"
|
||||
@ -464,7 +464,7 @@
|
||||
#define D_SENSOR_I2C_SCL "I2C SCL"
|
||||
#define D_SENSOR_I2C_SDA "I2C SDA"
|
||||
#define D_SENSOR_WS2812 "WS2812"
|
||||
#define D_SENSOR_DFR562 "MP3 Player"
|
||||
#define D_SENSOR_DFR562 "MP3 плейър"
|
||||
#define D_SENSOR_IRSEND "IRsend"
|
||||
#define D_SENSOR_SWITCH "Ключ" // Suffix "1"
|
||||
#define D_SENSOR_BUTTON "Бутон" // Suffix "1"
|
||||
@ -506,7 +506,7 @@
|
||||
#define D_UNIT_KILOOHM "kΩ"
|
||||
#define D_UNIT_KILOWATTHOUR "kWh"
|
||||
#define D_UNIT_LUX "lx"
|
||||
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "µg/m3"
|
||||
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "µg/m³"
|
||||
#define D_UNIT_MICROMETER "µm"
|
||||
#define D_UNIT_MICROSECOND "µs"
|
||||
#define D_UNIT_MILLIAMPERE "mA"
|
||||
|
@ -163,15 +163,15 @@
|
||||
#define D_USER "Benutzer"
|
||||
#define D_UTC_TIME "UTC"
|
||||
#define D_UV_INDEX "UV-Index"
|
||||
#define D_UV_INDEX_1 "Low"
|
||||
#define D_UV_INDEX_2 "Mid"
|
||||
#define D_UV_INDEX_3 "High"
|
||||
#define D_UV_INDEX_4 "Danger"
|
||||
#define D_UV_INDEX_5 "BurnL1/2"
|
||||
#define D_UV_INDEX_6 "BurnL3"
|
||||
#define D_UV_INDEX_7 "OoR"
|
||||
#define D_UV_INDEX_1 "Niedrig"
|
||||
#define D_UV_INDEX_2 "Mittel"
|
||||
#define D_UV_INDEX_3 "Hoch"
|
||||
#define D_UV_INDEX_4 "Intensiv"
|
||||
#define D_UV_INDEX_5 "Gefährlich"
|
||||
#define D_UV_INDEX_6 "Schädlich"
|
||||
#define D_UV_INDEX_7 "Messwert!"
|
||||
#define D_UV_LEVEL "UV-Level"
|
||||
#define D_UV_POWER "UV Power"
|
||||
#define D_UV_POWER "UV Intensität"
|
||||
#define D_VERSION "Version"
|
||||
#define D_VOLTAGE "Spannung"
|
||||
#define D_WARMLIGHT "warm"
|
||||
|
@ -163,13 +163,13 @@
|
||||
#define D_USER "Usuario"
|
||||
#define D_UTC_TIME "UTC"
|
||||
#define D_UV_INDEX "Índice UV"
|
||||
#define D_UV_INDEX_1 "Low"
|
||||
#define D_UV_INDEX_2 "Mid"
|
||||
#define D_UV_INDEX_3 "High"
|
||||
#define D_UV_INDEX_4 "Danger"
|
||||
#define D_UV_INDEX_5 "BurnL1/2"
|
||||
#define D_UV_INDEX_6 "BurnL3"
|
||||
#define D_UV_INDEX_7 "OoR"
|
||||
#define D_UV_INDEX_1 "Bajo"
|
||||
#define D_UV_INDEX_2 "Medio"
|
||||
#define D_UV_INDEX_3 "Alto"
|
||||
#define D_UV_INDEX_4 "Peligroso"
|
||||
#define D_UV_INDEX_5 "Quemaduras 1 a 2 grad"
|
||||
#define D_UV_INDEX_6 "Quemaduras 3 grad"
|
||||
#define D_UV_INDEX_7 "Fuera de Rango"
|
||||
#define D_UV_LEVEL "Nivel UV"
|
||||
#define D_UV_POWER "UV Power"
|
||||
#define D_VERSION "Versión"
|
||||
|
@ -28,7 +28,7 @@
|
||||
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
|
||||
* Use online command Prefix to translate cmnd, stat and tele.
|
||||
*
|
||||
* Updated until v6.1.1.7
|
||||
* Updated until v6.2.1.7
|
||||
\*********************************************************************/
|
||||
|
||||
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
|
||||
@ -65,7 +65,7 @@
|
||||
#define D_BY "par" // Written by me
|
||||
#define D_BYTES "Bytes"
|
||||
#define D_CELSIUS "Celsius"
|
||||
#define D_CHANNEL "Channel"
|
||||
#define D_CHANNEL "Canal"
|
||||
#define D_CO2 "Dioxyde de carbone"
|
||||
#define D_CODE "code" // Button code
|
||||
#define D_COLDLIGHT "Froid"
|
||||
@ -163,15 +163,15 @@
|
||||
#define D_USER "Utilisateur"
|
||||
#define D_UTC_TIME "UTC"
|
||||
#define D_UV_INDEX "Indice UV"
|
||||
#define D_UV_INDEX_1 "Low"
|
||||
#define D_UV_INDEX_2 "Mid"
|
||||
#define D_UV_INDEX_3 "High"
|
||||
#define D_UV_INDEX_4 "Danger"
|
||||
#define D_UV_INDEX_5 "BurnL1/2"
|
||||
#define D_UV_INDEX_6 "BurnL3"
|
||||
#define D_UV_INDEX_7 "OoR"
|
||||
#define D_UV_INDEX_1 "Faible"
|
||||
#define D_UV_INDEX_2 "Modéré"
|
||||
#define D_UV_INDEX_3 "Élevé"
|
||||
#define D_UV_INDEX_4 "Très élevé"
|
||||
#define D_UV_INDEX_5 "Brûlure niv.1/2"
|
||||
#define D_UV_INDEX_6 "Brûlure niv.3"
|
||||
#define D_UV_INDEX_7 "Hors échelle"
|
||||
#define D_UV_LEVEL "Niveau UV"
|
||||
#define D_UV_POWER "UV Power"
|
||||
#define D_UV_POWER "Puissance UV"
|
||||
#define D_VERSION "Version"
|
||||
#define D_VOLTAGE "Tension"
|
||||
#define D_WARMLIGHT "Chaud"
|
||||
@ -184,7 +184,7 @@
|
||||
#define D_SERIAL_LOGGING_DISABLED "Journalisation série désactivée"
|
||||
#define D_SYSLOG_LOGGING_REENABLED "Jounalisation syslog réactivée"
|
||||
|
||||
#define D_SET_BAUDRATE_TO "Définir baudrate à"
|
||||
#define D_SET_BAUDRATE_TO "Définir le débit à"
|
||||
#define D_RECEIVED_TOPIC "Topic reçu" // Terme MQTT
|
||||
#define D_DATA_SIZE "Taille données"
|
||||
#define D_ANALOG_INPUT "Analogique"
|
||||
|
@ -86,20 +86,12 @@ void RtcSettingsSave()
|
||||
RtcSettings.valid = RTC_MEM_VALID;
|
||||
ESP.rtcUserMemoryWrite(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM));
|
||||
rtc_settings_crc = GetRtcSettingsCrc();
|
||||
#ifdef DEBUG_THEO
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("Dump: Save"));
|
||||
RtcSettingsDump();
|
||||
#endif // DEBUG_THEO
|
||||
}
|
||||
}
|
||||
|
||||
void RtcSettingsLoad()
|
||||
{
|
||||
ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RTCMEM)); // 0x290
|
||||
#ifdef DEBUG_THEO
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("Dump: Load"));
|
||||
RtcSettingsDump();
|
||||
#endif // DEBUG_THEO
|
||||
if (RtcSettings.valid != RTC_MEM_VALID) {
|
||||
memset(&RtcSettings, 0, sizeof(RTCMEM));
|
||||
RtcSettings.valid = RTC_MEM_VALID;
|
||||
|
@ -147,6 +147,7 @@ uint16_t blink_counter = 0; // Number of blink cycles
|
||||
uint16_t seriallog_timer = 0; // Timer to disable Seriallog
|
||||
uint16_t syslog_timer = 0; // Timer to re-enable syslog_level
|
||||
uint16_t holdbutton[MAX_KEYS] = { 0 }; // Timer for button hold
|
||||
uint16_t switch_no_pullup = 0; // Switch pull-up bitmask flags
|
||||
int16_t save_data_counter; // Counter and flag for config save to Flash
|
||||
RulesBitfield rules_flag; // Rule state flags (16 bits)
|
||||
uint8_t serial_local = 0; // Handle serial locally;
|
||||
@ -1119,6 +1120,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
||||
else if ((CMND_SWITCHMODE == command_code) && (index > 0) && (index <= MAX_SWITCHES)) {
|
||||
if ((payload >= 0) && (payload < MAX_SWITCH_OPTION)) {
|
||||
Settings.switchmode[index -1] = payload;
|
||||
GpioSwitchPinMode(index -1);
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, index, Settings.switchmode[index-1]);
|
||||
}
|
||||
@ -1412,6 +1414,7 @@ void PublishStatus(uint8_t payload)
|
||||
{
|
||||
uint8_t option = STAT;
|
||||
char stemp[MAX_FRIENDLYNAMES * (sizeof(Settings.friendlyname[0]) +MAX_FRIENDLYNAMES)];
|
||||
char stemp2[MAX_SWITCHES * 3];
|
||||
|
||||
// Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX
|
||||
if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) option++; // TELE
|
||||
@ -1426,8 +1429,12 @@ void PublishStatus(uint8_t payload)
|
||||
for (byte i = 0; i < maxfn; i++) {
|
||||
snprintf_P(stemp, sizeof(stemp), PSTR("%s%s\"%s\"" ), stemp, (i > 0 ? "," : ""), Settings.friendlyname[i]);
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"),
|
||||
Settings.module +1, stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_power_retain);
|
||||
stemp2[0] = '\0';
|
||||
for (byte i = 0; i < MAX_SWITCHES; i++) {
|
||||
snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings.switchmode[i]);
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_SWITCHTOPIC "\":\"%s\",\"" D_CMND_SWITCHMODE "\":[%s],\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_SWITCHRETAIN "\":%d,\"" D_CMND_SENSORRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"),
|
||||
Settings.module +1, stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.switch_topic, stemp2, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_switch_retain, Settings.flag.mqtt_sensor_retain, Settings.flag.mqtt_power_retain);
|
||||
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS));
|
||||
}
|
||||
|
||||
@ -2291,11 +2298,23 @@ void SerialInput()
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void GpioSwitchPinMode(uint8_t index)
|
||||
{
|
||||
if (pin[GPIO_SWT1 +index] < 99) {
|
||||
// pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : bitRead(switch_no_pullup, index) ? INPUT : INPUT_PULLUP);
|
||||
|
||||
uint8_t no_pullup = 0;
|
||||
if (bitRead(switch_no_pullup, index)) {
|
||||
no_pullup = (Settings.switchmode[index] < PUSHBUTTON);
|
||||
}
|
||||
pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : (no_pullup) ? INPUT : INPUT_PULLUP);
|
||||
}
|
||||
}
|
||||
|
||||
void GpioInit()
|
||||
{
|
||||
uint8_t mpin;
|
||||
uint8_t key_no_pullup = 0;
|
||||
uint16_t switch_no_pullup = 0;
|
||||
mytmplt def_module;
|
||||
|
||||
if (!Settings.module || (Settings.module >= MAXMODULE)) {
|
||||
@ -2452,7 +2471,7 @@ void GpioInit()
|
||||
for (byte i = 0; i < MAX_SWITCHES; i++) {
|
||||
lastwallswitch[i] = 1; // Init global to virtual switch state;
|
||||
if (pin[GPIO_SWT1 +i] < 99) {
|
||||
pinMode(pin[GPIO_SWT1 +i], (16 == pin[GPIO_SWT1 +i]) ? INPUT_PULLDOWN_16 : bitRead(switch_no_pullup, i) ? INPUT : INPUT_PULLUP);
|
||||
GpioSwitchPinMode(i);
|
||||
lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // Set global now so doesn't change the saved power state on first switch check
|
||||
}
|
||||
virtualswitch[i] = lastwallswitch[i];
|
||||
|
@ -51,7 +51,7 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
||||
#endif
|
||||
|
||||
#define USE_DHT // Default DHT11 sensor needs no external library
|
||||
#define USE_ENERGY_SENSOR // Use energy sensors
|
||||
#define USE_ENERGY_SENSOR // Use energy sensors (+14k code)
|
||||
#define USE_HLW8012 // Use energy sensor for Sonoff Pow and WolfBlitz
|
||||
#define USE_CSE7766 // Use energy sensor for Sonoff S31 and Pow R2
|
||||
|
||||
@ -167,6 +167,30 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
||||
#undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem)
|
||||
#endif // USE_KNX_NO_EMULATION
|
||||
|
||||
/*********************************************************************************************\
|
||||
* [sonoff-display.bin]
|
||||
* Provide an image with display drivers enabled
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_DISPLAYS
|
||||
|
||||
#undef USE_ENERGY_SENSOR // Disable energy sensors (-14k code)
|
||||
#undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem)
|
||||
|
||||
#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram)
|
||||
#define USE_DISPLAY // Add I2C Display Support (+2k code)
|
||||
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
|
||||
#define USE_DISPLAY_LCD // [DisplayModel 1] Enable Lcd display (I2C addresses 0x27 and 0x3F) (+6k code)
|
||||
#define USE_DISPLAY_SSD1306 // [DisplayModel 2] Enable SSD1306 Oled 128x64 display (I2C addresses 0x3C and 0x3D) (+16k code)
|
||||
#define USE_DISPLAY_MATRIX // [DisplayModel 3] Enable 8x8 Matrix display (I2C adresseses see below) (+11k code)
|
||||
|
||||
#define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC)
|
||||
#define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code)
|
||||
|
||||
#undef USE_ARILUX_RF // Remove support for Arilux RF remote controller (-0k8 code, 252 iram (non 2.3.0))
|
||||
#undef USE_RF_FLASH // Remove support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (-3k code)
|
||||
#endif // USE_DISPLAYS
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Mandatory define for DS18x20 if changed by above image selections
|
||||
\*********************************************************************************************/
|
||||
|
@ -231,6 +231,7 @@ enum SupportedModules {
|
||||
SHELLY1,
|
||||
SHELLY2,
|
||||
PHILIPS,
|
||||
NEO_COOLCAM,
|
||||
MAXMODULE };
|
||||
|
||||
/********************************************************************************************/
|
||||
@ -390,6 +391,7 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
|
||||
SHELLY1,
|
||||
SHELLY2,
|
||||
BLITZWOLF_BWSHP2,
|
||||
NEO_COOLCAM,
|
||||
H801,
|
||||
MAGICHOME,
|
||||
ARILUX_LC01,
|
||||
@ -399,9 +401,9 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
|
||||
HUAFAN_SS,
|
||||
KMC_70011,
|
||||
AILIGHT,
|
||||
WEMOS,
|
||||
PHILIPS,
|
||||
WITTY,
|
||||
PHILIPS
|
||||
WEMOS
|
||||
};
|
||||
|
||||
// Default module settings
|
||||
@ -1054,12 +1056,40 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
|
||||
0, 0,
|
||||
GPIO_PWM1, // GPIO15 light intensity
|
||||
0, 0
|
||||
},
|
||||
{ "Neo Coolcam", // Neo Coolcam (ESP8266)
|
||||
// https://www.banggood.com/NEO-COOLCAM-WiFi-Mini-Smart-Plug-APP-Remote-Control-Timing-Smart-Socket-EU-Plug-p-1288562.html?cur_warehouse=CN
|
||||
0, 0, 0, 0,
|
||||
GPIO_LED1_INV, // GPIO13 Red Led (0 = On, 1 = Off)
|
||||
0,
|
||||
0, 0, 0, 0, 0, 0, // Flash connection
|
||||
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||
GPIO_KEY1, // GPIO13 Button
|
||||
0, 0, 0, 0
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Optionals
|
||||
|
||||
{ "Arilux LC10", // Arilux LC10 (ESP8285), RGBW + RF
|
||||
// https://github.com/arendst/Sonoff-Tasmota/wiki/MagicHome-with-ESP8285
|
||||
// https://www.aliexpress.com/item/DC5-24V-Wireless-WIFI-LED-RGB-Controller-RGBW-Controller-IR-RF-Remote-Control-IOS-Android-for/32827253255.html
|
||||
// https://www.aliexpress.com/item/Wifi-LED-RGB-Controler-DC12V-MIni-Wifi-RGB-RGBW-LED-Controller-for-RGB-RGBW-LED-Strip/32673444047.html
|
||||
GPIO_USER, // GPIO00 Optional Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
0,
|
||||
GPIO_USER, // GPIO03 Serial TXD and Optional sensor0
|
||||
GPIO_ARIRFRCV, // GPIO04 RF receiver input
|
||||
GPIO_PWM2, // GPIO05 RGB LED Green
|
||||
0, 0, 0, 0, 0, 0, // Flash connection
|
||||
GPIO_PWM3, // GPIO12 RGB LED Blue
|
||||
GPIO_PWM4, // GPIO13 RGBW LED White
|
||||
GPIO_PWM1, // GPIO14 RGB LED Red
|
||||
GPIO_LED2_INV, // GPIO15 RF receiver control
|
||||
0, 0
|
||||
}
|
||||
|
||||
{ "Xenon 3CH", // Xenon 3CH (ESP8266) - (#1128)
|
||||
0, 0, 0,
|
||||
GPIO_KEY2, // GPIO03 Serial TXD and Optional sensor
|
||||
|
@ -20,7 +20,7 @@
|
||||
#ifndef _SONOFF_VERSION_H_
|
||||
#define _SONOFF_VERSION_H_
|
||||
|
||||
#define VERSION 0x06020107
|
||||
#define VERSION 0x06020109
|
||||
|
||||
#define D_PROGRAMNAME "Sonoff-Tasmota"
|
||||
#define D_AUTHOR "Theo Arends"
|
||||
|
@ -494,6 +494,32 @@ double FastPrecisePow(double a, double b)
|
||||
return r * u.d;
|
||||
}
|
||||
|
||||
uint32_t SqrtInt(uint32_t num)
|
||||
{
|
||||
if (num <= 1) {
|
||||
return num;
|
||||
}
|
||||
|
||||
uint32_t x = num / 2;
|
||||
uint32_t y;
|
||||
do {
|
||||
y = (x + num / x) / 2;
|
||||
if (y >= x) {
|
||||
return x;
|
||||
}
|
||||
x = y;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
uint32_t RoundSqrtInt(uint32_t num)
|
||||
{
|
||||
uint32_t s = SqrtInt(4 * num);
|
||||
if (s & 1) {
|
||||
s++;
|
||||
}
|
||||
return s / 2;
|
||||
}
|
||||
|
||||
char* GetTextIndexed(char* destination, size_t destination_size, uint16_t index, const char* haystack)
|
||||
{
|
||||
// Returns empty string if not found
|
||||
|
@ -282,9 +282,9 @@
|
||||
#define USE_BMP // Enable BMP085/BMP180/BMP280/BME280 sensor (I2C address 0x76 or 0x77) (+4k code)
|
||||
// #define USE_BME680 // Enable support for BME680 sensor using Bosch BME680 library (+4k code)
|
||||
#define USE_BH1750 // Enable BH1750 sensor (I2C address 0x23 or 0x5C) (+0k5 code)
|
||||
// #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+0k5 code)
|
||||
// #define USE_VEML6070_RSET 270000 // VEML6070, Rset in Ohm used on PCB board, default 270K = 270000ohm, range for this sensor: 220K ... 1Meg
|
||||
// #define USE_VEML6070_SHOW_RAW // VEML6070, shows the raw value of UV-A
|
||||
// #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+1k5 code)
|
||||
#define USE_VEML6070_RSET 270000 // VEML6070, Rset in Ohm used on PCB board, default 270K = 270000ohm, range for this sensor: 220K ... 1Meg
|
||||
#define USE_VEML6070_SHOW_RAW // VEML6070, shows the raw value of UV-A
|
||||
// #define USE_ADS1115 // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) based on Adafruit ADS1x15 library (no library needed) (+0k7 code)
|
||||
// #define USE_ADS1115_I2CDEV // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) using library i2cdevlib-Core and i2cdevlib-ADS1115 (+2k code)
|
||||
// #define USE_INA219 // Enable INA219 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+1k code)
|
||||
@ -323,7 +323,7 @@
|
||||
#endif // USE_I2C
|
||||
|
||||
// -- SPI sensors ---------------------------------
|
||||
//#define USE_SPI // SPI using library TasmotaTFT
|
||||
//#define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC)
|
||||
|
||||
#ifdef USE_SPI
|
||||
#ifndef USE_DISPLAY
|
||||
@ -386,6 +386,7 @@
|
||||
//#define USE_CLASSIC // Create sonoff-classic with initial configuration tools WPS, SmartConfig and WifiManager
|
||||
//#define USE_SENSORS // Create sonoff-sensors with useful sensors enabled
|
||||
//#define USE_KNX_NO_EMULATION // Create sonoff-knx with KNX but without Emulation
|
||||
//#define USE_DISPLAYS // Create sonoff-display with display drivers enabled
|
||||
//#define BE_MINIMAL // Create sonoff-minimal as intermediate firmware for OTA-MAGIC
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
@ -41,23 +41,25 @@ const char kEnergyCommands[] PROGMEM =
|
||||
D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|"
|
||||
D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW ;
|
||||
|
||||
float energy_voltage = 0; // 123.1 V
|
||||
float energy_current = 0; // 123.123 A
|
||||
float energy_power = 0; // 123.1 W
|
||||
float energy_power_factor = NAN; // 0.12
|
||||
int energy_calc_power_factor = 0; // Do not calculate power factor from data
|
||||
float energy_frequency = NAN; // 123.1 Hz
|
||||
float energy_start = 0; // 12345.12345 kWh total previous
|
||||
float energy_voltage = 0; // 123.1 V
|
||||
float energy_current = 0; // 123.123 A
|
||||
float energy_active_power = 0; // 123.1 W
|
||||
float energy_apparent_power = NAN; // 123.1 VA
|
||||
float energy_reactive_power = NAN; // 123.1 VAr
|
||||
float energy_power_factor = NAN; // 0.12
|
||||
float energy_frequency = NAN; // 123.1 Hz
|
||||
float energy_start = 0; // 12345.12345 kWh total previous
|
||||
|
||||
float energy_daily = 0; // 123.123 kWh
|
||||
float energy_total = 0; // 12345.12345 kWh
|
||||
float energy_daily = 0; // 123.123 kWh
|
||||
float energy_total = 0; // 12345.12345 kWh
|
||||
unsigned long energy_kWhtoday_delta = 0; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to energy_kWhtoday (HLW and CSE only)
|
||||
unsigned long energy_kWhtoday; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily
|
||||
unsigned long energy_period = 0; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily
|
||||
unsigned long energy_kWhtoday; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily
|
||||
unsigned long energy_period = 0; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = energy_daily
|
||||
|
||||
float energy_power_last[3] = { 0 };
|
||||
uint8_t energy_power_delta = 0;
|
||||
|
||||
bool energy_type_dc = false;
|
||||
bool energy_power_on = true;
|
||||
|
||||
byte energy_min_power_flag = 0;
|
||||
@ -124,15 +126,6 @@ void Energy200ms()
|
||||
}
|
||||
|
||||
XnrgCall(FUNC_EVERY_200_MSECOND);
|
||||
|
||||
if (energy_calc_power_factor) {
|
||||
float power_factor = 0;
|
||||
if (energy_voltage && energy_current && energy_power) {
|
||||
power_factor = energy_power / (energy_voltage * energy_current);
|
||||
if (power_factor > 1) power_factor = 1;
|
||||
}
|
||||
energy_power_factor = power_factor;
|
||||
}
|
||||
}
|
||||
|
||||
void EnergySaveState()
|
||||
@ -178,21 +171,21 @@ void EnergyMarginCheck()
|
||||
}
|
||||
|
||||
if (Settings.energy_power_delta) {
|
||||
float delta = abs(energy_power_last[0] - energy_power);
|
||||
float delta = abs(energy_power_last[0] - energy_active_power);
|
||||
// Any delta compared to minimal delta
|
||||
float min_power = (energy_power_last[0] > energy_power) ? energy_power : energy_power_last[0];
|
||||
float min_power = (energy_power_last[0] > energy_active_power) ? energy_active_power : energy_power_last[0];
|
||||
if (((delta / min_power) * 100) > Settings.energy_power_delta) {
|
||||
energy_power_delta = 1;
|
||||
energy_power_last[1] = energy_power; // We only want one report so reset history
|
||||
energy_power_last[2] = energy_power;
|
||||
energy_power_last[1] = energy_active_power; // We only want one report so reset history
|
||||
energy_power_last[2] = energy_active_power;
|
||||
}
|
||||
}
|
||||
energy_power_last[0] = energy_power_last[1]; // Shift in history every second allowing power changes to settle for up to three seconds
|
||||
energy_power_last[1] = energy_power_last[2];
|
||||
energy_power_last[2] = energy_power;
|
||||
energy_power_last[2] = energy_active_power;
|
||||
|
||||
if (energy_power_on && (Settings.energy_min_power || Settings.energy_max_power || Settings.energy_min_voltage || Settings.energy_max_voltage || Settings.energy_min_current || Settings.energy_max_current)) {
|
||||
energy_power_u = (uint16_t)(energy_power);
|
||||
energy_power_u = (uint16_t)(energy_active_power);
|
||||
energy_voltage_u = (uint16_t)(energy_voltage);
|
||||
energy_current_u = (uint16_t)(energy_current * 1000);
|
||||
|
||||
@ -235,7 +228,7 @@ void EnergyMarginCheck()
|
||||
#if FEATURE_POWER_LIMIT
|
||||
// Max Power
|
||||
if (Settings.energy_max_power_limit) {
|
||||
if (energy_power > Settings.energy_max_power_limit) {
|
||||
if (energy_active_power > Settings.energy_max_power_limit) {
|
||||
if (!energy_mplh_counter) {
|
||||
energy_mplh_counter = Settings.energy_max_power_limit_hold;
|
||||
} else {
|
||||
@ -535,6 +528,8 @@ const char HTTP_ENERGY_SNS1[] PROGMEM = "%s"
|
||||
"{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}";
|
||||
|
||||
const char HTTP_ENERGY_SNS2[] PROGMEM = "%s"
|
||||
"{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}"
|
||||
"{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}"
|
||||
"{s}" D_POWER_FACTOR "{m}%s{e}";
|
||||
|
||||
const char HTTP_ENERGY_SNS3[] PROGMEM = "%s"
|
||||
@ -548,27 +543,65 @@ const char HTTP_ENERGY_SNS4[] PROGMEM = "%s"
|
||||
|
||||
void EnergyShow(boolean json)
|
||||
{
|
||||
char energy_total_chr[10];
|
||||
char voltage_chr[10];
|
||||
char current_chr[10];
|
||||
char active_power_chr[10];
|
||||
char apparent_power_chr[10];
|
||||
char reactive_power_chr[10];
|
||||
char power_factor_chr[10];
|
||||
char frequency_chr[10];
|
||||
char energy_daily_chr[10];
|
||||
char energy_period_chr[10];
|
||||
char energy_power_chr[10];
|
||||
char energy_voltage_chr[10];
|
||||
char energy_current_chr[10];
|
||||
char energy_frequency_chr[10];
|
||||
char energy_power_factor_chr[10];
|
||||
char energy_yesterday_chr[10];
|
||||
char energy_total_chr[10];
|
||||
|
||||
char speriod[20];
|
||||
char spfactor[20];
|
||||
char sfrequency[20];
|
||||
|
||||
bool show_energy_period = (0 == tele_period);
|
||||
|
||||
dtostrfd(energy_power, Settings.flag2.wattage_resolution, energy_power_chr);
|
||||
dtostrfd(energy_voltage, Settings.flag2.voltage_resolution, energy_voltage_chr);
|
||||
dtostrfd(energy_current, Settings.flag2.current_resolution, energy_current_chr);
|
||||
dtostrfd(energy_total, Settings.flag2.energy_resolution, energy_total_chr);
|
||||
float power_factor = energy_power_factor;
|
||||
|
||||
if (!energy_type_dc) {
|
||||
float apparent_power = energy_apparent_power;
|
||||
if (isnan(apparent_power)) {
|
||||
apparent_power = energy_voltage * energy_current;
|
||||
}
|
||||
if (apparent_power < energy_active_power) { // Should be impossible
|
||||
energy_active_power = apparent_power;
|
||||
}
|
||||
|
||||
if (isnan(power_factor)) {
|
||||
power_factor = (energy_active_power && apparent_power) ? energy_active_power / apparent_power : 0;
|
||||
if (power_factor > 1) power_factor = 1;
|
||||
}
|
||||
|
||||
float reactive_power = energy_reactive_power;
|
||||
if (isnan(reactive_power)) {
|
||||
reactive_power = 0;
|
||||
uint32_t difference = ((uint32_t)(apparent_power * 100) - (uint32_t)(energy_active_power * 100)) / 10;
|
||||
if ((energy_current > 0.005) && ((difference > 15) || (difference > (uint32_t)(apparent_power * 100 / 1000)))) {
|
||||
// calculating reactive power only if current is greater than 0.005A and
|
||||
// difference between active and apparent power is greater than 1.5W or 1%
|
||||
reactive_power = (float)(RoundSqrtInt((uint32_t)(apparent_power * apparent_power * 100) - (uint32_t)(energy_active_power * energy_active_power * 100))) / 10;
|
||||
}
|
||||
}
|
||||
|
||||
dtostrfd(apparent_power, Settings.flag2.wattage_resolution, apparent_power_chr);
|
||||
dtostrfd(reactive_power, Settings.flag2.wattage_resolution, reactive_power_chr);
|
||||
dtostrfd(power_factor, 2, power_factor_chr);
|
||||
if (!isnan(energy_frequency)) {
|
||||
dtostrfd(energy_frequency, Settings.flag2.frequency_resolution, frequency_chr);
|
||||
snprintf_P(sfrequency, sizeof(sfrequency), PSTR(",\"" D_JSON_FREQUENCY "\":%s"), frequency_chr);
|
||||
}
|
||||
}
|
||||
|
||||
dtostrfd(energy_voltage, Settings.flag2.voltage_resolution, voltage_chr);
|
||||
dtostrfd(energy_current, Settings.flag2.current_resolution, current_chr);
|
||||
dtostrfd(energy_active_power, Settings.flag2.wattage_resolution, active_power_chr);
|
||||
dtostrfd(energy_daily, Settings.flag2.energy_resolution, energy_daily_chr);
|
||||
dtostrfd((float)Settings.energy_kWhyesterday / 100000, Settings.flag2.energy_resolution, energy_yesterday_chr);
|
||||
dtostrfd(energy_total, Settings.flag2.energy_resolution, energy_total_chr);
|
||||
|
||||
float energy = 0;
|
||||
if (show_energy_period) {
|
||||
@ -577,34 +610,30 @@ void EnergyShow(boolean json)
|
||||
dtostrfd(energy, Settings.flag2.wattage_resolution, energy_period_chr);
|
||||
snprintf_P(speriod, sizeof(speriod), PSTR(",\"" D_JSON_PERIOD "\":%s"), energy_period_chr);
|
||||
}
|
||||
if (!isnan(energy_frequency)) {
|
||||
dtostrfd(energy_frequency, Settings.flag2.frequency_resolution, energy_frequency_chr);
|
||||
snprintf_P(sfrequency, sizeof(sfrequency), PSTR(",\"" D_JSON_FREQUENCY "\":%s"), energy_frequency_chr);
|
||||
}
|
||||
if (!isnan(energy_power_factor)) {
|
||||
dtostrfd(energy_power_factor, 2, energy_power_factor_chr);
|
||||
snprintf_P(spfactor, sizeof(spfactor), PSTR(",\"" D_JSON_POWERFACTOR "\":%s"), energy_power_factor_chr);
|
||||
}
|
||||
|
||||
if (json) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s%s,\""
|
||||
D_JSON_POWERUSAGE "\":%s%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s%s}"),
|
||||
mqtt_data, energy_total_chr, energy_yesterday_chr, energy_daily_chr, (show_energy_period) ? speriod : "",
|
||||
energy_power_chr, (!isnan(energy_power_factor)) ? spfactor : "", energy_voltage_chr, energy_current_chr, (!isnan(energy_frequency)) ? sfrequency : "");
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s%s,\"" D_JSON_POWERUSAGE "\":%s"),
|
||||
mqtt_data, energy_total_chr, energy_yesterday_chr, energy_daily_chr, (show_energy_period) ? speriod : "", active_power_chr);
|
||||
if (!energy_type_dc) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s%s"),
|
||||
mqtt_data, apparent_power_chr, reactive_power_chr, power_factor_chr, (!isnan(energy_frequency)) ? sfrequency : "");
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"), mqtt_data, voltage_chr, current_chr);
|
||||
|
||||
#ifdef USE_DOMOTICZ
|
||||
if (show_energy_period) { // Only send if telemetry
|
||||
dtostrfd(energy_total * 1000, 1, energy_total_chr);
|
||||
DomoticzSensorPowerEnergy((int)energy_power, energy_total_chr); // PowerUsage, EnergyToday
|
||||
DomoticzSensor(DZ_VOLTAGE, energy_voltage_chr); // Voltage
|
||||
DomoticzSensor(DZ_CURRENT, energy_current_chr); // Current
|
||||
DomoticzSensorPowerEnergy((int)energy_active_power, energy_total_chr); // PowerUsage, EnergyToday
|
||||
DomoticzSensor(DZ_VOLTAGE, voltage_chr); // Voltage
|
||||
DomoticzSensor(DZ_CURRENT, current_chr); // Current
|
||||
}
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_KNX
|
||||
if (show_energy_period) {
|
||||
KnxSensor(KNX_ENERGY_VOLTAGE, energy_voltage);
|
||||
KnxSensor(KNX_ENERGY_CURRENT, energy_current);
|
||||
KnxSensor(KNX_ENERGY_POWER, energy_power);
|
||||
if (!isnan(energy_power_factor)) { KnxSensor(KNX_ENERGY_POWERFACTOR, energy_power_factor); }
|
||||
KnxSensor(KNX_ENERGY_POWER, energy_active_power);
|
||||
if (!energy_type_dc) { KnxSensor(KNX_ENERGY_POWERFACTOR, power_factor); }
|
||||
KnxSensor(KNX_ENERGY_DAILY, energy_daily);
|
||||
KnxSensor(KNX_ENERGY_TOTAL, energy_total);
|
||||
KnxSensor(KNX_ENERGY_START, energy_start);
|
||||
@ -612,9 +641,11 @@ void EnergyShow(boolean json)
|
||||
#endif // USE_KNX
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS1, mqtt_data, energy_voltage_chr, energy_current_chr, energy_power_chr);
|
||||
if (!isnan(energy_power_factor)) { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS2, mqtt_data, energy_power_factor_chr); }
|
||||
if (!isnan(energy_frequency)) { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS3, mqtt_data, energy_frequency_chr); }
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS1, mqtt_data, voltage_chr, current_chr, active_power_chr);
|
||||
if (!energy_type_dc) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS2, mqtt_data, apparent_power_chr, reactive_power_chr, power_factor_chr);
|
||||
if (!isnan(energy_frequency)) { snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS3, mqtt_data, frequency_chr); }
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_ENERGY_SNS4, mqtt_data, energy_daily_chr, energy_yesterday_chr, energy_total_chr);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
|
@ -376,6 +376,25 @@ void RulesEvery50ms()
|
||||
RulesProcessEvent(json_event);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Boot time POWER OUTPUTS (Relays) Status
|
||||
for (byte i = 0; i < devices_present; i++) {
|
||||
uint8_t new_state = (rules_new_power >> i) &1;
|
||||
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Power%d\":{\"Boot\":%d}}"), i +1, new_state);
|
||||
RulesProcessEvent(json_event);
|
||||
}
|
||||
// Boot time SWITCHES Status
|
||||
for (byte i = 0; i < MAX_SWITCHES; i++) {
|
||||
#ifdef USE_TM1638
|
||||
if ((pin[GPIO_SWT1 +i] < 99) || ((pin[GPIO_TM16CLK] < 99) && (pin[GPIO_TM16DIO] < 99) && (pin[GPIO_TM16STB] < 99))) {
|
||||
#else
|
||||
if (pin[GPIO_SWT1 +i] < 99) {
|
||||
#endif // USE_TM1638
|
||||
boolean swm = ((FOLLOW_INV == Settings.switchmode[i]) || (PUSHBUTTON_INV == Settings.switchmode[i]) || (PUSHBUTTONHOLD_INV == Settings.switchmode[i]));
|
||||
snprintf_P(json_event, sizeof(json_event), PSTR("{\"" D_JSON_SWITCH "%d\":{\"Boot\":%d}}"), i +1, (swm ^ lastwallswitch[i]));
|
||||
RulesProcessEvent(json_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
rules_old_power = rules_new_power;
|
||||
}
|
||||
@ -425,7 +444,7 @@ void RulesEvery50ms()
|
||||
|
||||
void RulesEvery100ms()
|
||||
{
|
||||
if (Settings.rule_enabled) { // Any rule enabled
|
||||
if (Settings.rule_enabled && (uptime > 4)) { // Any rule enabled and allow 4 seconds start-up time for sensors (#3811)
|
||||
mqtt_data[0] = '\0';
|
||||
int tele_period_save = tele_period;
|
||||
tele_period = 2; // Do not allow HA updates during next function call
|
||||
|
@ -76,7 +76,7 @@ void HAssDiscoverRelay()
|
||||
|
||||
for (int i = 1; i <= MAX_RELAYS; i++) {
|
||||
is_light = ((i == devices_present) && (light_type));
|
||||
is_topic_light = Settings.flag.hass_light;
|
||||
is_topic_light = Settings.flag.hass_light || is_light;
|
||||
|
||||
mqtt_data[0] = '\0'; // Clear retained message
|
||||
|
||||
|
@ -111,9 +111,9 @@ void HlwEvery200ms()
|
||||
|
||||
if (hlw_cf_pulse_length && energy_power_on && !hlw_load_off) {
|
||||
hlw_w = (hlw_power_ratio * Settings.energy_power_calibration) / hlw_cf_pulse_length;
|
||||
energy_power = (float)hlw_w / 10;
|
||||
energy_active_power = (float)hlw_w / 10;
|
||||
} else {
|
||||
energy_power = 0;
|
||||
energy_active_power = 0;
|
||||
}
|
||||
|
||||
hlw_cf1_timer++;
|
||||
@ -142,7 +142,7 @@ void HlwEvery200ms()
|
||||
hlw_cf1_current_pulse_length = hlw_cf1_pulse_length;
|
||||
hlw_cf1_current_max_pulse_counter = hlw_cf1_pulse_counter;
|
||||
|
||||
if (hlw_cf1_current_pulse_length && energy_power) { // No current if no power being consumed
|
||||
if (hlw_cf1_current_pulse_length && energy_active_power) { // No current if no power being consumed
|
||||
hlw_i = (hlw_current_ratio * Settings.energy_current_calibration) / hlw_cf1_current_pulse_length;
|
||||
energy_current = (float)hlw_i / 1000;
|
||||
} else {
|
||||
@ -217,7 +217,6 @@ void HlwDrvInit()
|
||||
{
|
||||
if (!energy_flg) {
|
||||
if ((pin[GPIO_HLW_SEL] < 99) && (pin[GPIO_HLW_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)) { // Sonoff Pow or any HLW8012 based device
|
||||
energy_calc_power_factor = 1; // Calculate power factor from data
|
||||
energy_flg = XNRG_01;
|
||||
}
|
||||
}
|
||||
|
@ -95,14 +95,14 @@ void CseReceived()
|
||||
if (adjustement & 0x10) { // Power valid
|
||||
cse_power_invalid = 0;
|
||||
if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range
|
||||
energy_power = 0;
|
||||
energy_active_power = 0;
|
||||
} else {
|
||||
if (0 == power_cycle_first) { power_cycle_first = power_cycle; } // Skip first incomplete power_cycle
|
||||
if (power_cycle_first != power_cycle) {
|
||||
power_cycle_first = -1;
|
||||
energy_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)power_cycle;
|
||||
energy_active_power = (float)(Settings.energy_power_calibration * CSE_PREF) / (float)power_cycle;
|
||||
} else {
|
||||
energy_power = 0;
|
||||
energy_active_power = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -110,11 +110,11 @@ void CseReceived()
|
||||
cse_power_invalid++;
|
||||
} else {
|
||||
power_cycle_first = 0;
|
||||
energy_power = 0; // Powered on but no load
|
||||
energy_active_power = 0; // Powered on but no load
|
||||
}
|
||||
}
|
||||
if (adjustement & 0x20) { // Current valid
|
||||
if (0 == energy_power) {
|
||||
if (0 == energy_active_power) {
|
||||
energy_current = 0;
|
||||
} else {
|
||||
energy_current = (float)Settings.energy_current_calibration / (float)current_cycle;
|
||||
@ -123,7 +123,7 @@ void CseReceived()
|
||||
} else { // Powered off
|
||||
power_cycle_first = 0;
|
||||
energy_voltage = 0;
|
||||
energy_power = 0;
|
||||
energy_active_power = 0;
|
||||
energy_current = 0;
|
||||
}
|
||||
}
|
||||
@ -180,7 +180,7 @@ void CseEverySecond()
|
||||
} else {
|
||||
cf_frequency = cf_pulses - cf_pulses_last_time;
|
||||
}
|
||||
if (cf_frequency && energy_power) {
|
||||
if (cf_frequency && energy_active_power) {
|
||||
cf_pulses_last_time = cf_pulses;
|
||||
energy_kWhtoday_delta += (cf_frequency * Settings.energy_power_calibration) / 36;
|
||||
EnergyUpdateToday();
|
||||
@ -194,7 +194,6 @@ void CseDrvInit()
|
||||
if ((SONOFF_S31 == Settings.module) || (SONOFF_POW_R2 == Settings.module)) { // Sonoff S31 or Sonoff Pow R2
|
||||
baudrate = 4800;
|
||||
serial_config = SERIAL_8E1;
|
||||
energy_calc_power_factor = 1; // Calculate power factor from data
|
||||
energy_flg = XNRG_02;
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ void PzemEvery200ms()
|
||||
energy_current = value;
|
||||
break;
|
||||
case 3: // Power as 20W
|
||||
energy_power = value;
|
||||
energy_active_power = value;
|
||||
break;
|
||||
case 4: // Total energy as 99999Wh
|
||||
if (!energy_start || (value < energy_start)) energy_start = value; // Init after restart and hanlde roll-over if any
|
||||
@ -215,7 +215,6 @@ void PzemDrvInit()
|
||||
{
|
||||
if (!energy_flg) {
|
||||
if ((pin[GPIO_PZEM_RX] < 99) && (pin[GPIO_PZEM_TX] < 99)) { // Any device with a Pzem004T
|
||||
energy_calc_power_factor = 1; // Calculate power factor from data
|
||||
energy_flg = XNRG_03;
|
||||
}
|
||||
}
|
||||
|
@ -448,8 +448,8 @@ void McpParseData(void)
|
||||
if (energy_power_on) { // Powered on
|
||||
energy_frequency = (float)mcp_line_frequency / 1000;
|
||||
energy_voltage = (float)mcp_voltage_rms / 10;
|
||||
energy_power = (float)mcp_active_power / 100;
|
||||
if (0 == energy_power) {
|
||||
energy_active_power = (float)mcp_active_power / 100;
|
||||
if (0 == energy_active_power) {
|
||||
energy_current = 0;
|
||||
} else {
|
||||
energy_current = (float)mcp_current_rms / 10000;
|
||||
@ -457,7 +457,7 @@ void McpParseData(void)
|
||||
} else { // Powered off
|
||||
energy_frequency = 0;
|
||||
energy_voltage = 0;
|
||||
energy_power = 0;
|
||||
energy_active_power = 0;
|
||||
energy_current = 0;
|
||||
}
|
||||
}
|
||||
@ -557,7 +557,6 @@ void McpDrvInit(void)
|
||||
mcp_calibrate = 0;
|
||||
mcp_timeout = 2; // Initial wait
|
||||
mcp_init = 2; // Initial setup steps
|
||||
energy_calc_power_factor = 1; // Calculate power factor from data
|
||||
energy_flg = XNRG_04;
|
||||
}
|
||||
}
|
||||
|
@ -141,12 +141,13 @@ void Pzem2Every200ms()
|
||||
float energy = 0;
|
||||
|
||||
if (PZEM2_TYPES_003_017 == pzem2_type) {
|
||||
energy_type_dc = true;
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
||||
// FE 04 10 27 10 00 64 03 E8 00 00 00 00 00 00 00 00 00 00 HH LL = PZEM-017
|
||||
// Id Cc Sz Volt- Curre Power------ Energy----- HiAlm LoAlm Crc--
|
||||
energy_voltage = (float)((buffer[3] << 8) + buffer[4]) / 100.0; // 655.00 V
|
||||
energy_current = (float)((buffer[5] << 8) + buffer[6]) / 100.0; // 655.00 A
|
||||
energy_power = (float)((uint32_t)buffer[9] << 24 + (uint32_t)buffer[10] << 16 + (uint32_t)buffer[7] << 8 + buffer[8]) / 10.0; // 429496729.0 W
|
||||
energy_active_power = (float)((uint32_t)buffer[9] << 24 + (uint32_t)buffer[10] << 16 + (uint32_t)buffer[7] << 8 + buffer[8]) / 10.0; // 429496729.0 W
|
||||
energy = (float)((uint32_t)buffer[13] << 24 + (uint32_t)buffer[14] << 16 + (uint32_t)buffer[11] << 8 + buffer[12]); // 4294967295 Wh
|
||||
if (!energy_start || (energy < energy_start)) { energy_start = energy; } // Init after restart and hanlde roll-over if any
|
||||
energy_kWhtoday += (energy - energy_start) * 100;
|
||||
@ -154,12 +155,13 @@ void Pzem2Every200ms()
|
||||
EnergyUpdateToday();
|
||||
}
|
||||
else if (PZEM2_TYPES_014_016 == pzem2_type) { // PZEM-014,016
|
||||
energy_type_dc = false;
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
||||
// FE 04 14 08 98 03 E8 00 00 08 98 00 00 00 00 00 00 01 F4 00 64 00 00 HH LL = PZEM-014
|
||||
// Id Cc Sz Volt- Current---- Power------ Energy----- Frequ PFact Alarm Crc--
|
||||
energy_voltage = (float)((buffer[3] << 8) + buffer[4]) / 10.0; // 6553.0 V
|
||||
energy_current = (float)((uint32_t)buffer[7] << 24 + (uint32_t)buffer[8] << 16 + (uint32_t)buffer[5] << 8 + buffer[6]) / 1000.0; // 4294967.000 A
|
||||
energy_power = (float)((uint32_t)buffer[11] << 24 + (uint32_t)buffer[12] << 16 + (uint32_t)buffer[9] << 8 + buffer[10]) / 10.0; // 429496729.0 W
|
||||
energy_active_power = (float)((uint32_t)buffer[11] << 24 + (uint32_t)buffer[12] << 16 + (uint32_t)buffer[9] << 8 + buffer[10]) / 10.0; // 429496729.0 W
|
||||
energy_frequency = (float)((buffer[17] << 8) + buffer[18]) / 10.0; // 50.0 Hz
|
||||
energy_power_factor = (float)((buffer[19] << 8) + buffer[20]) / 100.0; // 1.00
|
||||
energy = (float)((uint32_t)buffer[15] << 24 + (uint32_t)buffer[16] << 16 + (uint32_t)buffer[13] << 8 + buffer[14]); // 4294967295 Wh
|
||||
|
@ -30,7 +30,7 @@
|
||||
--------------------------------------------------------------------------------------------
|
||||
Version Date Action Description
|
||||
--------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
1.0.0.1 20180925 tests - all tests are done with 1x sonoff sv, 2x Wemos D1 (not the mini)
|
||||
- 3 different VEMl6070 sensors from 3 different online shops
|
||||
- all the last three test where good and all looks working so far
|
||||
@ -43,7 +43,7 @@
|
||||
cleaned - source code a little bit
|
||||
added - missing void in function calls: void name(void)
|
||||
added - UV Risk level now defined as UV Index, 0.00 based on NASA standard with text behind the value
|
||||
added - UV Power level now named as UV Power, used W/m2 because official standards
|
||||
added - UV Power level now named as UV Power, used W/m2 because official standards
|
||||
added - automatic fill of the uv-risk compare table based on the coefficient calculation
|
||||
added - suspend and wakeup mode for the uv seonsor
|
||||
- current drain in wake-up-ed mode was around 180uA incl. I2C bus
|
||||
@ -51,7 +51,7 @@
|
||||
changed - 2x the power calculation about some incorrent data sheet values
|
||||
changed - float to double calculation because a rare effect on uv compare map filling
|
||||
- in that case @andrethomas was a big help too (while(work){output=lot_of_fun};)
|
||||
added - USE_VEML6070_RSET
|
||||
added - USE_VEML6070_RSET
|
||||
- in user_config as possible input, different resistor values depending on PCB types
|
||||
added - USE_VEML6070_SHOW_RAW
|
||||
- in user_config, show or show-NOT the uv raw value
|
||||
@ -62,12 +62,12 @@
|
||||
safety - personal, please read this: http://www.segurancaetrabalho.com.br/download/uv_index_karel_vanicek.pdf
|
||||
next - possible i will add the calculation for LAT and LONG coordinates for much more precission
|
||||
- show not only the UV Power value in W/m2, possible a @define value to show it as joule value
|
||||
- add a #define to select how many characters are shown benhind the decimal point for the UV Index
|
||||
- add a #define to select how many characters are shown benhind the decimal point for the UV Index
|
||||
---
|
||||
1.0.0.0 20180912 started - further development by mike2nl - https://github.com/mike2nl/Sonoff-Tasmota
|
||||
forked - from arendst/tasmota - https://github.com/arendst/Sonoff-Tasmota
|
||||
base - code base from arendst too
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifdef USE_I2C
|
||||
@ -87,8 +87,8 @@
|
||||
#define VEML6070_RSET_DEFAULT 270000 // 270K default resistor value 270000 ohm, range from 220K..1Meg
|
||||
#define VEML6070_UV_MAX_INDEX 15 // normal 11, internal on weather laboratories and NASA it's 15 so far the sensor is linear
|
||||
#define VEML6070_UV_MAX_DEFAULT 11 // 11 = public default table values
|
||||
#define VEML6070_POWER_COEFFCIENT 0.025 // based on calculations from Karel Vanicek and reorder by hand
|
||||
#define VEML6070_TABLE_COEFFCIENT 32.86270591 // calculated by hand with help from a friend of mine, a professor which works in aero space things
|
||||
#define VEML6070_POWER_COEFFCIENT 0.025 // based on calculations from Karel Vanicek and reorder by hand
|
||||
#define VEML6070_TABLE_COEFFCIENT 32.86270591 // calculated by hand with help from a friend of mine, a professor which works in aero space things
|
||||
// (resistor, differences, power coefficients and official UV index calculations (LAT & LONG will be added later)
|
||||
|
||||
/********************************************************************************************/
|
||||
@ -110,7 +110,7 @@ void Veml6070Detect(void)
|
||||
Wire.beginTransmission(veml6070_address);
|
||||
Wire.write((itime << 2) | 0x02);
|
||||
uint8_t status = Wire.endTransmission();
|
||||
|
||||
|
||||
if (!status) {
|
||||
veml6070_type = 1;
|
||||
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "VEML6070", veml6070_address);
|
||||
@ -130,7 +130,7 @@ void Veml6070ModeCmd(boolean mode_cmd)
|
||||
} else {
|
||||
opmode = VEML6070_DISABLE;
|
||||
}
|
||||
|
||||
|
||||
veml6070_address = VEML6070_ADDR_L;
|
||||
Wire.beginTransmission(veml6070_address);
|
||||
Wire.write((opmode << 0) | 0x02 | (itime << 2));
|
||||
@ -165,7 +165,7 @@ double Veml6070UvRiskLevel(uint16_t uv_level)
|
||||
{
|
||||
double risk = 0;
|
||||
double uv_risk_map[VEML6070_UV_MAX_INDEX] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
|
||||
// fill the uv-risk compare table based on the coefficient calculation
|
||||
for (uint8_t i = 0; i < VEML6070_UV_MAX_INDEX; i++) {
|
||||
#ifdef USE_VEML6070_RSET
|
||||
@ -179,7 +179,7 @@ double Veml6070UvRiskLevel(uint16_t uv_level)
|
||||
#else
|
||||
uv_risk_map[i] = ( (VEML6070_RSET_DEFAULT / VEML6070_TABLE_COEFFCIENT) / VEML6070_UV_MAX_DEFAULT) * (i+1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// get the uv-risk level
|
||||
if (uv_level < uv_risk_map[VEML6070_UV_MAX_INDEX-1]) {
|
||||
@ -223,8 +223,8 @@ void Veml6070Show(boolean json)
|
||||
{
|
||||
if (veml6070_type) {
|
||||
// wakeup the sensor
|
||||
Veml6070ModeCmd(1);
|
||||
|
||||
Veml6070ModeCmd(1);
|
||||
|
||||
// get values from functions
|
||||
uint16_t uvlevel = Veml6070ReadUv();
|
||||
double uvrisk = Veml6070UvRiskLevel(uvlevel);
|
||||
@ -243,7 +243,7 @@ void Veml6070Show(boolean json)
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_INDEX "\":%s}"), mqtt_data, str_uvrisk);
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"VEML6070\":{\"" D_JSON_UV_POWER "\":%s}"), mqtt_data, str_uvpower);
|
||||
#ifdef USE_DOMOTICZ
|
||||
if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, uvlevel) };
|
||||
if (0 == tele_period) { DomoticzSensor(DZ_ILLUMINANCE, uvlevel); };
|
||||
#endif // USE_DOMOTICZ
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
@ -270,7 +270,7 @@ void Veml6070Show(boolean json)
|
||||
} else {
|
||||
// else for Unknown or Out Of Range error = 99
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_INDEX7, mqtt_data, str_uvrisk);
|
||||
}
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_UV_POWER, mqtt_data, str_uvpower);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
Requirements:
|
||||
- Python
|
||||
- pip json pycurl urllib2 configargparse
|
||||
- pip install json pycurl urllib2 configargparse
|
||||
|
||||
Instructions:
|
||||
Execute command with option -d to retrieve config data from device or
|
||||
@ -31,10 +31,11 @@ Instructions:
|
||||
|
||||
|
||||
Usage:
|
||||
decode-config.py [-h] [-f <filename>] [-d <devicename or IP address>]
|
||||
[-u <user>] [-p <password>] [--format <word>]
|
||||
[--sort <word>] [--raw] [--unhide-pw] [-o <filename>]
|
||||
[-c <filename>] [-V]
|
||||
decode-config.py [-h] [-f <filename>] [-d <host>] [-u <user>]
|
||||
[-p <password>] [--format <word>]
|
||||
[--json-indent <integer>] [--json-compact]
|
||||
[--sort <word>] [--raw] [--unhide-pw] [-o <filename>]
|
||||
[-c <filename>] [-V]
|
||||
|
||||
Decode configuration of Sonoff-Tasmota device. Args that start with '--' (eg.
|
||||
-f) can also be set in a config file (specified via -c). Config file syntax
|
||||
@ -46,21 +47,27 @@ Usage:
|
||||
-h, --help show this help message and exit
|
||||
-c <filename>, --config <filename>
|
||||
Config file, can be used instead of command parameter
|
||||
(defaults to None)
|
||||
(default: None)
|
||||
|
||||
source:
|
||||
-f <filename>, --file <filename>
|
||||
file to retrieve Tasmota configuration from (default:
|
||||
None)
|
||||
-d <devicename or IP address>, --device <devicename or IP address>
|
||||
device to retrieve configuration from (default: None)
|
||||
-d <host>, --device <host>
|
||||
hostname or IP address to retrieve Tasmota
|
||||
configuration from (default: None)
|
||||
-u <user>, --username <user>
|
||||
for -d usage: http access username (default: admin)
|
||||
host http access username (default: admin)
|
||||
-p <password>, --password <password>
|
||||
for -d usage: http access password (default: None)
|
||||
host http access password (default: None)
|
||||
|
||||
output:
|
||||
--format <word> output format ("json" or "text", default: "json")
|
||||
--json-indent <integer>
|
||||
pretty-printed JSON output using indent level
|
||||
(default: "None")
|
||||
--json-compact compact JSON output by eliminate whitespace (default:
|
||||
"not compact")
|
||||
--sort <word> sort result - <word> can be "none" or "name" (default:
|
||||
"name")
|
||||
--raw output raw values (default: processed)
|
||||
@ -72,7 +79,7 @@ Usage:
|
||||
info:
|
||||
-V, --version show program's version number and exit
|
||||
|
||||
Note: Either argument -d <device> or -f <tasmotafile> must be given.
|
||||
Either argument -d <host> or -f <filename> must be given.
|
||||
|
||||
|
||||
Examples:
|
||||
@ -113,7 +120,7 @@ except ImportError:
|
||||
sys.exit(9)
|
||||
|
||||
|
||||
VER = '1.5.0008'
|
||||
VER = '1.5.0009'
|
||||
PROG='{} v{} by Norbert Richter'.format(os.path.basename(sys.argv[0]),VER)
|
||||
|
||||
CONFIG_FILE_XOR = 0x5A
|
||||
@ -135,6 +142,8 @@ DEFAULTS = {
|
||||
'output':
|
||||
{
|
||||
'format': 'json',
|
||||
'jsonindent': None,
|
||||
'jsoncompact': False,
|
||||
'sort': 'name',
|
||||
'raw': False,
|
||||
'unhide-pw': False,
|
||||
@ -940,7 +949,7 @@ Setting_5_14_0 = {
|
||||
'knx_CB_addr': ('<H', 0x6CE, [10]),
|
||||
'knx_GA_param': ('B', 0x6E2, [10]),
|
||||
'knx_CB_param': ('B', 0x6EC, [10]),
|
||||
'rules': ('512s',0x800, [3])
|
||||
'rules': ('512s',0x800, None)
|
||||
}
|
||||
Setting_5_13_1 = {
|
||||
'cfg_holder': ('<L', 0x000, None),
|
||||
@ -1109,7 +1118,7 @@ Setting_5_13_1 = {
|
||||
'knx_CB_addr': ('<H', 0x6CE, [10]),
|
||||
'knx_GA_param': ('B', 0x6E2, [10]),
|
||||
'knx_CB_param': ('B', 0x6EC, [10]),
|
||||
'rules': ('512s',0x800, [3])
|
||||
'rules': ('512s',0x800, None)
|
||||
}
|
||||
Setting_5_12_0 = {
|
||||
'cfg_holder': ('<L', 0x000, None),
|
||||
@ -1550,9 +1559,9 @@ Settings = [(0x6020100, 0xe00, Setting_6_2_1),
|
||||
(0x6000000, 0xe00, Setting_6_0_0),
|
||||
(0x50e0000, 0xa00, Setting_5_14_0),
|
||||
(0x50d0100, 0xa00, Setting_5_13_1),
|
||||
(0x50c0000, 0x66d, Setting_5_12_0),
|
||||
(0x50b0000, 0x66d, Setting_5_11_0),
|
||||
(0x50a0000, 0x66d, Setting_5_10_0),
|
||||
(0x50c0000, 0x670, Setting_5_12_0),
|
||||
(0x50b0000, 0x670, Setting_5_11_0),
|
||||
(0x50a0000, 0x670, Setting_5_10_0),
|
||||
]
|
||||
|
||||
|
||||
@ -1666,7 +1675,7 @@ def GetFieldLength(fielddef):
|
||||
# it's a single value
|
||||
return length
|
||||
|
||||
def ConvertFieldValue(value, fielddef):
|
||||
def ConvertFieldValue(value, fielddef, raw=False):
|
||||
"""
|
||||
Convert field value based on field desc
|
||||
|
||||
@ -1674,10 +1683,12 @@ def ConvertFieldValue(value, fielddef):
|
||||
original value read from binary data
|
||||
@param fielddef
|
||||
field definition (contains possible conversion defiinition)
|
||||
@param raw
|
||||
return raw values (True) or converted values (False)
|
||||
|
||||
@return: (und)converted value
|
||||
@return: (un)converted value
|
||||
"""
|
||||
if not args.raw and len(fielddef)>3:
|
||||
if not raw and len(fielddef)>3:
|
||||
if isinstance(fielddef[3],str): # use a format string
|
||||
return fielddef[3].format(value)
|
||||
elif callable(fielddef[3]): # use a format function
|
||||
@ -1685,7 +1696,7 @@ def ConvertFieldValue(value, fielddef):
|
||||
return value
|
||||
|
||||
|
||||
def GetField(dobj, fieldname, fielddef):
|
||||
def GetField(dobj, fieldname, fielddef, raw=False):
|
||||
"""
|
||||
Get field value from definition
|
||||
|
||||
@ -1695,6 +1706,8 @@ def GetField(dobj, fieldname, fielddef):
|
||||
name of the field
|
||||
@param fielddef:
|
||||
see Settings desc above
|
||||
@param raw
|
||||
return raw values (True) or converted values (False)
|
||||
|
||||
@return: read field value
|
||||
"""
|
||||
@ -1715,13 +1728,13 @@ def GetField(dobj, fieldname, fielddef):
|
||||
subfielddef = (fielddef[0], addr, None, None if len(fielddef)<4 else fielddef[3])
|
||||
length = GetFieldLength(subfielddef)
|
||||
if length != 0:
|
||||
result.append(GetField(dobj, fieldname, subfielddef))
|
||||
result.append(GetField(dobj, fieldname, subfielddef, raw))
|
||||
addr += length
|
||||
# tuple 2 contains a list with dict
|
||||
elif isinstance(fielddef[2], list) and len(fielddef[2])>0 and isinstance(fielddef[2][0], dict):
|
||||
d = {}
|
||||
value = struct.unpack_from(fielddef[0], dobj, fielddef[1])[0]
|
||||
d['base'] = ConvertFieldValue(value, fielddef);
|
||||
d['base'] = ConvertFieldValue(value, fielddef, raw);
|
||||
union = fielddef[2]
|
||||
i = 0
|
||||
for l in union:
|
||||
@ -1738,8 +1751,8 @@ def GetField(dobj, fieldname, fielddef):
|
||||
if ord(result[:1])==0x00 or ord(result[:1])==0xff:
|
||||
result = ''
|
||||
s = str(result).split('\0')[0]
|
||||
result = s #unicode(s, errors='replace')
|
||||
result = ConvertFieldValue(result, fielddef)
|
||||
result = unicode(s, errors='replace')
|
||||
result = ConvertFieldValue(result, fielddef, raw)
|
||||
|
||||
return result
|
||||
|
||||
@ -1762,40 +1775,52 @@ def DeEncrypt(obj):
|
||||
|
||||
def Decode(obj):
|
||||
"""
|
||||
Decodes (already decrypted) binary data stream
|
||||
Decodes binary data stream
|
||||
|
||||
@param obj:
|
||||
binary config data
|
||||
binary config data (decrypted)
|
||||
"""
|
||||
# get header data
|
||||
cfg_size = GetField(obj, 'cfg_size', Setting_6_2_1['cfg_size'])
|
||||
version = GetField(obj, 'version', Setting_6_2_1['version'])
|
||||
version = GetField(obj, 'version', Setting_6_2_1['version'], raw=True)
|
||||
|
||||
# search setting definition
|
||||
setting = None
|
||||
template = None
|
||||
for cfg in Settings:
|
||||
if version >= cfg[0] and cfg_size == cfg[1]:
|
||||
if version >= cfg[0]:
|
||||
template = cfg
|
||||
break
|
||||
|
||||
setting = template[2]
|
||||
# if we did not found a mathching setting
|
||||
if setting is None:
|
||||
exit(2, "Can't handle Tasmota configuration data for version 0x{:x} with {} bytes".format(version, cfg_size) )
|
||||
if template is None:
|
||||
exit(2, "Can't handle Tasmota configuration data for version 0x{:x}".format(version) )
|
||||
|
||||
if GetField(obj, 'cfg_crc', setting['cfg_crc']) != GetSettingsCrc(obj):
|
||||
setting = template[2]
|
||||
|
||||
# check size if exists
|
||||
if 'cfg_size' in setting:
|
||||
cfg_size = GetField(obj, 'cfg_size', setting['cfg_size'], raw=True)
|
||||
# if we did not found a mathching setting
|
||||
if cfg_size != template[1]:
|
||||
exit(2, "Data size does not match. Expected {} bytes, read {} bytes.".format(template[1], cfg_size) )
|
||||
|
||||
# check crc if exists
|
||||
if 'cfg_crc' in setting:
|
||||
cfg_crc = GetField(obj, 'cfg_crc', setting['cfg_crc'], raw=True)
|
||||
else:
|
||||
cfg_crc = GetSettingsCrc(obj)
|
||||
if cfg_crc != GetSettingsCrc(obj):
|
||||
exit(3, 'Data crc error' )
|
||||
|
||||
config = {}
|
||||
config['version_template'] = '0x{:x}'.format(template[0])
|
||||
for name in setting:
|
||||
config[name] = GetField(obj, name, setting[name])
|
||||
config[name] = GetField(obj, name, setting[name], args.raw)
|
||||
|
||||
if args.sort == 'name':
|
||||
config = collections.OrderedDict(sorted(config.items()))
|
||||
|
||||
if args.format == 'json':
|
||||
print json.dumps(config, sort_keys=args.sort=='name')
|
||||
print json.dumps(config, sort_keys=args.sort=='name', indent=args.jsonindent, separators=(',', ':') if args.jsoncompact else (', ', ': ') )
|
||||
else:
|
||||
for key,value in config.items():
|
||||
print '{} = {}'.format(key, repr(value))
|
||||
@ -1804,7 +1829,7 @@ def Decode(obj):
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = configargparse.ArgumentParser(description='Decode configuration of Sonoff-Tasmota device.',
|
||||
epilog='Note: Either argument -d <device> or -f <tasmotafile> must be given.')
|
||||
epilog='Either argument -d <host> or -f <filename> must be given.')
|
||||
|
||||
source = parser.add_argument_group('source')
|
||||
source.add_argument('-f', '--file',
|
||||
@ -1813,20 +1838,20 @@ if __name__ == "__main__":
|
||||
default=DEFAULTS['source']['tasmotafile'],
|
||||
help='file to retrieve Tasmota configuration from (default: {})'.format(DEFAULTS['source']['tasmotafile']))
|
||||
source.add_argument('-d', '--device',
|
||||
metavar='<devicename or IP address>',
|
||||
metavar='<host>',
|
||||
dest='device',
|
||||
default=DEFAULTS['source']['device'],
|
||||
help='device to retrieve configuration from (default: {})'.format(DEFAULTS['source']['device']) )
|
||||
help='hostname or IP address to retrieve Tasmota configuration from (default: {})'.format(DEFAULTS['source']['device']) )
|
||||
source.add_argument('-u', '--username',
|
||||
metavar='<user>',
|
||||
dest='username',
|
||||
default=DEFAULTS['source']['username'],
|
||||
help='for -d usage: http access username (default: {})'.format(DEFAULTS['source']['username']))
|
||||
help='host http access username (default: {})'.format(DEFAULTS['source']['username']))
|
||||
source.add_argument('-p', '--password',
|
||||
metavar='<password>',
|
||||
dest='password',
|
||||
default=DEFAULTS['source']['password'],
|
||||
help='for -d usage: http access password (default: {})'.format(DEFAULTS['source']['password']))
|
||||
help='host http access password (default: {})'.format(DEFAULTS['source']['password']))
|
||||
|
||||
output = parser.add_argument_group('output')
|
||||
output.add_argument('--format',
|
||||
@ -1835,6 +1860,17 @@ if __name__ == "__main__":
|
||||
choices=['json', 'text'],
|
||||
default=DEFAULTS['output']['format'],
|
||||
help='output format ("json" or "text", default: "{}")'.format(DEFAULTS['output']['format']) )
|
||||
output.add_argument('--json-indent',
|
||||
metavar='<integer>',
|
||||
dest='jsonindent',
|
||||
type=int,
|
||||
default=DEFAULTS['output']['jsonindent'],
|
||||
help='pretty-printed JSON output using indent level (default: "{}")'.format(DEFAULTS['output']['jsonindent']) )
|
||||
output.add_argument('--json-compact',
|
||||
dest='jsoncompact',
|
||||
action='store_true',
|
||||
default=DEFAULTS['output']['jsoncompact'],
|
||||
help='compact JSON output by eliminate whitespace (default: "{}")'.format('compact' if DEFAULTS['output']['jsoncompact'] else 'not compact') )
|
||||
output.add_argument('--sort',
|
||||
metavar='<word>',
|
||||
dest='sort',
|
||||
@ -1862,7 +1898,7 @@ if __name__ == "__main__":
|
||||
dest='configfile',
|
||||
default=DEFAULTS['DEFAULT']['configfile'],
|
||||
is_config_file=True,
|
||||
help='Config file, can be used instead of command parameter (defaults to {})'.format(DEFAULTS['DEFAULT']['configfile']) )
|
||||
help='Config file, can be used instead of command parameter (default: {})'.format(DEFAULTS['DEFAULT']['configfile']) )
|
||||
|
||||
info = parser.add_argument_group('info')
|
||||
info.add_argument('-V', '--version', action='version', version=PROG)
|
||||
@ -1921,4 +1957,7 @@ if __name__ == "__main__":
|
||||
Decode(cfg)
|
||||
|
||||
else:
|
||||
exit(4, "Could not read configuration data from {} '{}'".format('device' if args.device is not None else 'file', args.device if args.device is not None else args.tasmotafile) )
|
||||
exit(4, "Could not read configuration data from {} '{}'".format('device' if args.device is not None else 'file', \
|
||||
args.device if args.device is not None else args.tasmotafile) )
|
||||
|
||||
sys.exit(0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user