diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 81b066e38..2fcda28f5 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.2.0.3 +### Version 8.2.0.4 - Change HM-10 sensor type detection and add features (#7962) - Change light scheme 2,3,4 cycle time speed from 24,48,72,... seconds to 4,6,12,24,36,48,... seconds (#8034) diff --git a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp index f4a17f368..6635f6d4d 100644 --- a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp +++ b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp @@ -20,18 +20,44 @@ #include #include #include "esp8266toEsp32.h" + // ESP Stuff -struct rst_info resetInfo; + +String ESP32GetResetReason(uint32_t cpu_no) +{ + // tools\sdk\include\esp32\rom\rtc.h + switch (rtc_get_reset_reason( (RESET_REASON) cpu_no)) { + case POWERON_RESET : return F("Vbat power on reset"); // 1 + case SW_RESET : return F("Software reset digital core"); // 3 + case OWDT_RESET : return F("Legacy watch dog reset digital core"); // 4 + case DEEPSLEEP_RESET : return F("Deep Sleep reset digital core"); // 5 + case SDIO_RESET : return F("Reset by SLC module, reset digital core"); // 6 + case TG0WDT_SYS_RESET : return F("Timer Group0 Watch dog reset digital core"); // 7 + case TG1WDT_SYS_RESET : return F("Timer Group1 Watch dog reset digital core"); // 8 + case RTCWDT_SYS_RESET : return F("RTC Watch dog Reset digital core"); // 9 + case INTRUSION_RESET : return F("Instrusion tested to reset CPU"); // 10 + case TGWDT_CPU_RESET : return F("Time Group reset CPU"); // 11 + case SW_CPU_RESET : return F("Software reset CPU"); // 12 + case RTCWDT_CPU_RESET : return F("RTC Watch dog Reset CPU"); // 13 + case EXT_CPU_RESET : return F("or APP CPU, reseted by PRO CPU"); // 14 + case RTCWDT_BROWN_OUT_RESET : return F("Reset when the vdd voltage is not stable"); // 15 + case RTCWDT_RTC_RESET : return F("RTC Watch dog reset digital core and rtc module"); // 16 + default : return F("NO_MEAN"); // 0 + } +} String ESP_getResetReason(void) { - // CPU 0 - return String(rtc_get_reset_reason(0)); + return ESP32GetResetReason(0); // CPU 0 } -String ESP_getResetInfo(void) +uint32_t ESP_ResetInfoReason(void) { - return String(PSTR("0")); + RESET_REASON reason = rtc_get_reset_reason(0); + if (POWERON_RESET == reason) { return REASON_DEFAULT_RST; } + if (SW_CPU_RESET == reason) { return REASON_SOFT_RESTART; } + if (DEEPSLEEP_RESET == reason) { return REASON_DEEP_SLEEP_AWAKE; } + if (SW_RESET == reason) { return REASON_EXT_SYS_RST; } } uint32_t ESP_getBootVersion(void) @@ -74,11 +100,6 @@ String String_ESP_getChipId() return String(uint32_t(mac >> 32)) + String(uint32_t(mac)); } -uint32_t ESP_getFlashChipRealSize() -{ - return ESP.getFlashChipSize(); -} - uint32_t ESP_getSketchSize(void) { static uint32_t sketchsize = 0; @@ -88,3 +109,12 @@ uint32_t ESP_getSketchSize(void) } return sketchsize; } + +#include "soc/soc.h" +#include "soc/rtc_cntl_reg.h" + +void DisableBrownout(void) +{ + // https://github.com/espressif/arduino-esp32/issues/863#issuecomment-347179737 + WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // Disable brownout detector +} diff --git a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h index 8a30da55d..276772b95 100644 --- a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h +++ b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h @@ -34,16 +34,16 @@ #define ESP_flashReadHeader(offset, data, size) ESP32_flashRead(offset, data, size) #define ESP_flashRead(offset, data, size) ESP32_flashRead(offset, data, size) String ESP_getResetReason(void); +uint32_t ESP_ResetInfoReason(void); uint32_t ESP_getBootVersion(void); bool ESP_rtcUserMemoryWrite(uint32_t offset, uint32_t *data, size_t size); bool ESP_rtcUserMemoryRead(uint32_t offset, uint32_t *data, size_t size); void ESP_reset(); -String ESP_getResetInfo(void); uint32_t ESP_getFlashChipId(); uint32_t ESP_getChipId(); String String_ESP_getChipId(); -uint32_t ESP_getFlashChipRealSize(); uint32_t ESP_getSketchSize(); +void DisableBrownout(void); // Analog inline void analogWrite(uint8_t pin, int val) @@ -67,7 +67,6 @@ typedef double real64_t; #define ETS_UART_INTR_DISABLE() #define ETS_UART_INTR_ENABLE() -#define getChipId() getEfuseMac() #define ESPhttpUpdate httpUpdate #define getFlashChipRealSize() getFlashChipSize() @@ -92,14 +91,13 @@ typedef int SerialConfig; #undef LWIP_IPV6 -struct rst_info -{ - int reason; -}; - -#define REASON_DEFAULT_RST 1 -#define REASON_EXT_SYS_RST 2 -#define REASON_DEEP_SLEEP_AWAKE 3 +#define REASON_DEFAULT_RST 0 // "Power on" normal startup by power on +#define REASON_WDT_RST 1 // "Hardware Watchdog" hardware watch dog reset +#define REASON_EXCEPTION_RST 2 // "Exception" exception reset, GPIO status won’t change +#define REASON_SOFT_WDT_RST 3 // "Software Watchdog" software watch dog reset, GPIO status won’t change +#define REASON_SOFT_RESTART 4 // "Software/System restart" software restart ,system_restart , GPIO status won’t change +#define REASON_DEEP_SLEEP_AWAKE 5 // "Deep-Sleep Wake" wake up from deep-sleep +#define REASON_EXT_SYS_RST 6 // "External System" external system reset // memmove ... #define memcpy_P memcpy diff --git a/pio/name-firmware.py b/pio/name-firmware.py index dfb9b7f85..1490ecc5c 100644 --- a/pio/name-firmware.py +++ b/pio/name-firmware.py @@ -28,6 +28,7 @@ def bin_map_copy(source, target, env): shutil.copy(str(target[0]), bin_file) # copy firmware.map to map/.map - shutil.copy("firmware.map", map_file) + if os.path.isfile("firmware.map"): + shutil.move("firmware.map", map_file) env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_map_copy]) diff --git a/platformio.ini b/platformio.ini index 6a3820d02..f29d5f363 100755 --- a/platformio.ini +++ b/platformio.ini @@ -87,17 +87,21 @@ extra_scripts = pio/strip-floats.py pio/name-firmware.py pio/gzip-firmware.py -[esp82xx_defaults] -build_flags = -D NDEBUG - -mtarget-align - -Wl,-Map,firmware.map - -DFP_IN_IROM -; new mechanism to set the IRremoteESP8266 supported protocols: none except HASH, NEC, RC5, RC6 - -D_IR_ENABLE_DEFAULT_=false +[esp_defaults] +build_flags = -D_IR_ENABLE_DEFAULT_=false -DDECODE_HASH=true -DDECODE_NEC=true -DSEND_NEC=true -DDECODE_RC5=true -DSEND_RC5=true -DDECODE_RC6=true -DSEND_RC6=true +; new mechanism to set the IRremoteESP8266 supported protocols: none except HASH, NEC, RC5, RC6 -[irremoteesp8266_full] +[esp82xx_defaults] +build_flags = ${esp_defaults.build_flags} + -Wl,-Map,firmware.map + -D NDEBUG + -mtarget-align + -DFP_IN_IROM + + +[irremoteesp_full] build_flags = -DUSE_IR_REMOTE_FULL -U_IR_ENABLE_DEFAULT_ -DDECODE_PRONTO=false -DSEND_PRONTO=false diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 11c0d7ee0..8e898f6b6 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -12,6 +12,7 @@ [platformio] extra_configs = platformio_tasmota_env32.ini + platformio_tasmota_cenv.ini ; *** Build/upload environment default_envs = @@ -54,7 +55,7 @@ build_flags = ${core_active.build_flags} upload_port = COM5 extra_scripts = ${scripts_defaults.extra_scripts} - pio/obj-dump.py +; pio/obj-dump.py ; *** Upload file to OTA server using SCP ;upload_port = user@host:/path @@ -227,7 +228,7 @@ build_type = debug [common32] platform = espressif32@1.12.0 -platform_packages = +platform_packages = tool-esptoolpy@1.20800.0 board = wemos_d1_mini32 board_build.ldscript = esp32_out.ld board_build.partitions = esp32_partition_app1984k_spiffs64k.csv @@ -240,7 +241,7 @@ upload_resetmethod = ${common.upload_resetmethod} upload_speed = 921600 extra_scripts = ${common.extra_scripts} -build_flags = +build_flags = ${esp_defaults.build_flags} -D BUFFER_LENGTH=128 -D MQTT_MAX_PACKET_SIZE=1200 -D uint32=uint32_t diff --git a/platformio_tasmota_env.ini b/platformio_tasmota_env.ini index a09f01ecd..f122eae1b 100644 --- a/platformio_tasmota_env.ini +++ b/platformio_tasmota_env.ini @@ -32,10 +32,10 @@ build_flags = ${common.build_flags} -DFIRMWARE_SENSORS build_flags = ${common.build_flags} -DFIRMWARE_DISPLAYS [env:tasmota-ir] -build_flags = ${common.build_flags} ${irremoteesp8266_full.build_flags} -DFIRMWARE_IR +build_flags = ${common.build_flags} ${irremoteesp_full.build_flags} -DFIRMWARE_IR [env:tasmota-ircustom] -build_flags = ${common.build_flags} ${irremoteesp8266_full.build_flags} +build_flags = ${common.build_flags} ${irremoteesp_full.build_flags} [env:tasmota-BG] build_flags = ${common.build_flags} -DMY_LANGUAGE=bg-BG diff --git a/platformio_tasmota_env32.ini b/platformio_tasmota_env32.ini index 4f6661c17..71bef8558 100644 --- a/platformio_tasmota_env32.ini +++ b/platformio_tasmota_env32.ini @@ -129,7 +129,7 @@ extra_scripts = ${common32.extra_scripts} lib_extra_dirs = ${common32.lib_extra_dirs} lib_ignore = ${common32.lib_ignore} build_unflags = ${common32.build_unflags} -build_flags = ${common32.build_flags} ${irremoteesp8266_full.build_flags} -DFIRMWARE_IR +build_flags = ${common32.build_flags} ${irremoteesp_full.build_flags} -DFIRMWARE_IR [env:tasmota32-ircustom] framework = ${common.framework} @@ -148,7 +148,7 @@ extra_scripts = ${common32.extra_scripts} lib_extra_dirs = ${common32.lib_extra_dirs} lib_ignore = ${common32.lib_ignore} build_unflags = ${common32.build_unflags} -build_flags = ${common32.build_flags} ${irremoteesp8266_full.build_flags} +build_flags = ${common32.build_flags} ${irremoteesp_full.build_flags} [env:tasmota32-BG] framework = ${common.framework} diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index ede692fb4..0fb205aff 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -1,5 +1,10 @@ ## Unreleased (development) +### 8.2.0.4 20200417 + +- Add config version tag +- Fix Zigbee DimmerUp/DimmerDown malformed + ### 8.2.0.3 20200329 - Change light scheme 2,3,4 cycle time speed from 24,48,72,... seconds to 4,6,12,24,36,48,... seconds (#8034) diff --git a/tasmota/Parsing.cpp b/tasmota/Parsing.cpp index 145b72572..a7665d7b1 100644 --- a/tasmota/Parsing.cpp +++ b/tasmota/Parsing.cpp @@ -19,6 +19,8 @@ Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling) */ +#ifdef ESP8266 + // Use patched Parsing.cpp to fix ALEXA parsing issue in v2.4.2 #include #if defined(ARDUINO_ESP8266_RELEASE_2_4_2) @@ -620,4 +622,6 @@ bool ESP8266WebServer::_parseFormUploadAborted(){ return false; } -#endif // ARDUINO_ESP8266_RELEASE \ No newline at end of file +#endif // ARDUINO_ESP8266_RELEASE + +#endif // ESP8266 diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 35a840acf..9f99d7c1d 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -297,6 +297,7 @@ #define D_CMND_DEVGROUP_NAME "DevGroupName" #define D_CMND_DEVGROUP_SEND "DevGroupSend" #define D_CMND_DEVGROUP_SHARE "DevGroupShare" +#define D_CMND_DEVGROUPSTATUS "DevGroupStatus" #define D_CMND_SERIALSEND "SerialSend" #define D_CMND_SERIALDELIMITER "SerialDelimiter" #define D_CMND_BAUDRATE "Baudrate" diff --git a/tasmota/language/it-IT.h b/tasmota/language/it-IT.h index 934fcfc75..4f1cfbe17 100644 --- a/tasmota/language/it-IT.h +++ b/tasmota/language/it-IT.h @@ -567,8 +567,8 @@ #define D_SENSOR_SPI_MOSI "SPI - MOSI" #define D_SENSOR_SPI_CLK "SPI - CLK" #define D_SENSOR_BACKLIGHT "Retroilluminazione" -#define D_SENSOR_PMS5003_TX "PMS5003 Tx" -#define D_SENSOR_PMS5003_RX "PMS5003 Rx" +#define D_SENSOR_PMS5003_TX "PMS5003 - TX" +#define D_SENSOR_PMS5003_RX "PMS5003 - RX" #define D_SENSOR_SDS0X1_RX "SDS0X1 - RX" #define D_SENSOR_SDS0X1_TX "SDS0X1 - TX" #define D_SENSOR_HPMA_RX "HPMA - RX" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 97476820f..6ac041770 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -391,7 +391,7 @@ #define SUNRISE_DAWN_ANGLE DAWN_NORMAL // Select desired Dawn Angle from (DAWN_NORMAL, DAWN_CIVIL, DAWN_NAUTIC, DAWN_ASTRONOMIC) // -- Ping ---------------------------------------- -// #define USE_PING // Enable Ping command (+3k code) +// #define USE_PING // Enable Ping command (+2k code) // -- Rules or Script ---------------------------- // Select none or only one of the below defines diff --git a/tasmota/settings.h b/tasmota/settings.h index 3f8827636..2c3a22af4 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -86,7 +86,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t energy_weekend : 1; // bit 20 (v6.6.0.8) - CMND_TARIFF uint32_t dds2382_model : 1; // bit 21 (v6.6.0.14) - SetOption71 - Select different Modbus registers for Active Energy (#6531) uint32_t hardware_energy_total : 1; // bit 22 (v6.6.0.15) - SetOption72 - Enable hardware energy total counter as reference (#6561) - uint32_t mqtt_buttons : 1; // bit 23 (v8.2.0.3) - SetOption73 - Detach buttons from relays and enable MQTT action state for multipress + uint32_t mqtt_buttons : 1; // bit 23 (v8.2.0.3) - SetOption73 - Detach buttons from relays and enable MQTT action state for multipress uint32_t ds18x20_internal_pullup : 1; // bit 24 (v7.0.0.1) - SetOption74 - Enable internal pullup for single DS18x20 sensor uint32_t grouptopic_mode : 1; // bit 25 (v7.0.0.1) - SetOption75 - GroupTopic replaces %topic% (0) or fixed topic cmnd/grouptopic (1) uint32_t bootcount_update : 1; // bit 26 (v7.0.0.4) - SetOption76 - Enable incrementing bootcount when deepsleep is enabled @@ -245,7 +245,7 @@ typedef struct { } EnergyUsage; -typedef struct PACKED { +typedef struct { uint8_t fnid = 0; uint8_t dpid = 0; } TuyaFnidDpidMap; @@ -253,7 +253,7 @@ typedef struct PACKED { const uint32_t settings_text_size = 699; // Settings.text_pool[size] = Settings.display_model (2D2) - Settings.text_pool (017) const uint8_t MAX_TUYA_FUNCTIONS = 16; -struct PACKED SYSCFG { +struct SYSCFG { uint16_t cfg_holder; // 000 v6 header uint16_t cfg_size; // 002 unsigned long save_flag; // 004 @@ -369,7 +369,13 @@ struct PACKED SYSCFG { uint8_t module; // 474 uint8_t ws_color[4][3]; // 475 uint8_t ws_width[3]; // 481 - myio my_gp; // 484 + +#ifdef ESP8266 + myio my_gp; // 484 - 17 bytes (ESP8266) +#else // ESP32 + uint8_t free_esp32_484[17]; // 484 +#endif // ESP8266 - ESP32 + uint8_t my_adc0; // 495 uint16_t light_pixels; // 496 uint8_t light_color[5]; // 498 @@ -397,7 +403,14 @@ struct PACKED SYSCFG { uint32_t ip_address[4]; // 544 unsigned long energy_kWhtotal; // 554 +#ifdef ESP8266 char ex_mqtt_fulltopic[100]; // 558 +#else // ESP32 + myio my_gp; // 558 - 40 bytes (ESP32) + mytmplt user_template; // 580 - 35 bytes (ESP32) + + uint8_t free_esp32_5a3[25]; // 5A3 +#endif // ESP8266 - ESP32 SysBitfield2 flag2; // 5BC unsigned long pulse_counter[MAX_COUNTERS]; // 5C0 @@ -423,7 +436,12 @@ struct PACKED SYSCFG { char user_template_name[15]; // 720 15 bytes - Backward compatibility since v8.2.0.3 - mytmplt user_template; // 72F 14 bytes +#ifdef ESP8266 + mytmplt user_template; // 72F 14 bytes (ESP8266) +#else // ESP32 + uint8_t free_esp32_72f[14]; // 72F +#endif // ESP8266 - ESP32 + uint8_t novasds_startingoffset; // 73D uint8_t web_color[18][3]; // 73E uint16_t display_width; // 774 @@ -506,9 +524,11 @@ struct PACKED SYSCFG { uint8_t zb_channel; // F32 uint8_t zb_free_byte; // F33 uint16_t pms_wake_interval; // F34 + uint8_t config_version; // F36 - uint8_t free_f36[130]; // F36 + uint8_t free_f37[129]; // F37 - Decrement if adding new Setting variables just above and below + // Only 32 bit boundary variables below uint16_t pulse_counter_debounce_low; // FB8 uint16_t pulse_counter_debounce_high; // FBA uint32_t keeloq_master_msb; // FBC diff --git a/tasmota/settings.ino b/tasmota/settings.ino index 53110155f..1769b676d 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -1337,6 +1337,15 @@ void SettingsDelta(void) } #endif // ESP8266 + if (Settings.version < 0x08020004) { +#ifdef ESP8266 + Settings.config_version = 0; // ESP8266 (Has been 0 for long time) +#endif // ESP8266 +#ifdef ESP32 + Settings.config_version = 1; // ESP32 +#endif // ESP32 + } + Settings.version = VERSION; SettingsSave(1); } diff --git a/tasmota/support.ino b/tasmota/support.ino index 9c720c996..65605abd3 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -99,7 +99,11 @@ uint32_t ResetReason(void) REASON_DEEP_SLEEP_AWAKE = 5, // "Deep-Sleep Wake" wake up from deep-sleep REASON_EXT_SYS_RST = 6 // "External System" external system reset */ +#ifdef ESP8266 return resetInfo.reason; +#else + return ESP_ResetInfoReason(); +#endif } String GetResetReason(void) @@ -1127,7 +1131,11 @@ void ModuleGpios(myio *gp) if (USER_MODULE == Settings.module) { memcpy(&src, &Settings.user_template.gp, sizeof(mycfgio)); } else { +#ifdef ESP8266 memcpy_P(&src, &kModules[Settings.module].gp, sizeof(mycfgio)); +#else // ESP32 + memcpy_P(&src, &kModules.gp, sizeof(mycfgio)); +#endif // ESP8266 - ESP32 } // 11 85 00 85 85 00 00 00 15 38 85 00 00 81 @@ -1138,10 +1146,9 @@ void ModuleGpios(myio *gp) #ifdef ESP8266 if (6 == i) { j = 9; } if (8 == i) { j = 12; } -#endif // ESP8266 -#ifdef ESP32 +#else // ESP32 if (6 == i) { j = 12; } -#endif // ESP32 +#endif // ESP8266 - ESP32 dest[j] = src[i]; j++; } @@ -1154,11 +1161,24 @@ gpio_flag ModuleFlag(void) { gpio_flag flag; +#ifdef ESP8266 if (USER_MODULE == Settings.module) { flag = Settings.user_template.flag; } else { memcpy_P(&flag, &kModules[Settings.module].flag, sizeof(gpio_flag)); } +#else // ESP32 + if (USER_MODULE == Settings.module) { +/* + gpio_flag gpio_adc0; + memcpy_P(&gpio_adc0, &Settings.user_template.gp + ADC0_PIN - MIN_FLASH_PINS, sizeof(gpio_flag)); + flag = Settings.user_template.flag.data + gpio_adc0.data; +*/ + memcpy_P(&flag, &Settings.user_template.gp + ADC0_PIN - MIN_FLASH_PINS, sizeof(gpio_flag)); + } else { + memcpy_P(&flag, &kModules.gp + ADC0_PIN - MIN_FLASH_PINS, sizeof(gpio_flag)); + } +#endif // ESP8266 - ESP32 return flag; } @@ -1169,7 +1189,11 @@ void ModuleDefault(uint32_t module) Settings.user_template_base = module; char name[TOPSZ]; SettingsUpdateText(SET_TEMPLATE_NAME, GetTextIndexed(name, sizeof(name), module, kModuleNames)); +#ifdef ESP8266 memcpy_P(&Settings.user_template, &kModules[module], sizeof(mytmplt)); +#else // ESP32 + memcpy_P(&Settings.user_template, &kModules, sizeof(mytmplt)); +#endif // ESP8266 - ESP32 } void SetModuleType(void) diff --git a/tasmota/support_button_v2.ino b/tasmota/support_button_v2.ino index d345b58d2..9548a2b4f 100644 --- a/tasmota/support_button_v2.ino +++ b/tasmota/support_button_v2.ino @@ -1,7 +1,7 @@ /* - support_button.ino - button support for Tasmota + support_button_v2.ino - button support for Tasmota - Copyright (C) 2020 Theo Arends + Copyright (C) 2020 Federico Leoni and Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,12 +23,8 @@ * Button support \*********************************************************************************************/ -#define MAX_BUTTON_COMMANDS_V2 3 // Max number of button commands supported #define MAX_RELAY_BUTTON1 4 // Max number of relay controlled by button1 -const char kCommands[] PROGMEM = - D_CMND_WIFICONFIG " 2|" D_CMND_RESTART " 1|" D_CMND_UPGRADE " 1"; - //D_CMND_WIFICONFIG " 2|" D_CMND_WIFICONFIG " 2|" D_CMND_WIFICONFIG " 2|" D_CMND_RESTART " 1|" D_CMND_UPGRADE " 1"; const char kMultiPress[] PROGMEM = "|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|"; @@ -107,7 +103,6 @@ uint8_t ButtonSerial(uint8_t serial_in_byte) * SetOption11 (0) - If set perform single press action on double press and reverse * SetOption13 (0) - If set act on single press only * SetOption32 (40) - Max button hold time in Seconds - * SetOption40 (0) - Number of 0.1 seconds until hold is discarded if SetOption1 1 and SetOption13 0 * SetOption73 (0) - Decouple button from relay and send just mqtt topic \*********************************************************************************************/ @@ -177,16 +172,19 @@ void ButtonHandler(void) if (!Button.hold_timer[button_index]) { button_pressed = true; } // Do not allow within 1 second } if (button_pressed) { - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - - } + if (!Settings.flag3.mqtt_buttons) { + if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally + } else { + MqttButtonTopic(button_index +1, 1, 0); // SetOption73 (0) - Decouple button from relay and send just mqtt topic } + } + } } } #endif // ESP8266 else { - - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { + if (((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index]) && !Button.inverted_mask) || + ((NOT_PRESSED == button) && (PRESSED == Button.last_state[button_index]) && Button.inverted_mask)) { if (Settings.flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action, SetOption73 (0) - Decouple button from relay and send just mqtt topic if (!Settings.flag3.mqtt_buttons) { @@ -203,9 +201,9 @@ void ButtonHandler(void) Button.window_timer[button_index] = loops_per_second / 2; // 0.5 second multi press window } blinks = 201; - } + } - if (NOT_PRESSED == button) { + if (((NOT_PRESSED == button) && !Button.inverted_mask) || ((PRESSED == button) && Button.inverted_mask)) { Button.hold_timer[button_index] = 0; } else { Button.hold_timer[button_index]++; @@ -223,11 +221,11 @@ void ButtonHandler(void) SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); // Execute Hold command via MQTT if ButtonTopic is set } } else { - if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button held for factor times longer + if ((Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings.param[P_HOLD_TIME] / 10)) { // SetOption32 (40) - Button held for factor times longer Button.press_counter[button_index] = 0; snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); ExecuteCommand(scmnd, SRC_BUTTON); - } + } } } } @@ -236,7 +234,9 @@ void ButtonHandler(void) if (Button.window_timer[button_index]) { Button.window_timer[button_index]--; } else { - if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < MAX_BUTTON_COMMANDS_V2 +6)) { + // if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < MAX_BUTTON_COMMANDS_V2 +6)) { + if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < 7)) { + bool single_press = false; if (Button.press_counter[button_index] < 3) { // Single or Double press #ifdef ESP8266 @@ -280,8 +280,12 @@ void ButtonHandler(void) } } } - } else { // 6 - 8 press are used to send commands - GetTextIndexed(scmnd, sizeof(scmnd), Button.press_counter[button_index] -6, kCommands); + // } else { // 6 - 8 press are used to send commands + // GetTextIndexed(scmnd, sizeof(scmnd), Button.press_counter[button_index] -6, kCommands); + // ExecuteCommand(scmnd, SRC_BUTTON); + // } + } else { // 6 press start wificonfig 2 + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2")); ExecuteCommand(scmnd, SRC_BUTTON); } if (Settings.flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index bfbd38078..28eae87f1 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -36,7 +36,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix #ifdef USE_DEVICE_GROUPS_SEND D_CMND_DEVGROUP_SEND "|" #endif // USE_DEVICE_GROUPS_SEND - D_CMND_DEVGROUP_SHARE "|" + D_CMND_DEVGROUP_SHARE "|" D_CMND_DEVGROUPSTATUS "|" #endif // USE_DEVICE_GROUPS D_CMND_SENSOR "|" D_CMND_DRIVER; @@ -59,7 +59,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = { #ifdef USE_DEVICE_GROUPS_SEND &CmndDevGroupSend, #endif // USE_DEVICE_GROUPS_SEND - &CmndDevGroupShare, + &CmndDevGroupShare, &CmndDevGroupStatus, #endif // USE_DEVICE_GROUPS &CmndSensor, &CmndDriver }; @@ -448,7 +448,7 @@ void CmndStatus(void) D_JSON_PROGRAMFLASHSIZE "\":%d,\"" D_JSON_FLASHSIZE "\":%d,\"" D_JSON_FLASHCHIPID "\":\"%06X\",\"" D_JSON_FLASHMODE "\":%d,\"" D_JSON_FEATURES "\":[\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\",\"%08X\"]"), ESP_getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, - ESP.getFlashChipSize()/1024, ESP_getFlashChipRealSize()/1024, ESP_getFlashChipId(), ESP.getFlashChipMode(), + ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024, ESP_getFlashChipId(), ESP.getFlashChipMode(), LANGUAGE_LCID, feature_drv1, feature_drv2, feature_sns1, feature_sns2, feature5, feature6); XsnsDriverState(); ResponseAppend_P(PSTR(",\"Sensors\":")); @@ -1117,10 +1117,9 @@ void CmndTemplate(void) #ifdef ESP8266 if (6 == i) { j = 9; } if (8 == i) { j = 12; } -#endif // ESP8266 -#ifdef ESP32 +#else // ESP32 if (6 == i) { j = 12; } -#endif // ESP32 +#endif // ESP8266 - ESP32 if (my_module.io[j] > GPIO_NONE) { Settings.user_template.gp.io[i] = my_module.io[j]; } @@ -1793,6 +1792,11 @@ void CmndDevGroupShare(void) Settings.device_group_share_out = parm[1]; Response_P(PSTR("{\"" D_CMND_DEVGROUP_SHARE "\":{\"In\":\"%X\",\"Out\":\"%X\"}}"), Settings.device_group_share_in, Settings.device_group_share_out); } + +void CmndDevGroupStatus(void) +{ + DeviceGroupStatus((XdrvMailbox.usridx ? XdrvMailbox.index - 1 : 0)); +} #endif // USE_DEVICE_GROUPS void CmndSensor(void) diff --git a/tasmota/support_device_groups.ino b/tasmota/support_device_groups.ino index e1719f59e..3a9258a60 100644 --- a/tasmota/support_device_groups.ino +++ b/tasmota/support_device_groups.ino @@ -34,6 +34,7 @@ struct device_group_member { IPAddress ip_address; uint16_t received_sequence; uint16_t acked_sequence; + uint32_t unicast_count; }; struct device_group { @@ -48,7 +49,6 @@ struct device_group { bool local; char group_name[TOPSZ]; char message[128]; - uint8_t group_member_count; struct device_group_member * device_group_members; #ifdef USE_DEVICE_GROUPS_SEND uint8_t values_8bit[DGR_ITEM_LAST_8BIT]; @@ -77,7 +77,7 @@ void DeviceGroupsInit(void) // Initialize the device information for each device group. device_groups = (struct device_group *)calloc(device_group_count, sizeof(struct device_group)); if (device_groups == nullptr) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: error allocating %u-element device group array"), device_group_count); + AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Error allocating %u-element device group array"), device_group_count); device_groups_initialization_failed = true; return; } @@ -169,7 +169,7 @@ void SendDeviceGroupPacket(IPAddress ip, char * packet, int len, const char * la } delay(10); } - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: error sending %s packet"), label); + AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Error sending %s packet"), label); } void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType message_type, ...) @@ -184,7 +184,7 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes if (processing_remote_device_message && message_type != DGR_MSGTYPE_UPDATE_COMMAND) return; // Get a pointer to the device information for this device. - device_group * device_group = &device_groups[device_group_index]; + struct device_group * device_group = &device_groups[device_group_index]; // If we're still sending initial status requests, ignore this request. if (device_group->initial_status_requests_remaining) return; @@ -551,7 +551,7 @@ void _SendDeviceGroupMessage(uint8_t device_group_index, DevGroupMessageType mes // Multicast the packet. #ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: sending %u-byte device group %s packet via multicast, sequence=%u"), device_group->message_length, device_group->group_name, device_group->message[device_group->message_header_length] | device_group->message[device_group->message_header_length + 1] << 8); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending %u-byte device group %s packet via multicast, sequence=%u"), device_group->message_length, device_group->group_name, device_group->message[device_group->message_header_length] | device_group->message[device_group->message_header_length + 1] << 8); #endif // DEVICE_GROUPS_DEBUG SendDeviceGroupPacket(IPAddress(0,0,0,0), device_group->message, device_group->message_length, PSTR("Multicast")); @@ -598,12 +598,10 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length) if (!device_group_member) { device_group_member = (struct device_group_member *)calloc(1, sizeof(struct device_group_member)); if (device_group_member == nullptr) { - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: error allocating device group member block")); + AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Error allocating device group member block")); return; } -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: adding member %s (%p)"), IPAddressToString(remote_ip), device_group_member); -#endif // DEVICE_GROUPS_DEBUG + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Adding member %s"), IPAddressToString(remote_ip)); device_group_member->ip_address = remote_ip; *flink = device_group_member; break; @@ -720,7 +718,7 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length) case DGR_ITEM_LIGHT_CHANNELS: break; default: - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: ********** invalid item=%u received from device group %s member %s"), item, device_group->group_name, IPAddressToString(remote_ip)); + AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: ********** Invalid item=%u received from device group %s member %s"), item, device_group->group_name, IPAddressToString(remote_ip)); } #endif // DEVICE_GROUPS_DEBUG @@ -802,13 +800,28 @@ void ProcessDeviceGroupMessage(char * packet, int packet_length) return; badmsg: - AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: malformed message received from %s"), IPAddressToString(remote_ip)); + AddLog_P2(LOG_LEVEL_ERROR, PSTR("DGR: Malformed message received from %s"), IPAddressToString(remote_ip)); #ifdef DEVICE_GROUPS_DEBUG AddLog_P2(LOG_LEVEL_DEBUG, PSTR("packet_length=%u, offset=%u"), packet_length, message_ptr - packet); #endif // DEVICE_GROUPS_DEBUG processing_remote_device_message = false; } +void DeviceGroupStatus(uint8_t device_group_index) +{ + if (Settings.flag4.device_groups_enabled && device_group_index < device_group_count) { + char buffer[1024]; + int member_count = 0; + struct device_group * device_group = &device_groups[device_group_index]; + buffer[0] = buffer[1] = 0; + for (struct device_group_member * device_group_member = device_group->device_group_members; device_group_member; device_group_member = device_group_member->flink) { + snprintf(buffer, sizeof(buffer), PSTR("%s,{\"IPAddress\":\"%s\",\"ResendCount\":%u,\"LastRcvdSeq\":%u,\"LastAckedSeq\":%u}"), buffer, IPAddressToString(device_group_member->ip_address), device_group_member->unicast_count, device_group_member->received_sequence, device_group_member->acked_sequence); + member_count++; + } + Response_P(PSTR("{\"" D_CMND_DEVGROUPSTATUS "\":{\"Index\":%u,\"GroupName\":\"%s\",\"MessageSeq\":%u,\"MemberCount\":%d,\"Members\":[%s]}"), device_group_index, device_group->group_name, outgoing_sequence, member_count, &buffer[1]); + } +} + void DeviceGroupsLoop(void) { if (!Settings.flag4.device_groups_enabled) return; @@ -822,16 +835,16 @@ void DeviceGroupsLoop(void) if (!device_groups_initialized) DeviceGroupsInit(); if (device_groups_initialization_failed) return; - // Load the status request message for all device groups. This message will be multicast 5 - // times. + // Load the status request message for all device groups. This message will be multicast 10 + // times at 200ms intervals. next_check_time = now + 3000; for (uint32_t device_group_index = 0; device_group_index < device_group_count; device_group_index++) { device_group * device_group = &device_groups[device_group_index]; device_group->message_length = BeginDeviceGroupMessage(device_group, DGR_FLAG_RESET | DGR_FLAG_STATUS_REQUEST) - device_group->message; - device_group->initial_status_requests_remaining = 5; + device_group->initial_status_requests_remaining = 10; device_group->next_ack_check_time = next_check_time; } - + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: (Re)discovering device groups")); } if (device_groups_initialization_failed) return; @@ -856,15 +869,15 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex if (device_group->initial_status_requests_remaining) { if (--device_group->initial_status_requests_remaining) { #ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: sending initial status request for group %s"), device_group->group_name); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending initial status request for group %s"), device_group->group_name); #endif // DEVICE_GROUPS_DEBUG SendDeviceGroupPacket(IPAddress(0,0,0,0), device_group->message, device_group->message_length, PSTR("Initial")); device_group->message[device_group->message_header_length + 2] = DGR_FLAG_STATUS_REQUEST; // The reset flag is on only for the first packet - turn it off now device_group->next_ack_check_time = now + 200; } - // If we've sent the initial status request message 5 times, send our status to all - // the members. + // If we've sent the initial status request message the set number of times, send our + // status to all the members. else { device_group->next_ack_check_time = 0; _SendDeviceGroupMessage(device_group_index, DGR_MSGTYP_FULL_STATUS); @@ -874,7 +887,7 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex // If we're done initializing, iterate through the group memebers, ... else { #ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: checking for ack's")); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Checking for ack's")); #endif // DEVICE_GROUPS_DEBUG bool acked = true; struct device_group_member ** flink = &device_group->device_group_members; @@ -887,9 +900,7 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex // If we haven't receive an ack from this member in DGR_MEMBER_TIMEOUT ms, assume // they're offline and remove them from the group. if (device_group->member_timeout_time < now) { -#ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: removing member %s (%p)"), IPAddressToString(device_group_member->ip_address), device_group_member); -#endif // DEVICE_GROUPS_DEBUG + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Removing member %s"), IPAddressToString(device_group_member->ip_address)); *flink = device_group_member->flink; free(device_group_member); } @@ -897,9 +908,10 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex // Otherwise, unicast the last message directly to this member. else { #ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: sending %u-byte device group %s packet via unicast to %s, sequence %u, last message acked=%u"), device_group->message_length, device_group->group_name, IPAddressToString(device_group_member->ip_address), outgoing_sequence, device_group_member->acked_sequence); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending %u-byte device group %s packet via unicast to %s, sequence %u, last message acked=%u"), device_group->message_length, device_group->group_name, IPAddressToString(device_group_member->ip_address), outgoing_sequence, device_group_member->acked_sequence); #endif // DEVICE_GROUPS_DEBUG SendDeviceGroupPacket(device_group_member->ip_address, device_group->message, device_group->message_length, PSTR("Unicast")); + device_group_member->unicast_count++; acked = false; flink = &device_group_member->flink; } @@ -940,7 +952,7 @@ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Ckecking next_check_time=%u, now=%u"), nex #endif // DEVICE_GROUPS_DEBUG if (device_group->next_announcement_time <= now) { #ifdef DEVICE_GROUPS_DEBUG - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: sending device group %s announcement"), device_group->group_name); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DGR: Sending device group %s announcement"), device_group->group_name); #endif // DEVICE_GROUPS_DEBUG SendDeviceGroupPacket(IPAddress(0,0,0,0), device_group->message, BeginDeviceGroupMessage(device_group, DGR_FLAG_ANNOUNCEMENT, true) - device_group->message, PSTR("Announcement")); device_group->next_announcement_time = now + DGR_ANNOUNCEMENT_INTERVAL + random(10000); diff --git a/tasmota/support_flash_log.ino b/tasmota/support_flash_log.ino index cf64de6d5..5f73c4078 100644 --- a/tasmota/support_flash_log.ino +++ b/tasmota/support_flash_log.ino @@ -371,13 +371,13 @@ void FLOG::stopRecording(void){ * * @param size: size of the data entry/record in bytes, i.e. sizeof(myStruct) * @param sendHeader: should implement at least something like: - * @example WebServer->setContentLength(CONTENT_LENGTH_UNKNOWN); // This is very likely unknown!! - * WebServer->sendHeader(F("Content-Disposition"), F("attachment; filename=myfile.txt")); + * @example Webserver->setContentLength(CONTENT_LENGTH_UNKNOWN); // This is very likely unknown!! + * Webserver->sendHeader(F("Content-Disposition"), F("attachment; filename=myfile.txt")); * @param sendRecord: will receive the memory address as "uint8_t* addr" and should consume the current entry/record * @example myStruct_t *entry = (myStruct_t*)addr; - * Then make useful Strings and send it, i.e.: WebServer->sendContent_P(myString); + * Then make useful Strings and send it, i.e.: Webserver->sendContent_P(myString); * @param sendFooter: finish the download, should implement at least: - * @example WebServer->sendContent(""); + * @example Webserver->sendContent(""); */ void FLOG::startDownload(size_t size, CallbackNoArgs sendHeader, CallbackWithArgs sendRecord, CallbackNoArgs sendFooter){ diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 1a7c250ae..a0d684517 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -192,6 +192,12 @@ void setup(void) { global_state.data = 3; // Init global state (wifi_down, mqtt_down) to solve possible network issues +#ifdef ESP32 +#ifdef DISABLE_BROWNOUT + DisableBrownout(); +#endif +#endif + RtcRebootLoad(); if (!RtcRebootValid()) { RtcReboot.fast_reboot_count = 0; diff --git a/tasmota/tasmota_compat.h b/tasmota/tasmota_compat.h index 6571d0f34..839f5cef8 100644 --- a/tasmota/tasmota_compat.h +++ b/tasmota/tasmota_compat.h @@ -17,7 +17,6 @@ #define ESP_reset() ESP.reset() #define ESP_getBootVersion() ESP.getBootVersion() #define ESP_getFlashChipId() ESP.getFlashChipId() -#define ESP_getFlashChipRealSize() ESP.getFlashChipRealSize() #define ESP_getSketchSize() ESP.getSketchSize() #define ESP_getChipId() ESP.getChipId() // diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h index b2d7a5846..967da9400 100644 --- a/tasmota/tasmota_template_ESP32.h +++ b/tasmota/tasmota_template_ESP32.h @@ -45,106 +45,61 @@ /********************************************************************************************/ // Supported hardware modules enum SupportedModules { - WEMOS, - ESP32_CAM, - MAXMODULE -}; + WEMOS, ESP32_CAM_AITHINKER, + MAXMODULE}; const char kModuleNames[] PROGMEM = - "WeMos D1 ESP32|ESP32 CAM|" - ; + "ESP32-DevKit|ESP32 Cam AiThinker"; // Default module settings const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { WEMOS, - ESP32_CAM + ESP32_CAM_AITHINKER }; -const mytmplt kModules[MAXMODULE] PROGMEM = { - { // "WeMos D1 ESP32", // Any ESP32 device like WeMos and NodeMCU hardware (ESP32) - GPIO_USER, //0 (I)O GPIO0, ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1, EMAC_TX_CLK - GPIO_USER, //1 IO TXD0 GPIO1, U0TXD, CLK_OUT3, EMAC_RXD2 - GPIO_USER, //2 IO GPIO2, ADC2_CH2, TOUCH2, RTC_GPIO12, HSPIWP, HS2_DATA0, SD_DATA0 - GPIO_USER, //3 IO RXD0 GPIO3, U0RXD, CLK_OUT2 - GPIO_USER, //4 IO GPIO4, ADC2_CH0, TOUCH0, RTC_GPIO10, HSPIHD, HS2_DATA1, SD_DATA1, EMAC_TX_ER - GPIO_USER, //5 IO GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK -// 0, //6 -// 0, //7 -// 0, //8 -// 0, //9 -// 0, //10 -// 0, //11 - GPIO_USER, //12 (I)O GPIO12, ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI, HSPIQ, HS2_DATA2, SD_DATA2, EMAC_TXD3 (If driven High, flash voltage (VDD_SDIO) is 1.8V not default 3.3V. Has internal pull-down, so unconnected = Low = 3.3V. May prevent flashing and/or booting if 3.3V flash is connected and pulled high. See ESP32 datasheet for more details.) - GPIO_USER, //13 IO GPIO13, ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, HS2_DATA3, SD_DATA3, EMAC_RX_ER - GPIO_USER, //14 IO GPIO14, ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, HS2_CLK, SD_CLK, EMAC_TXD2 - GPIO_USER, //15 (I)O GPIO15, ADC2_CH3, TOUCH3, MTDO, HSPICS0, RTC_GPIO13, HS2_CMD, SD_CMD, EMAC_RXD3 (If driven Low, silences boot messages from normal boot. Has internal pull-up, so unconnected = High = normal output.) - GPIO_USER, //16 IO GPIO16, HS1_DATA4, U2RXD, EMAC_CLK_OUT - GPIO_USER, //17 IO GPIO17, HS1_DATA5, U2TXD, EMAC_CLK_OUT_180 - GPIO_USER, //18 IO GPIO18, VSPICLK, HS1_DATA7 - GPIO_USER, //19 IO GPIO19, VSPIQ, U0CTS, EMAC_TXD0 - 0, //20 - 0, //21 IO GPIO21, VSPIHD, EMAC_TX_EN - GPIO_USER, //22 IO LED GPIO22, VSPIWP, U0RTS, EMAC_TXD1 - GPIO_USER, //23 IO GPIO23, VSPID, HS1_STROBE - 0, //24 - GPIO_USER, //25 IO GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0 - GPIO_USER, //26 IO GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1 - GPIO_USER, //27 IO GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17, EMAC_RX_DV - 0, //28 - 0, //29 - 0, //30 - 0, //31 - GPIO_USER, //32 IO GPIO32, XTAL_32K_P (32.768 kHz crystal oscillator input), ADC1_CH4, TOUCH9, RTC_GPIO9 - GPIO_USER, //33 IO GPIO33, XTAL_32K_N (32.768 kHz crystal oscillator output), ADC1_CH5, TOUCH8, RTC_GPIO8 - GPIO_USER, //34 I NO PULLUP GPIO34, ADC1_CH6, RTC_GPIO4 - GPIO_USER, //35 I NO PULLUP GPIO35, ADC1_CH7, RTC_GPIO5 - GPIO_USER, //36 I NO PULLUP GPIO36, SENSOR_VP, ADC_H, ADC1_CH0, RTC_GPIO0 - 0, //37 NO PULLUP - 0, //38 NO PULLUP - GPIO_USER //39 I NO PULLUP GPIO39, SENSOR_VN, ADC1_CH3, ADC_H, RTC_GPIO3 - }, - { //"ESP32 CAM", - GPIO_USER, //0 (I)O GPIO0, ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1, EMAC_TX_CLK - GPIO_USER, //1 IO TXD0 GPIO1, U0TXD, CLK_OUT3, EMAC_RXD2 - GPIO_USER, //2 IO GPIO2, ADC2_CH2, TOUCH2, RTC_GPIO12, HSPIWP, HS2_DATA0, SD_DATA0 - GPIO_USER, //3 IO RXD0 GPIO3, U0RXD, CLK_OUT2 - GPIO_USER, //4 IO GPIO4, ADC2_CH0, TOUCH0, RTC_GPIO10, HSPIHD, HS2_DATA1, SD_DATA1, EMAC_TX_ER - GPIO_USER, //5 IO GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK -// 0, //6 -// 0, //7 -// 0, //8 -// 0, //9 -// 0, //10 -// 0, //11 - GPIO_USER, //12 (I)O GPIO12, ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI, HSPIQ, HS2_DATA2, SD_DATA2, EMAC_TXD3 (If driven High, flash voltage (VDD_SDIO) is 1.8V not default 3.3V. Has internal pull-down, so unconnected = Low = 3.3V. May prevent flashing and/or booting if 3.3V flash is connected and pulled high. See ESP32 datasheet for more details.) - GPIO_USER, //13 IO GPIO13, ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, HS2_DATA3, SD_DATA3, EMAC_RX_ER - GPIO_USER, //14 IO GPIO14, ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, HS2_CLK, SD_CLK, EMAC_TXD2 - GPIO_USER, //15 (I)O GPIO15, ADC2_CH3, TOUCH3, MTDO, HSPICS0, RTC_GPIO13, HS2_CMD, SD_CMD, EMAC_RXD3 (If driven Low, silences boot messages from normal boot. Has internal pull-up, so unconnected = High = normal output.) - GPIO_USER, //16 IO GPIO16, HS1_DATA4, U2RXD, EMAC_CLK_OUT - GPIO_USER, //17 IO GPIO17, HS1_DATA5, U2TXD, EMAC_CLK_OUT_180 - GPIO_USER, //18 IO GPIO18, VSPICLK, HS1_DATA7 - GPIO_USER, //19 IO GPIO19, VSPIQ, U0CTS, EMAC_TXD0 - 0, //20 - 0, //21 IO GPIO21, VSPIHD, EMAC_TX_EN - GPIO_USER, //22 IO LED GPIO22, VSPIWP, U0RTS, EMAC_TXD1 - GPIO_USER, //23 IO GPIO23, VSPID, HS1_STROBE - 0, //24 - GPIO_USER, //25 IO GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0 - GPIO_USER, //26 IO GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1 - GPIO_USER, //27 IO GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17, EMAC_RX_DV - 0, //28 - 0, //29 - 0, //30 - 0, //31 - GPIO_USER, //32 IO GPIO32, XTAL_32K_P (32.768 kHz crystal oscillator input), ADC1_CH4, TOUCH9, RTC_GPIO9 - GPIO_USER, //33 IO GPIO33, XTAL_32K_N (32.768 kHz crystal oscillator output), ADC1_CH5, TOUCH8, RTC_GPIO8 - GPIO_USER, //34 I NO PULLUP GPIO34, ADC1_CH6, RTC_GPIO4 - GPIO_USER, //35 I NO PULLUP GPIO35, ADC1_CH7, RTC_GPIO5 - GPIO_USER, //36 I NO PULLUP GPIO36, SENSOR_VP, ADC_H, ADC1_CH0, RTC_GPIO0 - 0, //37 NO PULLUP - 0, //38 NO PULLUP - GPIO_USER //39 I NO PULLUP GPIO39, SENSOR_VN, ADC1_CH3, ADC_H, RTC_GPIO3 - } +const mytmplt kModules PROGMEM = +{ // WEMOS - Espressif ESP32-DevKitC - Any ESP32 device like WeMos and NodeMCU hardware (ESP32) + GPIO_USER, //0 (I)O GPIO0, ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1, EMAC_TX_CLK + GPIO_USER, //1 IO TXD0 GPIO1, U0TXD, CLK_OUT3, EMAC_RXD2 + GPIO_USER, //2 IO GPIO2, ADC2_CH2, TOUCH2, RTC_GPIO12, HSPIWP, HS2_DATA0, SD_DATA0 + GPIO_USER, //3 IO RXD0 GPIO3, U0RXD, CLK_OUT2 + GPIO_USER, //4 IO GPIO4, ADC2_CH0, TOUCH0, RTC_GPIO10, HSPIHD, HS2_DATA1, SD_DATA1, EMAC_TX_ER + GPIO_USER, //5 IO GPIO5, VSPICS0, HS1_DATA6, EMAC_RX_CLK + //6 IO GPIO6, Flash CLK + //7 IO GPIO7, Flash D0 + //8 IO GPIO8, Flash D1 + //9 IO GPIO9, Flash D2 + //10 IO GPIO10, Flash D3 + //11 IO GPIO11, Flash CMD + GPIO_USER, //12 (I)O GPIO12, ADC2_CH5, TOUCH5, RTC_GPIO15, MTDI, HSPIQ, HS2_DATA2, SD_DATA2, EMAC_TXD3 (If driven High, flash voltage (VDD_SDIO) is 1.8V not default 3.3V. Has internal pull-down, so unconnected = Low = 3.3V. May prevent flashing and/or booting if 3.3V flash is connected and pulled high. See ESP32 datasheet for more details.) + GPIO_USER, //13 IO GPIO13, ADC2_CH4, TOUCH4, RTC_GPIO14, MTCK, HSPID, HS2_DATA3, SD_DATA3, EMAC_RX_ER + GPIO_USER, //14 IO GPIO14, ADC2_CH6, TOUCH6, RTC_GPIO16, MTMS, HSPICLK, HS2_CLK, SD_CLK, EMAC_TXD2 + GPIO_USER, //15 (I)O GPIO15, ADC2_CH3, TOUCH3, MTDO, HSPICS0, RTC_GPIO13, HS2_CMD, SD_CMD, EMAC_RXD3 (If driven Low, silences boot messages from normal boot. Has internal pull-up, so unconnected = High = normal output.) + GPIO_USER, //16 IO GPIO16, HS1_DATA4, U2RXD, EMAC_CLK_OUT + GPIO_USER, //17 IO GPIO17, HS1_DATA5, U2TXD, EMAC_CLK_OUT_180 + GPIO_USER, //18 IO GPIO18, VSPICLK, HS1_DATA7 + GPIO_USER, //19 IO GPIO19, VSPIQ, U0CTS, EMAC_TXD0 + 0, //20 + GPIO_USER, //21 IO GPIO21, VSPIHD, EMAC_TX_EN + GPIO_USER, //22 IO LED GPIO22, VSPIWP, U0RTS, EMAC_TXD1 + GPIO_USER, //23 IO GPIO23, VSPID, HS1_STROBE + 0, //24 + GPIO_USER, //25 IO GPIO25, DAC_1, ADC2_CH8, RTC_GPIO6, EMAC_RXD0 + GPIO_USER, //26 IO GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1 + GPIO_USER, //27 IO GPIO27, ADC2_CH7, TOUCH7, RTC_GPIO17, EMAC_RX_DV + 0, //28 + 0, //29 + 0, //30 + 0, //31 + GPIO_USER, //32 IO GPIO32, XTAL_32K_P (32.768 kHz crystal oscillator input), ADC1_CH4, TOUCH9, RTC_GPIO9 + GPIO_USER, //33 IO GPIO33, XTAL_32K_N (32.768 kHz crystal oscillator output), ADC1_CH5, TOUCH8, RTC_GPIO8 + GPIO_USER, //34 I NO PULLUP GPIO34, ADC1_CH6, RTC_GPIO4 + GPIO_USER, //35 I NO PULLUP GPIO35, ADC1_CH7, RTC_GPIO5 + GPIO_USER, //36 I NO PULLUP GPIO36, SENSOR_VP, ADC_H, ADC1_CH0, RTC_GPIO0 + 0, //37 NO PULLUP + 0, //38 NO PULLUP + GPIO_USER, //39 I NO PULLUP GPIO39, SENSOR_VN, ADC1_CH3, ADC_H, RTC_GPIO3 + 0 // Flag }; #endif // ESP32 diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index 3b8314f65..4014ea4d5 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 = 0x08020003; +const uint32_t VERSION = 0x08020004; // Lowest compatible version const uint32_t VERSION_COMPATIBLE = 0x07010006; diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 178502150..d2e2e1813 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -109,7 +109,7 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM = "}" "};" "if (rfsh) {" - "x.open('GET','.?m=1'+a,true);" // ?m related to WebServer->hasArg("m") + "x.open('GET','.?m=1'+a,true);" // ?m related to Webserver->hasArg("m") "x.send();" "lt=setTimeout(la,%d);" // Settings.web_refresh "}" @@ -146,7 +146,7 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM = "eb('l1').innerHTML=s;" "}" "};" - "x.open('GET','.?m=1'+a,true);" // ?m related to WebServer->hasArg("m") + "x.open('GET','.?m=1'+a,true);" // ?m related to Webserver->hasArg("m") "x.send();" "lt=setTimeout(la,%d);" // Settings.web_refresh "}"; @@ -205,7 +205,7 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM = "sn=t.scrollTop;" "}" "};" - "x.open('GET','cs?c2='+id+o,true);" // Related to WebServer->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp)) + "x.open('GET','cs?c2='+id+o,true);" // Related to Webserver->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp)) "x.send();" "}" "lt=setTimeout(l,%d);" @@ -261,21 +261,18 @@ const char HTTP_SCRIPT_TEMPLATE[] PROGMEM = "as=o.shift();" // Complete ADC0 list "g=o.shift().split(',');" // Array separator "j=0;" -// "for(i=0;i<13;i++){" // Supports 13 GPIOs "for(i=0;i<" STR(MAX_USER_PINS) ";i++){" // Supports 13 GPIOs #ifdef ESP8266 "if(6==i){j=9;}" "if(8==i){j=12;}" -#endif -#ifdef ESP32 +#else // ESP32 "if(6==i){j=12;}" -#endif +#endif // ESP8266 - ESP32 "sk(g[i],j);" // Set GPIO "j++;" "}" "g=o.shift();" // FLAG "os=as;" -// "sk(g&15,17);" // Set ADC0 "sk(g&15," STR(ADC0_PIN) ");" // Set ADC0 "g>>=4;" "for(i=0;i<" STR(GPIO_FLAG_USED) ";i++){" @@ -295,16 +292,15 @@ const char HTTP_SCRIPT_TEMPLATE[] PROGMEM = "function x2(a){" "os=a.responseText;" -// "sk(17,99);" // 17 = WEMOS "sk(" STR(WEMOS_MODULE) ",99);" // 17 = WEMOS "st(" STR(USER_MODULE) ");" "}" #ifdef USE_JAVASCRIPT_ES6 - "sl=()=>ld('tp?m=1',x2);" // ?m related to WebServer->hasArg("m") + "sl=()=>ld('tp?m=1',x2);" // ?m related to Webserver->hasArg("m") #else "function sl(){" - "ld('tp?m=1',x2);" // ?m related to WebServer->hasArg("m") + "ld('tp?m=1',x2);" // ?m related to Webserver->hasArg("m") "}" #endif @@ -321,15 +317,13 @@ const char HTTP_SCRIPT_MODULE2[] PROGMEM = "}" "function x3(a){" // ADC0 "os=a.responseText;" -// "sk(%d,17);" "sk(%d," STR(ADC0_PIN) ");" "}" "function sl(){" - "ld('md?m=1',x1);" // ?m related to WebServer->hasArg("m") - "ld('md?g=1',x2);" // ?g related to WebServer->hasArg("g") -// "if(eb('g17')){" + "ld('md?m=1',x1);" // ?m related to Webserver->hasArg("m") + "ld('md?g=1',x2);" // ?g related to Webserver->hasArg("g") "if(eb('g" STR(ADC0_PIN) "')){" - "ld('md?a=1',x3);" // ?a related to WebServer->hasArg("a") + "ld('md?a=1',x3);" // ?a related to Webserver->hasArg("a") "}" "}" "wl(sl);"; @@ -544,7 +538,7 @@ const uint16_t DNS_PORT = 53; enum HttpOptions {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER, HTTP_MANAGER_RESET_ONLY}; DNSServer *DnsServer; -ESP8266WebServer *WebServer; +ESP8266WebServer *Webserver; struct WEB { String chunk_buffer = ""; // Could be max 2 * CHUNKED_BUFFER_SIZE @@ -561,7 +555,7 @@ struct WEB { // Helper function to avoid code duplication (saves 4k Flash) static void WebGetArg(const char* arg, char* out, size_t max) { - String s = WebServer->arg(arg); + String s = Webserver->arg(arg); strlcpy(out, s.c_str(), max); // out[max-1] = '\0'; // Ensure terminating NUL } @@ -574,7 +568,7 @@ void ShowWebSource(uint32_t source) { if ((source > 0) && (source < SRC_MAX)) { char stemp1[20]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SRC: %s from %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource), WebServer->client().remoteIP().toString().c_str()); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SRC: %s from %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource), Webserver->client().remoteIP().toString().c_str()); } } @@ -589,28 +583,28 @@ void StartWebserver(int type, IPAddress ipweb) { if (!Settings.web_refresh) { Settings.web_refresh = HTTP_REFRESH_TIME; } if (!Web.state) { - if (!WebServer) { - WebServer = new ESP8266WebServer((HTTP_MANAGER == type || HTTP_MANAGER_RESET_ONLY == type) ? 80 : WEB_PORT); - WebServer->on("/", HandleRoot); - WebServer->onNotFound(HandleNotFound); - WebServer->on("/up", HandleUpgradeFirmware); - WebServer->on("/u1", HandleUpgradeFirmwareStart); // OTA - WebServer->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop); - WebServer->on("/u2", HTTP_OPTIONS, HandlePreflightRequest); - WebServer->on("/cs", HTTP_GET, HandleConsole); - WebServer->on("/cs", HTTP_OPTIONS, HandlePreflightRequest); - WebServer->on("/cm", HandleHttpCommand); + if (!Webserver) { + Webserver = new ESP8266WebServer((HTTP_MANAGER == type || HTTP_MANAGER_RESET_ONLY == type) ? 80 : WEB_PORT); + Webserver->on("/", HandleRoot); + Webserver->onNotFound(HandleNotFound); + Webserver->on("/up", HandleUpgradeFirmware); + Webserver->on("/u1", HandleUpgradeFirmwareStart); // OTA + Webserver->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop); + Webserver->on("/u2", HTTP_OPTIONS, HandlePreflightRequest); + Webserver->on("/cs", HTTP_GET, HandleConsole); + Webserver->on("/cs", HTTP_OPTIONS, HandlePreflightRequest); + Webserver->on("/cm", HandleHttpCommand); #ifndef FIRMWARE_MINIMAL - WebServer->on("/cn", HandleConfiguration); - WebServer->on("/md", HandleModuleConfiguration); - WebServer->on("/wi", HandleWifiConfiguration); - WebServer->on("/lg", HandleLoggingConfiguration); - WebServer->on("/tp", HandleTemplateConfiguration); - WebServer->on("/co", HandleOtherConfiguration); - WebServer->on("/dl", HandleBackupConfiguration); - WebServer->on("/rs", HandleRestoreConfiguration); - WebServer->on("/rt", HandleResetConfiguration); - WebServer->on("/in", HandleInformation); + Webserver->on("/cn", HandleConfiguration); + Webserver->on("/md", HandleModuleConfiguration); + Webserver->on("/wi", HandleWifiConfiguration); + Webserver->on("/lg", HandleLoggingConfiguration); + Webserver->on("/tp", HandleTemplateConfiguration); + Webserver->on("/co", HandleOtherConfiguration); + Webserver->on("/dl", HandleBackupConfiguration); + Webserver->on("/rs", HandleRestoreConfiguration); + Webserver->on("/rt", HandleResetConfiguration); + Webserver->on("/in", HandleInformation); XdrvCall(FUNC_WEB_ADD_HANDLER); XsnsCall(FUNC_WEB_ADD_HANDLER); #endif // Not FIRMWARE_MINIMAL @@ -619,9 +613,9 @@ void StartWebserver(int type, IPAddress ipweb) // Collect User-Agent for Alexa Hue Emulation // This is used in xdrv_20_hue.ino in function findEchoGeneration() - WebServer->collectHeaders(HEADER_KEYS, sizeof(HEADER_KEYS)/sizeof(char*)); + Webserver->collectHeaders(HEADER_KEYS, sizeof(HEADER_KEYS)/sizeof(char*)); - WebServer->begin(); // Web server start + Webserver->begin(); // Web server start } if (Web.state != type) { #if LWIP_IPV6 @@ -639,7 +633,7 @@ void StartWebserver(int type, IPAddress ipweb) void StopWebserver(void) { if (Web.state) { - WebServer->close(); + Webserver->close(); Web.state = HTTP_OFF; AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_STOPPED)); } @@ -684,7 +678,7 @@ void WifiManagerBegin(bool reset_only) void PollDnsWebserver(void) { if (DnsServer) { DnsServer->processNextRequest(); } - if (WebServer) { WebServer->handleClient(); } + if (Webserver) { Webserver->handleClient(); } } /*********************************************************************************************/ @@ -692,7 +686,7 @@ void PollDnsWebserver(void) bool WebAuthenticate(void) { if (strlen(SettingsText(SET_WEBPWD)) && (HTTP_MANAGER_RESET_ONLY != Web.state)) { - return WebServer->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD)); + return Webserver->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD)); } else { return true; } @@ -705,7 +699,7 @@ bool HttpCheckPriviledgedAccess(bool autorequestauth = true) return false; } if (autorequestauth && !WebAuthenticate()) { - WebServer->requestAuthentication(); + Webserver->requestAuthentication(); return false; } return true; @@ -714,15 +708,15 @@ bool HttpCheckPriviledgedAccess(bool autorequestauth = true) void HttpHeaderCors(void) { if (strlen(SettingsText(SET_CORS))) { - WebServer->sendHeader(F("Access-Control-Allow-Origin"), SettingsText(SET_CORS)); + Webserver->sendHeader(F("Access-Control-Allow-Origin"), SettingsText(SET_CORS)); } } void WSHeaderSend(void) { - WebServer->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); - WebServer->sendHeader(F("Pragma"), F("no-cache")); - WebServer->sendHeader(F("Expires"), F("-1")); + Webserver->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate")); + Webserver->sendHeader(F("Pragma"), F("no-cache")); + Webserver->sendHeader(F("Expires"), F("-1")); HttpHeaderCors(); } @@ -733,7 +727,7 @@ void WSHeaderSend(void) void WSSend(int code, int ctype, const String& content) { char ct[25]; // strlen("application/octet-stream") +1 = Longest Content type string - WebServer->send(code, GetTextIndexed(ct, sizeof(ct), ctype, kContentTypes), content); + Webserver->send(code, GetTextIndexed(ct, sizeof(ct), ctype, kContentTypes), content); } /********************************************************************************************** @@ -742,13 +736,13 @@ void WSSend(int code, int ctype, const String& content) void WSContentBegin(int code, int ctype) { - WebServer->client().flush(); + Webserver->client().flush(); WSHeaderSend(); #ifdef ARDUINO_ESP8266_RELEASE_2_3_0 - WebServer->sendHeader(F("Accept-Ranges"),F("none")); - WebServer->sendHeader(F("Transfer-Encoding"),F("chunked")); + Webserver->sendHeader(F("Accept-Ranges"),F("none")); + Webserver->sendHeader(F("Transfer-Encoding"),F("chunked")); #endif - WebServer->setContentLength(CONTENT_LENGTH_UNKNOWN); + Webserver->setContentLength(CONTENT_LENGTH_UNKNOWN); WSSend(code, ctype, ""); // Signal start of chunked content Web.chunk_buffer = ""; } @@ -761,9 +755,9 @@ void _WSContentSend(const String& content) // Low level sendContent for a const char * footer = "\r\n"; char chunk_size[11]; sprintf(chunk_size, "%x\r\n", len); - WebServer->sendContent(String() + chunk_size + content + footer); + Webserver->sendContent(String() + chunk_size + content + footer); #else - WebServer->sendContent(content); + Webserver->sendContent(content); #endif #ifdef USE_DEBUG_DRIVER @@ -849,8 +843,8 @@ void WSContentSend_PD(const char* formatP, ...) // Content send snprintf_P ch void WSContentStart_P(const char* title, bool auth) { - if (auth && strlen(SettingsText(SET_WEBPWD)) && !WebServer->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD))) { - return WebServer->requestAuthentication(); + if (auth && strlen(SettingsText(SET_WEBPWD)) && !Webserver->authenticate(WEB_USERNAME, SettingsText(SET_WEBPWD))) { + return Webserver->requestAuthentication(); } WSContentBegin(200, CT_HTML); @@ -961,7 +955,7 @@ void WSContentEnd(void) { WSContentFlush(); // Flush chunk buffer _WSContentSend(""); // Signal end of chunked content - WebServer->client().stop(); + Webserver->client().stop(); } void WSContentStop(void) @@ -1043,17 +1037,17 @@ void HandleRoot(void) { if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the page. - if (WebServer->hasArg("rst")) { + if (Webserver->hasArg("rst")) { WebRestart(0); return; } if (WifiIsInManagerMode()) { #ifndef FIRMWARE_MINIMAL - if (strlen(SettingsText(SET_WEBPWD)) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1")) && HTTP_MANAGER_RESET_ONLY != Web.state) { + if (strlen(SettingsText(SET_WEBPWD)) && !(Webserver->hasArg("USER1")) && !(Webserver->hasArg("PASS1")) && HTTP_MANAGER_RESET_ONLY != Web.state) { HandleWifiLogin(); } else { - if (!strlen(SettingsText(SET_WEBPWD)) || (((WebServer->arg("USER1") == WEB_USERNAME ) && (WebServer->arg("PASS1") == SettingsText(SET_WEBPWD) )) || HTTP_MANAGER_RESET_ONLY == Web.state)) { + if (!strlen(SettingsText(SET_WEBPWD)) || (((Webserver->arg("USER1") == WEB_USERNAME ) && (Webserver->arg("PASS1") == SettingsText(SET_WEBPWD) )) || HTTP_MANAGER_RESET_ONLY == Web.state)) { HandleWifiConfiguration(); } else { // wrong user and pass @@ -1243,11 +1237,11 @@ void HandleRoot(void) bool HandleRootStatusRefresh(void) { if (!WebAuthenticate()) { - WebServer->requestAuthentication(); + Webserver->requestAuthentication(); return true; } - if (!WebServer->hasArg("m")) { // Status refresh requested + if (!Webserver->hasArg("m")) { // Status refresh requested return false; } @@ -1429,7 +1423,7 @@ void HandleTemplateConfiguration(void) { if (!HttpCheckPriviledgedAccess()) { return; } - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { TemplateSaveSettings(); WebRestart(1); return; @@ -1437,7 +1431,7 @@ void HandleTemplateConfiguration(void) char stemp[30]; // Template number and Sensor name - if (WebServer->hasArg("m")) { + if (Webserver->hasArg("m")) { WSContentBegin(200, CT_PLAIN); for (uint32_t i = 0; i < sizeof(kModuleNiceList); i++) { // "}2'%d'>%s (%d)}3" - "}2'0'>Sonoff Basic (1)}3" uint32_t midx = pgm_read_byte(kModuleNiceList + i); @@ -1532,10 +1526,9 @@ void TemplateSaveSettings(void) #ifdef ESP8266 if (6 == i) { j = 9; } if (8 == i) { j = 12; } -#endif // ESP8266 -#ifdef ESP32 +#else // ESP32 if (6 == i) { j = 12; } -#endif // ESP32 +#endif // ESP8266 - ESP32 snprintf_P(webindex, sizeof(webindex), PSTR("g%d"), j); WebGetArg(webindex, tmp, sizeof(tmp)); // GPIO uint8_t gpio = atoi(tmp); @@ -1543,12 +1536,11 @@ void TemplateSaveSettings(void) j++; } -// WebGetArg("g17", tmp, sizeof(tmp)); // FLAG - ADC0 WebGetArg("g" STR(ADC0_PIN), tmp, sizeof(tmp)); // FLAG - ADC0 uint32_t flag = atoi(tmp); for (uint32_t i = 0; i < GPIO_FLAG_USED; i++) { snprintf_P(webindex, sizeof(webindex), PSTR("c%d"), i); - uint32_t state = WebServer->hasArg(webindex) << i +4; // FLAG + uint32_t state = Webserver->hasArg(webindex) << i +4; // FLAG flag += state; } WebGetArg("g99", tmp, sizeof(tmp)); // BASE @@ -1564,7 +1556,7 @@ void HandleModuleConfiguration(void) { if (!HttpCheckPriviledgedAccess()) { return; } - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { ModuleSaveSettings(); WebRestart(1); return; @@ -1575,7 +1567,7 @@ void HandleModuleConfiguration(void) myio cmodule; ModuleGpios(&cmodule); - if (WebServer->hasArg("m")) { + if (Webserver->hasArg("m")) { WSContentBegin(200, CT_PLAIN); uint32_t vidx = 0; for (uint32_t i = 0; i <= sizeof(kModuleNiceList); i++) { // "}2'%d'>%s (%d)}3" - "}2'255'>UserTemplate (0)}3" - "}2'0'>Sonoff Basic (1)}3" @@ -1592,7 +1584,7 @@ void HandleModuleConfiguration(void) return; } - if (WebServer->hasArg("g")) { + if (Webserver->hasArg("g")) { WSContentBegin(200, CT_PLAIN); for (uint32_t j = 0; j < sizeof(kGpioNiceList); j++) { midx = pgm_read_byte(kGpioNiceList + j); @@ -1605,7 +1597,7 @@ void HandleModuleConfiguration(void) } #ifndef USE_ADC_VCC - if (WebServer->hasArg("a")) { + if (Webserver->hasArg("a")) { WSContentBegin(200, CT_PLAIN); for (uint32_t j = 0; j < ADC0_END; j++) { WSContentSend_P(HTTP_MODULE_TEMPLATE_REPLACE, j, GetTextIndexed(stemp, sizeof(stemp), j, kAdc0Names), j); @@ -1675,17 +1667,28 @@ void ModuleSaveSettings(void) if (ValidGPIO(i, cmodule.io[i])) { snprintf_P(webindex, sizeof(webindex), PSTR("g%d"), i); WebGetArg(webindex, tmp, sizeof(tmp)); - Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]); + uint8_t value = (!strlen(tmp)) ? 0 : atoi(tmp); +#ifdef ESP8266 + Settings.my_gp.io[i] = value; +#else // ESP32 + if (i == ADC0_PIN) { + Settings.my_adc0 = value; + } else { + Settings.my_gp.io[i] = value; + } +#endif // ESP8266 - ESP32 + gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(value); } } } +#ifdef ESP8266 #ifndef USE_ADC_VCC // WebGetArg("g17", tmp, sizeof(tmp)); WebGetArg("g" STR(ADC0_PIN), tmp, sizeof(tmp)); Settings.my_adc0 = (!strlen(tmp)) ? 0 : atoi(tmp); gpios += F(", " D_ADC "0 "); gpios += String(Settings.my_adc0); #endif // USE_ADC_VCC +#endif // ESP8266 AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), ModuleName().c_str(), gpios.c_str()); } @@ -1720,7 +1723,7 @@ void HandleWifiConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI); - if (WebServer->hasArg("save") && HTTP_MANAGER_RESET_ONLY != Web.state) { + if (Webserver->hasArg("save") && HTTP_MANAGER_RESET_ONLY != Web.state) { WifiSaveSettings(); WebRestart(2); return; @@ -1731,7 +1734,7 @@ void HandleWifiConfiguration(void) WSContentSendStyle(); if (HTTP_MANAGER_RESET_ONLY != Web.state) { - if (WebServer->hasArg("scan")) { + if (Webserver->hasArg("scan")) { #ifdef USE_EMULATION UdpDisconnect(); #endif // USE_EMULATION @@ -1844,7 +1847,7 @@ void HandleLoggingConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_LOGGING); - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { LoggingSaveSettings(); HandleConfiguration(); return; @@ -1909,7 +1912,7 @@ void HandleOtherConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_OTHER); - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { OtherSaveSettings(); WebRestart(1); return; @@ -1973,7 +1976,7 @@ void OtherSaveSettings(void) WebGetArg("wp", tmp, sizeof(tmp)); SettingsUpdateText(SET_WEBPWD, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? SettingsText(SET_WEBPWD) : tmp); - Settings.flag.mqtt_enabled = WebServer->hasArg("b1"); // SetOption3 - Enable MQTT + Settings.flag.mqtt_enabled = Webserver->hasArg("b1"); // SetOption3 - Enable MQTT #ifdef USE_EMULATION UdpDisconnect(); #if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE) @@ -1994,7 +1997,7 @@ void OtherSaveSettings(void) /* // This sometimes provides intermittent watchdog - bool template_activate = WebServer->hasArg("t2"); // Try this to tackle intermittent watchdog after execution of Template command + bool template_activate = Webserver->hasArg("t2"); // Try this to tackle intermittent watchdog after execution of Template command WebGetArg("t1", tmp, sizeof(tmp)); if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255} char svalue[128]; @@ -2010,7 +2013,7 @@ void OtherSaveSettings(void) */ WebGetArg("t1", tmp, sizeof(tmp)); if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255} - snprintf_P(message, sizeof(message), PSTR(D_CMND_BACKLOG " " D_CMND_TEMPLATE " %s%s"), tmp, (WebServer->hasArg("t2")) ? "; " D_CMND_MODULE " 0" : ""); + snprintf_P(message, sizeof(message), PSTR(D_CMND_BACKLOG " " D_CMND_TEMPLATE " %s%s"), tmp, (Webserver->hasArg("t2")) ? "; " D_CMND_MODULE " 0" : ""); ExecuteWebCommand(message, SRC_WEBGUI); } } @@ -2025,8 +2028,8 @@ void HandleBackupConfiguration(void) if (!SettingsBufferAlloc()) { return; } - WiFiClient myClient = WebServer->client(); - WebServer->setContentLength(sizeof(Settings)); + WiFiClient myClient = Webserver->client(); + Webserver->setContentLength(sizeof(Settings)); char attachment[TOPSZ]; @@ -2036,7 +2039,7 @@ void HandleBackupConfiguration(void) char hostname[sizeof(my_hostname)]; snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"), NoAlNumToUnderscore(hostname, my_hostname), my_version); - WebServer->sendHeader(F("Content-Disposition"), attachment); + Webserver->sendHeader(F("Content-Disposition"), attachment); WSSend(200, CT_STREAM, ""); @@ -2202,7 +2205,7 @@ void HandleInformation(void) WSContentSend_P(PSTR("}1}2 ")); // Empty line WSContentSend_P(PSTR("}1" D_ESP_CHIP_ID "}2%d"), ESP_getChipId()); WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP_getFlashChipId()); - WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP_getFlashChipRealSize() / 1024); + WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP.getFlashChipRealSize() / 1024); WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%dkB"), ESP.getFlashChipSize() / 1024); WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%dkB"), ESP_getSketchSize() / 1024); WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%dkB"), ESP.getFreeSketchSpace() / 1024); @@ -2336,7 +2339,7 @@ void HandleUploadLoop(void) return; } - HTTPUpload& upload = WebServer->upload(); + HTTPUpload& upload = Webserver->upload(); if (UPLOAD_FILE_START == upload.status) { restart_flag = 60; @@ -2498,6 +2501,16 @@ void HandleUploadLoop(void) } else { valid_settings = (settings_buffer[0] == CONFIG_FILE_SIGN); } + + if (valid_settings) { +#ifdef ESP8266 + valid_settings = (0 == settings_buffer[0xF36]); // Settings.config_version +#endif // ESP8266 +#ifdef ESP32 + valid_settings = (1 == settings_buffer[0xF36]); // Settings.config_version +#endif // ESP32 + } + if (valid_settings) { SettingsDefaultSet2(); memcpy((char*)&Settings +16, settings_buffer +16, sizeof(Settings) -16); @@ -2549,8 +2562,8 @@ void HandleUploadLoop(void) void HandlePreflightRequest(void) { HttpHeaderCors(); - WebServer->sendHeader(F("Access-Control-Allow-Methods"), F("GET, POST")); - WebServer->sendHeader(F("Access-Control-Allow-Headers"), F("authorization")); + Webserver->sendHeader(F("Access-Control-Allow-Methods"), F("GET, POST")); + Webserver->sendHeader(F("Access-Control-Allow-Headers"), F("authorization")); WSSend(200, CT_HTML, ""); } @@ -2562,54 +2575,54 @@ void HandleHttpCommand(void) AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_COMMAND)); - bool valid = true; if (strlen(SettingsText(SET_WEBPWD))) { char tmp1[33]; WebGetArg("user", tmp1, sizeof(tmp1)); char tmp2[strlen(SettingsText(SET_WEBPWD)) +1]; WebGetArg("password", tmp2, sizeof(tmp2)); - if (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, SettingsText(SET_WEBPWD)))) { valid = false; } + if (!(!strcmp(tmp1, WEB_USERNAME) && !strcmp(tmp2, SettingsText(SET_WEBPWD)))) { + WSContentBegin(401, CT_JSON); + WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_NEED_USER_AND_PASSWORD "\"}")); + WSContentEnd(); + return; + } } WSContentBegin(200, CT_JSON); - if (valid) { - uint32_t curridx = web_log_index; - String svalue = WebServer->arg("cmnd"); - if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) { - ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCOMMAND); - if (web_log_index != curridx) { - uint32_t counter = curridx; - WSContentSend_P(PSTR("{")); - bool cflg = false; - do { - char* tmp; - size_t len; - GetLog(counter, &tmp, &len); - if (len) { - // [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}] - char* JSON = (char*)memchr(tmp, '{', len); - if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O]) - size_t JSONlen = len - (JSON - tmp); - if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); } - char stemp[JSONlen]; - strlcpy(stemp, JSON +1, JSONlen -2); - WSContentSend_P(PSTR("%s%s"), (cflg) ? "," : "", stemp); - cflg = true; - } + uint32_t curridx = web_log_index; + String svalue = Webserver->arg("cmnd"); + if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) { + ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCOMMAND); + if (web_log_index != curridx) { + uint32_t counter = curridx; + WSContentSend_P(PSTR("{")); + bool cflg = false; + do { + char* tmp; + size_t len; + GetLog(counter, &tmp, &len); + if (len) { + // [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}] + char* JSON = (char*)memchr(tmp, '{', len); + if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O]) + size_t JSONlen = len - (JSON - tmp); + if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); } + char stemp[JSONlen]; + strlcpy(stemp, JSON +1, JSONlen -2); + WSContentSend_P(PSTR("%s%s"), (cflg) ? "," : "", stemp); + cflg = true; } - counter++; - counter &= 0xFF; - if (!counter) counter++; // Skip 0 as it is not allowed - } while (counter != web_log_index); - WSContentSend_P(PSTR("}")); - } else { - WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}")); - } + } + counter++; + counter &= 0xFF; + if (!counter) counter++; // Skip 0 as it is not allowed + } while (counter != web_log_index); + WSContentSend_P(PSTR("}")); } else { - WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENTER_COMMAND " cmnd=\"}")); + WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}")); } } else { - WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_NEED_USER_AND_PASSWORD "\"}")); + WSContentSend_P(PSTR("{\"" D_RSLT_WARNING "\":\"" D_ENTER_COMMAND " cmnd=\"}")); } WSContentEnd(); } @@ -2620,7 +2633,7 @@ void HandleConsole(void) { if (!HttpCheckPriviledgedAccess()) { return; } - if (WebServer->hasArg("c2")) { // Console refresh requested + if (Webserver->hasArg("c2")) { // Console refresh requested HandleConsoleRefresh(); return; } @@ -2640,7 +2653,7 @@ void HandleConsoleRefresh(void) bool cflg = true; uint32_t counter = 0; // Initial start, should never be 0 again - String svalue = WebServer->arg("c1"); + String svalue = Webserver->arg("c1"); if (svalue.length() && (svalue.length() < MQTT_MAX_PACKET_SIZE)) { AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), svalue.c_str()); ExecuteWebCommand((char*)svalue.c_str(), SRC_WEBCONSOLE); @@ -2685,13 +2698,13 @@ void HandleConsoleRefresh(void) void HandleNotFound(void) { -// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Not found (%s)"), WebServer->uri().c_str()); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Not found (%s)"), Webserver->uri().c_str()); if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the error page. #ifdef USE_EMULATION #ifdef USE_EMULATION_HUE - String path = WebServer->uri(); + String path = Webserver->uri(); if ((EMUL_HUE == Settings.flag2.emulation) && (path.startsWith("/api"))) { HandleHueApi(&path); } else @@ -2699,9 +2712,9 @@ void HandleNotFound(void) #endif // USE_EMULATION { WSContentBegin(404, CT_PLAIN); - WSContentSend_P(PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"), WebServer->uri().c_str(), (WebServer->method() == HTTP_GET) ? "GET" : "POST", WebServer->args()); - for (uint32_t i = 0; i < WebServer->args(); i++) { - WSContentSend_P(PSTR(" %s: %s\n"), WebServer->argName(i).c_str(), WebServer->arg(i).c_str()); + WSContentSend_P(PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"), Webserver->uri().c_str(), (Webserver->method() == HTTP_GET) ? "GET" : "POST", Webserver->args()); + for (uint32_t i = 0; i < Webserver->args(); i++) { + WSContentSend_P(PSTR(" %s: %s\n"), Webserver->argName(i).c_str(), Webserver->arg(i).c_str()); } WSContentEnd(); } @@ -2711,12 +2724,12 @@ void HandleNotFound(void) bool CaptivePortal(void) { // Possible hostHeader: connectivitycheck.gstatic.com or 192.168.4.1 - if ((WifiIsInManagerMode()) && !ValidIpAddress(WebServer->hostHeader().c_str())) { + if ((WifiIsInManagerMode()) && !ValidIpAddress(Webserver->hostHeader().c_str())) { AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED)); - WebServer->sendHeader(F("Location"), String("http://") + WebServer->client().localIP().toString(), true); + Webserver->sendHeader(F("Location"), String("http://") + Webserver->client().localIP().toString(), true); WSSend(302, CT_PLAIN, ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. - WebServer->client().stop(); // Stop is needed because we sent no content length + Webserver->client().stop(); // Stop is needed because we sent no content length return true; } return false; diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index 780d94c98..6ad843980 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -1252,7 +1252,7 @@ void HandleMqttConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT); - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { MqttSaveSettings(); WebRestart(1); return; @@ -1334,7 +1334,7 @@ bool Xdrv02(uint8_t function) WSContentSend_P(HTTP_BTN_MENU_MQTT); break; case FUNC_WEB_ADD_HANDLER: - WebServer->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration); + Webserver->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration); break; #endif // USE_WEBSERVER case FUNC_COMMAND: diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index eda02eafb..1c5751829 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -1985,6 +1985,17 @@ bool isChannelGammaCorrected(uint32_t channel) { return true; } +// is the channel a regular PWM or ColorTemp control +bool isChannelCT(uint32_t channel) { +#ifdef ESP8266 + if (PHILIPS == my_module_type) { + if ((LST_COLDWARM == Light.subtype) && (1 == channel)) { return true; } // PMW reserved for CT + if ((LST_RGBCW == Light.subtype) && (4 == channel)) { return true; } // PMW reserved for CT + } +#endif // ESP8266 + return false; +} + // Calculate the Gamma correction, if any, for fading, using the fast Gamma curve (10 bits in+out) uint16_t fadeGamma(uint32_t channel, uint16_t v) { if (isChannelGammaCorrected(channel)) { @@ -2106,7 +2117,9 @@ void LightSetOutputs(const uint16_t *cur_col_10) { if (pin[GPIO_PWM1 +i] < 99) { //AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d 10 bits %d"), i, cur_col_10[i]); uint16_t cur_col = cur_col_10[i + Light.pwm_offset]; - cur_col = cur_col > 0 ? changeUIntScale(cur_col, 0, Settings.pwm_range, Light.pwm_min, Light.pwm_max) : 0; // shrink to the range of pwm_min..pwm_max + if (!isChannelCT(i)) { // if CT don't use pwm_min and pwm_max + cur_col = cur_col > 0 ? changeUIntScale(cur_col, 0, Settings.pwm_range, Light.pwm_min, Light.pwm_max) : 0; // shrink to the range of pwm_min..pwm_max + } analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - cur_col : cur_col); } } diff --git a/tasmota/xdrv_07_domoticz.ino b/tasmota/xdrv_07_domoticz.ino index 1fddf5890..ef7202fa7 100644 --- a/tasmota/xdrv_07_domoticz.ino +++ b/tasmota/xdrv_07_domoticz.ino @@ -559,7 +559,7 @@ void HandleDomoticzConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ); - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { DomoticzSaveSettings(); WebRestart(1); return; @@ -651,7 +651,7 @@ bool Xdrv07(uint8_t function) WSContentSend_P(HTTP_BTN_MENU_DOMOTICZ); break; case FUNC_WEB_ADD_HANDLER: - WebServer->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration); + Webserver->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration); break; #endif // USE_WEBSERVER case FUNC_MQTT_SUBSCRIBE: diff --git a/tasmota/xdrv_09_timers.ino b/tasmota/xdrv_09_timers.ino index f751d853f..a5cb67f41 100644 --- a/tasmota/xdrv_09_timers.ino +++ b/tasmota/xdrv_09_timers.ino @@ -702,7 +702,7 @@ void HandleTimerConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TIMER); - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { TimerSaveSettings(); HandleConfiguration(); return; @@ -740,7 +740,7 @@ void TimerSaveSettings(void) char message[LOGSZ]; Timer timer; - Settings.flag3.timers_enable = WebServer->hasArg("e0"); // CMND_TIMERS + Settings.flag3.timers_enable = Webserver->hasArg("e0"); // CMND_TIMERS WebGetArg("t0", tmp, sizeof(tmp)); char *p = tmp; snprintf_P(message, sizeof(message), PSTR(D_LOG_MQTT D_CMND_TIMERS " %d"), Settings.flag3.timers_enable); // CMND_TIMERS @@ -781,7 +781,7 @@ bool Xdrv09(uint8_t function) #endif // USE_RULES break; case FUNC_WEB_ADD_HANDLER: - WebServer->on("/" WEB_HANDLE_TIMER, HandleTimerConfiguration); + Webserver->on("/" WEB_HANDLE_TIMER, HandleTimerConfiguration); break; #endif // USE_TIMERS_WEB #endif // USE_WEBSERVER diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index e086adedb..ae4f9a9af 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -65,6 +65,35 @@ keywords if then else endif, or, and are better readable for beginners (others m uint32_t EncodeLightId(uint8_t relay_id); uint32_t DecodeLightId(uint32_t hue_id); +#if defined(ESP32) && defined(ESP32_SCRIPT_SIZE) && !defined(USE_24C256) && !defined(USE_SCRIPT_FATFS) + +#include "FS.h" +#include "SPIFFS.h" +void SaveFile(const char *name,const uint8_t *buf,uint32_t len) { + File file = SPIFFS.open(name, FILE_WRITE); + if (!file) return; + file.write(buf, len); + file.close(); +} + +#define FORMAT_SPIFFS_IF_FAILED true +uint8_t spiffs_mounted=0; + +void LoadFile(const char *name,uint8_t *buf,uint32_t len) { + if (!spiffs_mounted) { + if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){ + //Serial.println("SPIFFS Mount Failed"); + return; + } + spiffs_mounted=1; + } + File file = SPIFFS.open(name); + if (!file) return; + file.read(buf, len); + file.close(); +} +#endif + // offsets epoch readings by 1.1.2019 00:00:00 to fit into float with second resolution #define EPOCH_OFFSET 1546300800 @@ -3341,8 +3370,8 @@ void Script_FileUploadConfiguration(void) if (!HttpCheckPriviledgedAccess()) { return; } - if (WebServer->hasArg("download")) { - String stmp = WebServer->arg("download"); + if (Webserver->hasArg("download")) { + String stmp = Webserver->arg("download"); char *cp=(char*)stmp.c_str(); if (DownloadFile(cp)) { // is directory @@ -3386,7 +3415,7 @@ void script_upload(void) { //AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: file upload")); - HTTPUpload& upload = WebServer->upload(); + HTTPUpload& upload = Webserver->upload(); if (upload.status == UPLOAD_FILE_START) { char npath[48]; sprintf(npath,"%s/%s",path,upload.filename.c_str()); @@ -3402,7 +3431,7 @@ void script_upload(void) { } } else { Web.upload_error=1; - WebServer->send(500, "text/plain", "500: couldn't create file"); + Webserver->send(500, "text/plain", "500: couldn't create file"); } } @@ -3428,8 +3457,8 @@ uint8_t DownloadFile(char *file) { uint32_t flen=download_file.size(); - download_Client = WebServer->client(); - WebServer->setContentLength(flen); + download_Client = Webserver->client(); + Webserver->setContentLength(flen); char attachment[100]; char *cp; @@ -3440,7 +3469,7 @@ uint8_t DownloadFile(char *file) { } } snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"),cp); - WebServer->sendHeader(F("Content-Disposition"), attachment); + Webserver->sendHeader(F("Content-Disposition"), attachment); WSSend(200, CT_STREAM, ""); uint8_t buff[512]; @@ -3472,7 +3501,7 @@ uint8_t DownloadFile(char *file) { void HandleScriptTextareaConfiguration(void) { if (!HttpCheckPriviledgedAccess()) { return; } - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { ScriptSaveSettings(); HandleConfiguration(); return; @@ -3486,13 +3515,13 @@ void HandleScriptConfiguration(void) { AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_SCRIPT); #ifdef USE_SCRIPT_FATFS - if (WebServer->hasArg("d1")) { + if (Webserver->hasArg("d1")) { DownloadFile(glob_script_mem.flink[0]); } - if (WebServer->hasArg("d2")) { + if (Webserver->hasArg("d2")) { DownloadFile(glob_script_mem.flink[1]); } - if (WebServer->hasArg("upl")) { + if (Webserver->hasArg("upl")) { Script_FileUploadConfiguration(); } #endif @@ -3532,14 +3561,14 @@ void HandleScriptConfiguration(void) { void ScriptSaveSettings(void) { - if (WebServer->hasArg("c1")) { + if (Webserver->hasArg("c1")) { bitWrite(Settings.rule_enabled,0,1); } else { bitWrite(Settings.rule_enabled,0,0); } - String str = WebServer->arg("t1"); + String str = Webserver->arg("t1"); if (*str.c_str()) { @@ -3597,6 +3626,11 @@ void ScriptSaveSettings(void) { } #endif +#if defined(ESP32) && defined(ESP32_SCRIPT_SIZE) && !defined(USE_24C256) && !defined(USE_SCRIPT_FATFS) + if (glob_script_mem.flags&1) { + SaveFile("/script.txt",(uint8_t*)glob_script_mem.script_ram,ESP32_SCRIPT_SIZE); + } +#endif } if (glob_script_mem.script_mem) { @@ -3990,11 +4024,11 @@ void Script_Handle_Hue(String *path) { uint8_t device = DecodeLightId(atoi(path->c_str())); uint8_t index = device-devices_present-1; - if (WebServer->args()) { + if (Webserver->args()) { response = "["; StaticJsonBuffer<400> jsonBuffer; - JsonObject &hue_json = jsonBuffer.parseObject(WebServer->arg((WebServer->args())-1)); + JsonObject &hue_json = jsonBuffer.parseObject(Webserver->arg((Webserver->args())-1)); if (hue_json.containsKey("on")) { response += FPSTR(sHUE_LIGHT_RESPONSE_JSON); @@ -4436,8 +4470,8 @@ void Script_Check_HTML_Setvars(void) { if (!HttpCheckPriviledgedAccess()) { return; } - if (WebServer->hasArg("sv")) { - String stmp = WebServer->arg("sv"); + if (Webserver->hasArg("sv")) { + String stmp = Webserver->arg("sv"); char cmdbuf[64]; memset(cmdbuf,0,sizeof(cmdbuf)); char *cp=cmdbuf; @@ -4820,6 +4854,13 @@ bool Xdrv10(uint8_t function) switch (function) { case FUNC_PRE_INIT: + /* +#ifdef USE_WEBCAM + if (Settings.module==ESP32_CAM_AITHINKER) { + webcam_setup(); + } +#endif +*/ // set defaults to rules memory glob_script_mem.script_ram=Settings.rules[0]; glob_script_mem.script_size=MAX_SCRIPT_SIZE; @@ -4889,6 +4930,21 @@ bool Xdrv10(uint8_t function) } #endif + +#if defined(ESP32) && defined(ESP32_SCRIPT_SIZE) && !defined(USE_24C256) && !defined(USE_SCRIPT_FATFS) + char *script; + script=(char*)calloc(ESP32_SCRIPT_SIZE+4,1); + if (!script) break; + LoadFile("/script.txt",(uint8_t*)script,ESP32_SCRIPT_SIZE); + glob_script_mem.script_ram=script; + glob_script_mem.script_size=ESP32_SCRIPT_SIZE; + script[ESP32_SCRIPT_SIZE-1]=0; + // use rules storage for permanent vars + glob_script_mem.script_pram=(uint8_t*)Settings.rules[0]; + glob_script_mem.script_pram_size=MAX_SCRIPT_SIZE; + glob_script_mem.flags=1; +#endif + // assure permanent memory is 4 byte aligned { uint32_t ptr=(uint32_t)glob_script_mem.script_pram; ptr&=0xfffffffc; @@ -4932,13 +4988,13 @@ bool Xdrv10(uint8_t function) WSContentSend_P(HTTP_BTN_MENU_RULES); break; case FUNC_WEB_ADD_HANDLER: - WebServer->on("/" WEB_HANDLE_SCRIPT, HandleScriptConfiguration); - WebServer->on("/ta",HTTP_POST, HandleScriptTextareaConfiguration); + Webserver->on("/" WEB_HANDLE_SCRIPT, HandleScriptConfiguration); + Webserver->on("/ta",HTTP_POST, HandleScriptTextareaConfiguration); #ifdef USE_SCRIPT_FATFS - WebServer->on("/u3", HTTP_POST,[]() { WebServer->sendHeader("Location","/u3");WebServer->send(303);},script_upload); - WebServer->on("/u3", HTTP_GET,ScriptFileUploadSuccess); - WebServer->on("/upl", HTTP_GET,Script_FileUploadConfiguration); + Webserver->on("/u3", HTTP_POST,[]() { Webserver->sendHeader("Location","/u3");Webserver->send(303);},script_upload); + Webserver->on("/u3", HTTP_GET,ScriptFileUploadSuccess); + Webserver->on("/upl", HTTP_GET,Script_FileUploadConfiguration); #endif break; #endif // USE_WEBSERVER diff --git a/tasmota/xdrv_11_knx.ino b/tasmota/xdrv_11_knx.ino index b8177c1ad..d6f2864dc 100644 --- a/tasmota/xdrv_11_knx.ino +++ b/tasmota/xdrv_11_knx.ino @@ -809,22 +809,22 @@ void HandleKNXConfiguration(void) char tmp[100]; String stmp; - if ( WebServer->hasArg("save") ) { + if ( Webserver->hasArg("save") ) { KNX_Save_Settings(); HandleConfiguration(); } else { - if ( WebServer->hasArg("btn_add") ) { - if ( WebServer->arg("btn_add") == "1" ) { + if ( Webserver->hasArg("btn_add") ) { + if ( Webserver->arg("btn_add") == "1" ) { - stmp = WebServer->arg("GAop"); //option selected + stmp = Webserver->arg("GAop"); //option selected uint8_t GAop = stmp.toInt(); - stmp = WebServer->arg("GA_FNUM"); + stmp = Webserver->arg("GA_FNUM"); uint8_t GA_FNUM = stmp.toInt(); - stmp = WebServer->arg("GA_AREA"); + stmp = Webserver->arg("GA_AREA"); uint8_t GA_AREA = stmp.toInt(); - stmp = WebServer->arg("GA_FDEF"); + stmp = Webserver->arg("GA_FDEF"); uint8_t GA_FDEF = stmp.toInt(); if (GAop) { @@ -834,13 +834,13 @@ void HandleKNXConfiguration(void) else { - stmp = WebServer->arg("CBop"); //option selected + stmp = Webserver->arg("CBop"); //option selected uint8_t CBop = stmp.toInt(); - stmp = WebServer->arg("CB_FNUM"); + stmp = Webserver->arg("CB_FNUM"); uint8_t CB_FNUM = stmp.toInt(); - stmp = WebServer->arg("CB_AREA"); + stmp = Webserver->arg("CB_AREA"); uint8_t CB_AREA = stmp.toInt(); - stmp = WebServer->arg("CB_FDEF"); + stmp = Webserver->arg("CB_FDEF"); uint8_t CB_FDEF = stmp.toInt(); if (CBop) { @@ -848,19 +848,19 @@ void HandleKNXConfiguration(void) } } } - else if ( WebServer->hasArg("btn_del_ga") ) + else if ( Webserver->hasArg("btn_del_ga") ) { - stmp = WebServer->arg("btn_del_ga"); + stmp = Webserver->arg("btn_del_ga"); uint8_t GA_NUM = stmp.toInt(); KNX_DEL_GA(GA_NUM); } - else if ( WebServer->hasArg("btn_del_cb") ) + else if ( Webserver->hasArg("btn_del_cb") ) { - stmp = WebServer->arg("btn_del_cb"); + stmp = Webserver->arg("btn_del_cb"); uint8_t CB_NUM = stmp.toInt(); KNX_DEL_CB(CB_NUM); @@ -954,16 +954,16 @@ void KNX_Save_Settings(void) String stmp; address_t KNX_addr; - Settings.flag.knx_enabled = WebServer->hasArg("b1"); - Settings.flag.knx_enable_enhancement = WebServer->hasArg("b2"); + Settings.flag.knx_enabled = Webserver->hasArg("b1"); + Settings.flag.knx_enable_enhancement = Webserver->hasArg("b2"); AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_KNX D_ENABLED ": %d, " D_KNX_ENHANCEMENT ": %d"), Settings.flag.knx_enabled, Settings.flag.knx_enable_enhancement ); - stmp = WebServer->arg("area"); + stmp = Webserver->arg("area"); KNX_addr.pa.area = stmp.toInt(); - stmp = WebServer->arg("line"); + stmp = Webserver->arg("line"); KNX_addr.pa.line = stmp.toInt(); - stmp = WebServer->arg("member"); + stmp = Webserver->arg("member"); KNX_addr.pa.member = stmp.toInt(); Settings.knx_physsical_addr = KNX_addr.value; knx.physical_address_set( KNX_addr ); // Set Physical KNX Address of the device @@ -1224,7 +1224,7 @@ bool Xdrv11(uint8_t function) WSContentSend_P(HTTP_BTN_MENU_KNX); break; case FUNC_WEB_ADD_HANDLER: - WebServer->on("/kn", HandleKNXConfiguration); + Webserver->on("/kn", HandleKNXConfiguration); break; #endif // USE_KNX_WEB_MENU #endif // USE_WEBSERVER diff --git a/tasmota/xdrv_20_hue.ino b/tasmota/xdrv_20_hue.ino index 32a852b50..201491d09 100644 --- a/tasmota/xdrv_20_hue.ino +++ b/tasmota/xdrv_20_hue.ino @@ -448,7 +448,7 @@ static const char * FIRST_GEN_UA[] = { // list of User-Agents signature // Check if the Echo device is of 1st generation, which triggers different results uint32_t findEchoGeneration(void) { // result is 1 for 1st gen, 2 for 2nd gen and further - String user_agent = WebServer->header("User-Agent"); + String user_agent = Webserver->header("User-Agent"); uint32_t gen = 2; for (uint32_t i = 0; i < sizeof(FIRST_GEN_UA)/sizeof(char*); i++) { @@ -521,11 +521,11 @@ void HueLightsCommand(uint8_t device, uint32_t device_id, String &response) { const size_t buf_size = 100; char * buf = (char*) malloc(buf_size); - if (WebServer->args()) { + if (Webserver->args()) { response = "["; StaticJsonBuffer<300> jsonBuffer; - JsonObject &hue_json = jsonBuffer.parseObject(WebServer->arg((WebServer->args())-1)); + JsonObject &hue_json = jsonBuffer.parseObject(Webserver->arg((Webserver->args())-1)); if (hue_json.containsKey("on")) { on = hue_json["on"]; snprintf_P(buf, buf_size, @@ -542,6 +542,7 @@ void HueLightsCommand(uint8_t device, uint32_t device_id, String &response) { } } else { #endif +/* switch(on) { case false : ExecuteCommandPower(device, POWER_OFF, SRC_HUE); @@ -549,6 +550,8 @@ void HueLightsCommand(uint8_t device, uint32_t device_id, String &response) { case true : ExecuteCommandPower(device, POWER_ON, SRC_HUE); break; } +*/ + ExecuteCommandPower(device, (on) ? POWER_ON : POWER_OFF, SRC_HUE); response += buf; resp = true; #ifdef USE_SHUTTER @@ -827,8 +830,8 @@ void HandleHueApi(String *path) path->remove(0, 4); // remove /api uint16_t apilen = path->length(); AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_API " (%s)"), path->c_str()); // HTP: Hue API (//lights/1/state - for (args = 0; args < WebServer->args(); args++) { - String json = WebServer->arg(args); + for (args = 0; args < Webserver->args(); args++) { + String json = Webserver->arg(args); AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE_POST_ARGS " (%s)"), json.c_str()); // HTP: Hue POST args ({"on":false}) } @@ -861,7 +864,7 @@ bool Xdrv20(uint8_t function) #endif switch (function) { case FUNC_WEB_ADD_HANDLER: - WebServer->on(F("/description.xml"), HandleUpnpSetupHue); + Webserver->on(F("/description.xml"), HandleUpnpSetupHue); break; } } diff --git a/tasmota/xdrv_21_wemo.ino b/tasmota/xdrv_21_wemo.ino index cb3566f89..eef509e2a 100644 --- a/tasmota/xdrv_21_wemo.ino +++ b/tasmota/xdrv_21_wemo.ino @@ -198,7 +198,7 @@ void HandleUpnpEvent(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_BASIC_EVENT)); char event[500]; - strlcpy(event, WebServer->arg(0).c_str(), sizeof(event)); + strlcpy(event, Webserver->arg(0).c_str(), sizeof(event)); // AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), event); @@ -259,10 +259,10 @@ bool Xdrv21(uint8_t function) if (devices_present && (EMUL_WEMO == Settings.flag2.emulation)) { switch (function) { case FUNC_WEB_ADD_HANDLER: - WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); - WebServer->on("/eventservice.xml", HandleUpnpService); - WebServer->on("/metainfoservice.xml", HandleUpnpMetaService); - WebServer->on("/setup.xml", HandleUpnpSetupWemo); + Webserver->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); + Webserver->on("/eventservice.xml", HandleUpnpService); + Webserver->on("/metainfoservice.xml", HandleUpnpMetaService); + Webserver->on("/setup.xml", HandleUpnpSetupWemo); break; } } diff --git a/tasmota/xdrv_23_zigbee_1_headers.ino b/tasmota/xdrv_23_zigbee_1_headers.ino index 051858697..5a250c781 100644 --- a/tasmota/xdrv_23_zigbee_1_headers.ino +++ b/tasmota/xdrv_23_zigbee_1_headers.ino @@ -25,15 +25,15 @@ void ZigbeeZCLSend_Raw(uint16_t dtsAddr, uint16_t groupaddr, uint16_t clusterId, // Get an JSON attribute, with case insensitive key search -JsonVariant &getCaseInsensitive(const JsonObject &json, const char *needle) { +const JsonVariant &getCaseInsensitive(const JsonObject &json, const char *needle) { // key can be in PROGMEM if ((nullptr == &json) || (nullptr == needle) || (0 == pgm_read_byte(needle))) { return *(JsonVariant*)nullptr; } - for (auto kv : json) { - const char *key = kv.key; - JsonVariant &value = kv.value; + for (JsonObject::const_iterator it=json.begin(); it!=json.end(); ++it) { + const char *key = it->key; + const JsonVariant &value = it->value; if (0 == strcasecmp_P(key, needle)) { return value; diff --git a/tasmota/xdrv_23_zigbee_2_devices.ino b/tasmota/xdrv_23_zigbee_2_devices.ino index 9f5ef60a9..23970042e 100644 --- a/tasmota/xdrv_23_zigbee_2_devices.ino +++ b/tasmota/xdrv_23_zigbee_2_devices.ino @@ -65,7 +65,7 @@ typedef int32_t (*Z_DeviceTimer)(uint16_t shortaddr, uint16_t groupaddr, uint16_ typedef enum Z_Def_Category { Z_CAT_NONE = 0, // no category, it will happen anyways Z_CAT_READ_ATTR, // Attribute reporting, either READ_ATTRIBUTE or REPORT_ATTRIBUTE, we coalesce all attributes reported if we can - Z_CAT_VIRTUAL_ATTR, // Creation of a virtual attribute, typically after a time-out. Ex: Aqara presence sensor + Z_CAT_VIRTUAL_OCCUPANCY, // Creation of a virtual attribute, typically after a time-out. Ex: Aqara presence sensor Z_CAT_REACHABILITY, // timer set to measure reachability of device, i.e. if we don't get an answer after 1s, it is marked as unreachable (for Alexa) Z_CAT_READ_0006, // Read 0x0006 cluster Z_CAT_READ_0008, // Read 0x0008 cluster diff --git a/tasmota/xdrv_23_zigbee_3_hue.ino b/tasmota/xdrv_23_zigbee_3_hue.ino index 0d00ad9e0..87b7d39da 100644 --- a/tasmota/xdrv_23_zigbee_3_hue.ino +++ b/tasmota/xdrv_23_zigbee_3_hue.ino @@ -190,23 +190,21 @@ void ZigbeeHandleHue(uint16_t shortaddr, uint32_t device_id, String &response) { const size_t buf_size = 100; char * buf = (char*) malloc(buf_size); - if (WebServer->args()) { + if (Webserver->args()) { response = "["; StaticJsonBuffer<300> jsonBuffer; - JsonObject &hue_json = jsonBuffer.parseObject(WebServer->arg((WebServer->args())-1)); + JsonObject &hue_json = jsonBuffer.parseObject(Webserver->arg((Webserver->args())-1)); if (hue_json.containsKey("on")) { on = hue_json["on"]; snprintf_P(buf, buf_size, PSTR("{\"success\":{\"/lights/%d/state/on\":%s}}"), device_id, on ? "true" : "false"); - switch(on) - { - case false : ZigbeeHuePower(shortaddr, 0x00); - break; - case true : ZigbeeHuePower(shortaddr, 0x01); - break; + if (on) { + ZigbeeHuePower(shortaddr, 0x01); + } else { + ZigbeeHuePower(shortaddr, 0x00); } response += buf; resp = true; diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 7a8ea4806..67ff8993f 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -23,6 +23,72 @@ * ZCL \*********************************************************************************************/ + +enum Z_DataTypes { + Znodata = 0x00, + Zdata8 = 0x08, Zdata16, Zdata24, Zdata32, Zdata40, Zdata48, Zdata56, Zdata64, + Zbool = 0x10, + Zmap8 = 0x18, Zmap16, Zmap24, Zmap32, Zmap40, Zmap48, Zmap56, Zmap64, + Zuint8 = 0x20, Zuint16, Zuint24, Zuint32, Zuint40, Zuint48, Zuint56, Zuint64, + Zint8 = 0x28, Zint16, Zint24, Zint32, Zint40, Zint48, Zint56, Zint64, + Zenum8 = 0x30, Zenum16 = 0x31, + Zsemi = 0x38, Zsingle = 0x39, Zdouble = 0x3A, + Zoctstr = 0x41, Zstring = 0x42, Zoctstr16 = 0x43, Zstring16 = 0x44, + Arrray = 0x48, + Zstruct = 0x4C, + Zset = 0x50, Zbag = 0x51, + ZToD = 0xE0, Zdate = 0xE1, ZUTC = 0xE2, + ZclusterId = 0xE8, ZattribId = 0xE9, ZbacOID = 0xEA, + ZEUI64 = 0xF0, Zkey128 = 0xF1, + Zunk = 0xFF +}; + +// +// get the lenth in bytes for a data-type +// return 0 if unknown of type specific +// +// Note: this code is smaller than a static array +uint8_t Z_getDatatypeLen(uint8_t t) { + if ( ((t >= 0x08) && (t <= 0x0F)) || // data8 - data64 + ((t >= 0x18) && (t <= 0x2F)) ) { // map/uint/int + return (t & 0x07) + 1; + } + switch (t) { + case Zbool: + case Zenum8: + return 1; + case Zenum16: + case Zsemi: + case ZclusterId: + case ZattribId: + return 2; + case Zsingle: + case ZToD: + case Zdate: + case ZUTC: + case ZbacOID: + return 4; + case Zdouble: + case ZEUI64: + return 8; + case Zkey128: + return 16; + case Znodata: + default: + return 0; + } +} + +// typedef struct Z_DataTypeMapping { +// uint8_t datatype; +// uint8_t len; // len in bytes and add 0x80 if DISCRETE +// } + +// const Z_DataTypeMapping Z_types[] PROGMEM = { +// { Znodata, 0 }, +// { Zdata8, 0 }, +// }; + typedef union ZCLHeaderFrameControl_t { struct { uint8_t frame_type : 2; // 00 = across entire profile, 01 = cluster specific @@ -43,7 +109,7 @@ public: uint16_t srcaddr, uint8_t srcendpoint, uint8_t dstendpoint, uint8_t wasbroadcast, uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber, uint32_t timestamp): - _cmd_id(cmd_id), _manuf_code(manuf_code), _transact_seq(transact_seq), + _manuf_code(manuf_code), _transact_seq(transact_seq), _cmd_id(cmd_id), _payload(buf_len ? buf_len : 250), // allocate the data frame from source or preallocate big enough _cluster_id(clusterid), _groupaddr(groupaddr), _srcaddr(srcaddr), _srcendpoint(srcendpoint), _dstendpoint(dstendpoint), _wasbroadcast(wasbroadcast), @@ -149,9 +215,9 @@ private: uint16_t _manuf_code = 0; // optional uint8_t _transact_seq = 0; // transaction sequence number uint8_t _cmd_id = 0; + SBuffer _payload; uint16_t _cluster_id = 0; uint16_t _groupaddr = 0; - SBuffer _payload; // information from decoded ZCL frame uint16_t _srcaddr; uint8_t _srcendpoint; @@ -188,7 +254,7 @@ uint8_t toPercentageCR2032(uint32_t voltage) { uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer &buf, - uint32_t offset, uint32_t len) { + uint32_t offset, uint32_t buflen) { uint32_t i = offset; uint32_t attrtype = buf.get8(i++); @@ -196,105 +262,98 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer // fallback - enter a null value json[attrid_str] = (char*) nullptr; + uint32_t len = Z_getDatatypeLen(attrtype); // pre-compute lenght, overloaded for variable length attributes + // now parse accordingly to attr type switch (attrtype) { - case 0x00: // nodata - case 0xFF: // unk - break; - case 0x10: // bool - case 0x20: // uint8 - case 0x30: // enum8 + // case Znodata: // nodata + // case Zunk: // unk + // break; + case Zbool: // bool + case Zuint8: // uint8 + case Zenum8: // enum8 { uint8_t uint8_val = buf.get8(i); - i += 1; + // i += 1; if (0xFF != uint8_val) { json[attrid_str] = uint8_val; } } break; - case 0x21: // uint16 - case 0x31: // enum16 + case Zuint16: // uint16 + case Zenum16: // enum16 { uint16_t uint16_val = buf.get16(i); - i += 2; + // i += 2; if (0xFFFF != uint16_val) { json[attrid_str] = uint16_val; } } break; - case 0x23: // uint32 + case Zuint32: // uint32 { uint32_t uint32_val = buf.get32(i); - i += 4; + // i += 4; if (0xFFFFFFFF != uint32_val) { json[attrid_str] = uint32_val; } } break; - // Note: uint40, uint48, uint56, uint64 are stored as Hex - case 0x24: // uint40 - case 0x25: // uint48 - case 0x26: // uint56 - case 0x27: // uint64 + // Note: uint40, uint48, uint56, uint64 are displayed as Hex + // Note: int40, int48, int56, int64 are displayed as Hex + case Zuint40: // uint40 + case Zuint48: // uint48 + case Zuint56: // uint56 + case Zuint64: // uint64 + case Zint40: // int40 + case Zint48: // int48 + case Zint56: // int56 + case Zint64: // int64 { - uint8_t len = attrtype - 0x1F; // 5 - 8 + // uint8_t len = attrtype - 0x27; // 5 - 8 // print as HEX char hex[2*len+1]; ToHex_P(buf.buf(i), len, hex, sizeof(hex)); json[attrid_str] = hex; - i += len; + // i += len; } break; - case 0x28: // uint8 + case Zint8: // int8 { int8_t int8_val = buf.get8(i); - i += 1; + // i += 1; if (0x80 != int8_val) { json[attrid_str] = int8_val; } } break; - case 0x29: // uint16 + case Zint16: // int16 { int16_t int16_val = buf.get16(i); - i += 2; + // i += 2; if (0x8000 != int16_val) { json[attrid_str] = int16_val; } } break; - case 0x2B: // uint16 + case Zint32: // int32 { int32_t int32_val = buf.get32(i); - i += 4; + // i += 4; if (0x80000000 != int32_val) { json[attrid_str] = int32_val; } } break; - // Note: int40, int48, int56, int64 are not stored as Hex - case 0x2C: // int40 - case 0x2D: // int48 - case 0x2E: // int56 - case 0x2F: // int64 - { - uint8_t len = attrtype - 0x27; // 5 - 8 - // print as HEX - char hex[2*len+1]; - ToHex_P(buf.buf(i), len, hex, sizeof(hex)); - json[attrid_str] = hex; - i += len; - } - break; - case 0x41: // octet string, 1 byte len - case 0x42: // char string, 1 byte len - case 0x43: // octet string, 2 bytes len - case 0x44: // char string, 2 bytes len + case Zoctstr: // octet string, 1 byte len + case Zstring: // char string, 1 byte len + case Zoctstr16: // octet string, 2 bytes len + case Zstring16: // char string, 2 bytes len // For strings, default is to try to do a real string, but reverts to octet stream if null char is present or on some exceptions { bool parse_as_string = true; - uint32_t len = (attrtype <= 0x42) ? buf.get8(i) : buf.get16(i); // len is 8 or 16 bits + len = (attrtype <= 0x42) ? buf.get8(i) : buf.get16(i); // len is 8 or 16 bits i += (attrtype <= 0x42) ? 1 : 2; // increment pointer if (i + len > buf.len()) { // make sure we don't get past the buffer len = buf.len() - i; @@ -302,14 +361,6 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer // check if we can safely use a string if ((0x41 == attrtype) || (0x43 == attrtype)) { parse_as_string = false; } - // else { - // for (uint32_t j = 0; j < len; j++) { - // if (0x00 == buf.get8(i+j)) { - // parse_as_string = false; - // break; - // } - // } - // } if (parse_as_string) { char str[len+1]; @@ -323,97 +374,82 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer json[attrid_str] = hex; } - i += len; - break; + // i += len; + // break; } - i += buf.get8(i) + 1; + // i += buf.get8(i) + 1; break; - case 0x08: // data8 - case 0x18: // map8 + case Zdata8: // data8 + case Zmap8: // map8 { uint8_t uint8_val = buf.get8(i); - i += 1; + // i += 1; json[attrid_str] = uint8_val; } break; - case 0x09: // data16 - case 0x19: // map16 + case Zdata16: // data16 + case Zmap16: // map16 { uint16_t uint16_val = buf.get16(i); - i += 2; + // i += 2; json[attrid_str] = uint16_val; } break; - case 0x0B: // data32 - case 0x1B: // map32 + case Zdata32: // data32 + case Zmap32: // map32 { uint32_t uint32_val = buf.get32(i); - i += 4; + // i += 4; json[attrid_str] = uint32_val; } break; - // TODO - case 0x39: // float + case Zsingle: // float { uint32_t uint32_val = buf.get32(i); float * float_val = (float*) &uint32_val; - i += 4; + // i += 4; json[attrid_str] = *float_val; } break; - case 0xE0: // ToD - case 0xE1: // date - case 0xE2: // UTC - i += 4; - break; - - case 0xE8: // clusterId - case 0xE9: // attribId - i += 2; - break; - case 0xEA: // bacOID - i += 4; - break; - - case 0xF0: // EUI64 - i += 8; - break; - case 0xF1: // key128 - i += 16; + // TODO + case ZToD: // ToD + case Zdate: // date + case ZUTC: // UTC + case ZclusterId: // clusterId + case ZattribId: // attribId + case ZbacOID: // bacOID + case ZEUI64: // EUI64 + case Zkey128: // key128 + case Zsemi: // semi (float on 2 bytes) break; // Other un-implemented data types - case 0x0A: // data24 - case 0x0C: // data40 - case 0x0D: // data48 - case 0x0E: // data56 - case 0x0F: // data64 - i += attrtype - 0x07; // 2-8 + case Zdata24: // data24 + case Zdata40: // data40 + case Zdata48: // data48 + case Zdata56: // data56 + case Zdata64: // data64 break; // map - case 0x1A: // map24 - case 0x1C: // map40 - case 0x1D: // map48 - case 0x1E: // map56 - case 0x1F: // map64 - i += attrtype - 0x17; + case Zmap24: // map24 + case Zmap40: // map40 + case Zmap48: // map48 + case Zmap56: // map56 + case Zmap64: // map64 break; - // semi - case 0x38: // semi (float on 2 bytes) - i += 2; - break; - case 0x3A: // double precision + case Zdouble: // double precision { uint64_t uint64_val = buf.get64(i); double * double_val = (double*) &uint64_val; - i += 8; + // i += 8; json[attrid_str] = *double_val; } break; } + i += len; // String pp; // pretty print // json[attrid_str].prettyPrintTo(pp); @@ -529,12 +565,36 @@ void ZCLFrame::parseClusterSpecificCommand(JsonObject& json, uint8_t offset) { // 1 = remove initial value typedef int32_t (*Z_AttrConverter)(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, uint16_t cluster, uint16_t attr); typedef struct Z_AttributeConverter { - uint16_t cluster; + uint8_t type; + uint8_t cluster_short; uint16_t attribute; const char * name; Z_AttrConverter func; } Z_AttributeConverter; +enum Cx_cluster_short { + Cx0000, Cx0001, Cx0002, Cx0003, Cx0004, Cx0005, Cx0006, Cx0007, + Cx0008, Cx0009, Cx000A, Cx000B, Cx000C, Cx000D, Cx000E, Cx000F, + Cx0010, Cx0011, Cx0012, Cx0013, Cx0014, Cx001A, Cx0020, Cx0100, + Cx0101, Cx0102, Cx0300, Cx0400, Cx0401, Cx0402, Cx0403, Cx0404, + Cx0405, Cx0406, Cx0B01, Cx0B05, +}; + +const uint16_t Cx_cluster[] PROGMEM = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x001A, 0x0020, 0x0100, + 0x0101, 0x0102, 0x0300, 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, + 0x0405, 0x0406, 0x0B01, 0x0B05, +}; + +uint16_t CxToCluster(uint8_t cx) { + if (cx < sizeof(Cx_cluster)/sizeof(Cx_cluster[0])) { + return pgm_read_word(&Cx_cluster[cx]); + } + return 0xFFFF; +} + ZF(ZCLVersion) ZF(AppVersion) ZF(StackVersion) ZF(HWVersion) ZF(Manufacturer) ZF(ModelId) ZF(DateCode) ZF(PowerSource) ZF(SWBuildID) ZF(Power) ZF(SwitchType) ZF(Dimmer) ZF(MainsVoltage) ZF(MainsFrequency) ZF(BatteryVoltage) ZF(BatteryPercentage) @@ -606,7 +666,7 @@ ZF(WhitePointY) ZF(ColorPointRX) ZF(ColorPointRY) ZF(ColorPointRIntensity) ZF(Co ZF(ColorPointGIntensity) ZF(ColorPointBX) ZF(ColorPointBY) ZF(ColorPointBIntensity) ZF(Illuminance) ZF(IlluminanceMinMeasuredValue) ZF(IlluminanceMaxMeasuredValue) ZF(IlluminanceTolerance) -ZF(IlluminanceLightSensorType) ZF(IlluminanceLevelStatus) +ZF(IlluminanceLightSensorType) ZF(IlluminanceLevelStatus) ZF(IlluminanceTargetLevel) ZF(Temperature) ZF(TemperatureMinMeasuredValue) ZF(TemperatureMaxMeasuredValue) ZF(TemperatureTolerance) @@ -621,341 +681,361 @@ ZF(Humidity) ZF(HumidityMinMeasuredValue) ZF(HumidityMaxMeasuredValue) ZF(Humidi ZF(Occupancy) ZF(OccupancySensorType) ZF(CompanyName) ZF(MeterTypeID) ZF(DataQualityID) ZF(CustomerName) ZF(Model) ZF(PartNumber) -ZF(SoftwareRevision) ZF(POD) ZF(AvailablePower) ZF(PowerThreshold) +ZF(SoftwareRevision) ZF(POD) ZF(AvailablePower) ZF(PowerThreshold) ZF(ProductRevision) ZF(UtilityName) ZF(NumberOfResets) ZF(PersistentMemoryWrites) ZF(LastMessageLQI) ZF(LastMessageRSSI) // list of post-processing directives const Z_AttributeConverter Z_PostProcess[] PROGMEM = { - { 0x0000, 0x0000, Z(ZCLVersion), &Z_Copy }, - { 0x0000, 0x0001, Z(AppVersion), &Z_Copy }, - { 0x0000, 0x0002, Z(StackVersion), &Z_Copy }, - { 0x0000, 0x0003, Z(HWVersion), &Z_Copy }, - { 0x0000, 0x0004, Z(Manufacturer), &Z_ManufKeep }, // record Manufacturer - { 0x0000, 0x0005, Z(ModelId), &Z_ModelKeep }, // record Model - { 0x0000, 0x0006, Z(DateCode), &Z_Copy }, - { 0x0000, 0x0007, Z(PowerSource), &Z_Copy }, - { 0x0000, 0x4000, Z(SWBuildID), &Z_Copy }, - { 0x0000, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values + { Zuint8, Cx0000, 0x0000, Z(ZCLVersion), &Z_Copy }, + { Zuint8, Cx0000, 0x0001, Z(AppVersion), &Z_Copy }, + { Zuint8, Cx0000, 0x0002, Z(StackVersion), &Z_Copy }, + { Zuint8, Cx0000, 0x0003, Z(HWVersion), &Z_Copy }, + { Zstring, Cx0000, 0x0004, Z(Manufacturer), &Z_ManufKeep }, // record Manufacturer + { Zstring, Cx0000, 0x0005, Z(ModelId), &Z_ModelKeep }, // record Model + { Zstring, Cx0000, 0x0006, Z(DateCode), &Z_Copy }, + { Zenum8, Cx0000, 0x0007, Z(PowerSource), &Z_Copy }, + { Zstring, Cx0000, 0x4000, Z(SWBuildID), &Z_Copy }, + { Zunk, Cx0000, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values // Cmd 0x0A - Cluster 0x0000, attribute 0xFF01 - proprietary - { 0x0000, 0xFF01, nullptr, &Z_AqaraSensor }, // Occupancy (map8) + { Zmap8, Cx0000, 0xFF01, nullptr, &Z_AqaraSensor }, // Occupancy (map8) // Power Configuration cluster - { 0x0001, 0x0000, Z(MainsVoltage), &Z_Copy }, - { 0x0001, 0x0001, Z(MainsFrequency), &Z_Copy }, - { 0x0001, 0x0020, Z(BatteryVoltage), &Z_FloatDiv10 }, - { 0x0001, 0x0021, Z(BatteryPercentage), &Z_Copy }, + { Zuint16, Cx0001, 0x0000, Z(MainsVoltage), &Z_Copy }, + { Zuint8, Cx0001, 0x0001, Z(MainsFrequency), &Z_Copy }, + { Zuint8, Cx0001, 0x0020, Z(BatteryVoltage), &Z_FloatDiv10 }, + { Zuint8, Cx0001, 0x0021, Z(BatteryPercentage), &Z_Copy }, // Device Temperature Configuration cluster - { 0x0002, 0x0000, Z(CurrentTemperature), &Z_Copy }, - { 0x0002, 0x0001, Z(MinTempExperienced), &Z_Copy }, - { 0x0002, 0x0002, Z(MaxTempExperienced), &Z_Copy }, - { 0x0002, 0x0003, Z(OverTempTotalDwell), &Z_Copy }, + { Zint16, Cx0002, 0x0000, Z(CurrentTemperature), &Z_Copy }, + { Zint16, Cx0002, 0x0001, Z(MinTempExperienced), &Z_Copy }, + { Zint16, Cx0002, 0x0002, Z(MaxTempExperienced), &Z_Copy }, + { Zuint16, Cx0002, 0x0003, Z(OverTempTotalDwell), &Z_Copy }, // Scenes cluster - { 0x0005, 0x0000, Z(SceneCount), &Z_Copy }, - { 0x0005, 0x0001, Z(CurrentScene), &Z_Copy }, - { 0x0005, 0x0002, Z(CurrentGroup), &Z_Copy }, - { 0x0005, 0x0003, Z(SceneValid), &Z_Copy }, - //{ 0x0005, 0x0004, Z(NameSupport), &Z_Copy }, + { Zuint8, Cx0005, 0x0000, Z(SceneCount), &Z_Copy }, + { Zuint8, Cx0005, 0x0001, Z(CurrentScene), &Z_Copy }, + { Zuint16, Cx0005, 0x0002, Z(CurrentGroup), &Z_Copy }, + { Zbool, Cx0005, 0x0003, Z(SceneValid), &Z_Copy }, + //{ Zmap8, Cx0005, 0x0004, Z(NameSupport), &Z_Copy }, // On/off cluster - { 0x0006, 0x0000, Z(Power), &Z_Copy }, - { 0x0006, 0x8000, Z(Power), &Z_Copy }, // See 7280 + { Zbool, Cx0006, 0x0000, Z(Power), &Z_Copy }, + { Zbool, Cx0006, 0x8000, Z(Power), &Z_Copy }, // See 7280 // On/Off Switch Configuration cluster - { 0x0007, 0x0000, Z(SwitchType), &Z_Copy }, + { Zenum8, Cx0007, 0x0000, Z(SwitchType), &Z_Copy }, // Level Control cluster - { 0x0008, 0x0000, Z(Dimmer), &Z_Copy }, - // { 0x0008, 0x0001, Z(RemainingTime", &Z_Copy }, - // { 0x0008, 0x0010, Z(OnOffTransitionTime", &Z_Copy }, - // { 0x0008, 0x0011, Z(OnLevel", &Z_Copy }, - // { 0x0008, 0x0012, Z(OnTransitionTime", &Z_Copy }, - // { 0x0008, 0x0013, Z(OffTransitionTime", &Z_Copy }, - // { 0x0008, 0x0014, Z(DefaultMoveRate", &Z_Copy }, + { Zuint8, Cx0008, 0x0000, Z(Dimmer), &Z_Copy }, + // { Zuint16, Cx0008, 0x0001, Z(RemainingTime", &Z_Copy }, + // { Zuint16, Cx0008, 0x0010, Z(OnOffTransitionTime", &Z_Copy }, + // { Zuint8, Cx0008, 0x0011, Z(OnLevel", &Z_Copy }, + // { Zuint16, Cx0008, 0x0012, Z(OnTransitionTime", &Z_Copy }, + // { Zuint16, Cx0008, 0x0013, Z(OffTransitionTime", &Z_Copy }, + // { Zuint16, Cx0008, 0x0014, Z(DefaultMoveRate", &Z_Copy }, // Alarms cluster - { 0x0009, 0x0000, Z(AlarmCount), &Z_Copy }, + { Zuint16, Cx0009, 0x0000, Z(AlarmCount), &Z_Copy }, + // Time cluster - { 0x000A, 0x0000, Z(Time), &Z_Copy }, - { 0x000A, 0x0001, Z(TimeStatus), &Z_Copy }, - { 0x000A, 0x0002, Z(TimeZone), &Z_Copy }, - { 0x000A, 0x0003, Z(DstStart), &Z_Copy }, - { 0x000A, 0x0004, Z(DstEnd), &Z_Copy }, - { 0x000A, 0x0005, Z(DstShift), &Z_Copy }, - { 0x000A, 0x0006, Z(StandardTime), &Z_Copy }, - { 0x000A, 0x0007, Z(LocalTime), &Z_Copy }, - { 0x000A, 0x0008, Z(LastSetTime), &Z_Copy }, - { 0x000A, 0x0009, Z(ValidUntilTime), &Z_Copy }, + { ZUTC, Cx000A, 0x0000, Z(Time), &Z_Copy }, + { Zmap8, Cx000A, 0x0001, Z(TimeStatus), &Z_Copy }, + { Zint32, Cx000A, 0x0002, Z(TimeZone), &Z_Copy }, + { Zuint32, Cx000A, 0x0003, Z(DstStart), &Z_Copy }, + { Zuint32, Cx000A, 0x0004, Z(DstEnd), &Z_Copy }, + { Zint32, Cx000A, 0x0005, Z(DstShift), &Z_Copy }, + { Zuint32, Cx000A, 0x0006, Z(StandardTime), &Z_Copy }, + { Zuint32, Cx000A, 0x0007, Z(LocalTime), &Z_Copy }, + { ZUTC, Cx000A, 0x0008, Z(LastSetTime), &Z_Copy }, + { ZUTC, Cx000A, 0x0009, Z(ValidUntilTime), &Z_Copy }, + // RSSI Location cluster - { 0x000B, 0x0000, Z(LocationType), &Z_Copy }, - { 0x000B, 0x0000, Z(LocationMethod), &Z_Copy }, - { 0x000B, 0x0000, Z(LocationAge), &Z_Copy }, - { 0x000B, 0x0000, Z(QualityMeasure), &Z_Copy }, - { 0x000B, 0x0000, Z(NumberOfDevices), &Z_Copy }, + { Zdata8, Cx000B, 0x0000, Z(LocationType), &Z_Copy }, + { Zenum8, Cx000B, 0x0001, Z(LocationMethod), &Z_Copy }, + { Zuint16, Cx000B, 0x0002, Z(LocationAge), &Z_Copy }, + { Zuint8, Cx000B, 0x0003, Z(QualityMeasure), &Z_Copy }, + { Zuint8, Cx000B, 0x0004, Z(NumberOfDevices), &Z_Copy }, + // Analog Input cluster - { 0x000C, 0x0004, Z(AnalogInActiveText), &Z_Copy }, - { 0x000C, 0x001C, Z(AnalogInDescription), &Z_Copy }, - { 0x000C, 0x002E, Z(AnalogInInactiveText), &Z_Copy }, - { 0x000C, 0x0041, Z(AnalogInMaxValue), &Z_Copy }, - { 0x000C, 0x0045, Z(AnalogInMinValue), &Z_Copy }, - { 0x000C, 0x0051, Z(AnalogInOutOfService), &Z_Copy }, - { 0x000C, 0x0055, Z(AqaraRotate), &Z_Copy }, - { 0x000C, 0x0057, Z(AnalogInPriorityArray),&Z_Copy }, - { 0x000C, 0x0067, Z(AnalogInReliability), &Z_Copy }, - { 0x000C, 0x0068, Z(AnalogInRelinquishDefault),&Z_Copy }, - { 0x000C, 0x006A, Z(AnalogInResolution), &Z_Copy }, - { 0x000C, 0x006F, Z(AnalogInStatusFlags), &Z_Copy }, - { 0x000C, 0x0075, Z(AnalogInEngineeringUnits),&Z_Copy }, - { 0x000C, 0x0100, Z(AnalogInApplicationType),&Z_Copy }, - { 0x000C, 0xFF05, Z(Aqara_FF05), &Z_Copy }, + // { 0xFF, Cx000C, 0x0004, Z(AnalogInActiveText), &Z_Copy }, + { Zstring, Cx000C, 0x001C, Z(AnalogInDescription), &Z_Copy }, + // { 0xFF, Cx000C, 0x002E, Z(AnalogInInactiveText), &Z_Copy }, + { Zsingle, Cx000C, 0x0041, Z(AnalogInMaxValue), &Z_Copy }, + { Zsingle, Cx000C, 0x0045, Z(AnalogInMinValue), &Z_Copy }, + { Zbool, Cx000C, 0x0051, Z(AnalogInOutOfService), &Z_Copy }, + { Zsingle, Cx000C, 0x0055, Z(AqaraRotate), &Z_Copy }, + // { 0xFF, Cx000C, 0x0057, Z(AnalogInPriorityArray),&Z_Copy }, + { Zenum8, Cx000C, 0x0067, Z(AnalogInReliability), &Z_Copy }, + // { 0xFF, Cx000C, 0x0068, Z(AnalogInRelinquishDefault),&Z_Copy }, + { Zsingle, Cx000C, 0x006A, Z(AnalogInResolution), &Z_Copy }, + { Zmap8, Cx000C, 0x006F, Z(AnalogInStatusFlags), &Z_Copy }, + { Zenum16, Cx000C, 0x0075, Z(AnalogInEngineeringUnits),&Z_Copy }, + { Zuint32, Cx000C, 0x0100, Z(AnalogInApplicationType),&Z_Copy }, + { Zuint16, Cx000C, 0xFF05, Z(Aqara_FF05), &Z_Copy }, + // Analog Output cluster - { 0x000D, 0x001C, Z(AnalogOutDescription), &Z_Copy }, - { 0x000D, 0x0041, Z(AnalogOutMaxValue), &Z_Copy }, - { 0x000D, 0x0045, Z(AnalogOutMinValue), &Z_Copy }, - { 0x000D, 0x0051, Z(AnalogOutOutOfService),&Z_Copy }, - { 0x000D, 0x0055, Z(AnalogOutValue), &Z_Copy }, - { 0x000D, 0x0057, Z(AnalogOutPriorityArray),&Z_Copy }, - { 0x000D, 0x0067, Z(AnalogOutReliability), &Z_Copy }, - { 0x000D, 0x0068, Z(AnalogOutRelinquishDefault),&Z_Copy }, - { 0x000D, 0x006A, Z(AnalogOutResolution), &Z_Copy }, - { 0x000D, 0x006F, Z(AnalogOutStatusFlags), &Z_Copy }, - { 0x000D, 0x0075, Z(AnalogOutEngineeringUnits),&Z_Copy }, - { 0x000D, 0x0100, Z(AnalogOutApplicationType),&Z_Copy }, + { Zstring, Cx000D, 0x001C, Z(AnalogOutDescription), &Z_Copy }, + { Zsingle, Cx000D, 0x0041, Z(AnalogOutMaxValue), &Z_Copy }, + { Zsingle, Cx000D, 0x0045, Z(AnalogOutMinValue), &Z_Copy }, + { Zbool, Cx000D, 0x0051, Z(AnalogOutOutOfService),&Z_Copy }, + { Zsingle, Cx000D, 0x0055, Z(AnalogOutValue), &Z_Copy }, + // { Zunk, Cx000D, 0x0057, Z(AnalogOutPriorityArray),&Z_Copy }, + { Zenum8, Cx000D, 0x0067, Z(AnalogOutReliability), &Z_Copy }, + { Zsingle, Cx000D, 0x0068, Z(AnalogOutRelinquishDefault),&Z_Copy }, + { Zsingle, Cx000D, 0x006A, Z(AnalogOutResolution), &Z_Copy }, + { Zmap8, Cx000D, 0x006F, Z(AnalogOutStatusFlags), &Z_Copy }, + { Zenum16, Cx000D, 0x0075, Z(AnalogOutEngineeringUnits),&Z_Copy }, + { Zuint32, Cx000D, 0x0100, Z(AnalogOutApplicationType),&Z_Copy }, + // Analog Value cluster - { 0x000E, 0x001C, Z(AnalogDescription), &Z_Copy }, - { 0x000E, 0x0051, Z(AnalogOutOfService), &Z_Copy }, - { 0x000E, 0x0055, Z(AnalogValue), &Z_Copy }, - { 0x000E, 0x0057, Z(AnalogPriorityArray), &Z_Copy }, - { 0x000E, 0x0067, Z(AnalogReliability), &Z_Copy }, - { 0x000E, 0x0068, Z(AnalogRelinquishDefault),&Z_Copy }, - { 0x000E, 0x006F, Z(AnalogStatusFlags), &Z_Copy }, - { 0x000E, 0x0075, Z(AnalogEngineeringUnits),&Z_Copy }, - { 0x000E, 0x0100, Z(AnalogApplicationType),&Z_Copy }, + { Zstring, Cx000E, 0x001C, Z(AnalogDescription), &Z_Copy }, + { Zbool, Cx000E, 0x0051, Z(AnalogOutOfService), &Z_Copy }, + { Zsingle, Cx000E, 0x0055, Z(AnalogValue), &Z_Copy }, + { Zunk, Cx000E, 0x0057, Z(AnalogPriorityArray), &Z_Copy }, + { Zenum8, Cx000E, 0x0067, Z(AnalogReliability), &Z_Copy }, + { Zsingle, Cx000E, 0x0068, Z(AnalogRelinquishDefault),&Z_Copy }, + { Zmap8, Cx000E, 0x006F, Z(AnalogStatusFlags), &Z_Copy }, + { Zenum16, Cx000E, 0x0075, Z(AnalogEngineeringUnits),&Z_Copy }, + { Zuint32, Cx000E, 0x0100, Z(AnalogApplicationType),&Z_Copy }, + // Binary Input cluster - { 0x000F, 0x0004, Z(BinaryInActiveText), &Z_Copy }, - { 0x000F, 0x001C, Z(BinaryInDescription), &Z_Copy }, - { 0x000F, 0x002E, Z(BinaryInInactiveText),&Z_Copy }, - { 0x000F, 0x0051, Z(BinaryInOutOfService),&Z_Copy }, - { 0x000F, 0x0054, Z(BinaryInPolarity), &Z_Copy }, - { 0x000F, 0x0055, Z(BinaryInValue), &Z_Copy }, - { 0x000F, 0x0057, Z(BinaryInPriorityArray),&Z_Copy }, - { 0x000F, 0x0067, Z(BinaryInReliability), &Z_Copy }, - { 0x000F, 0x006F, Z(BinaryInStatusFlags), &Z_Copy }, - { 0x000F, 0x0100, Z(BinaryInApplicationType),&Z_Copy }, + { Zstring, Cx000F, 0x0004, Z(BinaryInActiveText), &Z_Copy }, + { Zstring, Cx000F, 0x001C, Z(BinaryInDescription), &Z_Copy }, + { Zstring, Cx000F, 0x002E, Z(BinaryInInactiveText),&Z_Copy }, + { Zbool, Cx000F, 0x0051, Z(BinaryInOutOfService),&Z_Copy }, + { Zenum8, Cx000F, 0x0054, Z(BinaryInPolarity), &Z_Copy }, + { Zstring, Cx000F, 0x0055, Z(BinaryInValue), &Z_Copy }, + // { 0xFF, Cx000F, 0x0057, Z(BinaryInPriorityArray),&Z_Copy }, + { Zenum8, Cx000F, 0x0067, Z(BinaryInReliability), &Z_Copy }, + { Zmap8, Cx000F, 0x006F, Z(BinaryInStatusFlags), &Z_Copy }, + { Zuint32, Cx000F, 0x0100, Z(BinaryInApplicationType),&Z_Copy }, + // Binary Output cluster - { 0x0010, 0x0004, Z(BinaryOutActiveText), &Z_Copy }, - { 0x0010, 0x001C, Z(BinaryOutDescription), &Z_Copy }, - { 0x0010, 0x002E, Z(BinaryOutInactiveText),&Z_Copy }, - { 0x0010, 0x0042, Z(BinaryOutMinimumOffTime),&Z_Copy }, - { 0x0010, 0x0043, Z(BinaryOutMinimumOnTime),&Z_Copy }, - { 0x0010, 0x0051, Z(BinaryOutOutOfService),&Z_Copy }, - { 0x0010, 0x0054, Z(BinaryOutPolarity), &Z_Copy }, - { 0x0010, 0x0055, Z(BinaryOutValue), &Z_Copy }, - { 0x0010, 0x0057, Z(BinaryOutPriorityArray),&Z_Copy }, - { 0x0010, 0x0067, Z(BinaryOutReliability), &Z_Copy }, - { 0x0010, 0x0068, Z(BinaryOutRelinquishDefault),&Z_Copy }, - { 0x0010, 0x006F, Z(BinaryOutStatusFlags), &Z_Copy }, - { 0x0010, 0x0100, Z(BinaryOutApplicationType),&Z_Copy }, + { Zstring, Cx0010, 0x0004, Z(BinaryOutActiveText), &Z_Copy }, + { Zstring, Cx0010, 0x001C, Z(BinaryOutDescription), &Z_Copy }, + { Zstring, Cx0010, 0x002E, Z(BinaryOutInactiveText),&Z_Copy }, + { Zuint32, Cx0010, 0x0042, Z(BinaryOutMinimumOffTime),&Z_Copy }, + { Zuint32, Cx0010, 0x0043, Z(BinaryOutMinimumOnTime),&Z_Copy }, + { Zbool, Cx0010, 0x0051, Z(BinaryOutOutOfService),&Z_Copy }, + { Zenum8, Cx0010, 0x0054, Z(BinaryOutPolarity), &Z_Copy }, + { Zbool, Cx0010, 0x0055, Z(BinaryOutValue), &Z_Copy }, + // { Zunk, Cx0010, 0x0057, Z(BinaryOutPriorityArray),&Z_Copy }, + { Zenum8, Cx0010, 0x0067, Z(BinaryOutReliability), &Z_Copy }, + { Zbool, Cx0010, 0x0068, Z(BinaryOutRelinquishDefault),&Z_Copy }, + { Zmap8, Cx0010, 0x006F, Z(BinaryOutStatusFlags), &Z_Copy }, + { Zuint32, Cx0010, 0x0100, Z(BinaryOutApplicationType),&Z_Copy }, + // Binary Value cluster - { 0x0011, 0x0004, Z(BinaryActiveText), &Z_Copy }, - { 0x0011, 0x001C, Z(BinaryDescription), &Z_Copy }, - { 0x0011, 0x002E, Z(BinaryInactiveText), &Z_Copy }, - { 0x0011, 0x0042, Z(BinaryMinimumOffTime), &Z_Copy }, - { 0x0011, 0x0043, Z(BinaryMinimumOnTime), &Z_Copy }, - { 0x0011, 0x0051, Z(BinaryOutOfService), &Z_Copy }, - { 0x0011, 0x0055, Z(BinaryValue), &Z_Copy }, - { 0x0011, 0x0057, Z(BinaryPriorityArray), &Z_Copy }, - { 0x0011, 0x0067, Z(BinaryReliability), &Z_Copy }, - { 0x0011, 0x0068, Z(BinaryRelinquishDefault),&Z_Copy }, - { 0x0011, 0x006F, Z(BinaryStatusFlags), &Z_Copy }, - { 0x0011, 0x0100, Z(BinaryApplicationType),&Z_Copy }, + { Zstring, Cx0011, 0x0004, Z(BinaryActiveText), &Z_Copy }, + { Zstring, Cx0011, 0x001C, Z(BinaryDescription), &Z_Copy }, + { Zstring, Cx0011, 0x002E, Z(BinaryInactiveText), &Z_Copy }, + { Zuint32, Cx0011, 0x0042, Z(BinaryMinimumOffTime), &Z_Copy }, + { Zuint32, Cx0011, 0x0043, Z(BinaryMinimumOnTime), &Z_Copy }, + { Zbool, Cx0011, 0x0051, Z(BinaryOutOfService), &Z_Copy }, + { Zbool, Cx0011, 0x0055, Z(BinaryValue), &Z_Copy }, + // { Zunk, Cx0011, 0x0057, Z(BinaryPriorityArray), &Z_Copy }, + { Zenum8, Cx0011, 0x0067, Z(BinaryReliability), &Z_Copy }, + { Zbool, Cx0011, 0x0068, Z(BinaryRelinquishDefault),&Z_Copy }, + { Zmap8, Cx0011, 0x006F, Z(BinaryStatusFlags), &Z_Copy }, + { Zuint32, Cx0011, 0x0100, Z(BinaryApplicationType),&Z_Copy }, + // Multistate Input cluster - { 0x0012, 0x000E, Z(MultiInStateText), &Z_Copy }, - { 0x0012, 0x001C, Z(MultiInDescription), &Z_Copy }, - { 0x0012, 0x004A, Z(MultiInNumberOfStates),&Z_Copy }, - { 0x0012, 0x0051, Z(MultiInOutOfService), &Z_Copy }, - { 0x0012, 0x0055, Z(MultiInValue), &Z_AqaraCube }, - { 0x0012, 0x0067, Z(MultiInReliability), &Z_Copy }, - { 0x0012, 0x006F, Z(MultiInStatusFlags), &Z_Copy }, - { 0x0012, 0x0100, Z(MultiInApplicationType),&Z_Copy }, + // { Zunk, Cx0012, 0x000E, Z(MultiInStateText), &Z_Copy }, + { Zstring, Cx0012, 0x001C, Z(MultiInDescription), &Z_Copy }, + { Zuint16, Cx0012, 0x004A, Z(MultiInNumberOfStates),&Z_Copy }, + { Zbool, Cx0012, 0x0051, Z(MultiInOutOfService), &Z_Copy }, + { Zuint16, Cx0012, 0x0055, Z(MultiInValue), &Z_AqaraCube }, + { Zenum8, Cx0012, 0x0067, Z(MultiInReliability), &Z_Copy }, + { Zmap8, Cx0012, 0x006F, Z(MultiInStatusFlags), &Z_Copy }, + { Zuint32, Cx0012, 0x0100, Z(MultiInApplicationType),&Z_Copy }, + // Multistate output - { 0x0013, 0x000E, Z(MultiOutStateText), &Z_Copy }, - { 0x0013, 0x001C, Z(MultiOutDescription), &Z_Copy }, - { 0x0013, 0x004A, Z(MultiOutNumberOfStates),&Z_Copy }, - { 0x0013, 0x0051, Z(MultiOutOutOfService), &Z_Copy }, - { 0x0013, 0x0055, Z(MultiOutValue), &Z_Copy }, - { 0x0013, 0x0057, Z(MultiOutPriorityArray),&Z_Copy }, - { 0x0013, 0x0067, Z(MultiOutReliability), &Z_Copy }, - { 0x0013, 0x0068, Z(MultiOutRelinquishDefault),&Z_Copy }, - { 0x0013, 0x006F, Z(MultiOutStatusFlags), &Z_Copy }, - { 0x0013, 0x0100, Z(MultiOutApplicationType),&Z_Copy }, + // { Zunk, Cx0013, 0x000E, Z(MultiOutStateText), &Z_Copy }, + { Zstring, Cx0013, 0x001C, Z(MultiOutDescription), &Z_Copy }, + { Zuint16, Cx0013, 0x004A, Z(MultiOutNumberOfStates),&Z_Copy }, + { Zbool, Cx0013, 0x0051, Z(MultiOutOutOfService), &Z_Copy }, + { Zuint16, Cx0013, 0x0055, Z(MultiOutValue), &Z_Copy }, + // { Zunk, Cx0013, 0x0057, Z(MultiOutPriorityArray),&Z_Copy }, + { Zenum8, Cx0013, 0x0067, Z(MultiOutReliability), &Z_Copy }, + { Zuint16, Cx0013, 0x0068, Z(MultiOutRelinquishDefault),&Z_Copy }, + { Zmap8, Cx0013, 0x006F, Z(MultiOutStatusFlags), &Z_Copy }, + { Zuint32, Cx0013, 0x0100, Z(MultiOutApplicationType),&Z_Copy }, + // Multistate Value cluster - { 0x0014, 0x000E, Z(MultiStateText), &Z_Copy }, - { 0x0014, 0x001C, Z(MultiDescription), &Z_Copy }, - { 0x0014, 0x004A, Z(MultiNumberOfStates), &Z_Copy }, - { 0x0014, 0x0051, Z(MultiOutOfService), &Z_Copy }, - { 0x0014, 0x0055, Z(MultiValue), &Z_Copy }, - { 0x0014, 0x0067, Z(MultiReliability), &Z_Copy }, - { 0x0014, 0x0068, Z(MultiRelinquishDefault),&Z_Copy }, - { 0x0014, 0x006F, Z(MultiStatusFlags), &Z_Copy }, - { 0x0014, 0x0100, Z(MultiApplicationType), &Z_Copy }, + // { Zunk, Cx0014, 0x000E, Z(MultiStateText), &Z_Copy }, + { Zstring, Cx0014, 0x001C, Z(MultiDescription), &Z_Copy }, + { Zuint16, Cx0014, 0x004A, Z(MultiNumberOfStates), &Z_Copy }, + { Zbool, Cx0014, 0x0051, Z(MultiOutOfService), &Z_Copy }, + { Zuint16, Cx0014, 0x0055, Z(MultiValue), &Z_Copy }, + { Zenum8, Cx0014, 0x0067, Z(MultiReliability), &Z_Copy }, + { Zuint16, Cx0014, 0x0068, Z(MultiRelinquishDefault),&Z_Copy }, + { Zmap8, Cx0014, 0x006F, Z(MultiStatusFlags), &Z_Copy }, + { Zuint32, Cx0014, 0x0100, Z(MultiApplicationType), &Z_Copy }, + // Power Profile cluster - { 0x001A, 0x0000, Z(TotalProfileNum), &Z_Copy }, - { 0x001A, 0x0001, Z(MultipleScheduling), &Z_Copy }, - { 0x001A, 0x0002, Z(EnergyFormatting), &Z_Copy }, - { 0x001A, 0x0003, Z(EnergyRemote), &Z_Copy }, - { 0x001A, 0x0004, Z(ScheduleMode), &Z_Copy }, + { Zuint8, Cx001A, 0x0000, Z(TotalProfileNum), &Z_Copy }, + { Zbool, Cx001A, 0x0001, Z(MultipleScheduling), &Z_Copy }, + { Zmap8, Cx001A, 0x0002, Z(EnergyFormatting), &Z_Copy }, + { Zbool, Cx001A, 0x0003, Z(EnergyRemote), &Z_Copy }, + { Zmap8, Cx001A, 0x0004, Z(ScheduleMode), &Z_Copy }, + // Poll Control cluster - { 0x0020, 0x0000, Z(CheckinInterval), &Z_Copy }, - { 0x0020, 0x0001, Z(LongPollInterval), &Z_Copy }, - { 0x0020, 0x0002, Z(ShortPollInterval), &Z_Copy }, - { 0x0020, 0x0003, Z(FastPollTimeout), &Z_Copy }, - { 0x0020, 0x0004, Z(CheckinIntervalMin), &Z_Copy }, - { 0x0020, 0x0005, Z(LongPollIntervalMin), &Z_Copy }, - { 0x0020, 0x0006, Z(FastPollTimeoutMax), &Z_Copy }, + { Zuint32, Cx0020, 0x0000, Z(CheckinInterval), &Z_Copy }, + { Zuint32, Cx0020, 0x0001, Z(LongPollInterval), &Z_Copy }, + { Zuint16, Cx0020, 0x0002, Z(ShortPollInterval), &Z_Copy }, + { Zuint16, Cx0020, 0x0003, Z(FastPollTimeout), &Z_Copy }, + { Zuint32, Cx0020, 0x0004, Z(CheckinIntervalMin), &Z_Copy }, + { Zuint32, Cx0020, 0x0005, Z(LongPollIntervalMin), &Z_Copy }, + { Zuint16, Cx0020, 0x0006, Z(FastPollTimeoutMax), &Z_Copy }, + // Shade Configuration cluster - { 0x0100, 0x0000, Z(PhysicalClosedLimit), &Z_Copy }, - { 0x0100, 0x0001, Z(MotorStepSize), &Z_Copy }, - { 0x0100, 0x0002, Z(Status), &Z_Copy }, - { 0x0100, 0x0010, Z(ClosedLimit), &Z_Copy }, - { 0x0100, 0x0011, Z(Mode), &Z_Copy }, + { Zuint16, Cx0100, 0x0000, Z(PhysicalClosedLimit), &Z_Copy }, + { Zuint8, Cx0100, 0x0001, Z(MotorStepSize), &Z_Copy }, + { Zmap8, Cx0100, 0x0002, Z(Status), &Z_Copy }, + { Zuint16, Cx0100, 0x0010, Z(ClosedLimit), &Z_Copy }, + { Zenum8, Cx0100, 0x0011, Z(Mode), &Z_Copy }, + // Door Lock cluster - { 0x0101, 0x0000, Z(LockState), &Z_Copy }, - { 0x0101, 0x0001, Z(LockType), &Z_Copy }, - { 0x0101, 0x0002, Z(ActuatorEnabled), &Z_Copy }, - { 0x0101, 0x0003, Z(DoorState), &Z_Copy }, - { 0x0101, 0x0004, Z(DoorOpenEvents), &Z_Copy }, - { 0x0101, 0x0005, Z(DoorClosedEvents), &Z_Copy }, - { 0x0101, 0x0006, Z(OpenPeriod), &Z_Copy }, + { Zenum8, Cx0101, 0x0000, Z(LockState), &Z_Copy }, + { Zenum8, Cx0101, 0x0001, Z(LockType), &Z_Copy }, + { Zbool, Cx0101, 0x0002, Z(ActuatorEnabled), &Z_Copy }, + { Zenum8, Cx0101, 0x0003, Z(DoorState), &Z_Copy }, + { Zuint32, Cx0101, 0x0004, Z(DoorOpenEvents), &Z_Copy }, + { Zuint32, Cx0101, 0x0005, Z(DoorClosedEvents), &Z_Copy }, + { Zuint16, Cx0101, 0x0006, Z(OpenPeriod), &Z_Copy }, + // Aqara Lumi Vibration Sensor - { 0x0101, 0x0055, Z(AqaraVibrationMode), &Z_AqaraVibration }, - { 0x0101, 0x0503, Z(AqaraVibrationsOrAngle), &Z_Copy }, - { 0x0101, 0x0505, Z(AqaraVibration505), &Z_Copy }, - { 0x0101, 0x0508, Z(AqaraAccelerometer), &Z_AqaraVibration }, + { Zuint16, Cx0101, 0x0055, Z(AqaraVibrationMode), &Z_AqaraVibration }, + { Zuint16, Cx0101, 0x0503, Z(AqaraVibrationsOrAngle), &Z_Copy }, + { Zuint32, Cx0101, 0x0505, Z(AqaraVibration505), &Z_Copy }, + { Zuint48, Cx0101, 0x0508, Z(AqaraAccelerometer), &Z_AqaraVibration }, + // Window Covering cluster - { 0x0102, 0x0000, Z(WindowCoveringType), &Z_Copy }, - { 0x0102, 0x0001, Z(PhysicalClosedLimitLift),&Z_Copy }, - { 0x0102, 0x0002, Z(PhysicalClosedLimitTilt),&Z_Copy }, - { 0x0102, 0x0003, Z(CurrentPositionLift), &Z_Copy }, - { 0x0102, 0x0004, Z(CurrentPositionTilt), &Z_Copy }, - { 0x0102, 0x0005, Z(NumberofActuationsLift),&Z_Copy }, - { 0x0102, 0x0006, Z(NumberofActuationsTilt),&Z_Copy }, - { 0x0102, 0x0007, Z(ConfigStatus), &Z_Copy }, - { 0x0102, 0x0008, Z(CurrentPositionLiftPercentage),&Z_Copy }, - { 0x0102, 0x0009, Z(CurrentPositionTiltPercentage),&Z_Copy }, - { 0x0102, 0x0010, Z(InstalledOpenLimitLift),&Z_Copy }, - { 0x0102, 0x0011, Z(InstalledClosedLimitLift),&Z_Copy }, - { 0x0102, 0x0012, Z(InstalledOpenLimitTilt),&Z_Copy }, - { 0x0102, 0x0013, Z(InstalledClosedLimitTilt),&Z_Copy }, - { 0x0102, 0x0014, Z(VelocityLift), &Z_Copy }, - { 0x0102, 0x0015, Z(AccelerationTimeLift),&Z_Copy }, - { 0x0102, 0x0016, Z(DecelerationTimeLift), &Z_Copy }, - { 0x0102, 0x0017, Z(Mode), &Z_Copy }, - { 0x0102, 0x0018, Z(IntermediateSetpointsLift),&Z_Copy }, - { 0x0102, 0x0019, Z(IntermediateSetpointsTilt),&Z_Copy }, + { Zenum8, Cx0102, 0x0000, Z(WindowCoveringType), &Z_Copy }, + { Zuint16, Cx0102, 0x0001, Z(PhysicalClosedLimitLift),&Z_Copy }, + { Zuint16, Cx0102, 0x0002, Z(PhysicalClosedLimitTilt),&Z_Copy }, + { Zuint16, Cx0102, 0x0003, Z(CurrentPositionLift), &Z_Copy }, + { Zuint16, Cx0102, 0x0004, Z(CurrentPositionTilt), &Z_Copy }, + { Zuint16, Cx0102, 0x0005, Z(NumberofActuationsLift),&Z_Copy }, + { Zuint16, Cx0102, 0x0006, Z(NumberofActuationsTilt),&Z_Copy }, + { Zmap8, Cx0102, 0x0007, Z(ConfigStatus), &Z_Copy }, + { Zuint8, Cx0102, 0x0008, Z(CurrentPositionLiftPercentage),&Z_Copy }, + { Zuint8, Cx0102, 0x0009, Z(CurrentPositionTiltPercentage),&Z_Copy }, + { Zuint16, Cx0102, 0x0010, Z(InstalledOpenLimitLift),&Z_Copy }, + { Zuint16, Cx0102, 0x0011, Z(InstalledClosedLimitLift),&Z_Copy }, + { Zuint16, Cx0102, 0x0012, Z(InstalledOpenLimitTilt),&Z_Copy }, + { Zuint16, Cx0102, 0x0013, Z(InstalledClosedLimitTilt),&Z_Copy }, + { Zuint16, Cx0102, 0x0014, Z(VelocityLift), &Z_Copy }, + { Zuint16, Cx0102, 0x0015, Z(AccelerationTimeLift),&Z_Copy }, + { Zuint16, Cx0102, 0x0016, Z(DecelerationTimeLift), &Z_Copy }, + { Zmap8, Cx0102, 0x0017, Z(Mode), &Z_Copy }, + { Zoctstr, Cx0102, 0x0018, Z(IntermediateSetpointsLift),&Z_Copy }, + { Zoctstr, Cx0102, 0x0019, Z(IntermediateSetpointsTilt),&Z_Copy }, // Color Control cluster - { 0x0300, 0x0000, Z(Hue), &Z_Copy }, - { 0x0300, 0x0001, Z(Sat), &Z_Copy }, - { 0x0300, 0x0002, Z(RemainingTime), &Z_Copy }, - { 0x0300, 0x0003, Z(X), &Z_Copy }, - { 0x0300, 0x0004, Z(Y), &Z_Copy }, - { 0x0300, 0x0005, Z(DriftCompensation), &Z_Copy }, - { 0x0300, 0x0006, Z(CompensationText), &Z_Copy }, - { 0x0300, 0x0007, Z(CT), &Z_Copy }, - { 0x0300, 0x0008, Z(ColorMode), &Z_Copy }, - { 0x0300, 0x0010, Z(NumberOfPrimaries), &Z_Copy }, - { 0x0300, 0x0011, Z(Primary1X), &Z_Copy }, - { 0x0300, 0x0012, Z(Primary1Y), &Z_Copy }, - { 0x0300, 0x0013, Z(Primary1Intensity), &Z_Copy }, - { 0x0300, 0x0015, Z(Primary2X), &Z_Copy }, - { 0x0300, 0x0016, Z(Primary2Y), &Z_Copy }, - { 0x0300, 0x0017, Z(Primary2Intensity), &Z_Copy }, - { 0x0300, 0x0019, Z(Primary3X), &Z_Copy }, - { 0x0300, 0x001A, Z(Primary3Y), &Z_Copy }, - { 0x0300, 0x001B, Z(Primary3Intensity), &Z_Copy }, - { 0x0300, 0x0030, Z(WhitePointX), &Z_Copy }, - { 0x0300, 0x0031, Z(WhitePointY), &Z_Copy }, - { 0x0300, 0x0032, Z(ColorPointRX), &Z_Copy }, - { 0x0300, 0x0033, Z(ColorPointRY), &Z_Copy }, - { 0x0300, 0x0034, Z(ColorPointRIntensity), &Z_Copy }, - { 0x0300, 0x0036, Z(ColorPointGX), &Z_Copy }, - { 0x0300, 0x0037, Z(ColorPointGY), &Z_Copy }, - { 0x0300, 0x0038, Z(ColorPointGIntensity), &Z_Copy }, - { 0x0300, 0x003A, Z(ColorPointBX), &Z_Copy }, - { 0x0300, 0x003B, Z(ColorPointBY), &Z_Copy }, - { 0x0300, 0x003C, Z(ColorPointBIntensity), &Z_Copy }, + { Zuint8, Cx0300, 0x0000, Z(Hue), &Z_Copy }, + { Zuint8, Cx0300, 0x0001, Z(Sat), &Z_Copy }, + { Zuint16, Cx0300, 0x0002, Z(RemainingTime), &Z_Copy }, + { Zuint16, Cx0300, 0x0003, Z(X), &Z_Copy }, + { Zuint16, Cx0300, 0x0004, Z(Y), &Z_Copy }, + { Zenum8, Cx0300, 0x0005, Z(DriftCompensation), &Z_Copy }, + { Zstring, Cx0300, 0x0006, Z(CompensationText), &Z_Copy }, + { Zuint16, Cx0300, 0x0007, Z(CT), &Z_Copy }, + { Zenum8, Cx0300, 0x0008, Z(ColorMode), &Z_Copy }, + { Zuint8, Cx0300, 0x0010, Z(NumberOfPrimaries), &Z_Copy }, + { Zuint16, Cx0300, 0x0011, Z(Primary1X), &Z_Copy }, + { Zuint16, Cx0300, 0x0012, Z(Primary1Y), &Z_Copy }, + { Zuint8, Cx0300, 0x0013, Z(Primary1Intensity), &Z_Copy }, + { Zuint16, Cx0300, 0x0015, Z(Primary2X), &Z_Copy }, + { Zuint16, Cx0300, 0x0016, Z(Primary2Y), &Z_Copy }, + { Zuint8, Cx0300, 0x0017, Z(Primary2Intensity), &Z_Copy }, + { Zuint16, Cx0300, 0x0019, Z(Primary3X), &Z_Copy }, + { Zuint16, Cx0300, 0x001A, Z(Primary3Y), &Z_Copy }, + { Zuint8, Cx0300, 0x001B, Z(Primary3Intensity), &Z_Copy }, + { Zuint16, Cx0300, 0x0030, Z(WhitePointX), &Z_Copy }, + { Zuint16, Cx0300, 0x0031, Z(WhitePointY), &Z_Copy }, + { Zuint16, Cx0300, 0x0032, Z(ColorPointRX), &Z_Copy }, + { Zuint16, Cx0300, 0x0033, Z(ColorPointRY), &Z_Copy }, + { Zuint8, Cx0300, 0x0034, Z(ColorPointRIntensity), &Z_Copy }, + { Zuint16, Cx0300, 0x0036, Z(ColorPointGX), &Z_Copy }, + { Zuint16, Cx0300, 0x0037, Z(ColorPointGY), &Z_Copy }, + { Zuint8, Cx0300, 0x0038, Z(ColorPointGIntensity), &Z_Copy }, + { Zuint16, Cx0300, 0x003A, Z(ColorPointBX), &Z_Copy }, + { Zuint16, Cx0300, 0x003B, Z(ColorPointBY), &Z_Copy }, + { Zuint8, Cx0300, 0x003C, Z(ColorPointBIntensity), &Z_Copy }, // Illuminance Measurement cluster - { 0x0400, 0x0000, Z(Illuminance), &Z_Copy }, // Illuminance (in Lux) - { 0x0400, 0x0001, Z(IlluminanceMinMeasuredValue), &Z_Copy }, // - { 0x0400, 0x0002, Z(IlluminanceMaxMeasuredValue), &Z_Copy }, // - { 0x0400, 0x0003, Z(IlluminanceTolerance), &Z_Copy }, // - { 0x0400, 0x0004, Z(IlluminanceLightSensorType), &Z_Copy }, // - { 0x0400, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values + { Zuint16, Cx0400, 0x0000, Z(Illuminance), &Z_Copy }, // Illuminance (in Lux) + { Zuint16, Cx0400, 0x0001, Z(IlluminanceMinMeasuredValue), &Z_Copy }, // + { Zuint16, Cx0400, 0x0002, Z(IlluminanceMaxMeasuredValue), &Z_Copy }, // + { Zuint16, Cx0400, 0x0003, Z(IlluminanceTolerance), &Z_Copy }, // + { Zenum8, Cx0400, 0x0004, Z(IlluminanceLightSensorType), &Z_Copy }, // + { Zunk, Cx0400, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values // Illuminance Level Sensing cluster - { 0x0401, 0x0000, Z(IlluminanceLevelStatus), &Z_Copy }, // Illuminance (in Lux) - { 0x0401, 0x0001, Z(IlluminanceLightSensorType), &Z_Copy }, // LightSensorType - { 0x0401, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values + { Zenum8, Cx0401, 0x0000, Z(IlluminanceLevelStatus), &Z_Copy }, // Illuminance (in Lux) + { Zenum8, Cx0401, 0x0001, Z(IlluminanceLightSensorType), &Z_Copy }, // LightSensorType + { Zuint16, Cx0401, 0x0010, Z(IlluminanceTargetLevel), &Z_Copy }, // + { Zunk, Cx0401, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values // Temperature Measurement cluster - { 0x0402, 0x0000, Z(Temperature), &Z_FloatDiv100 }, // Temperature - { 0x0402, 0x0001, Z(TemperatureMinMeasuredValue), &Z_FloatDiv100 }, // - { 0x0402, 0x0002, Z(TemperatureMaxMeasuredValue), &Z_FloatDiv100 }, // - { 0x0402, 0x0003, Z(TemperatureTolerance), &Z_FloatDiv100 }, // - { 0x0402, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values + { Zint16, Cx0402, 0x0000, Z(Temperature), &Z_FloatDiv100 }, // Temperature + { Zint16, Cx0402, 0x0001, Z(TemperatureMinMeasuredValue), &Z_FloatDiv100 }, // + { Zint16, Cx0402, 0x0002, Z(TemperatureMaxMeasuredValue), &Z_FloatDiv100 }, // + { Zuint16, Cx0402, 0x0003, Z(TemperatureTolerance), &Z_FloatDiv100 }, // + { Zunk, Cx0402, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values // Pressure Measurement cluster - { 0x0403, 0x0000, Z(PressureUnit), &Z_AddPressureUnit }, // Pressure Unit - { 0x0403, 0x0000, Z(Pressure), &Z_Copy }, // Pressure - { 0x0403, 0x0001, Z(PressureMinMeasuredValue), &Z_Copy }, // - { 0x0403, 0x0002, Z(PressureMaxMeasuredValue), &Z_Copy }, // - { 0x0403, 0x0003, Z(PressureTolerance), &Z_Copy }, // - { 0x0403, 0x0010, Z(PressureScaledValue), &Z_Copy }, // - { 0x0403, 0x0011, Z(PressureMinScaledValue), &Z_Copy }, // - { 0x0403, 0x0012, Z(PressureMaxScaledValue), &Z_Copy }, // - { 0x0403, 0x0013, Z(PressureScaledTolerance), &Z_Copy }, // - { 0x0403, 0x0014, Z(PressureScale), &Z_Copy }, // - { 0x0403, 0xFFFF, nullptr, &Z_Remove }, // Remove all other Pressure values + { Zunk, Cx0403, 0x0000, Z(PressureUnit), &Z_AddPressureUnit }, // Pressure Unit + { Zint16, Cx0403, 0x0000, Z(Pressure), &Z_Copy }, // Pressure + { Zint16, Cx0403, 0x0001, Z(PressureMinMeasuredValue), &Z_Copy }, // + { Zint16, Cx0403, 0x0002, Z(PressureMaxMeasuredValue), &Z_Copy }, // + { Zuint16, Cx0403, 0x0003, Z(PressureTolerance), &Z_Copy }, // + { Zint16, Cx0403, 0x0010, Z(PressureScaledValue), &Z_Copy }, // + { Zint16, Cx0403, 0x0011, Z(PressureMinScaledValue), &Z_Copy }, // + { Zint16, Cx0403, 0x0012, Z(PressureMaxScaledValue), &Z_Copy }, // + { Zuint16, Cx0403, 0x0013, Z(PressureScaledTolerance), &Z_Copy }, // + { Zint8, Cx0403, 0x0014, Z(PressureScale), &Z_Copy }, // + { Zunk, Cx0403, 0xFFFF, nullptr, &Z_Remove }, // Remove all other Pressure values // Flow Measurement cluster - { 0x0404, 0x0000, Z(FlowRate), &Z_FloatDiv10 }, // Flow (in m3/h) - { 0x0404, 0x0001, Z(FlowMinMeasuredValue), &Z_Copy }, // - { 0x0404, 0x0002, Z(FlowMaxMeasuredValue), &Z_Copy }, // - { 0x0404, 0x0003, Z(FlowTolerance), &Z_Copy }, // - { 0x0404, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values + { Zuint16, Cx0404, 0x0000, Z(FlowRate), &Z_FloatDiv10 }, // Flow (in m3/h) + { Zuint16, Cx0404, 0x0001, Z(FlowMinMeasuredValue), &Z_Copy }, // + { Zuint16, Cx0404, 0x0002, Z(FlowMaxMeasuredValue), &Z_Copy }, // + { Zuint16, Cx0404, 0x0003, Z(FlowTolerance), &Z_Copy }, // + { Zunk, Cx0404, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values // Relative Humidity Measurement cluster - { 0x0405, 0x0000, Z(Humidity), &Z_FloatDiv100 }, // Humidity - { 0x0405, 0x0001, Z(HumidityMinMeasuredValue), &Z_Copy }, // - { 0x0405, 0x0002, Z(HumidityMaxMeasuredValue), &Z_Copy }, // - { 0x0405, 0x0003, "HumidityTolerance", &Z_Copy }, // - { 0x0405, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values + { Zuint16, Cx0405, 0x0000, Z(Humidity), &Z_FloatDiv100 }, // Humidity + { Zuint16, Cx0405, 0x0001, Z(HumidityMinMeasuredValue), &Z_Copy }, // + { Zuint16, Cx0405, 0x0002, Z(HumidityMaxMeasuredValue), &Z_Copy }, // + { Zuint16, Cx0405, 0x0003, Z(HumidityTolerance), &Z_Copy }, // + { Zunk, Cx0405, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values // Occupancy Sensing cluster - { 0x0406, 0x0000, Z(Occupancy), &Z_Copy }, // Occupancy (map8) - { 0x0406, 0x0001, Z(OccupancySensorType), &Z_Copy }, // OccupancySensorType - { 0x0406, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values + { Zmap8, Cx0406, 0x0000, Z(Occupancy), &Z_Copy }, // Occupancy (map8) + { Zenum8, Cx0406, 0x0001, Z(OccupancySensorType), &Z_Copy }, // OccupancySensorType + { Zunk, Cx0406, 0xFFFF, nullptr, &Z_Remove }, // Remove all other values // Meter Identification cluster - { 0x0B01, 0x0000, Z(CompanyName), &Z_Copy }, - { 0x0B01, 0x0001, Z(MeterTypeID), &Z_Copy }, - { 0x0B01, 0x0004, Z(DataQualityID), &Z_Copy }, - { 0x0B01, 0x0005, Z(CustomerName), &Z_Copy }, - { 0x0B01, 0x0006, Z(Model), &Z_Copy }, - { 0x0B01, 0x0007, Z(PartNumber), &Z_Copy }, - { 0x0B01, 0x000A, Z(SoftwareRevision), &Z_Copy }, - { 0x0B01, 0x000C, Z(POD), &Z_Copy }, - { 0x0B01, 0x000D, Z(AvailablePower), &Z_Copy }, - { 0x0B01, 0x000E, Z(PowerThreshold), &Z_Copy }, + { Zstring, Cx0B01, 0x0000, Z(CompanyName), &Z_Copy }, + { Zuint16, Cx0B01, 0x0001, Z(MeterTypeID), &Z_Copy }, + { Zuint16, Cx0B01, 0x0004, Z(DataQualityID), &Z_Copy }, + { Zstring, Cx0B01, 0x0005, Z(CustomerName), &Z_Copy }, + { Zoctstr, Cx0B01, 0x0006, Z(Model), &Z_Copy }, + { Zoctstr, Cx0B01, 0x0007, Z(PartNumber), &Z_Copy }, + { Zoctstr, Cx0B01, 0x0008, Z(ProductRevision), &Z_Copy }, + { Zoctstr, Cx0B01, 0x000A, Z(SoftwareRevision), &Z_Copy }, + { Zstring, Cx0B01, 0x000B, Z(UtilityName), &Z_Copy }, + { Zstring, Cx0B01, 0x000C, Z(POD), &Z_Copy }, + { Zint24, Cx0B01, 0x000D, Z(AvailablePower), &Z_Copy }, + { Zint24, Cx0B01, 0x000E, Z(PowerThreshold), &Z_Copy }, // Diagnostics cluster - { 0x0B05, 0x0000, Z(NumberOfResets), &Z_Copy }, - { 0x0B05, 0x0001, Z(PersistentMemoryWrites),&Z_Copy }, - { 0x0B05, 0x011C, Z(LastMessageLQI), &Z_Copy }, - { 0x0B05, 0x011D, Z(LastMessageRSSI), &Z_Copy }, + { Zuint16, Cx0B05, 0x0000, Z(NumberOfResets), &Z_Copy }, + { Zuint16, Cx0B05, 0x0001, Z(PersistentMemoryWrites),&Z_Copy }, + { Zuint8, Cx0B05, 0x011C, Z(LastMessageLQI), &Z_Copy }, + { Zuint8, Cx0B05, 0x011D, Z(LastMessageRSSI), &Z_Copy }, }; @@ -1245,7 +1325,7 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) { // Iterate on filter for (uint32_t i = 0; i < sizeof(Z_PostProcess) / sizeof(Z_PostProcess[0]); i++) { const Z_AttributeConverter *converter = &Z_PostProcess[i]; - uint16_t conv_cluster = pgm_read_word(&converter->cluster); + uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); uint16_t conv_attribute = pgm_read_word(&converter->attribute); if ((conv_cluster == cluster) && diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index 1893925f3..8cb695bd6 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -53,7 +53,7 @@ ZF(DimmerMove) ZF(DimmerStep) ZF(HueMove) ZF(HueStep) ZF(SatMove) ZF(SatStep) ZF(ColorMove) ZF(ColorStep) ZF(ArrowClick) ZF(ArrowHold) ZF(ArrowRelease) ZF(ZoneStatusChange) -ZF(xxxx00) ZF(xxxx) ZF(01xxxx) ZF(00) ZF(01) ZF() ZF(xxxxyy) ZF(001902) ZF(011902) ZF(xxyyyy) ZF(xx) +ZF(xxxx00) ZF(xxxx) ZF(01xxxx) ZF(00) ZF(01) ZF() ZF(xxxxyy) ZF(00190200) ZF(01190200) ZF(xxyyyy) ZF(xx) ZF(xx000A00) ZF(xx0A00) ZF(xxyy0A00) ZF(xxxxyyyy0A00) ZF(xxxx0A00) ZF(xx0A) ZF(xx190A00) ZF(xx19) ZF(xx190A) ZF(xxxxyyyy) ZF(xxxxyyzz) ZF(xxyyzzzz) ZF(xxyyyyzz) @@ -82,8 +82,8 @@ const Z_CommandConverter Z_Commands[] PROGMEM = { // Light & Shutter commands { Z(Power), 0x0006, 0xFF, 0x01, Z() }, // 0=Off, 1=On, 2=Toggle { Z(Dimmer), 0x0008, 0x04, 0x01, Z(xx0A00) }, // Move to Level with On/Off, xx=0..254 (255 is invalid) - { Z(DimmerUp), 0x0008, 0x06, 0x01, Z(001902) }, // Step up by 10%, 0.2 secs - { Z(DimmerDown), 0x0008, 0x06, 0x01, Z(011902) }, // Step down by 10%, 0.2 secs + { Z(DimmerUp), 0x0008, 0x06, 0x01, Z(00190200) }, // Step up by 10%, 0.2 secs + { Z(DimmerDown), 0x0008, 0x06, 0x01, Z(01190200) }, // Step down by 10%, 0.2 secs { Z(DimmerStop), 0x0008, 0x03, 0x01, Z() }, // Stop any Dimmer animation { Z(ResetAlarm), 0x0009, 0x00, 0x01, Z(xxyyyy) }, // Reset alarm (alarm code + cluster identifier) { Z(ResetAllAlarms), 0x0009, 0x01, 0x01, Z() }, // Reset all alarms diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index aa9505bd7..acccbb8fe 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -534,7 +534,9 @@ void Z_AqaraOccupancy(uint16_t shortaddr, uint16_t cluster, uint8_t endpoint, co uint32_t occupancy = strToUInt(val_endpoint); if (occupancy) { - zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, OCCUPANCY_TIMEOUT, cluster, endpoint, Z_CAT_VIRTUAL_ATTR, 0, &Z_OccupancyCallback); + zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, OCCUPANCY_TIMEOUT, cluster, endpoint, Z_CAT_VIRTUAL_OCCUPANCY, 0, &Z_OccupancyCallback); + } else { + zigbee_devices.resetTimersForDevice(shortaddr, 0 /* groupaddr */, Z_CAT_VIRTUAL_OCCUPANCY); } } } diff --git a/tasmota/xdrv_28_pcf8574.ino b/tasmota/xdrv_28_pcf8574.ino index 95074fab8..888f34fee 100644 --- a/tasmota/xdrv_28_pcf8574.ino +++ b/tasmota/xdrv_28_pcf8574.ino @@ -160,7 +160,7 @@ void HandlePcf8574(void) AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_PCF8574)); - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { Pcf8574SaveSettings(); WebRestart(1); return; @@ -193,9 +193,9 @@ void Pcf8574SaveSettings(void) char stemp[7]; char tmp[100]; - //AddLog_P(LOG_LEVEL_DEBUG, PSTR("PCF: Start working on Save arguements: inverted:%d")), WebServer->hasArg("b1"); + //AddLog_P(LOG_LEVEL_DEBUG, PSTR("PCF: Start working on Save arguements: inverted:%d")), Webserver->hasArg("b1"); - Settings.flag3.pcf8574_ports_inverted = WebServer->hasArg("b1"); // SetOption81 - Invert all ports on PCF8574 devices + Settings.flag3.pcf8574_ports_inverted = Webserver->hasArg("b1"); // SetOption81 - Invert all ports on PCF8574 devices for (byte idx = 0; idx < Pcf8574.max_devices; idx++) { byte count=0; byte n = Settings.pcf8574_config[idx]; @@ -248,7 +248,7 @@ bool Xdrv28(uint8_t function) WSContentSend_P(HTTP_BTN_MENU_PCF8574); break; case FUNC_WEB_ADD_HANDLER: - WebServer->on("/" WEB_HANDLE_PCF8574, HandlePcf8574); + Webserver->on("/" WEB_HANDLE_PCF8574, HandlePcf8574); break; #endif // USE_WEBSERVER } diff --git a/tasmota/xdrv_38_ping.ino b/tasmota/xdrv_38_ping.ino index 0156314a7..d30c0093d 100644 --- a/tasmota/xdrv_38_ping.ino +++ b/tasmota/xdrv_38_ping.ino @@ -21,7 +21,10 @@ #define XDRV_38 38 -#include +#include "lwip/icmp.h" +#include "lwip/inet_chksum.h" +#include "lwip/raw.h" +#include "lwip/timeouts.h" const char kPingCommands[] PROGMEM = "|" // no prefix D_CMND_PING @@ -31,119 +34,291 @@ void (* const PingCommand[])(void) PROGMEM = { &CmndPing, }; -// inspired by https://github.com/dancol90/ESP8266Ping - -typedef struct Ping_t { - uint16_t total_count; // total count if packets sent - uint16_t timeout_count; // time-outs (no responses) - uint32_t min_time; // minimum time in ms for a successful response - uint32_t max_time; // maximum time in ms for a successful response - uint32_t sum_time; // cumulated time in ms for all successful responses (used to compute the average) - bool busy; // is ping on-going - bool done; // indicates the ping campaign is finished -} Ping_t; - -ping_option ping_opt; -Ping_t ping; - extern "C" { - // callbacks for ping + + extern uint32 system_relative_time(uint32 time); + extern void ets_bzero(void *s, size_t n); - // called after a ping response is received or time-out - void ICACHE_RAM_ATTR ping_recv_cb(ping_option *popt, struct ping_resp *p_resp) { - // If successful - if (p_resp->ping_err >= 0) { - uint32_t resp_time = p_resp->resp_time; - ping.sum_time += resp_time; - if (resp_time < ping.min_time) { ping.min_time = resp_time; } - if (resp_time > ping.max_time) { ping.max_time = resp_time; } + const uint16_t Ping_ID = 0xAFAF; // PING packet ID + const size_t Ping_data_size = 32; // default packet size + const uint32_t Ping_timeout_ms = 1000; // default time-out of 1 second, which is enough for LAN/WIFI + const uint32_t Ping_coarse = 1000; // interval between sending packets, 1 packet every second + + typedef struct Ping_t { + uint32 ip; // target IPv4 address + Ping_t *next; // next object in linked list + uint16_t seq_num; // next sequence number + uint16_t seqno; // reject a packet already received + uint8_t success_count; // sucessful responses received + uint8_t timeout_count; // time-outs (no responses) + uint8_t to_send_count; // number of packets remaining to send + uint32_t ping_time_sent; // timestamp when the packet was sent + uint32_t min_time; // minimum time in ms for a successful response + uint32_t max_time; // maximum time in ms for a successful response + uint32_t sum_time; // cumulated time in ms for all successful responses (used to compute the average) + bool done; // indicates the ping campaign is finished + bool fast; // fast mode, i.e. stop pings when first successful response + } Ping_t; + + // globals + Ping_t *ping_head = nullptr; // head of the Linked List for ping objects + struct raw_pcb *t_ping_pcb = nullptr; // registered with first ping, deregistered after last ping, the same pcb is used for all packets + + // ================================================================================ + // Find the Ping object indexed by IP address + // ================================================================================ + // + // find the ping structure corresponding to the specified IP, or nullptr if not found + // + Ping_t ICACHE_FLASH_ATTR * t_ping_find(uint32_t ip) { + Ping_t *ping = ping_head; + while (ping != nullptr) { + if (ping->ip == ip) { + return ping; + } + ping = ping->next; + } + return nullptr; + } + + // ================================================================================ + // Timer called a packet response is in time-out + // ================================================================================ + // + // called after the ICMP timeout occured + // we never received the packet, increase the timeout count + // + void ICACHE_FLASH_ATTR t_ping_timeout(void* arg) { + Ping_t *ping = (Ping_t*) arg; + ping->timeout_count++; + } + + // ================================================================================ + // Send ICMP packet + // ================================================================================ + // Prepare a echo ICMP request + // + void ICACHE_FLASH_ATTR t_ping_prepare_echo(struct icmp_echo_hdr *iecho, uint16_t len, Ping_t *ping) { + size_t data_len = len - sizeof(struct icmp_echo_hdr); + + ICMPH_TYPE_SET(iecho, ICMP_ECHO); + ICMPH_CODE_SET(iecho, 0); + iecho->chksum = 0; + iecho->id = Ping_ID; + ping->seq_num++; + if (ping->seq_num == 0x7fff) { ping->seq_num = 0; } + + iecho->seqno = htons(ping->seq_num); // TODO + + /* fill the additional data buffer with some data */ + for (uint32_t i = 0; i < data_len; i++) { + ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; + } + + iecho->chksum = inet_chksum(iecho, len); + } + // + // send the ICMP packet + // + void ICACHE_FLASH_ATTR t_ping_send(struct raw_pcb *raw, Ping_t *ping) { + struct pbuf *p; + uint16_t ping_size = sizeof(struct icmp_echo_hdr) + Ping_data_size; + + ping->ping_time_sent = system_get_time(); + p = pbuf_alloc(PBUF_IP, ping_size, PBUF_RAM); + if (!p) { return; } + if ((p->len == p->tot_len) && (p->next == nullptr)) { + ip_addr_t ping_target; + struct icmp_echo_hdr *iecho; + + ping_target.addr = ping->ip; + iecho = (struct icmp_echo_hdr *) p->payload; + + t_ping_prepare_echo(iecho, ping_size, ping); + raw_sendto(raw, p, &ping_target); + } + pbuf_free(p); + } + + // ================================================================================ + // Timer called when it's time to send next packet, of when finished + // ================================================================================ + // this timer is called every x seconds to send a new packet, whatever happened to the previous packet + static void ICACHE_FLASH_ATTR t_ping_coarse_tmr(void *arg) { + Ping_t *ping = (Ping_t*) arg; + if (ping->to_send_count > 0) { + ping->to_send_count--; + // have we sent all packets? + t_ping_send(t_ping_pcb, ping); + + sys_timeout(Ping_timeout_ms, t_ping_timeout, ping); + sys_timeout(Ping_coarse, t_ping_coarse_tmr, ping); + } else { + sys_untimeout(t_ping_coarse_tmr, ping); + ping->done = true; } } - // called after the ping campaign is finished - void ICACHE_RAM_ATTR ping_sent_cb(ping_option *popt, struct ping_resp *p_resp) { - // copy counters to build the MQTT response - ping.total_count = p_resp->total_count; - ping.timeout_count = p_resp->timeout_count; - ping.done = true; + // ================================================================================ + // Callback: a packet response was received + // ================================================================================ + // + // Reveived packet + // + static uint8_t ICACHE_FLASH_ATTR t_ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) { + Ping_t *ping = t_ping_find(addr->addr); + + if (nullptr == ping) { // unknown source address + return 0; // don't eat the packet and ignore it + } + + if (pbuf_header( p, -PBUF_IP_HLEN)==0) { + struct icmp_echo_hdr *iecho; + iecho = (struct icmp_echo_hdr *)p->payload; + + if ((iecho->id == Ping_ID) && (iecho->seqno == htons(ping->seq_num)) && iecho->type == ICMP_ER) { + + if (iecho->seqno != ping->seqno){ // debounce already received packet + /* do some ping result processing */ + sys_untimeout(t_ping_timeout, ping); // remove time-out handler + uint32_t delay = system_relative_time(ping->ping_time_sent); + delay /= 1000; + + ping->sum_time += delay; + if (delay < ping->min_time) { ping->min_time = delay; } + if (delay > ping->max_time) { ping->max_time = delay; } + + ping->success_count++; + ping->seqno = iecho->seqno; + if (ping->fast) { // if fast mode, abort further pings when first successful response is received + sys_untimeout(t_ping_coarse_tmr, ping); + ping->done = true; + ping->to_send_count = 0; + } + } + + pbuf_free(p); + return 1; /* eat the packet */ + } + } + + return 0; /* don't eat the packet */ } + + // ================================================================================ + // Internal structure PCB management + // ================================================================================ + // we are going to send a packet, make sure pcb is initialized + void t_ping_register_pcb(void) { + if (nullptr == t_ping_pcb) { + t_ping_pcb = raw_new(IP_PROTO_ICMP); + + raw_recv(t_ping_pcb, t_ping_recv, nullptr); // we cannot register data structure here as we can only register one + raw_bind(t_ping_pcb, IP_ADDR_ANY); + } + } + + // we have finsihed a ping series, deallocated if no more ongoing + void t_ping_deregister_pcb(void) { + if (nullptr == ping_head) { // deregister only if no ping is flying + raw_remove(t_ping_pcb); + t_ping_pcb = nullptr; + } + } + + // ================================================================================ + // Start pings + // ================================================================================ + bool t_ping_start(uint32_t ip, uint32_t count) { + // check if pings are already ongoing for this IP + if (t_ping_find(ip)) { + return false; + } + + Ping_t *ping = new Ping_t(); + if (0 == count) { + count = 4; + ping->fast = true; + } + ping->min_time = UINT32_MAX; + ping->ip = ip; + ping->to_send_count = count - 1; + + // add to Linked List from head + ping->next = ping_head; + ping_head = ping; // insert at head + + t_ping_register_pcb(); + t_ping_send(t_ping_pcb, ping); + + // set timers for time-out and cadence + sys_timeout(Ping_timeout_ms, t_ping_timeout, ping); + sys_timeout(Ping_coarse, t_ping_coarse_tmr, ping); + } + } // Check if any ping requests is completed, and publish the results void PingResponsePoll(void) { - if (ping.done) { - uint32_t success = ping.total_count - ping.timeout_count; - uint32_t ip = ping_opt.ip; + Ping_t *ping = ping_head; + Ping_t **prev_link = &ping_head; // previous link pointer (used to remove en entry) - // Serial.printf( - // "DEBUG ping_sent_cb: ping reply\n" - // "\tsuccess_count = %d \n" - // "\ttimeout_count = %d \n" - // "\tmin_time = %d \n" - // "\tmax_time = %d \n" - // "\tavg_time = %d \n", - // success, ping.timeout_count, - // ping.min_time, ping.max_time, - // success ? ping.sum_time / success : 0 - // ); + while (ping != nullptr) { + if (ping->done) { + uint32_t success = ping->success_count; + uint32_t ip = ping->ip; - Response_P(PSTR("{\"" D_JSON_PING "\":{\"%d.%d.%d.%d\":{" - "\"Reachable\":%s" - ",\"Success\":%d" - ",\"Timeout\":%d" - ",\"MinTime\":%d" - ",\"MaxTime\":%d" - ",\"AvgTime\":%d" - "}}}"), - ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, ip >> 24, - success ? "true" : "false", - success, ping.timeout_count, - ping.min_time, ping.max_time, - success ? ping.sum_time / success : 0 - ); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_PING)); - XdrvRulesProcess(); - ping.done = false; - ping.busy = false; + Response_P(PSTR("{\"" D_JSON_PING "\":{\"%d.%d.%d.%d\":{" + "\"Reachable\":%s" + ",\"Success\":%d" + ",\"Timeout\":%d" + ",\"MinTime\":%d" + ",\"MaxTime\":%d" + ",\"AvgTime\":%d" + "}}}"), + ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, ip >> 24, + success ? "true" : "false", + success, ping->timeout_count, + success ? ping->min_time : 0, ping->max_time, + success ? ping->sum_time / success : 0 + ); + MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_PING)); + XdrvRulesProcess(); + + // remove from linked list + *prev_link = ping->next; + // don't increment prev_link + Ping_t *ping_to_delete = ping; + ping = ping->next; // move to next before deleting the object + delete ping_to_delete; // free memory allocated + } else { + prev_link = &ping->next; + ping = ping->next; + } } } +/*********************************************************************************************\ + * Ping Command +\*********************************************************************************************/ + void CmndPing(void) { uint32_t count = XdrvMailbox.index; IPAddress ip; RemoveSpace(XdrvMailbox.data); - if (count > 8) { count = 8; } - - if (ping.busy) { - ResponseCmndChar_P(PSTR("Ping busy")); - return; - } + if (count > 10) { count = 8; } // max 8 seconds if (WiFi.hostByName(XdrvMailbox.data, ip)) { - memset(&ping_opt, 0, sizeof(ping_opt)); - memset(&ping, 0, sizeof(ping)); - ping.min_time = UINT32_MAX; - - ping_opt.count = count; - ping_opt.coarse_time = 1; // wait 1 second between messages - ping_opt.ip = ip; - - // callbacks - ping_opt.recv_function = (ping_recv_function) ping_recv_cb; // at each response or time-out - ping_opt.sent_function = (ping_sent_function) ping_sent_cb; // when all packets have been sent and reveived - - ping.busy = true; - if (ping_start(&ping_opt)) { + bool ok = t_ping_start(ip, count); + if (ok) { ResponseCmndDone(); } else { - ResponseCmndChar_P(PSTR("Unable to send Ping")); - ping.busy = false; + ResponseCmndChar_P(PSTR("Ping already ongoing for this IP")); } } else { ResponseCmndChar_P(PSTR("Unable to resolve IP address")); } - } @@ -157,7 +332,7 @@ bool Xdrv38(uint8_t function) switch (function) { case FUNC_EVERY_250_MSECOND: - PingResponsePoll(); + PingResponsePoll(); // TODO break; case FUNC_COMMAND: result = DecodeCommand(kPingCommands, PingCommand); @@ -166,4 +341,4 @@ bool Xdrv38(uint8_t function) return result; } -#endif // USE_PING +#endif // USE_PING \ No newline at end of file diff --git a/tasmota/xdrv_99_debug.ino b/tasmota/xdrv_99_debug.ino index 538ac7f71..feb04cabd 100644 --- a/tasmota/xdrv_99_debug.ino +++ b/tasmota/xdrv_99_debug.ino @@ -172,11 +172,11 @@ void CpuLoadLoop(void) CPU_loops ++; if ((CPU_last_millis + (CPU_load_check *1000)) <= CPU_last_loop_time) { #if defined(F_CPU) && (F_CPU == 160000000L) - int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *800) ); + int CPU_load = 100 - ( (CPU_loops*(1 + 30*ssleep)) / (CPU_load_check *800) ); CPU_loops = CPU_loops / CPU_load_check; AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(160MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops); #else - int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *400) ); + int CPU_load = 100 - ( (CPU_loops*(1 + 30*ssleep)) / (CPU_load_check *400) ); CPU_loops = CPU_loops / CPU_load_check; AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(80MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops); #endif @@ -188,6 +188,7 @@ void CpuLoadLoop(void) /*******************************************************************************************/ +#ifdef ESP8266 #if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) // All version before core 2.4.2 // https://github.com/esp8266/Arduino/issues/2557 @@ -224,10 +225,22 @@ void DebugFreeMem(void) #endif // ARDUINO_ESP8266_RELEASE_2_x_x +#else // ESP32 + +void DebugFreeMem(void) +{ + register uint8_t *sp asm("a1"); + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), sp - pxTaskGetStackStart(NULL), XdrvMailbox.data); +} + +#endif // ESP8266 - ESP32 + /*******************************************************************************************/ void DebugRtcDump(char* parms) { +#ifdef ESP8266 #define CFG_COLS 16 uint16_t idx; @@ -283,6 +296,7 @@ void DebugRtcDump(char* parms) snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data); AddLog(LOG_LEVEL_INFO); } +#endif // ESP8266 } /*******************************************************************************************/ @@ -385,6 +399,7 @@ void DebugCfgPoke(char* parms) void SetFlashMode(uint8_t mode) { +#ifdef ESP8266 uint8_t *_buffer; uint32_t address; @@ -400,6 +415,7 @@ void SetFlashMode(uint8_t mode) } } delete[] _buffer; +#endif // ESP8266 } /*********************************************************************************************\ @@ -503,6 +519,7 @@ uint32_t DebugSwap32(uint32_t x) { void CmndFlashDump(void) { +#ifdef ESP8266 // FlashDump // FlashDump 0xFF000 // FlashDump 0xFC000 10 @@ -533,6 +550,7 @@ void CmndFlashDump(void) DebugSwap32(values[4]), DebugSwap32(values[5]), DebugSwap32(values[6]), DebugSwap32(values[7])); } ResponseCmndDone(); +#endif // ESP8266 } #ifdef USE_I2C @@ -600,10 +618,12 @@ void CmndI2cRead(void) void CmndI2cStretch(void) { +#ifdef ESP8266 if (i2c_flg && (XdrvMailbox.payload > 0)) { Wire.setClockStretchLimit(XdrvMailbox.payload); } ResponseCmndDone(); +#endif // ESP8266 } void CmndI2cClock(void) diff --git a/tasmota/xsns_22_sr04.ino b/tasmota/xsns_22_sr04.ino index 54e1c00f8..dd8d87ab1 100644 --- a/tasmota/xsns_22_sr04.ino +++ b/tasmota/xsns_22_sr04.ino @@ -32,40 +32,39 @@ #define XSNS_22 22 uint8_t sr04_type = 1; -int sr04_echo_pin = 0; -int sr04_trig_pin = 0; real64_t distance; NewPing* sonar = nullptr; TasmotaSerial* sonar_serial = nullptr; - - uint8_t Sr04TModeDetect(void) { sr04_type = 0; - if (pin[GPIO_SR04_ECHO]>=99) return sr04_type; + if (99 == pin[GPIO_SR04_ECHO]) { return sr04_type; } - sr04_echo_pin = pin[GPIO_SR04_ECHO]; - sr04_trig_pin = (pin[GPIO_SR04_TRIG] < 99) ? pin[GPIO_SR04_TRIG] : pin[GPIO_SR04_ECHO]; // if GPIO_SR04_TRIG is not configured use single PIN mode with GPIO_SR04_ECHO only + int sr04_echo_pin = pin[GPIO_SR04_ECHO]; + int sr04_trig_pin = (pin[GPIO_SR04_TRIG] < 99) ? pin[GPIO_SR04_TRIG] : pin[GPIO_SR04_ECHO]; // if GPIO_SR04_TRIG is not configured use single PIN mode with GPIO_SR04_ECHO only sonar_serial = new TasmotaSerial(sr04_echo_pin, sr04_trig_pin, 1); if (sonar_serial->begin(9600,1)) { DEBUG_SENSOR_LOG(PSTR("SR04: Detect mode")); - if (sr04_trig_pin!=-1) { - sr04_type = (Sr04TMiddleValue(Sr04TMode3Distance(),Sr04TMode3Distance(),Sr04TMode3Distance())!=NO_ECHO)?3:1; + if (sr04_trig_pin != -1) { + sr04_type = (Sr04TMiddleValue(Sr04TMode3Distance(), Sr04TMode3Distance(), Sr04TMode3Distance()) != NO_ECHO) ? 3 : 1; } else { - sr04_type = 2; + sr04_type = 2; } } else { sr04_type = 1; } if (sr04_type < 2) { - delete sonar_serial; - sonar_serial = nullptr; - sonar = new NewPing(sr04_trig_pin, sr04_echo_pin, 300); + delete sonar_serial; + sonar_serial = nullptr; + if (-1 == sr04_trig_pin) { + sr04_trig_pin = pin[GPIO_SR04_ECHO]; // if GPIO_SR04_TRIG is not configured use single PIN mode with GPIO_SR04_ECHO only + } + sonar = new NewPing(sr04_trig_pin, sr04_echo_pin, 300); } else { if (sonar_serial->hardwareSerial()) { ClaimSerial(); diff --git a/tasmota/xsns_34_hx711.ino b/tasmota/xsns_34_hx711.ino index 44bb9036c..86e920945 100644 --- a/tasmota/xsns_34_hx711.ino +++ b/tasmota/xsns_34_hx711.ino @@ -494,7 +494,7 @@ void HandleHxAction(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_HX711); - if (WebServer->hasArg("save")) { + if (Webserver->hasArg("save")) { HxSaveSettings(); HandleConfiguration(); return; @@ -502,7 +502,7 @@ void HandleHxAction(void) char stemp1[20]; - if (WebServer->hasArg("reset")) { + if (Webserver->hasArg("reset")) { snprintf_P(stemp1, sizeof(stemp1), PSTR("Sensor34 1")); // Reset ExecuteWebCommand(stemp1, SRC_WEBGUI); @@ -510,7 +510,7 @@ void HandleHxAction(void) return; } - if (WebServer->hasArg("calibrate")) { + if (Webserver->hasArg("calibrate")) { WebGetArg("p1", stemp1, sizeof(stemp1)); Settings.weight_reference = (!strlen(stemp1)) ? 0 : (unsigned long)(CharToFloat(stemp1) * 1000); @@ -593,7 +593,7 @@ bool Xsns34(uint8_t function) WSContentSend_P(HTTP_BTN_MENU_HX711); break; case FUNC_WEB_ADD_HANDLER: - WebServer->on("/" WEB_HANDLE_HX711, HandleHxAction); + Webserver->on("/" WEB_HANDLE_HX711, HandleHxAction); break; #endif // USE_HX711_GUI #endif // USE_WEBSERVER diff --git a/tasmota/xsns_60_GPS.ino b/tasmota/xsns_60_GPS.ino index 966b3a609..87e15d6a2 100644 --- a/tasmota/xsns_60_GPS.ino +++ b/tasmota/xsns_60_GPS.ino @@ -98,7 +98,7 @@ The serial pins are GPS_RX and GPS_TX, no further installation steps needed. To set latitude and longitude in settings + sensor60 14 - open virtual serial port over TCP, usable for u-center + open virtual serial port over TCP, usable for u-center + sensor60 15 pause virtual serial port over TCP @@ -137,7 +137,7 @@ const char kUBXTypes[] PROGMEM = "UBX"; #define UBX_SERIAL_BUFFER_SIZE 256 #define UBX_TCP_PORT 1234 -#define NTP_MILLIS_OFFSET 50 // estimated latency in milliseconds +#define NTP_MILLIS_OFFSET 50 // estimated latency in milliseconds /********************************************************************************************\ | *globals @@ -504,8 +504,8 @@ uint32_t UBXprocessGPS() #ifdef USE_FLOG void UBXsendHeader(void) { - WebServer->setContentLength(CONTENT_LENGTH_UNKNOWN); - WebServer->sendHeader(F("Content-Disposition"), F("attachment; filename=TASMOTA.gpx")); + Webserver->setContentLength(CONTENT_LENGTH_UNKNOWN); + Webserver->sendHeader(F("Content-Disposition"), F("attachment; filename=TASMOTA.gpx")); WSSend(200, CT_STREAM, F( "\r\n" "lon/10000000.0f,7,lon); snprintf_P(record, sizeof(record),PSTR("\n\t\n\n"),lat ,lon, stime); // DEBUG_SENSOR_LOG(PSTR("FLOG: DL %u %u"), Flog->sector.dword_buffer[k+j],Flog->sector.dword_buffer[k+j+1]); - WebServer->sendContent_P(record); + Webserver->sendContent_P(record); } void UBXsendFooter(void) { - WebServer->sendContent(F("\n\n")); - WebServer->sendContent(""); + Webserver->sendContent(F("\n\n")); + Webserver->sendContent(""); Rtc.user_time_entry = false; // we have blocked the main loop and want a new valid time } @@ -707,7 +707,7 @@ void UBXHandleTIME() if (UBX.mode.forceUTCupdate || Rtc.user_time_entry == false){ AddLog_P(LOG_LEVEL_INFO, PSTR("UBX: UTC-Time is valid, set system time")); Rtc.utc_time = UBX.rec_buffer.values.time; - } + } Rtc.user_time_entry = true; } } @@ -928,7 +928,7 @@ bool Xsns60(uint8_t function) break; #ifdef USE_FLOG case FUNC_WEB_ADD_HANDLER: - WebServer->on("/UBX", UBXsendFile); + Webserver->on("/UBX", UBXsendFile); break; #endif //USE_FLOG case FUNC_JSON_APPEND: diff --git a/tasmota/xsns_91_prometheus.ino b/tasmota/xsns_91_prometheus.ino index ea4c0047a..f5b0eba9d 100644 --- a/tasmota/xsns_91_prometheus.ino +++ b/tasmota/xsns_91_prometheus.ino @@ -90,7 +90,7 @@ bool Xsns91(uint8_t function) switch (function) { case FUNC_WEB_ADD_HANDLER: - WebServer->on("/metrics", HandleMetrics); + Webserver->on("/metrics", HandleMetrics); break; } return result;