Merge remote-tracking branch 'Tasmota/development'

This commit is contained in:
Platformio BUILD 2020-12-08 20:16:58 +00:00
commit 7c28b2e237
23 changed files with 266 additions and 119 deletions

View File

@ -13,17 +13,22 @@ All notable changes to this project will be documented in this file.
- TyuaMcu update 2/3 by Federico Leoni (#10004) - TyuaMcu update 2/3 by Federico Leoni (#10004)
- Optional CCloader support for CC25xx Zigbee or CC26xx BLE by Christian Baars (#9970) - Optional CCloader support for CC25xx Zigbee or CC26xx BLE by Christian Baars (#9970)
- Command ``RfProtocol`` to control RcSwitch receive protocols by BBBits (#10063) - Command ``RfProtocol`` to control RcSwitch receive protocols by BBBits (#10063)
- Zigbee better support for Tuya Protocol (#10074)
- Support for SPI connected MFRC522 13.56MHz rfid card reader (#9916) - Support for SPI connected MFRC522 13.56MHz rfid card reader (#9916)
- Letsencrypt R3 in addition to X3 CA (#10086)
### Breaking Changed ### Breaking Changed
- KNX DPT9 (16-bit float) to DPT14 (32-bit float) by Adrian Scillato (#9811, #9888) - KNX DPT9 (16-bit float) to DPT14 (32-bit float) by Adrian Scillato (#9811, #9888)
### Changed ### Changed
- Core library from v2.7.4.7 to v2.7.4.9
- Shelly Dimmer fw upgrade using WebGUI Firmware Upgrade and file from folder `tools/fw_shd_stm32/` - Shelly Dimmer fw upgrade using WebGUI Firmware Upgrade and file from folder `tools/fw_shd_stm32/`
- MQTT Wifi connection timeout from 5000 to 200 mSec (#9886) - MQTT Wifi connection timeout from 5000 to 200 mSec (#9886)
- Platformio compiler option `-free -fipa-pta` enabled (#9875) - Platformio compiler option `-free -fipa-pta` enabled (#9875)
- IRremoteESP8266 library from v2.7.12 to v2.7.13 - IRremoteESP8266 library from v2.7.12 to v2.7.13
- Shelly Dimmer 1 and 2 stm32 firmware from v51.4 to v51.5 - Shelly Dimmer 1 and 2 stm32 firmware from v51.4 to v51.5
- Force bigger Thunk Stack if 4K RSA even without EC ciphers (#10075)
- mDNS has been disabled from all pre-compiled binaries to allow new features
### Fixed ### Fixed
- KNX ESP32 UDP mulicastpackage (#9811) - KNX ESP32 UDP mulicastpackage (#9811)
@ -31,6 +36,8 @@ All notable changes to this project will be documented in this file.
- ESP32 TasmotaClient firmware upgrade (#9218) - ESP32 TasmotaClient firmware upgrade (#9218)
- Reset to defaults after 6 hours of DeepSleep (#9993) - Reset to defaults after 6 hours of DeepSleep (#9993)
- Backlog timing wraparound (#9995) - Backlog timing wraparound (#9995)
- First LED in addressable string does not fade when using scheme (#10088)
- Improved Opentherm error handling (#10055)
### Removed ### Removed
- PN532 define USE_PN532_CAUSE_EVENTS replaced by generic rule trigger `on pn532#uid=` - PN532 define USE_PN532_CAUSE_EVENTS replaced by generic rule trigger `on pn532#uid=`
@ -66,8 +73,7 @@ All notable changes to this project will be documented in this file.
## [Released] ## [Released]
### 9.1.0 20201105 ## [9.1.0] 20201105
- Release Imogen - Release Imogen
## [9.0.0.3] - 20201105 ## [9.0.0.3] - 20201105

View File

@ -24,7 +24,7 @@ While fallback or downgrading is common practice it was never supported due to S
## Supported Core versions ## Supported Core versions
This release will be supported from ESP8266/Arduino library Core version **2.7.4.7** due to reported security and stability issues on previous Core version. This will also support gzipped binaries. This release will be supported from ESP8266/Arduino library Core version **2.7.4.9** due to reported security and stability issues on previous Core version. This will also support gzipped binaries.
Support of Core versions before 2.7.1 has been removed. Support of Core versions before 2.7.1 has been removed.
@ -38,7 +38,7 @@ For initial configuration this release supports Webserver based **WifiManager**
## Provided Binary Downloads ## Provided Binary Downloads
The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.4.7**. The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.4.9**.
- **tasmota.bin** = The Tasmota version with most drivers. **RECOMMENDED RELEASE BINARY** - **tasmota.bin** = The Tasmota version with most drivers. **RECOMMENDED RELEASE BINARY**
- **tasmota-BG.bin** to **tasmota-TW.bin** = The Tasmota version in different languages. - **tasmota-BG.bin** to **tasmota-TW.bin** = The Tasmota version in different languages.
@ -67,6 +67,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- Zigbee support for Mi Door and Contact (#9759) - Zigbee support for Mi Door and Contact (#9759)
- Zigbee alarm persistence (#9785) - Zigbee alarm persistence (#9785)
- Zigbee persistence of device/sensor data in EEPROM (only ZBBridge) - Zigbee persistence of device/sensor data in EEPROM (only ZBBridge)
- Zigbee better support for Tuya Protocol (#10074)
- TyuaMcu update 2/3 by Federico Leoni (#10004) - TyuaMcu update 2/3 by Federico Leoni (#10004)
- Support for additional EZO sensors by Christopher Tremblay - Support for additional EZO sensors by Christopher Tremblay
- Support for AS608 optical and R503 capacitive fingerprint sensor - Support for AS608 optical and R503 capacitive fingerprint sensor
@ -77,17 +78,20 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- KNX read reply for Power (#9236, #9891) - KNX read reply for Power (#9236, #9891)
- Fallback NTP server from x.pool.ntp.org if no ntpservers are configured - Fallback NTP server from x.pool.ntp.org if no ntpservers are configured
- Optional CCloader support for CC25xx Zigbee or CC26xx BLE by Christian Baars (#9970) - Optional CCloader support for CC25xx Zigbee or CC26xx BLE by Christian Baars (#9970)
- Letsencrypt R3 in addition to X3 CA (#10086)
### Breaking Changed ### Breaking Changed
- KNX DPT9 (16-bit float) to DPT14 (32-bit float) by Adrian Scillato (#9811, #9888) - KNX DPT9 (16-bit float) to DPT14 (32-bit float) by Adrian Scillato (#9811, #9888)
### Changed ### Changed
- Core library from v2.7.4.5 to v2.7.4.7 - Core library from v2.7.4.5 to v2.7.4.9
- IRremoteESP8266 library from v2.7.12 to v2.7.13 - IRremoteESP8266 library from v2.7.12 to v2.7.13
- Shelly Dimmer 1 and 2 stm32 firmware from v51.4 to v51.5 - Shelly Dimmer 1 and 2 stm32 firmware from v51.4 to v51.5
- mDNS has been disabled from all pre-compiled binaries to allow new features
- Platformio compiler option `no target align` enabled (#9749) - Platformio compiler option `no target align` enabled (#9749)
- Sonoff L1 color up scaling and color margin detection (#9545) - Sonoff L1 color up scaling and color margin detection (#9545)
- MQTT Wifi connection timeout from 5000 to 200 mSec (#9886) - MQTT Wifi connection timeout from 5000 to 200 mSec (#9886)
- Force bigger Thunk Stack if 4K RSA even without EC ciphers (#10075)
### Fixed ### Fixed
- Command ``gpio`` using non-indexed functions regression from v9.1.0 (#9962) - Command ``gpio`` using non-indexed functions regression from v9.1.0 (#9962)
@ -99,6 +103,8 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- ESP32 TasmotaClient firmware upgrade (#9218) - ESP32 TasmotaClient firmware upgrade (#9218)
- Reset to defaults after 6 hours of DeepSleep (#9993) - Reset to defaults after 6 hours of DeepSleep (#9993)
- Backlog timing wraparound (#9995) - Backlog timing wraparound (#9995)
- First LED in addressable string does not fade when using scheme (#10088)
- Improved Opentherm error handling (#10055)
### Removed ### Removed
- Version compatibility check - Version compatibility check

View File

@ -19,6 +19,7 @@
// //
#include "Arduino.h" #include "Arduino.h"
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <esp_wifi.h>
// //
// Wifi // Wifi
@ -35,7 +36,15 @@ void WiFiClass32::setSleepMode(int iSleepMode)
int WiFiClass32::getPhyMode() int WiFiClass32::getPhyMode()
{ {
return 0; // " BGN" int phy_mode = 0; // " BGNL"
uint8_t protocol_bitmap;
if (esp_wifi_get_protocol(WIFI_IF_STA, &protocol_bitmap) == ESP_OK) {
if (protocol_bitmap & 1) { phy_mode = 1; } // 11b
if (protocol_bitmap & 2) { phy_mode = 2; } // 11g
if (protocol_bitmap & 4) { phy_mode = 3; } // 11n
if (protocol_bitmap & 8) { phy_mode = 4; } // Low rate
}
return phy_mode;
} }
void WiFiClass32::wps_disable() void WiFiClass32::wps_disable()

View File

@ -100,13 +100,14 @@ extra_scripts = pio-tools/strip-floats.py
[esp_defaults] [esp_defaults]
; *** remove undesired all warnings ; *** remove undesired all warnings
build_unflags = -mtarget-align build_unflags = -Wall
-Wall ; -mtarget-align
-Wdeprecated-declarations -Wdeprecated-declarations
build_flags = -mno-target-align build_flags = -Wno-deprecated-declarations
; -mno-target-align
-mtarget-align
-free -free
-fipa-pta -fipa-pta
-Wno-deprecated-declarations
-Wreturn-type -Wreturn-type
-D_IR_ENABLE_DEFAULT_=false -D_IR_ENABLE_DEFAULT_=false
-DDECODE_HASH=true -DDECODE_NEC=true -DSEND_NEC=true -DDECODE_HASH=true -DDECODE_NEC=true -DSEND_NEC=true

View File

@ -131,9 +131,8 @@ lib_extra_dirs = ${library.lib_extra_dirs}
[core32_stage] [core32_stage]
platform = espressif32 @ 2.0.0 platform = espressif32 @ 2.1.0
platform_packages = platformio/tool-esptoolpy @ ~1.30000.0 platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/1.0.5-rc4/esp32-1.0.5-rc4.zip
framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/1.0.5-rc2/esp32-1.0.5-rc2.zip
build_unflags = ${esp32_defaults.build_unflags} build_unflags = ${esp32_defaults.build_unflags}
build_flags = ${esp32_defaults.build_flags} build_flags = ${esp32_defaults.build_flags}
;-DESP32_STAGE=true ;-DESP32_STAGE=true

View File

@ -86,8 +86,7 @@ build_flags = ${esp_defaults.build_flags}
[core32] [core32]
platform = espressif32 @ 2.0.0 platform = espressif32 @ 2.1.0
platform_packages = platformio/tool-esptoolpy @ ~1.30000.0 platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/1.0.4.2/esp32-1.0.4.2.zip
framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/1.0.4.2/esp32-1.0.4.2.zip
build_unflags = ${esp32_defaults.build_unflags} build_unflags = ${esp32_defaults.build_unflags}
build_flags = ${esp32_defaults.build_flags} build_flags = ${esp32_defaults.build_flags}

View File

@ -421,7 +421,7 @@
// #define USE_CCLOADER // Enable CCLoader FW upgrade tool (for CC25xx devices) // #define USE_CCLOADER // Enable CCLoader FW upgrade tool (for CC25xx devices)
// -- mDNS ---------------------------------------- // -- mDNS ----------------------------------------
#define USE_DISCOVERY // Enable mDNS for the following services (+8k code or +23.5k code with core 2_5_x, +0.3k mem) //#define USE_DISCOVERY // Enable mDNS for the following services (+8k code or +23.5k code with core 2_5_x, +0.3k mem)
#define WEBSERVER_ADVERTISE // Provide access to webserver by name <Hostname>.local/ #define WEBSERVER_ADVERTISE // Provide access to webserver by name <Hostname>.local/
#define MQTT_HOST_DISCOVERY // Find MQTT host server (overrides MQTT_HOST if found) #define MQTT_HOST_DISCOVERY // Find MQTT host server (overrides MQTT_HOST if found)

View File

@ -683,17 +683,18 @@ typedef struct {
uint16_t valid; // 290 (RTC memory offset 100) uint16_t valid; // 290 (RTC memory offset 100)
uint8_t oswatch_blocked_loop; // 292 uint8_t oswatch_blocked_loop; // 292
uint8_t ota_loader; // 293 uint8_t ota_loader; // 293
unsigned long energy_kWhtoday; // 294 unsigned long energy_kWhtoday; // 294
unsigned long energy_kWhtotal; // 298 unsigned long energy_kWhtotal; // 298
volatile unsigned long pulse_counter[MAX_COUNTERS]; // 29C - See #9521 why volatile volatile unsigned long pulse_counter[MAX_COUNTERS]; // 29C - See #9521 why volatile
power_t power; // 2AC power_t power; // 2AC
EnergyUsage energy_usage; // 2B0 EnergyUsage energy_usage; // 2B0
unsigned long nextwakeup; // 2C8 unsigned long nextwakeup; // 2C8
uint8_t free_004[4]; // 2CC uint32_t baudrate; // 2CC
uint32_t ultradeepsleep; // 2D0 uint32_t ultradeepsleep; // 2D0
uint16_t deepsleep_slip; // 2D4 uint16_t deepsleep_slip; // 2D4
uint8_t free_022[22]; // 2D6 uint8_t free_2d6[22]; // 2D6
// 2EC - 2FF free locations // 2EC - 2FF free locations
} TRtcSettings; } TRtcSettings;
TRtcSettings RtcSettings; TRtcSettings RtcSettings;

View File

@ -38,6 +38,7 @@ uint32_t GetRtcSettingsCrc(void)
void RtcSettingsSave(void) void RtcSettingsSave(void)
{ {
RtcSettings.baudrate = Settings.baudrate * 300;
if (GetRtcSettingsCrc() != rtc_settings_crc) { if (GetRtcSettingsCrc() != rtc_settings_crc) {
RtcSettings.valid = RTC_MEM_VALID; RtcSettings.valid = RTC_MEM_VALID;
#ifdef ESP8266 #ifdef ESP8266
@ -50,8 +51,8 @@ void RtcSettingsSave(void)
} }
} }
void RtcSettingsLoad(void) bool RtcSettingsLoad(void) {
{ bool was_read_valid = true;
#ifdef ESP8266 #ifdef ESP8266
ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RtcSettings)); // 0x290 ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RtcSettings)); // 0x290
#endif // ESP8266 #endif // ESP8266
@ -59,6 +60,7 @@ void RtcSettingsLoad(void)
RtcSettings = RtcDataSettings; RtcSettings = RtcDataSettings;
#endif // ESP32 #endif // ESP32
if (RtcSettings.valid != RTC_MEM_VALID) { if (RtcSettings.valid != RTC_MEM_VALID) {
was_read_valid = false;
memset(&RtcSettings, 0, sizeof(RtcSettings)); memset(&RtcSettings, 0, sizeof(RtcSettings));
RtcSettings.valid = RTC_MEM_VALID; RtcSettings.valid = RTC_MEM_VALID;
RtcSettings.energy_kWhtoday = Settings.energy_kWhtoday; RtcSettings.energy_kWhtoday = Settings.energy_kWhtoday;
@ -68,9 +70,12 @@ void RtcSettingsLoad(void)
RtcSettings.pulse_counter[i] = Settings.pulse_counter[i]; RtcSettings.pulse_counter[i] = Settings.pulse_counter[i];
} }
RtcSettings.power = Settings.power; RtcSettings.power = Settings.power;
// RtcSettings.baudrate = Settings.baudrate * 300;
RtcSettings.baudrate = APP_BAUDRATE;
RtcSettingsSave(); RtcSettingsSave();
} }
rtc_settings_crc = GetRtcSettingsCrc(); rtc_settings_crc = GetRtcSettingsCrc();
return was_read_valid;
} }
bool RtcSettingsValid(void) bool RtcSettingsValid(void)

View File

@ -911,6 +911,10 @@ String GetSerialConfig(void) {
return String(config); return String(config);
} }
uint32_t GetSerialBaudrate(void) {
return (Serial.baudRate() / 300) * 300; // Fix ESP32 strange results like 115201
}
void SetSerialBegin(void) { void SetSerialBegin(void) {
TasmotaGlobal.baudrate = Settings.baudrate * 300; TasmotaGlobal.baudrate = Settings.baudrate * 300;
AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_SERIAL "Set to %s %d bit/s"), GetSerialConfig().c_str(), TasmotaGlobal.baudrate); AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_SERIAL "Set to %s %d bit/s"), GetSerialConfig().c_str(), TasmotaGlobal.baudrate);
@ -940,7 +944,7 @@ void SetSerialConfig(uint32_t serial_config) {
void SetSerialBaudrate(uint32_t baudrate) { void SetSerialBaudrate(uint32_t baudrate) {
TasmotaGlobal.baudrate = baudrate; TasmotaGlobal.baudrate = baudrate;
Settings.baudrate = TasmotaGlobal.baudrate / 300; Settings.baudrate = TasmotaGlobal.baudrate / 300;
if (Serial.baudRate() != TasmotaGlobal.baudrate) { if (GetSerialBaudrate() != TasmotaGlobal.baudrate) {
SetSerialBegin(); SetSerialBegin();
} }
} }
@ -958,7 +962,7 @@ void ClaimSerial(void) {
TasmotaGlobal.serial_local = true; TasmotaGlobal.serial_local = true;
AddLog_P(LOG_LEVEL_INFO, PSTR("SNS: Hardware Serial")); AddLog_P(LOG_LEVEL_INFO, PSTR("SNS: Hardware Serial"));
SetSeriallog(LOG_LEVEL_NONE); SetSeriallog(LOG_LEVEL_NONE);
TasmotaGlobal.baudrate = Serial.baudRate(); TasmotaGlobal.baudrate = GetSerialBaudrate();
Settings.baudrate = TasmotaGlobal.baudrate / 300; Settings.baudrate = TasmotaGlobal.baudrate / 300;
} }

View File

@ -1495,13 +1495,6 @@ void GpioInit(void)
} }
SetModuleType(); SetModuleType();
TasmotaGlobal.module_changed = (Settings.module != Settings.last_module);
if (TasmotaGlobal.module_changed) {
Settings.baudrate = APP_BAUDRATE / 300;
Settings.serial_config = TS_SERIAL_8N1;
SetSerialBegin();
}
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("DBG: Used GPIOs %d"), GPIO_SENSOR_END); // AddLog_P(LOG_LEVEL_DEBUG, PSTR("DBG: Used GPIOs %d"), GPIO_SENSOR_END);
#ifdef ESP8266 #ifdef ESP8266

View File

@ -163,7 +163,7 @@ void WiFiSetSleepMode(void)
void WifiBegin(uint8_t flag, uint8_t channel) void WifiBegin(uint8_t flag, uint8_t channel)
{ {
const char kWifiPhyMode[] = " BGN"; const char kWifiPhyMode[] = " bgnl";
#ifdef USE_EMULATION #ifdef USE_EMULATION
UdpDisconnect(); UdpDisconnect();

View File

@ -193,6 +193,7 @@ void setup(void) {
memset(&TasmotaGlobal, 0, sizeof(TasmotaGlobal)); memset(&TasmotaGlobal, 0, sizeof(TasmotaGlobal));
TasmotaGlobal.baudrate = APP_BAUDRATE; TasmotaGlobal.baudrate = APP_BAUDRATE;
TasmotaGlobal.seriallog_timer = SERIALLOG_TIMER;
TasmotaGlobal.temperature_celsius = NAN; TasmotaGlobal.temperature_celsius = NAN;
TasmotaGlobal.blinks = 201; TasmotaGlobal.blinks = 201;
TasmotaGlobal.wifi_state_flag = WIFI_RESTART; TasmotaGlobal.wifi_state_flag = WIFI_RESTART;
@ -215,29 +216,34 @@ void setup(void) {
#endif #endif
RtcRebootSave(); RtcRebootSave();
if (RtcSettingsLoad()) {
uint32_t baudrate = (RtcSettings.baudrate / 300) * 300; // Make it a valid baudrate
if (baudrate) { TasmotaGlobal.baudrate = baudrate; }
}
Serial.begin(TasmotaGlobal.baudrate); Serial.begin(TasmotaGlobal.baudrate);
Serial.println();
// Serial.setRxBufferSize(INPUT_BUFFER_SIZE); // Default is 256 chars // Serial.setRxBufferSize(INPUT_BUFFER_SIZE); // Default is 256 chars
TasmotaGlobal.seriallog_level = LOG_LEVEL_INFO; // Allow specific serial messages until config loaded TasmotaGlobal.seriallog_level = LOG_LEVEL_INFO; // Allow specific serial messages until config loaded
snprintf_P(TasmotaGlobal.version, sizeof(TasmotaGlobal.version), PSTR("%d.%d.%d"), VERSION >> 24 & 0xff, VERSION >> 16 & 0xff, VERSION >> 8 & 0xff); // Release version 6.3.0
if (VERSION & 0xff) { // Development or patched version 6.3.0.10
snprintf_P(TasmotaGlobal.version, sizeof(TasmotaGlobal.version), PSTR("%s.%d"), TasmotaGlobal.version, VERSION & 0xff);
}
// Thehackbox inserts "release" or "commit number" before compiling using sed -i -e 's/PSTR("(%s)")/PSTR("(85cff52-%s)")/g' tasmota.ino
snprintf_P(TasmotaGlobal.image_name, sizeof(TasmotaGlobal.image_name), PSTR("(%s)"), CODE_IMAGE_STR); // Results in (85cff52-tasmota) or (release-tasmota)
SettingsLoad(); SettingsLoad();
SettingsDelta(); SettingsDelta();
OsWatchInit(); OsWatchInit();
if (1 == RtcReboot.fast_reboot_count) { // Allow setting override only when all is well TasmotaGlobal.seriallog_level = Settings.seriallog_level;
TasmotaGlobal.syslog_level = Settings.syslog_level;
TasmotaGlobal.module_changed = (Settings.module != Settings.last_module);
if (TasmotaGlobal.module_changed) {
Settings.baudrate = APP_BAUDRATE / 300;
Settings.serial_config = TS_SERIAL_8N1;
}
SetSerialBaudrate(Settings.baudrate * 300); // Reset serial interface if current baudrate is different from requested baudrate
if (1 == RtcReboot.fast_reboot_count) { // Allow setting override only when all is well
UpdateQuickPowerCycle(true); UpdateQuickPowerCycle(true);
} }
TasmotaGlobal.seriallog_level = Settings.seriallog_level;
TasmotaGlobal.seriallog_timer = SERIALLOG_TIMER;
TasmotaGlobal.syslog_level = Settings.syslog_level;
TasmotaGlobal.stop_flash_rotate = Settings.flag.stop_flash_rotate; // SetOption12 - Switch between dynamic or fixed slot flash save location TasmotaGlobal.stop_flash_rotate = Settings.flag.stop_flash_rotate; // SetOption12 - Switch between dynamic or fixed slot flash save location
TasmotaGlobal.save_data_counter = Settings.save_data; TasmotaGlobal.save_data_counter = Settings.save_data;
TasmotaGlobal.sleep = Settings.sleep; TasmotaGlobal.sleep = Settings.sleep;
@ -281,6 +287,13 @@ void setup(void) {
} }
} }
snprintf_P(TasmotaGlobal.version, sizeof(TasmotaGlobal.version), PSTR("%d.%d.%d"), VERSION >> 24 & 0xff, VERSION >> 16 & 0xff, VERSION >> 8 & 0xff); // Release version 6.3.0
if (VERSION & 0xff) { // Development or patched version 6.3.0.10
snprintf_P(TasmotaGlobal.version, sizeof(TasmotaGlobal.version), PSTR("%s.%d"), TasmotaGlobal.version, VERSION & 0xff);
}
// Thehackbox inserts "release" or "commit number" before compiling using sed -i -e 's/PSTR("(%s)")/PSTR("(85cff52-%s)")/g' tasmota.ino
snprintf_P(TasmotaGlobal.image_name, sizeof(TasmotaGlobal.image_name), PSTR("(%s)"), CODE_IMAGE_STR); // Results in (85cff52-tasmota) or (release-tasmota)
Format(TasmotaGlobal.mqtt_client, SettingsText(SET_MQTT_CLIENT), sizeof(TasmotaGlobal.mqtt_client)); Format(TasmotaGlobal.mqtt_client, SettingsText(SET_MQTT_CLIENT), sizeof(TasmotaGlobal.mqtt_client));
Format(TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_TOPIC), sizeof(TasmotaGlobal.mqtt_topic)); Format(TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_TOPIC), sizeof(TasmotaGlobal.mqtt_topic));
if (strchr(SettingsText(SET_HOSTNAME), '%') != nullptr) { if (strchr(SettingsText(SET_HOSTNAME), '%') != nullptr) {
@ -293,8 +306,6 @@ void setup(void) {
GetEspHardwareType(); GetEspHardwareType();
GpioInit(); GpioInit();
// SetSerialBaudrate(Settings.baudrate * 300); // Allow reset of serial interface if current baudrate is different from requested baudrate
WifiConnect(); WifiConnect();
SetPowerOnState(); SetPowerOnState();

View File

@ -85,6 +85,66 @@ static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = {
} }
}; };
/*********************************************************************************************\
* LetsEncrypt R3 certificate, RSA 2048 bits SHA 256, valid until 20250915
*
* https://letsencrypt.org/certificates/
* Downloaded from https://letsencrypt.org/certs/lets-encrypt-r3.pem
*
* to convert do: `bearssl ta lets-encrypt-r3.pem`
* then copy and paste below, chain the generic names to the same as below
* remove "static" and add "PROGMEM"
\*********************************************************************************************/
static const unsigned char PROGMEM LetsEncryptR3_DN[] = {
0x30, 0x32, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x0D, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72,
0x79, 0x70, 0x74, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x03,
0x13, 0x02, 0x52, 0x33
};
static const unsigned char PROGMEM LetsEncryptR3_RSA_N[] = {
0xBB, 0x02, 0x15, 0x28, 0xCC, 0xF6, 0xA0, 0x94, 0xD3, 0x0F, 0x12, 0xEC,
0x8D, 0x55, 0x92, 0xC3, 0xF8, 0x82, 0xF1, 0x99, 0xA6, 0x7A, 0x42, 0x88,
0xA7, 0x5D, 0x26, 0xAA, 0xB5, 0x2B, 0xB9, 0xC5, 0x4C, 0xB1, 0xAF, 0x8E,
0x6B, 0xF9, 0x75, 0xC8, 0xA3, 0xD7, 0x0F, 0x47, 0x94, 0x14, 0x55, 0x35,
0x57, 0x8C, 0x9E, 0xA8, 0xA2, 0x39, 0x19, 0xF5, 0x82, 0x3C, 0x42, 0xA9,
0x4E, 0x6E, 0xF5, 0x3B, 0xC3, 0x2E, 0xDB, 0x8D, 0xC0, 0xB0, 0x5C, 0xF3,
0x59, 0x38, 0xE7, 0xED, 0xCF, 0x69, 0xF0, 0x5A, 0x0B, 0x1B, 0xBE, 0xC0,
0x94, 0x24, 0x25, 0x87, 0xFA, 0x37, 0x71, 0xB3, 0x13, 0xE7, 0x1C, 0xAC,
0xE1, 0x9B, 0xEF, 0xDB, 0xE4, 0x3B, 0x45, 0x52, 0x45, 0x96, 0xA9, 0xC1,
0x53, 0xCE, 0x34, 0xC8, 0x52, 0xEE, 0xB5, 0xAE, 0xED, 0x8F, 0xDE, 0x60,
0x70, 0xE2, 0xA5, 0x54, 0xAB, 0xB6, 0x6D, 0x0E, 0x97, 0xA5, 0x40, 0x34,
0x6B, 0x2B, 0xD3, 0xBC, 0x66, 0xEB, 0x66, 0x34, 0x7C, 0xFA, 0x6B, 0x8B,
0x8F, 0x57, 0x29, 0x99, 0xF8, 0x30, 0x17, 0x5D, 0xBA, 0x72, 0x6F, 0xFB,
0x81, 0xC5, 0xAD, 0xD2, 0x86, 0x58, 0x3D, 0x17, 0xC7, 0xE7, 0x09, 0xBB,
0xF1, 0x2B, 0xF7, 0x86, 0xDC, 0xC1, 0xDA, 0x71, 0x5D, 0xD4, 0x46, 0xE3,
0xCC, 0xAD, 0x25, 0xC1, 0x88, 0xBC, 0x60, 0x67, 0x75, 0x66, 0xB3, 0xF1,
0x18, 0xF7, 0xA2, 0x5C, 0xE6, 0x53, 0xFF, 0x3A, 0x88, 0xB6, 0x47, 0xA5,
0xFF, 0x13, 0x18, 0xEA, 0x98, 0x09, 0x77, 0x3F, 0x9D, 0x53, 0xF9, 0xCF,
0x01, 0xE5, 0xF5, 0xA6, 0x70, 0x17, 0x14, 0xAF, 0x63, 0xA4, 0xFF, 0x99,
0xB3, 0x93, 0x9D, 0xDC, 0x53, 0xA7, 0x06, 0xFE, 0x48, 0x85, 0x1D, 0xA1,
0x69, 0xAE, 0x25, 0x75, 0xBB, 0x13, 0xCC, 0x52, 0x03, 0xF5, 0xED, 0x51,
0xA1, 0x8B, 0xDB, 0x15
};
static const unsigned char LetsEncryptR3_RSA_E[] = {
0x01, 0x00, 0x01
};
static const br_x509_trust_anchor PROGMEM LetsEncryptR3_TA = {
{ (unsigned char *)LetsEncryptR3_DN, sizeof LetsEncryptR3_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ .rsa = {
(unsigned char *)LetsEncryptR3_RSA_N, sizeof LetsEncryptR3_RSA_N,
(unsigned char *)LetsEncryptR3_RSA_E, sizeof LetsEncryptR3_RSA_E,
} }
}
};
/*********************************************************************************************\ /*********************************************************************************************\
* Amazon Root CA, RSA 2048 bits SHA 256, valid until 20380117 * Amazon Root CA, RSA 2048 bits SHA 256, valid until 20380117
* *
@ -160,6 +220,18 @@ const br_x509_trust_anchor PROGMEM Tasmota_TA[] = {
} }
} }
, ,
{
{ (unsigned char *)LetsEncryptR3_DN, sizeof LetsEncryptR3_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ .rsa = {
(unsigned char *)LetsEncryptR3_RSA_N, sizeof LetsEncryptR3_RSA_N,
(unsigned char *)LetsEncryptR3_RSA_E, sizeof LetsEncryptR3_RSA_E,
} }
}
}
,
{ {
{ (unsigned char *)AmazonRootCA1_DN, sizeof AmazonRootCA1_DN }, { (unsigned char *)AmazonRootCA1_DN, sizeof AmazonRootCA1_DN },
BR_X509_TA_CA, BR_X509_TA_CA,

View File

@ -817,8 +817,8 @@ ESP8266WebServer *Webserver;
struct WEB { struct WEB {
String chunk_buffer = ""; // Could be max 2 * CHUNKED_BUFFER_SIZE String chunk_buffer = ""; // Could be max 2 * CHUNKED_BUFFER_SIZE
uint16_t upload_progress_dot_count; uint16_t upload_progress_dot_count;
uint16_t upload_error = 0;
uint8_t state = HTTP_OFF; uint8_t state = HTTP_OFF;
uint8_t upload_error = 0;
uint8_t upload_file_type; uint8_t upload_file_type;
uint8_t config_block_count = 0; uint8_t config_block_count = 0;
uint8_t config_xor_on = 0; uint8_t config_xor_on = 0;
@ -2946,8 +2946,8 @@ void HandleUploadLoop(void)
} }
#endif // USE_ZIGBEE_EZSP #endif // USE_ZIGBEE_EZSP
if (error != 0) { if (error != 0) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Transfer error %d"), error); // AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Transfer error %d"), error);
Web.upload_error = 8; // File invalid Web.upload_error = error + (100 * Web.upload_file_type); // Add offset to discriminate transfer errors
return; return;
} }
} }

View File

@ -117,7 +117,7 @@ void CmndRfProtocol(void) {
} }
} else { } else {
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
if ('a' == XdrvMailbox.data[0]) { if ('A' == toupper(XdrvMailbox.data[0])) {
Settings.rf_protocol_mask = (1ULL << mySwitch.getNumProtos()) -1; Settings.rf_protocol_mask = (1ULL << mySwitch.getNumProtos()) -1;
} else { } else {
thisdat = strtoull(XdrvMailbox.data, nullptr, 0); thisdat = strtoull(XdrvMailbox.data, nullptr, 0);

View File

@ -166,6 +166,10 @@ public:
void setBuf(const SBuffer &buf, size_t index, size_t len); void setBuf(const SBuffer &buf, size_t index, size_t len);
// specific formatters
void setHex32(uint32_t _val);
void setHex64(uint64_t _val);
// set the string value // set the string value
// PMEM argument is allowed // PMEM argument is allowed
// string will be copied, so it can be changed later // string will be copied, so it can be changed later
@ -388,6 +392,19 @@ void Z_attribute::setBuf(const SBuffer &buf, size_t index, size_t len) {
type = Za_type::Za_raw; type = Za_type::Za_raw;
} }
void Z_attribute::setHex32(uint32_t _val) {
char hex[8];
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), _val);
setStr(hex);
}
void Z_attribute::setHex64(uint64_t _val) {
char hex[22];
hex[0] = '0'; // prefix with '0x'
hex[1] = 'x';
Uint64toHex(_val, &hex[2], 64);
setStr(hex);
}
// set the string value // set the string value
// PMEM argument is allowed // PMEM argument is allowed
// string will be copied, so it can be changed later // string will be copied, so it can be changed later

View File

@ -912,6 +912,7 @@ public:
// Dump json // Dump json
String dumpDevice(uint32_t dump_mode, const Z_Device & device) const; String dumpDevice(uint32_t dump_mode, const Z_Device & device) const;
String dumpCoordinator(void) const;
int32_t deviceRestore(JsonParserObject json); int32_t deviceRestore(JsonParserObject json);
// Hue support // Hue support
@ -950,7 +951,7 @@ public:
void clean(void); // avoid writing to flash the last changes void clean(void); // avoid writing to flash the last changes
// Find device by name, can be short_addr, long_addr, number_in_array or name // Find device by name, can be short_addr, long_addr, number_in_array or name
Z_Device & parseDeviceFromName(const char * param, bool short_must_be_known = false); Z_Device & parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr = nullptr);
bool isTuyaProtocol(uint16_t shortaddr, uint8_t ep = 0) const; bool isTuyaProtocol(uint16_t shortaddr, uint8_t ep = 0) const;

View File

@ -588,12 +588,15 @@ void Z_Devices::clean(void) {
// - a long address starting with "0x", example: 0x7CB03EBB0A0292DD // - a long address starting with "0x", example: 0x7CB03EBB0A0292DD
// - a number 0..99, the index number in ZigbeeStatus // - a number 0..99, the index number in ZigbeeStatus
// - a friendly name, between quotes, example: "Room_Temp" // - a friendly name, between quotes, example: "Room_Temp"
Z_Device & Z_Devices::parseDeviceFromName(const char * param, bool short_must_be_known) { //
// In case the device is not found, the parsed 0x.... short address is passed to *parsed_shortaddr
Z_Device & Z_Devices::parseDeviceFromName(const char * param, uint16_t * parsed_shortaddr) {
if (nullptr == param) { return device_unk; } if (nullptr == param) { return device_unk; }
size_t param_len = strlen(param); size_t param_len = strlen(param);
char dataBuf[param_len + 1]; char dataBuf[param_len + 1];
strcpy(dataBuf, param); strcpy(dataBuf, param);
RemoveSpace(dataBuf); RemoveSpace(dataBuf);
if (parsed_shortaddr != nullptr) { *parsed_shortaddr = BAD_SHORTADDR; } // if it goes wrong, mark as bad
if ((dataBuf[0] >= '0') && (dataBuf[0] <= '9') && (strlen(dataBuf) < 4)) { if ((dataBuf[0] >= '0') && (dataBuf[0] <= '9') && (strlen(dataBuf) < 4)) {
// simple number 0..99 // simple number 0..99
@ -607,11 +610,8 @@ Z_Device & Z_Devices::parseDeviceFromName(const char * param, bool short_must_be
if (strlen(dataBuf) < 18) { if (strlen(dataBuf) < 18) {
// expect a short address // expect a short address
uint16_t shortaddr = strtoull(dataBuf, nullptr, 0); uint16_t shortaddr = strtoull(dataBuf, nullptr, 0);
if (short_must_be_known) { if (parsed_shortaddr != nullptr) { *parsed_shortaddr = shortaddr; } // return the parsed shortaddr even if the device doesn't exist
return (Z_Device&) findShortAddr(shortaddr); // if not found, it reverts to the unknown_device with address BAD_SHORTADDR return (Z_Device&) findShortAddr(shortaddr); // if not found, it reverts to the unknown_device with address BAD_SHORTADDR
} else {
return getShortAddr(shortaddr); // create it if not registered
}
} else { } else {
// expect a long address // expect a long address
uint64_t longaddr = strtoull(dataBuf, nullptr, 0); uint64_t longaddr = strtoull(dataBuf, nullptr, 0);
@ -632,12 +632,10 @@ Z_Device & Z_Devices::parseDeviceFromName(const char * param, bool short_must_be
// Add "Device":"0x1234","Name":"FrienflyName" // Add "Device":"0x1234","Name":"FrienflyName"
void Z_Device::jsonAddDeviceNamme(Z_attribute_list & attr_list) const { void Z_Device::jsonAddDeviceNamme(Z_attribute_list & attr_list) const {
char hex[8];
const char * fname = friendlyName; const char * fname = friendlyName;
bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); // should we replace shortaddr with friendlyname? bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); // should we replace shortaddr with friendlyname?
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), shortaddr);
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_DEVICE)).setStr(hex); attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_DEVICE)).setHex32(shortaddr);
if (fname) { if (fname) {
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_NAME)).setStr(fname); attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_NAME)).setStr(fname);
} }
@ -645,11 +643,7 @@ void Z_Device::jsonAddDeviceNamme(Z_attribute_list & attr_list) const {
// Add "IEEEAddr":"0x1234567812345678" // Add "IEEEAddr":"0x1234567812345678"
void Z_Device::jsonAddIEEE(Z_attribute_list & attr_list) const { void Z_Device::jsonAddIEEE(Z_attribute_list & attr_list) const {
char hex[22]; attr_list.addAttributePMEM(PSTR("IEEEAddr")).setHex64(longaddr);
hex[0] = '0'; // prefix with '0x'
hex[1] = 'x';
Uint64toHex(longaddr, &hex[2], 64);
attr_list.addAttributePMEM(PSTR("IEEEAddr")).setStr(hex);
} }
// Add "ModelId":"","Manufacturer":"" // Add "ModelId":"","Manufacturer":""
void Z_Device::jsonAddModelManuf(Z_attribute_list & attr_list) const { void Z_Device::jsonAddModelManuf(Z_attribute_list & attr_list) const {
@ -751,6 +745,17 @@ void Z_Device::jsonDumpSingleDevice(Z_attribute_list & attr_list, uint32_t dump_
} }
} }
// Dump coordinator specific data
String Z_Devices::dumpCoordinator(void) const {
Z_attribute_list attr_list;
attr_list.addAttributePMEM(PSTR(D_JSON_ZIGBEE_DEVICE)).setHex32(localShortAddr);
attr_list.addAttributePMEM(PSTR("IEEEAddr")).setHex64(localIEEEAddr);
attr_list.addAttributePMEM(PSTR("TotalDevices")).setUInt(zigbee_devices.devicesSize());
return attr_list.toString();
}
// If &device == nullptr, then dump all // If &device == nullptr, then dump all
String Z_Devices::dumpDevice(uint32_t dump_mode, const Z_Device & device) const { String Z_Devices::dumpDevice(uint32_t dump_mode, const Z_Device & device) const {
JsonGeneratorArray json_arr; JsonGeneratorArray json_arr;

View File

@ -2063,8 +2063,8 @@ void Z_Data::toAttributes(Z_attribute_list & attr_list) const {
case Zenum16: case Zenum16:
case Zuint16: uval32 = *(uint16_t*)attr_address; if (uval32 != 0x0000FFFF) data_size = 16; break; case Zuint16: uval32 = *(uint16_t*)attr_address; if (uval32 != 0x0000FFFF) data_size = 16; break;
case Zuint32: uval32 = *(uint32_t*)attr_address; if (uval32 != 0xFFFFFFFF) data_size = 32; break; case Zuint32: uval32 = *(uint32_t*)attr_address; if (uval32 != 0xFFFFFFFF) data_size = 32; break;
case Zint8: ival32 = *(int8_t*)attr_address; if (ival32 != -0xFFFFFF80) data_size = -8; break; case Zint8: ival32 = *(int8_t*)attr_address; if (ival32 != -0x80) data_size = -8; break;
case Zint16: ival32 = *(int16_t*)attr_address; if (ival32 != -0xFFFF8000) data_size = -16; break; case Zint16: ival32 = *(int16_t*)attr_address; if (ival32 != -0x8000) data_size = -16; break;
case Zint32: ival32 = *(int32_t*)attr_address; if (ival32 != -0x80000000) data_size = -32; break; case Zint32: ival32 = *(int32_t*)attr_address; if (ival32 != -0x80000000) data_size = -32; break;
} }
if (data_size != 0) { if (data_size != 0) {

View File

@ -479,10 +479,12 @@ void parseSingleTuyaAttribute(Z_attribute & attr, const SBuffer &buf,
attr.setUInt(buf.get32BigEndian(i)); attr.setUInt(buf.get32BigEndian(i));
break; break;
case 0x03: // String (we expect it is not ended with \00) case 0x03: // String (we expect it is not ended with \00)
{
char str[len+1]; char str[len+1];
strncpy(str, buf.charptr(i), len); strncpy(str, buf.charptr(i), len);
str[len] = 0x00; str[len] = 0x00;
attr.setStr(str); attr.setStr(str);
}
break; break;
case 0x05: // enum in 1/2/4 bytes, Big Endian case 0x05: // enum in 1/2/4 bytes, Big Endian
if (1 == len) { if (1 == len) {

View File

@ -734,7 +734,7 @@ void CmndZbSend(void) {
// parse "Device" and "Group" // parse "Device" and "Group"
JsonParserToken val_device = root[PSTR(D_CMND_ZIGBEE_DEVICE)]; JsonParserToken val_device = root[PSTR(D_CMND_ZIGBEE_DEVICE)];
if (val_device) { if (val_device) {
device = zigbee_devices.parseDeviceFromName(val_device.getStr(), true).shortaddr; device = zigbee_devices.parseDeviceFromName(val_device.getStr()).shortaddr;
if (BAD_SHORTADDR == device) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; } if (BAD_SHORTADDR == device) { ResponseCmndChar_P(PSTR("Invalid parameter")); return; }
} }
if (BAD_SHORTADDR == device) { // if not found, check if we have a group if (BAD_SHORTADDR == device) { // if not found, check if we have a group
@ -877,7 +877,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
// Information about source device: "Device", "Endpoint", "Cluster" // Information about source device: "Device", "Endpoint", "Cluster"
// - the source endpoint must have a known IEEE address // - the source endpoint must have a known IEEE address
const Z_Device & src_device = zigbee_devices.parseDeviceFromName(root.getStr(PSTR(D_CMND_ZIGBEE_DEVICE), nullptr), true); const Z_Device & src_device = zigbee_devices.parseDeviceFromName(root.getStr(PSTR(D_CMND_ZIGBEE_DEVICE), nullptr));
if (!src_device.valid()) { ResponseCmndChar_P(PSTR("Unknown source device")); return; } if (!src_device.valid()) { ResponseCmndChar_P(PSTR("Unknown source device")); return; }
// check if IEEE address is known // check if IEEE address is known
uint64_t srcLongAddr = src_device.longaddr; uint64_t srcLongAddr = src_device.longaddr;
@ -912,7 +912,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
} }
if (dst_device) { if (dst_device) {
const Z_Device & dstDevice = zigbee_devices.parseDeviceFromName(dst_device.getStr(nullptr), true); const Z_Device & dstDevice = zigbee_devices.parseDeviceFromName(dst_device.getStr(nullptr));
if (!dstDevice.valid()) { ResponseCmndChar_P(PSTR("Unknown dest device")); return; } if (!dstDevice.valid()) { ResponseCmndChar_P(PSTR("Unknown dest device")); return; }
dstLongAddr = dstDevice.longaddr; dstLongAddr = dstDevice.longaddr;
} }
@ -990,7 +990,7 @@ void CmndZbUnbind(void) {
// //
void CmndZbLeave(void) { void CmndZbLeave(void) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true).shortaddr; uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data).shortaddr;
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
#ifdef USE_ZIGBEE_ZNP #ifdef USE_ZIGBEE_ZNP
@ -1019,11 +1019,26 @@ void CmndZbLeave(void) {
void CmndZbBindState_or_Map(uint16_t zdo_cmd) { void CmndZbBindState_or_Map(bool map) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true).shortaddr; uint16_t parsed_shortaddr;;
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, &parsed_shortaddr).shortaddr;
if (BAD_SHORTADDR == shortaddr) {
if ((map) && (parsed_shortaddr != shortaddr)) {
shortaddr = parsed_shortaddr; // allow a non-existent address when ZbMap
} else {
ResponseCmndChar_P(PSTR("Unknown device"));
return;
}
}
uint8_t index = XdrvMailbox.index - 1; // change default 1 to 0 uint8_t index = XdrvMailbox.index - 1; // change default 1 to 0
uint16_t zdo_cmd;
#ifdef USE_ZIGBEE_ZNP
zdo_cmd = map ? ZDO_MGMT_LQI_REQ : ZDO_MGMT_BIND_REQ;
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
zdo_cmd = map ? ZDO_Mgmt_Lqi_req : ZDO_Mgmt_Bind_req;
#endif // USE_ZIGBEE_EZSP
Z_Send_State_or_Map(shortaddr, index, zdo_cmd); Z_Send_State_or_Map(shortaddr, index, zdo_cmd);
ResponseCmndDone(); ResponseCmndDone();
@ -1034,12 +1049,7 @@ void CmndZbBindState_or_Map(uint16_t zdo_cmd) {
// `ZbBindState<x>` as index if it does not fit. If default, `1` starts at the beginning // `ZbBindState<x>` as index if it does not fit. If default, `1` starts at the beginning
// //
void CmndZbBindState(void) { void CmndZbBindState(void) {
#ifdef USE_ZIGBEE_ZNP CmndZbBindState_or_Map(false);
CmndZbBindState_or_Map(ZDO_MGMT_BIND_REQ);
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
CmndZbBindState_or_Map(ZDO_Mgmt_Bind_req);
#endif // USE_ZIGBEE_EZSP
} }
// //
@ -1062,12 +1072,7 @@ void CmndZbMap(void) {
zigbee_devices.setTimer(BAD_SHORTADDR, 0, wait_ms, 0, 0, Z_CAT_ALWAYS, 0 /* value = index */, &Z_Map); zigbee_devices.setTimer(BAD_SHORTADDR, 0, wait_ms, 0, 0, Z_CAT_ALWAYS, 0 /* value = index */, &Z_Map);
ResponseCmndDone(); ResponseCmndDone();
} else { } else {
#ifdef USE_ZIGBEE_ZNP CmndZbBindState_or_Map(true);
CmndZbBindState_or_Map(ZDO_MGMT_LQI_REQ);
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
CmndZbBindState_or_Map(ZDO_Mgmt_Lqi_req);
#endif // USE_ZIGBEE_EZSP
} }
} }
@ -1081,7 +1086,7 @@ void CmndZbProbe(void) {
// //
void CmndZbProbeOrPing(boolean probe) { void CmndZbProbeOrPing(boolean probe) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true).shortaddr; uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data).shortaddr;
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
// set a timer for Reachable - 2s default value // set a timer for Reachable - 2s default value
@ -1119,7 +1124,7 @@ void CmndZbName(void) {
strtok_r(XdrvMailbox.data, ",", &p); strtok_r(XdrvMailbox.data, ",", &p);
// parse first part, <device_id> // parse first part, <device_id>
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, false); // it's the only case where we create a new device Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // it's the only case where we create a new device
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; } if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
if (p == nullptr) { if (p == nullptr) {
@ -1151,7 +1156,7 @@ void CmndZbModelId(void) {
strtok_r(XdrvMailbox.data, ",", &p); strtok_r(XdrvMailbox.data, ",", &p);
// parse first part, <device_id> // parse first part, <device_id>
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; } if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
if (p != nullptr) { if (p != nullptr) {
@ -1178,7 +1183,7 @@ void CmndZbLight(void) {
strtok_r(XdrvMailbox.data, ", ", &p); strtok_r(XdrvMailbox.data, ", ", &p);
// parse first part, <device_id> // parse first part, <device_id>
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; } if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
if (p) { if (p) {
@ -1222,7 +1227,7 @@ void CmndZbOccupancy(void) {
strtok_r(XdrvMailbox.data, ", ", &p); strtok_r(XdrvMailbox.data, ", ", &p);
// parse first part, <device_id> // parse first part, <device_id>
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; } if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
int8_t occupancy_time = -1; int8_t occupancy_time = -1;
@ -1249,7 +1254,7 @@ void CmndZbOccupancy(void) {
// //
void CmndZbForget(void) { void CmndZbForget(void) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; } if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
// everything is good, we can send the command // everything is good, we can send the command
@ -1264,16 +1269,30 @@ void CmndZbForget(void) {
// Command `ZbInfo` // Command `ZbInfo`
// Display all information known about a device, this equivalent to `2bStatus3` with a simpler JSON output // Display all information known about a device, this equivalent to `2bStatus3` with a simpler JSON output
// //
void CmndZbInfo_inner(const Z_Device & device) {
Z_attribute_list attr_list;
device.jsonDumpSingleDevice(attr_list, 3, false); // don't add Device/Name
device.jsonPublishAttrList(PSTR(D_JSON_ZIGBEE_INFO), attr_list); // publish as ZbReceived
}
void CmndZbInfo(void) { void CmndZbInfo(void) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered RemoveSpace(XdrvMailbox.data);
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
// everything is good, we can send the command if (strlen(XdrvMailbox.data) == 0) {
// if empty, dump for all values
for (const auto & device : zigbee_devices.getDevices()) {
CmndZbInfo_inner(device);
}
} else { // try JSON
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
Z_attribute_list attr_list; // everything is good, we can send the command
device.jsonDumpSingleDevice(attr_list, 3, false); // don't add Device/Name
device.jsonPublishAttrList(PSTR(D_JSON_ZIGBEE_INFO), attr_list); // publish as ZbReceived Z_attribute_list attr_list;
device.jsonDumpSingleDevice(attr_list, 3, false); // don't add Device/Name
device.jsonPublishAttrList(PSTR(D_JSON_ZIGBEE_INFO), attr_list); // publish as ZbReceived
}
ResponseCmndDone(); ResponseCmndDone();
} }
@ -1502,13 +1521,17 @@ void CmndZbStatus(void) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
String dump; String dump;
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); if (0 == XdrvMailbox.index) {
if (XdrvMailbox.data_len > 0) { dump = zigbee_devices.dumpCoordinator();
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
dump = zigbee_devices.dumpDevice(XdrvMailbox.index, device);
} else { } else {
if (XdrvMailbox.index >= 2) { ResponseCmndChar_P(PSTR("Unknown device")); return; } Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data);
dump = zigbee_devices.dumpDevice(XdrvMailbox.index, *(Z_Device*)nullptr); if (XdrvMailbox.data_len > 0) {
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
dump = zigbee_devices.dumpDevice(XdrvMailbox.index, device);
} else {
if (XdrvMailbox.index >= 2) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
dump = zigbee_devices.dumpDevice(XdrvMailbox.index, *(Z_Device*)nullptr);
}
} }
Response_P(PSTR("{\"%s%d\":%s}"), XdrvMailbox.command, XdrvMailbox.index, dump.c_str()); Response_P(PSTR("{\"%s%d\":%s}"), XdrvMailbox.command, XdrvMailbox.index, dump.c_str());
@ -1533,7 +1556,7 @@ void CmndZbData(void) {
strtok_r(XdrvMailbox.data, ",", &p); strtok_r(XdrvMailbox.data, ",", &p);
// parse first part, <device_id> // parse first part, <device_id>
Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, true); // in case of short_addr, it must be already registered Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data); // in case of short_addr, it must be already registered
if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; } if (!device.valid()) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
if (p) { if (p) {

View File

@ -304,22 +304,15 @@ void Ws2812Gradient(uint32_t schemenr)
WsColor oldColor, currentColor; WsColor oldColor, currentColor;
Ws2812GradientColor(schemenr, &oldColor, range, gradRange, offset); Ws2812GradientColor(schemenr, &oldColor, range, gradRange, offset);
currentColor = oldColor; currentColor = oldColor;
speed = speed ? speed : 1; // should never happen, just avoid div0
for (uint32_t i = 0; i < Settings.light_pixels; i++) { for (uint32_t i = 0; i < Settings.light_pixels; i++) {
if (kWsRepeat[Settings.light_width] > 1) { if (kWsRepeat[Settings.light_width] > 1) {
Ws2812GradientColor(schemenr, &currentColor, range, gradRange, i +offset); Ws2812GradientColor(schemenr, &currentColor, range, gradRange, i + offset + 1);
}
if (Settings.light_speed > 0) {
// Blend old and current color based on time for smooth movement.
c.R = map(Light.strip_timer_counter % speed, 0, speed, oldColor.red, currentColor.red);
c.G = map(Light.strip_timer_counter % speed, 0, speed, oldColor.green, currentColor.green);
c.B = map(Light.strip_timer_counter % speed, 0, speed, oldColor.blue, currentColor.blue);
}
else {
// No animation, just use the current color.
c.R = currentColor.red;
c.G = currentColor.green;
c.B = currentColor.blue;
} }
// Blend old and current color based on time for smooth movement.
c.R = map(Light.strip_timer_counter % speed, 0, speed, oldColor.red, currentColor.red);
c.G = map(Light.strip_timer_counter % speed, 0, speed, oldColor.green, currentColor.green);
c.B = map(Light.strip_timer_counter % speed, 0, speed, oldColor.blue, currentColor.blue);
strip->SetPixelColor(i, c); strip->SetPixelColor(i, c);
oldColor = currentColor; oldColor = currentColor;
} }
@ -586,4 +579,4 @@ bool Xlgt01(uint8_t function)
} }
#endif // USE_WS2812 #endif // USE_WS2812
#endif // USE_LIGHT #endif // USE_LIGHT