Merge branch 'development' into pre-release-9.1.0

This commit is contained in:
Theo Arends 2020-11-04 16:59:29 +01:00
commit 4f92d4984f
23 changed files with 386 additions and 122 deletions

View File

@ -22,8 +22,10 @@ All notable changes to this project will be documented in this file.
- Zigbee command ``ZbOccupancy`` to configure the time-out for PIR - Zigbee command ``ZbOccupancy`` to configure the time-out for PIR
- Command ``Gpios 255`` to show all possible GPIO configurations - Command ``Gpios 255`` to show all possible GPIO configurations
- Command ``SwitchText`` to change JSON switch names by barbudor (#9691) - Command ``SwitchText`` to change JSON switch names by barbudor (#9691)
- Command ``SetOption114 1`` to detach Swiches from Relays and enable MQTT action state for all the SwitchModes returning `{"Switch1":{"Action":"ON"}}` - Command ``SetOption114 1`` to detach Switches from Relays and enable MQTT action state for all the SwitchModes returning `{"Switch1":{"Action":"ON"}}`
- HM10 Beacon support and refactoring by Christian Baars (#9702) - HM10 Beacon support and refactoring by Christian Baars (#9702)
- Support for Hass discovery of TuyaMcu and Sonoff Ifan by Federico Leoni (#9727)
- Initial support for iBeacons (Sensor52) on ESP32 using internal BLE by rvbglas (#9732)
### Changed ### Changed
- PlatformIO library structure redesigned for compilation speed by Jason2866 - PlatformIO library structure redesigned for compilation speed by Jason2866
@ -36,6 +38,7 @@ All notable changes to this project will be documented in this file.
- Rule expressions using mems corrupts character pool (#9301) - Rule expressions using mems corrupts character pool (#9301)
- Button press rules regression introduced by #9589 (#9700) - Button press rules regression introduced by #9589 (#9700)
- Rule handling of JSON ``null`` regression from v8.5.0.1 (#9685) - Rule handling of JSON ``null`` regression from v8.5.0.1 (#9685)
- Arilux RF remote detection regression from v8.3.0
## [9.0.0.2] - 20201025 ## [9.0.0.2] - 20201025
### Added ### Added

View File

@ -21,7 +21,7 @@ In addition to the [release webpage](https://github.com/arendst/Tasmota/releases
## Development ## Development
[![Dev Version](https://img.shields.io/badge/development%20version-v9.0.x.x-blue.svg)](https://github.com/arendst/Tasmota) [![Dev Version](https://img.shields.io/badge/development%20version-v9.1.x.x-blue.svg)](https://github.com/arendst/Tasmota)
[![Download Dev](https://img.shields.io/badge/download-development-yellow.svg)](http://ota.tasmota.com/tasmota/) [![Download Dev](https://img.shields.io/badge/download-development-yellow.svg)](http://ota.tasmota.com/tasmota/)
[![Tasmota CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+CI%22) [![Tasmota CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+CI%22)
[![Tasmota ESP32 CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20ESP32%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+ESP32+CI%22) [![Tasmota ESP32 CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20ESP32%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+ESP32+CI%22)
@ -68,17 +68,17 @@ See [wiki migration path](https://tasmota.github.io/docs/Upgrading#migration-pat
1. Migrate to **Sonoff-Tasmota 3.9.x** 1. Migrate to **Sonoff-Tasmota 3.9.x**
2. Migrate to **Sonoff-Tasmota 4.x** 2. Migrate to **Sonoff-Tasmota 4.x**
3. Migrate to **Sonoff-Tasmota 5.14** 3. Migrate to **Sonoff-Tasmota 5.14**
4. Migrate to **Sonoff-Tasmota 6.x** 4. Migrate to **Sonoff-Tasmota 6.7.1**
5. Migrate to **Tasmota 7.x** 5. Migrate to **Tasmota 7.2.0**
--- Major change in parameter storage layout --- --- Major change in parameter storage layout ---
6. Migrate to **Tasmota 8.1** 6. Migrate to **Tasmota 8.1**
7. Migrate to **Tasmota 8.x** 7. Migrate to **Tasmota 8.5.1**
--- Major change in internal GPIO function representation --- --- Major change in internal GPIO function representation ---
8. Migrate to **Tasmota 9.x** 8. Migrate to **Tasmota 9.1**
While fallback or downgrading is common practice it was never supported due to Settings additions or changes in newer releases. Starting with version **v9.0.0.1** the internal GPIO function representation has changed in such a way that fallback is only possible to the latest GPIO configuration before installing **v9.0.0.1**. While fallback or downgrading is common practice it was never supported due to Settings additions or changes in newer releases. Starting with version **v9.0.0.1** the internal GPIO function representation has changed in such a way that fallback is only possible to the latest GPIO configuration before installing **v9.0.0.1**.

View File

@ -9,13 +9,13 @@ See [migration path](https://tasmota.github.io/docs/Upgrading#migration-path) fo
1. Migrate to **Sonoff-Tasmota 3.9.x** 1. Migrate to **Sonoff-Tasmota 3.9.x**
2. Migrate to **Sonoff-Tasmota 4.x** 2. Migrate to **Sonoff-Tasmota 4.x**
3. Migrate to **Sonoff-Tasmota 5.14** 3. Migrate to **Sonoff-Tasmota 5.14**
4. Migrate to **Sonoff-Tasmota 6.x** 4. Migrate to **Sonoff-Tasmota 6.7.1**
5. Migrate to **Tasmota 7.x** 5. Migrate to **Tasmota 7.2.0**
--- Major change in parameter storage layout --- --- Major change in parameter storage layout ---
6. Migrate to **Tasmota 8.1** 6. Migrate to **Tasmota 8.1**
7. Migrate to **Tasmota 8.x** 7. Migrate to **Tasmota 8.5.1**
--- Major change in internal GPIO function representation --- --- Major change in internal GPIO function representation ---
@ -64,7 +64,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- Command ``ShutterChange`` to increment change position (#9594) - Command ``ShutterChange`` to increment change position (#9594)
- Command ``SwitchMode 15`` sending only MQTT message on switch change (#9593) - Command ``SwitchMode 15`` sending only MQTT message on switch change (#9593)
- Command ``SetOption113 1`` to set dimmer low on rotary dial after power off - Command ``SetOption113 1`` to set dimmer low on rotary dial after power off
- Command ``SetOption114 1`` to detach Swiches from Relays and enable MQTT action state for all the SwitchModes - Command ``SetOption114 1`` to detach Switches from Relays and enable MQTT action state for all the SwitchModes
- Command ``SwitchText`` to change JSON switch names by barbudor (#9691) - Command ``SwitchText`` to change JSON switch names by barbudor (#9691)
- Zigbee command ``ZbData`` for better support of device specific data - Zigbee command ``ZbData`` for better support of device specific data
- Zigbee command ``ZbOccupancy`` to configure the time-out for PIR - Zigbee command ``ZbOccupancy`` to configure the time-out for PIR
@ -79,11 +79,13 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- Support for timers in case of no-sunset permanent day by cybermaus (#9543) - Support for timers in case of no-sunset permanent day by cybermaus (#9543)
- Support for EZO sensors by Christopher Tremblay - Support for EZO sensors by Christopher Tremblay
- Support for fixed output Hi or Lo GPIO selection - Support for fixed output Hi or Lo GPIO selection
- Support for Hass discovery of TuyaMcu and Sonoff Ifan by Federico Leoni (#9727)
- TLS in binary tasmota-zbbridge (#9620) - TLS in binary tasmota-zbbridge (#9620)
- Zigbee reduce battery drain (#9642) - Zigbee reduce battery drain (#9642)
- ESP32 support for Wireless-Tag WT32-ETH01 (#9496) - ESP32 support for Wireless-Tag WT32-ETH01 (#9496)
- ESP32 MI32 Beacon support, RSSI at TELEPERIOD, refactoring by Christian Baars (#9609) - ESP32 MI32 Beacon support, RSSI at TELEPERIOD, refactoring by Christian Baars (#9609)
- HM10 Beacon support and refactoring by Christian Baars (#9702) - HM10 Beacon support and refactoring by Christian Baars (#9702)
- Initial support for iBeacons (Sensor52) on ESP32 using internal BLE by rvbglas (#9732)
### Breaking Changed ### Breaking Changed
- Redesigned ESP8266 GPIO internal representation in line with ESP32 changing ``Template`` layout too - Redesigned ESP8266 GPIO internal representation in line with ESP32 changing ``Template`` layout too
@ -98,8 +100,6 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- New IR Raw compact format (#9444) - New IR Raw compact format (#9444)
- A4988 optional microstep pin selection - A4988 optional microstep pin selection
- Pulsetime to allow use for all relays with 8 interleaved so ``Pulsetime1`` is valid for Relay1, Relay9, Relay17 etc. (#9279) - Pulsetime to allow use for all relays with 8 interleaved so ``Pulsetime1`` is valid for Relay1, Relay9, Relay17 etc. (#9279)
- IRremoteESP8266 library from v2.7.10 to v2.7.11
- NeoPixelBus library from v2.5.0.09 to v2.6.0
- Management of serial baudrate (#9554) - Management of serial baudrate (#9554)
- Rotary driver adjusted accordingly if Mi Desk Lamp module is selected (#9399) - Rotary driver adjusted accordingly if Mi Desk Lamp module is selected (#9399)
- Tasmota Arduino Core v2.7.4.5 allowing webpassword over 47 characters (#9687) - Tasmota Arduino Core v2.7.4.5 allowing webpassword over 47 characters (#9687)
@ -107,26 +107,29 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- PlatformIO library structure redesigned for compilation speed by Jason2866 - PlatformIO library structure redesigned for compilation speed by Jason2866
- Zigbee flash storage refactor adding commands ``ZbProbe``, ``ZbStatus2`` and ``ZbRestore`` (#9641) - Zigbee flash storage refactor adding commands ``ZbProbe``, ``ZbStatus2`` and ``ZbRestore`` (#9641)
- Default otaurl in my_user_config.h to http://ota.tasmota.com/tasmota/release/tasmota.bin.gz - Default otaurl in my_user_config.h to http://ota.tasmota.com/tasmota/release/tasmota.bin.gz
- IRremoteESP8266 library from v2.7.10 to v2.7.11
- NeoPixelBus library from v2.5.0.09 to v2.6.0
### Fixed ### Fixed
- Ledlink blink when no network connected regression from v8.3.1.4 (#9292) - Light wakeup Exception 0 (divide by zero) when ``WakeupDuration`` is not initialised (#9466)
- Exception 28 due to device group buffer overflow (#9459) - Exception 28 due to device group buffer overflow (#9459)
- Shutter timing problem due to buffer overflow in calibration matrix (#9458) - Arilux RF remote detection regression from v8.3.0
- Light wakeup exception 0 (divide by zero) when ``WakeupDuration`` is not initialised (#9466) - Ledlink blink when no network connected regression from v8.3.1.4 (#9292)
- TuyaMcu energy display regression from v8.5.0.1 (#9547)
- Thermostat sensor status corruption regression from v8.5.0.1 (#9449) - Thermostat sensor status corruption regression from v8.5.0.1 (#9449)
- Telegram message decoding error regression from v8.5.0.1 - Telegram message decoding error regression from v8.5.0.1
- Rule handling of Var or Mem using text regression from v8.5.0.1 (#9540) - Rule handling of Var or Mem using text regression from v8.5.0.1 (#9540)
- Rule handling of JSON ``null`` regression from v8.5.0.1 (#9685) - Rule handling of JSON ``null`` regression from v8.5.0.1 (#9685)
- Rule Break not working as expected when ONCE is enabled (#9245)
- Rule expressions using mems corrupts character pool (#9301)
- Shutter timing problem due to buffer overflow in calibration matrix (#9458)
- Correct Energy period display shortly after midnight by gominoa (#9536) - Correct Energy period display shortly after midnight by gominoa (#9536)
- TuyaMcu energy display regression from v8.5.0.1 (#9547)
- Tuyamcu dimmers MQTT topic (#9606) - Tuyamcu dimmers MQTT topic (#9606)
- Scripter memory alignment (#9608) - Scripter memory alignment (#9608)
- Zigbee battery percentage (#9607) - Zigbee battery percentage (#9607)
- HassAnyKey anomaly (#9601) - HassAnyKey anomaly (#9601)
- Rule Break not working as expected when ONCE is enabled (#9245)
- Rule expressions using mems corrupts character pool (#9301)
### Removed ### Removed
- Support for direct upgrade from Tasmota versions before v7.0 - Support for direct upgrade from Tasmota versions before v7.0
- Auto config update for all Friendlynames and Switchtopic from Tasmota versions before v8.0
- Support for downgrade to versions before 9.0 keeping current GPIO configuration - Support for downgrade to versions before 9.0 keeping current GPIO configuration
- Auto config update for all Friendlynames and Switchtopic from Tasmota versions before v8.0

View File

@ -89,6 +89,7 @@ lib_extra_dirs = ${library.lib_extra_dirs}
[tasmota_stage] [tasmota_stage]
; *** Esp8266 core for Arduino version Tasmota stage (PR7231 and Backport PR7514) ; *** Esp8266 core for Arduino version Tasmota stage (PR7231 and Backport PR7514)
platform_packages = framework-arduinoespressif8266@https://github.com/Jason2866/Arduino.git#2.7.4.4 platform_packages = framework-arduinoespressif8266@https://github.com/Jason2866/Arduino.git#2.7.4.4
platformio/tool-esptool @ 1.413.0
build_unflags = ${esp_defaults.build_unflags} build_unflags = ${esp_defaults.build_unflags}
build_flags = ${esp82xx_defaults.build_flags} build_flags = ${esp82xx_defaults.build_flags}
@ -122,10 +123,11 @@ build_flags = ${esp82xx_defaults.build_flags}
; -lstdc++-exc ; -lstdc++-exc
[core_stage] [core_stage]
; *** Esp8266 core version. Tasmota stage or Arduino stage version. Built with GCC 10.1 toolchain ; *** Esp8266 core for Arduino version stage
platform_packages = framework-arduinoespressif8266 @ https://github.com/Jason2866/platform-espressif8266/releases/download/2.9.1/framework-arduinoespressif8266-3.20901.0.tar.gz platform_packages = framework-arduinoespressif8266@https://github.com/esp8266/Arduino.git
;framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git ; *** Use Xtensa build chain 10.2. GNU13 from https://github.com/earlephilhower/esp-quick-toolchain
toolchain-xtensa @ ~2.100100.0 mcspr/toolchain-xtensa@5.100200.200918
platformio/tool-esptool @ 1.413.0
build_unflags = ${esp_defaults.build_unflags} build_unflags = ${esp_defaults.build_unflags}
-Wswitch-unreachable -Wswitch-unreachable
build_flags = ${esp82xx_defaults.build_flags} build_flags = ${esp82xx_defaults.build_flags}

View File

@ -139,7 +139,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
typedef union { // Restricted by MISRA-C Rule 18.4 but so useful... typedef union { // Restricted by MISRA-C Rule 18.4 but so useful...
uint32_t data; // Allow bit manipulation using SetOption uint32_t data; // Allow bit manipulation using SetOption
struct { // SetOption114 .. SetOption145 struct { // SetOption114 .. SetOption145
uint32_t mqtt_switches : 1; // bit 0 (V9.0.0.3) - SetOption114 - Detach Swiches from relays and enable MQTT action state for all the SwitchModes uint32_t mqtt_switches : 1; // bit 0 (V9.0.0.3) - SetOption114 - Detach Switches from relays and enable MQTT action state for all the SwitchModes
//uint32_t spare00 : 1; // bit 0 //uint32_t spare00 : 1; // bit 0
uint32_t spare01 : 1; // bit 1 uint32_t spare01 : 1; // bit 1
uint32_t spare02 : 1; // bit 2 uint32_t spare02 : 1; // bit 2

View File

@ -1242,7 +1242,7 @@ void CmndTemplate(void)
bool error = false; bool error = false;
if (strstr(XdrvMailbox.data, "{") == nullptr) { // If no JSON it must be parameter if (strchr(XdrvMailbox.data, '{') == nullptr) { // If no JSON it must be parameter
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= MAXMODULE)) { if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= MAXMODULE)) {
XdrvMailbox.payload--; XdrvMailbox.payload--;
if (ValidTemplateModule(XdrvMailbox.payload)) { if (ValidTemplateModule(XdrvMailbox.payload)) {
@ -1550,7 +1550,7 @@ void CmndHostname(void)
{ {
if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) { if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) {
SettingsUpdateText(SET_HOSTNAME, (SC_DEFAULT == Shortcut()) ? WIFI_HOSTNAME : XdrvMailbox.data); SettingsUpdateText(SET_HOSTNAME, (SC_DEFAULT == Shortcut()) ? WIFI_HOSTNAME : XdrvMailbox.data);
if (strstr(SettingsText(SET_HOSTNAME), "%") != nullptr) { if (strchr(SettingsText(SET_HOSTNAME), '%') != nullptr) {
SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME); SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME);
} }
TasmotaGlobal.restart_flag = 2; TasmotaGlobal.restart_flag = 2;
@ -1643,7 +1643,7 @@ void CmndInterlock(void)
if (max_relays > sizeof(Settings.interlock[0]) * 8) { max_relays = sizeof(Settings.interlock[0]) * 8; } if (max_relays > sizeof(Settings.interlock[0]) * 8) { max_relays = sizeof(Settings.interlock[0]) * 8; }
if (max_relays > 1) { // Only interlock with more than 1 relay if (max_relays > 1) { // Only interlock with more than 1 relay
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Interlock entry if (strchr(XdrvMailbox.data, ',') != nullptr) { // Interlock entry
for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) { Settings.interlock[i] = 0; } // Reset current interlocks for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) { Settings.interlock[i] = 0; } // Reset current interlocks
char *group; char *group;
char *q; char *q;
@ -1801,7 +1801,7 @@ void CmndTimeStdDst(uint32_t ts)
{ {
// TimeStd 0/1, 0/1/2/3/4, 1..12, 1..7, 0..23, +/-780 // TimeStd 0/1, 0/1/2/3/4, 1..12, 1..7, 0..23, +/-780
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry if (strchr(XdrvMailbox.data, ',') != nullptr) { // Process parameter entry
uint32_t tpos = 0; // Parameter index uint32_t tpos = 0; // Parameter index
int value = 0; int value = 0;
char *p = XdrvMailbox.data; // Parameters like "1, 2,3 , 4 ,5, -120" or ",,,,,+240" char *p = XdrvMailbox.data; // Parameters like "1, 2,3 , 4 ,5, -120" or ",,,,,+240"

View File

@ -410,13 +410,13 @@ void SwitchHandler(uint32_t mode) {
Switch.last_state[i] = button; Switch.last_state[i] = button;
} }
if (switchflag <= POWER_TOGGLE) { if (switchflag <= POWER_TOGGLE) {
if (!Settings.flag5.mqtt_switches) { // SetOption114 (0) - Detach Swiches from relays and enable MQTT action state for all the SwitchModes if (!Settings.flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes
if (!SendKey(KEY_SWITCH, i +1, switchflag)) { // Execute command via MQTT if (!SendKey(KEY_SWITCH, i +1, switchflag)) { // Execute command via MQTT
ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < TasmotaGlobal.devices_present) ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < TasmotaGlobal.devices_present)
} }
} else { mqtt_action = switchflag; } } else { mqtt_action = switchflag; }
} }
if ((mqtt_action != POWER_NONE) && Settings.flag5.mqtt_switches) { // SetOption114 (0) - Detach Swiches from relays and enable MQTT action state for all the SwitchModes if ((mqtt_action != POWER_NONE) && Settings.flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes
if (!Settings.flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) if (!Settings.flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59)
char mqtt_state_str[16]; char mqtt_state_str[16];
char *mqtt_state = mqtt_state_str; char *mqtt_state = mqtt_state_str;

View File

@ -25,10 +25,10 @@ char* Format(char* output, const char* input, int size)
char *token; char *token;
uint32_t digits = 0; uint32_t digits = 0;
if (strstr(input, "%") != nullptr) { if (strchr(input, '%') != nullptr) {
strlcpy(output, input, size); strlcpy(output, input, size);
token = strtok(output, "%"); token = strtok(output, "%");
if (strstr(input, "%") == input) { if (strchr(input, '%') == input) {
output[0] = '\0'; output[0] = '\0';
} else { } else {
token = strtok(nullptr, ""); token = strtok(nullptr, "");

View File

@ -280,7 +280,7 @@ void setup(void) {
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 (strstr(SettingsText(SET_HOSTNAME), "%") != nullptr) { if (strchr(SettingsText(SET_HOSTNAME), '%') != nullptr) {
SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME); SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME);
snprintf_P(TasmotaGlobal.hostname, sizeof(TasmotaGlobal.hostname)-1, SettingsText(SET_HOSTNAME), TasmotaGlobal.mqtt_topic, ESP_getChipId() & 0x1FFF); snprintf_P(TasmotaGlobal.hostname, sizeof(TasmotaGlobal.hostname)-1, SettingsText(SET_HOSTNAME), TasmotaGlobal.mqtt_topic, ESP_getChipId() & 0x1FFF);
} else { } else {

View File

@ -2185,7 +2185,7 @@ void WifiSaveSettings(void)
WebGetArg("h", tmp, sizeof(tmp)); WebGetArg("h", tmp, sizeof(tmp));
SettingsUpdateText(SET_HOSTNAME, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp); SettingsUpdateText(SET_HOSTNAME, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp);
if (strstr(SettingsText(SET_HOSTNAME), "%") != nullptr) { if (strchr(SettingsText(SET_HOSTNAME), '%') != nullptr) {
SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME); SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME);
} }
WebGetArg("c", tmp, sizeof(tmp)); WebGetArg("c", tmp, sizeof(tmp));
@ -3429,7 +3429,7 @@ void CmndWebSend(void)
void CmndWebColor(void) void CmndWebColor(void)
{ {
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
if (strstr(XdrvMailbox.data, "{") == nullptr) { // If no JSON it must be parameter if (strchr(XdrvMailbox.data, '{') == nullptr) { // If no JSON it must be parameter
if ((XdrvMailbox.data_len > 3) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= COL_LAST)) { if ((XdrvMailbox.data_len > 3) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= COL_LAST)) {
WebHexCode(XdrvMailbox.index -1, XdrvMailbox.data); WebHexCode(XdrvMailbox.index -1, XdrvMailbox.data);
} }

View File

@ -2513,7 +2513,7 @@ bool LightColorEntry(char *buffer, uint32_t buffer_length)
buffer_length--; // remove all trailing '=' buffer_length--; // remove all trailing '='
memcpy(&Light.entry_color, &Light.current_color, sizeof(Light.entry_color)); memcpy(&Light.entry_color, &Light.current_color, sizeof(Light.entry_color));
} }
if (strstr(buffer, ",") != nullptr) { // Decimal entry if (strchr(buffer, ',') != nullptr) { // Decimal entry
int8_t i = 0; int8_t i = 0;
for (str = strtok_r(buffer, ",", &p); str && i < 6; str = strtok_r(nullptr, ",", &p)) { for (str = strtok_r(buffer, ",", &p); str && i < 6; str = strtok_r(nullptr, ",", &p)) {
if (i < LST_MAX) { if (i < LST_MAX) {

View File

@ -318,7 +318,7 @@ void CmndIrSend(void)
uint8_t error = IE_SYNTAX_IRSEND; uint8_t error = IE_SYNTAX_IRSEND;
if (XdrvMailbox.data_len) { if (XdrvMailbox.data_len) {
if (strstr(XdrvMailbox.data, "{") == nullptr) { if (strchr(XdrvMailbox.data, '{') == nullptr) {
error = IE_INVALID_JSON; error = IE_INVALID_JSON;
} else { } else {
error = IrRemoteCmndIrSendJson(); error = IrRemoteCmndIrSendJson();

View File

@ -805,7 +805,7 @@ void CmndIrSend(void)
uint8_t error = IE_SYNTAX_IRSEND; uint8_t error = IE_SYNTAX_IRSEND;
if (XdrvMailbox.data_len) { if (XdrvMailbox.data_len) {
if (strstr(XdrvMailbox.data, "{") == nullptr) { if (strchr(XdrvMailbox.data, '{') == nullptr) {
error = IrRemoteCmndIrSendRaw(); error = IrRemoteCmndIrSendRaw();
} else { } else {
error = IrRemoteCmndIrSendJson(); error = IrRemoteCmndIrSendJson();

View File

@ -497,7 +497,7 @@ void CmndDomoticzSend(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) {
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry if (strchr(XdrvMailbox.data, ',') != nullptr) { // Process parameter entry
char *data; char *data;
uint32_t index = strtoul(strtok_r(XdrvMailbox.data, ",", &data), nullptr, 10); uint32_t index = strtoul(strtok_r(XdrvMailbox.data, ",", &data), nullptr, 10);
if ((index > 0) && (data != nullptr)) { if ((index > 0) && (data != nullptr)) {

View File

@ -2249,7 +2249,7 @@ void CmndScale(void)
{ {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_VARS)) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry if (strchr(XdrvMailbox.data, ',') != nullptr) { // Process parameter entry
char sub_string[XdrvMailbox.data_len +1]; char sub_string[XdrvMailbox.data_len +1];
float valueIN = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 1)); float valueIN = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 1));

View File

@ -1120,7 +1120,7 @@ void CmndKnxEnhanced(void)
void CmndKnxPa(void) void CmndKnxPa(void)
{ {
if (XdrvMailbox.data_len) { if (XdrvMailbox.data_len) {
if (strstr(XdrvMailbox.data, ".") != nullptr) { // Process parameter entry if (strchr(XdrvMailbox.data, '.') != nullptr) { // Process parameter entry
char sub_string[XdrvMailbox.data_len]; char sub_string[XdrvMailbox.data_len];
int pa_area = atoi(subStr(sub_string, XdrvMailbox.data, ".", 1)); int pa_area = atoi(subStr(sub_string, XdrvMailbox.data, ".", 1));
@ -1148,7 +1148,7 @@ void CmndKnxGa(void)
{ {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_KNX_GA)) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_KNX_GA)) {
if (XdrvMailbox.data_len) { if (XdrvMailbox.data_len) {
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry if (strchr(XdrvMailbox.data, ',') != nullptr) { // Process parameter entry
char sub_string[XdrvMailbox.data_len]; char sub_string[XdrvMailbox.data_len];
int ga_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1)); int ga_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1));
@ -1199,7 +1199,7 @@ void CmndKnxCb(void)
{ {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_KNX_CB)) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_KNX_CB)) {
if (XdrvMailbox.data_len) { if (XdrvMailbox.data_len) {
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry if (strchr(XdrvMailbox.data, ',') != nullptr) { // Process parameter entry
char sub_string[XdrvMailbox.data_len]; char sub_string[XdrvMailbox.data_len];
int cb_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1)); int cb_option = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1));

View File

@ -187,17 +187,17 @@ const char HASS_DISCOVER_DEVICE[] PROGMEM = // Basic par
"\"hn\":\"%s\"," // Host Name "\"hn\":\"%s\"," // Host Name
"\"mac\":\"%s\"," // Full MAC as Device id "\"mac\":\"%s\"," // Full MAC as Device id
"\"md\":\"%s\"," // Module or Template Name "\"md\":\"%s\"," // Module or Template Name
"\"ty\":%d," // Flag for TuyaMCU devices "\"ty\":%d,\"if\":%d," // Flag for TuyaMCU and Ifan devices
"\"ofln\":\"" MQTT_LWT_OFFLINE "\"," // Payload Offline "\"ofln\":\"" MQTT_LWT_OFFLINE "\"," // Payload Offline
"\"onln\":\"" MQTT_LWT_ONLINE "\"," // Payload Online "\"onln\":\"" MQTT_LWT_ONLINE "\"," // Payload Online
"\"state\":[\"%s\",\"%s\",\"%s\",\"%s\"]," // State text for "OFF","ON","TOGGLE","HOLD" "\"state\":[\"%s\",\"%s\",\"%s\",\"%s\"]," // State text for "OFF","ON","TOGGLE","HOLD"
"\"sw\":\"%s\"," // Software Version "\"sw\":\"%s\"," // Software Version
"\"t\":\"%s\"," // Topic "\"t\":\"%s\"," // Topic
"\"ft\":\"%s\"," // Ful Topic "\"ft\":\"%s\"," // Full Topic
"\"tp\":[\"%s\",\"%s\",\"%s\"]," // Topics for command, stat and tele "\"tp\":[\"%s\",\"%s\",\"%s\"]," // Topics for command, stat and tele
"\"rl\":[%s],\"swc\":[%s],\"btn\":[%s]," // Inputs / Outputs "\"rl\":[%s],\"swc\":[%s],\"swn\":[%s],\"btn\":[%s]," // Inputs / Outputs
"\"so\":{\"11\":%d,\"13\":%d,\"17\":%d,\"20\":%d," // SetOptions "\"so\":{\"4\":%d,\"11\":%d,\"13\":%d,\"17\":%d,\"20\":%d," // SetOptions
"\"30\":%d,\"68\":%d,\"73\":%d,\"80\":%d,\"82\":%d}," "\"30\":%d,\"68\":%d,\"73\":%d,\"82\":%d,\"114\":%d},"
"\"lk\":%d,\"lt_st\":%d,\"ver\":1}"; // Light SubType, and Discovery version "\"lk\":%d,\"lt_st\":%d,\"ver\":1}"; // Light SubType, and Discovery version
typedef struct HASS { typedef struct HASS {
@ -272,16 +272,23 @@ void NewHAssDiscovery(void)
char stemp2[200]; char stemp2[200];
char stemp3[TOPSZ]; char stemp3[TOPSZ];
char stemp4[TOPSZ]; char stemp4[TOPSZ];
char stemp5[TOPSZ];
char unique_id[30]; char unique_id[30];
char relays[TOPSZ]; char relays[TOPSZ];
char *state_topic = stemp1; char *state_topic = stemp1;
bool SerialButton = false; bool SerialButton = false;
bool TuyaMod = false; bool TuyaMod = false;
bool iFanMod = false;
stemp2[0] = '\0'; stemp2[0] = '\0';
struct HASS Hass; struct HASS Hass;
HassDiscoveryRelays(Hass); HassDiscoveryRelays(Hass);
#ifdef ESP8266
if (TUYA_DIMMER == TasmotaGlobal.module_type || SK03_TUYA == TasmotaGlobal.module_type) { TuyaMod = true; }
if (SONOFF_IFAN02 == TasmotaGlobal.module_type || SONOFF_IFAN03 == TasmotaGlobal.module_type) { iFanMod = true; }
#endif // ESP8266
uint32_t maxfn = (TasmotaGlobal.devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!TasmotaGlobal.devices_present) ? 1 : TasmotaGlobal.devices_present; uint32_t maxfn = (TasmotaGlobal.devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!TasmotaGlobal.devices_present) ? 1 : TasmotaGlobal.devices_present;
for (uint32_t i = 0; i < MAX_FRIENDLYNAMES; i++) { for (uint32_t i = 0; i < MAX_FRIENDLYNAMES; i++) {
char fname[TOPSZ]; char fname[TOPSZ];
@ -290,22 +297,21 @@ void NewHAssDiscovery(void)
} }
stemp3[0] = '\0'; stemp3[0] = '\0';
// Enable Discovery for Switches only if SwitchTopic is set to a custom name or if there is not a Power device // Enable Discovery for Switches only if SetOption114 is enabled
auto discover_switches = ((KeyTopicActive(1) && (strcmp(SettingsText(SET_MQTT_SWITCH_TOPIC), TasmotaGlobal.mqtt_topic))) || !Hass.RelPst);
for (uint32_t i = 0; i < MAX_SWITCHES; i++) { for (uint32_t i = 0; i < MAX_SWITCHES; i++) {
snprintf_P(stemp3, sizeof(stemp3), PSTR("%s%s%d"), stemp3, (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) & discover_switches) ? Settings.switchmode[i] : -1); char sname[TOPSZ];
snprintf_P(sname, sizeof(sname), PSTR("\"%s\""), GetSwitchText(i).c_str());
snprintf_P(stemp3, sizeof(stemp3), PSTR("%s%s%d"), stemp3, (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) & Settings.flag5.mqtt_switches) ? Settings.switchmode[i] : -1);
snprintf_P(stemp4, sizeof(stemp4), PSTR("%s%s%s"), stemp4, (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) & Settings.flag5.mqtt_switches) ? sname : "null");
} }
stemp4[0] = '\0'; stemp5[0] = '\0';
// Enable Discovery for Buttons only if SetOption73 is enabled // Enable Discovery for Buttons only if SetOption73 is enabled
for (uint32_t i = 0; i < MAX_KEYS; i++) { for (uint32_t i = 0; i < MAX_KEYS; i++) {
#ifdef ESP8266 #ifdef ESP8266
if (i == 0 && (SONOFF_DUAL == TasmotaGlobal.module_type )) { SerialButton = true; } if (i == 0 && (SONOFF_DUAL == TasmotaGlobal.module_type )) { SerialButton = true; }
if (TUYA_DIMMER == TasmotaGlobal.module_type || SK03_TUYA == TasmotaGlobal.module_type) { TuyaMod = true; }
#endif // ESP8266 #endif // ESP8266
snprintf_P(stemp5, sizeof(stemp5), PSTR("%s%s%d"), stemp5, (i > 0 ? "," : ""), (SerialButton ? 1 : (PinUsed(GPIO_KEY1, i)) & Settings.flag3.mqtt_buttons));
snprintf_P(stemp4, sizeof(stemp4), PSTR("%s%s%d"), stemp4, (i > 0 ? "," : ""), (SerialButton ? 1 : (PinUsed(GPIO_KEY1, i)) & Settings.flag3.mqtt_buttons));
SerialButton = false; SerialButton = false;
} }
@ -318,13 +324,14 @@ void NewHAssDiscovery(void)
snprintf_P(stopic, sizeof(stopic), PSTR("tasmota/discovery/%s/config"), unique_id); snprintf_P(stopic, sizeof(stopic), PSTR("tasmota/discovery/%s/config"), unique_id);
// Send empty message if new discovery is disabled // Send empty message if new discovery is disabled
TasmotaGlobal.masterlog_level = 4; // Hide topic on clean and remove use weblog 4 to see it TasmotaGlobal.masterlog_level = 4; // Hide topic on clean and remove use weblog 4 to show it
if (!Settings.flag.hass_discovery) { // HassDiscoveryRelays(relays) if (!Settings.flag.hass_discovery) { // HassDiscoveryRelays(relays)
Response_P(HASS_DISCOVER_DEVICE, WiFi.localIP().toString().c_str(), SettingsText(SET_DEVICENAME), Response_P(HASS_DISCOVER_DEVICE, WiFi.localIP().toString().c_str(), SettingsText(SET_DEVICENAME),
stemp2, TasmotaGlobal.hostname, unique_id, ModuleName().c_str(), TuyaMod, GetStateText(0), GetStateText(1), GetStateText(2), GetStateText(3), stemp2, TasmotaGlobal.hostname, unique_id, ModuleName().c_str(), TuyaMod, iFanMod, GetStateText(0), GetStateText(1), GetStateText(2), GetStateText(3),
TasmotaGlobal.version, TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_FULLTOPIC), SUB_PREFIX, PUB_PREFIX, PUB_PREFIX2, Hass.RelLst, stemp3, stemp4, Settings.flag.button_swap, TasmotaGlobal.version, TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_FULLTOPIC), SUB_PREFIX, PUB_PREFIX, PUB_PREFIX2, Hass.RelLst, stemp3, stemp4,
Settings.flag.button_single, Settings.flag.decimal_text, Settings.flag.not_power_linked, Settings.flag.hass_light, Settings.flag3.pwm_multi_channels, stemp5, Settings.flag.mqtt_response, Settings.flag.button_swap, Settings.flag.button_single, Settings.flag.decimal_text, Settings.flag.not_power_linked,
Settings.flag3.mqtt_buttons, Settings.flag3.shutter_mode, Settings.flag4.alexa_ct_range, light_controller.isCTRGBLinked(), Light.subtype); Settings.flag.hass_light, Settings.flag3.pwm_multi_channels, Settings.flag3.mqtt_buttons, Settings.flag4.alexa_ct_range, Settings.flag5.mqtt_switches,
light_controller.isCTRGBLinked(), Light.subtype);
} }
MqttPublish(stopic, true); MqttPublish(stopic, true);

View File

@ -88,7 +88,7 @@ void PWMModulePreInit(void)
Settings.ledstate = 0; // Disable LED usage Settings.ledstate = 0; // Disable LED usage
// If the module was just changed to PWM Dimmer, set the defaults. // If the module was just changed to PWM Dimmer, set the defaults.
if (TasmotaGlobal.module_changed) { if (TasmotaGlobal.module_changed) {
Settings.flag.pwm_control = true; // SetOption15 - Switch between commands PWM or COLOR/DIMMER/CT/CHANNEL Settings.flag.pwm_control = true; // SetOption15 - Switch between commands PWM or COLOR/DIMMER/CT/CHANNEL
Settings.bri_power_on = Settings.bri_preset_low = Settings.bri_preset_high = 0; Settings.bri_power_on = Settings.bri_preset_low = Settings.bri_preset_high = 0;

View File

@ -132,7 +132,7 @@ void AdcGetSettings(uint32_t idx) {
Adc[idx].param2 = 0; Adc[idx].param2 = 0;
Adc[idx].param3 = 0; Adc[idx].param3 = 0;
Adc[idx].param4 = 0; Adc[idx].param4 = 0;
if (strstr(SettingsText(SET_ADC_PARAM1 + idx), ",") != nullptr) { if (strchr(SettingsText(SET_ADC_PARAM1 + idx), ',') != nullptr) {
Adcs.type = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 1)); Adcs.type = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 1));
Adc[idx].param1 = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 2)); Adc[idx].param1 = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 2));
Adc[idx].param2 = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 3)); Adc[idx].param2 = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 3));

View File

@ -205,7 +205,7 @@ bool HxCommand(void)
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, "Reset"); Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, "Reset");
break; break;
case 2: // Calibrate case 2: // Calibrate
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.weight_reference = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.weight_reference = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
} }
Hx.scale = 1; Hx.scale = 1;
@ -215,26 +215,26 @@ bool HxCommand(void)
HxCalibrationStateTextJson(3); HxCalibrationStateTextJson(3);
break; break;
case 3: // WeightRef to user reference case 3: // WeightRef to user reference
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.weight_reference = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.weight_reference = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
} }
show_parms = true; show_parms = true;
break; break;
case 4: // WeightCal to user calculated value case 4: // WeightCal to user calculated value
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.weight_calibration = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.weight_calibration = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
Hx.scale = Settings.weight_calibration; Hx.scale = Settings.weight_calibration;
} }
show_parms = true; show_parms = true;
break; break;
case 5: // WeightMax case 5: // WeightMax
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.weight_max = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10) / 1000; Settings.weight_max = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10) / 1000;
} }
show_parms = true; show_parms = true;
break; break;
case 6: // WeightItem case 6: // WeightItem
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.weight_item = (unsigned long)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 2)) * 10); Settings.weight_item = (unsigned long)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 2)) * 10);
} }
show_parms = true; show_parms = true;
@ -244,13 +244,13 @@ bool HxCommand(void)
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, D_JSON_DONE); Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, D_JSON_DONE);
break; break;
case 8: // Json on weight change case 8: // Json on weight change
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.SensorBits1.hx711_json_weight_change = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10) & 1; Settings.SensorBits1.hx711_json_weight_change = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10) & 1;
} }
show_parms = true; show_parms = true;
break; break;
case 9: // WeightDelta case 9: // WeightDelta
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.weight_change = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.weight_change = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
SetWeightDelta(); SetWeightDelta();
} }

View File

@ -19,44 +19,13 @@
#ifdef USE_IBEACON #ifdef USE_IBEACON
#define XSNS_52 52 #define XSNS_52 52
#include <TasmotaSerial.h>
#define TMSBSIZ52 512
#define HM17_BAUDRATE 9600
#define IBEACON_DEBUG
// use this for Version 110
#define HM17_V110
// keyfob expires after N seconds // keyfob expires after N seconds
#define IB_TIMEOUT_INTERVAL 30 #define IB_TIMEOUT_INTERVAL 30
// does a passive scan every N seconds // does a passive scan every N seconds
#define IB_UPDATE_TIME_INTERVAL 10 #define IB_UPDATE_TIME_INTERVAL 10
TasmotaSerial *IBEACON_Serial = nullptr;
uint8_t hm17_found,hm17_cmd,hm17_flag;
#ifdef IBEACON_DEBUG
uint8_t hm17_debug=0;
#endif
// 78 is max serial response
#define HM17_BSIZ 128
char hm17_sbuffer[HM17_BSIZ];
uint8_t hm17_sindex,hm17_result,hm17_scanning,hm17_connecting;
uint32_t hm17_lastms;
char ib_mac[14];
// should be in Settings // should be in Settings
#if 1 #if 1
uint8_t ib_upd_interval,ib_tout_interval; uint8_t ib_upd_interval,ib_tout_interval;
@ -69,9 +38,71 @@ uint8_t ib_upd_interval,ib_tout_interval;
#define IB_TIMEOUT_TIME Settings.ib_tout_interval #define IB_TIMEOUT_TIME Settings.ib_tout_interval
#endif #endif
char ib_mac[14];
#ifdef USE_IBEACON_ESP32
struct {
union {
struct {
uint32_t init:1;
uint32_t autoScan:1;
uint32_t canScan:1;
uint32_t runningScan:1;
uint32_t shallClearResults:1; // BLE scan results
uint32_t firstAutodiscoveryDone:1;
uint32_t activeBeacon;
};
uint32_t all = 0;
} mode;
struct {
uint8_t sensor; // points to to the number 0...255
uint8_t beaconScanCounter; // countdown timer in seconds
} state;
} ESP32BLE;
#include <NimBLEDevice.h>
#include <NimBLEAdvertisedDevice.h>
#include "NimBLEEddystoneURL.h"
#include "NimBLEEddystoneTLM.h"
#include "NimBLEBeacon.h"
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
BLEScan *ESP32BLEScan;
#else
#include <TasmotaSerial.h>
#define TMSBSIZ52 512
#define HM17_BAUDRATE 9600
#define IBEACON_DEBUG
// use this for Version 110
#define HM17_V110
TasmotaSerial *IBEACON_Serial = nullptr;
uint8_t hm17_found,hm17_cmd,hm17_flag;
#ifdef IBEACON_DEBUG
uint8_t hm17_debug=0;
#endif
// 78 is max serial response
#define HM17_BSIZ 128
char hm17_sbuffer[HM17_BSIZ];
uint8_t hm17_sindex,hm17_result,hm17_scanning,hm17_connecting;
uint32_t hm17_lastms;
enum {HM17_TEST,HM17_ROLE,HM17_IMME,HM17_DISI,HM17_IBEA,HM17_SCAN,HM17_DISC,HM17_RESET,HM17_RENEW,HM17_CON}; enum {HM17_TEST,HM17_ROLE,HM17_IMME,HM17_DISI,HM17_IBEA,HM17_SCAN,HM17_DISC,HM17_RESET,HM17_RENEW,HM17_CON};
#define HM17_SUCESS 99 #define HM17_SUCESS 99
#endif
struct IBEACON { struct IBEACON {
char FACID[8]; char FACID[8];
char UID[32]; char UID[32];
@ -82,7 +113,11 @@ struct IBEACON {
char RSSI[4]; char RSSI[4];
}; };
#define MAX_IBEACONS 16 #ifdef USE_IBEACON_ESP32
#define MAX_IBEACONS 32
#else
#define MAX_IBEACONS 16
#endif
struct IBEACON_UID { struct IBEACON_UID {
char MAC[12]; char MAC[12];
@ -92,11 +127,159 @@ struct IBEACON_UID {
char MINOR[4]; char MINOR[4];
uint8_t FLAGS; uint8_t FLAGS;
uint8_t TIME; uint8_t TIME;
#ifdef USE_IBEACON_ESP32
uint8_t REPTIME;
#endif
} ibeacons[MAX_IBEACONS]; } ibeacons[MAX_IBEACONS];
#ifdef USE_IBEACON_ESP32
uint32_t ibeacon_add(struct IBEACON *ib);
void ESP32BLE_ReverseStr(uint8_t _mac[], uint8_t len=6){
uint8_t _reversedMAC[len];
for (uint8_t i=0; i<len; i++){
_reversedMAC[len-1-i] = _mac[i];
}
memcpy(_mac,_reversedMAC, sizeof(_reversedMAC));
}
void DumpHex(const unsigned char * in, size_t insz, char * out)
{
static const char * hex = "0123456789ABCDEF";
const unsigned char * pin = in;
char * pout = out;
for (; pin < in+insz; pout+=2, pin++) {
pout[0] = hex[(pgm_read_byte(pin)>>4) & 0xF];
pout[1] = hex[ pgm_read_byte(pin) & 0xF];
}
}
class ESP32BLEScanCallback : public BLEAdvertisedDeviceCallbacks
{
void onResult(BLEAdvertisedDevice *advertisedDevice)
{
struct IBEACON ib;
ESP32BLEScan->erase(advertisedDevice->getAddress());
if (advertisedDevice->haveManufacturerData() == true) {
std::string strManufacturerData = advertisedDevice->getManufacturerData();
uint8_t cManufacturerData[100];
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
int16_t RSSI = advertisedDevice->getRSSI();
char sRSSI[6];
itoa(RSSI,sRSSI,10);
DumpHex(cManufacturerData,2,ib.FACID);
uint8_t MAC[6];
memcpy(MAC,advertisedDevice->getAddress().getNative(),6);
ESP32BLE_ReverseStr(MAC,6);
if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
{
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setData(strManufacturerData);
uint8_t UUID[16];
memcpy(UUID,oBeacon.getProximityUUID().getNative()->u128.value,16);
ESP32BLE_ReverseStr(UUID,16);
uint16_t Major = ENDIAN_CHANGE_U16(oBeacon.getMajor());
uint16_t Minor = ENDIAN_CHANGE_U16(oBeacon.getMinor());
uint8_t PWR = oBeacon.getSignalPower();
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MAC: %s Major: %d Minor: %d UUID: %s Power: %d RSSI: %d"),
advertisedDevice->getAddress().toString().c_str(),
Major, Minor,
oBeacon.getProximityUUID().toString().c_str(),
PWR, RSSI);
DumpHex((const unsigned char*)&UUID,16,ib.UID);
DumpHex((const unsigned char*)&Major,2,ib.MAJOR);
DumpHex((const unsigned char*)&Minor,2,ib.MINOR);
DumpHex((const unsigned char*)&PWR,1,ib.PWR);
DumpHex((const unsigned char*)&MAC,6,ib.MAC);
memcpy(ib.RSSI,sRSSI,4);
if (ibeacon_add(&ib)==2) {
ibeacon_mqtt(ib.MAC,ib.RSSI,ib.UID,ib.MAJOR,ib.MINOR);
}
} else {
memset(ib.UID,'0',32);
memset(ib.MAJOR,'0',4);
memset(ib.MINOR,'0',4);
memset(ib.PWR,'0',2);
DumpHex((const unsigned char*)&MAC,6,ib.MAC);
memcpy(ib.RSSI,sRSSI,4);
if (ibeacon_add(&ib)==2) {
ibeacon_mqtt(ib.MAC,ib.RSSI,ib.UID,ib.MAJOR,ib.MINOR);
}
}
}
}
};
void ESP32StartScanTask(){
ESP32BLE.mode.runningScan = 1;
xTaskCreatePinnedToCore(
ESP32ScanTask, /* Function to implement the task */
"ESP32ScanTask", /* Name of the task */
2048, /* Stack size in words */
NULL, /* Task input parameter */
0, /* Priority of the task */
NULL, /* Task handle. */
0); /* Core where the task should run */
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s: Start scanning"),"IBEACON_ESP32");
}
void ESP32scanEndedCB(NimBLEScanResults results);
void ESP32ScanTask(void *pvParameters){
if (ESP32BLEScan == nullptr) ESP32BLEScan = NimBLEDevice::getScan();
ESP32BLEScan->setInterval(70);
ESP32BLEScan->setWindow(50);
ESP32BLEScan->setAdvertisedDeviceCallbacks(new ESP32BLEScanCallback());
ESP32BLEScan->setActiveScan(false);
ESP32BLEScan->setDuplicateFilter(false);
for (;;) {
ESP32BLEScan->start(0, ESP32scanEndedCB, false);
}
}
void ESP32scanEndedCB(NimBLEScanResults results) {
ESP32BLE.mode.runningScan = 0;
}
#endif
void IBEACON_Init() { void IBEACON_Init() {
#ifdef USE_IBEACON_ESP32
ESP32BLE.mode.init = false;
if (!ESP32BLE.mode.init) {
NimBLEDevice::init("");
ESP32BLE.mode.canScan = 1;
ESP32BLE.mode.init = 1;
ESP32StartScanTask(); // Let's get started !!
IB_UPDATE_TIME=IB_UPDATE_TIME_INTERVAL;
IB_TIMEOUT_TIME=IB_TIMEOUT_INTERVAL;
}
#else
hm17_found=0; hm17_found=0;
// actually doesnt work reliably with software serial // actually doesnt work reliably with software serial
@ -113,8 +296,28 @@ void IBEACON_Init() {
IB_TIMEOUT_TIME=IB_TIMEOUT_INTERVAL; IB_TIMEOUT_TIME=IB_TIMEOUT_INTERVAL;
} }
} }
#endif
} }
#ifdef USE_IBEACON_ESP32
void esp32_every_second(void) {
for (uint32_t cnt=0;cnt<MAX_IBEACONS;cnt++) {
if (ibeacons[cnt].FLAGS) {
ibeacons[cnt].TIME++;
ibeacons[cnt].REPTIME++;
if (ibeacons[cnt].TIME>IB_TIMEOUT_TIME) {
ibeacons[cnt].FLAGS=0;
ibeacon_mqtt(ibeacons[cnt].MAC,"0000",ibeacons[cnt].UID,ibeacons[cnt].MAJOR,ibeacons[cnt].MINOR);
}
}
}
}
#else
void hm17_every_second(void) { void hm17_every_second(void) {
if (!IBEACON_Serial) return; if (!IBEACON_Serial) return;
@ -196,6 +399,8 @@ void hm17_sendcmd(uint8_t cmd) {
} }
} }
#endif
uint32_t ibeacon_add(struct IBEACON *ib) { uint32_t ibeacon_add(struct IBEACON *ib) {
/* if (!strncmp(ib->MAJOR,"4B1C",4)) { /* if (!strncmp(ib->MAJOR,"4B1C",4)) {
return 0; return 0;
@ -214,6 +419,12 @@ uint32_t ibeacon_add(struct IBEACON *ib) {
// exists // exists
memcpy(ibeacons[cnt].RSSI,ib->RSSI,4); memcpy(ibeacons[cnt].RSSI,ib->RSSI,4);
ibeacons[cnt].TIME=0; ibeacons[cnt].TIME=0;
#ifdef USE_IBEACON_ESP32
if (ibeacons[cnt].REPTIME >= IB_UPDATE_TIME) {
ibeacons[cnt].REPTIME = 0;
return 2;
}
#endif
return 1; return 1;
} }
} else { } else {
@ -221,6 +432,12 @@ uint32_t ibeacon_add(struct IBEACON *ib) {
// exists // exists
memcpy(ibeacons[cnt].RSSI,ib->RSSI,4); memcpy(ibeacons[cnt].RSSI,ib->RSSI,4);
ibeacons[cnt].TIME=0; ibeacons[cnt].TIME=0;
#ifdef USE_IBEACON_ESP32
if (ibeacons[cnt].REPTIME >= IB_UPDATE_TIME) {
ibeacons[cnt].REPTIME = 0;
return 2;
}
#endif
return 1; return 1;
} }
} }
@ -235,6 +452,9 @@ uint32_t ibeacon_add(struct IBEACON *ib) {
memcpy(ibeacons[cnt].MINOR,ib->MINOR,4); memcpy(ibeacons[cnt].MINOR,ib->MINOR,4);
ibeacons[cnt].FLAGS=1; ibeacons[cnt].FLAGS=1;
ibeacons[cnt].TIME=0; ibeacons[cnt].TIME=0;
#ifdef USE_IBEACON_ESP32
ibeacons[cnt].REPTIME = 0;
#endif
return 1; return 1;
} }
} }
@ -242,6 +462,8 @@ uint32_t ibeacon_add(struct IBEACON *ib) {
return 0; return 0;
} }
#ifndef USE_IBEACON_ESP32
void hm17_decode(void) { void hm17_decode(void) {
struct IBEACON ib; struct IBEACON ib;
switch (hm17_cmd) { switch (hm17_cmd) {
@ -438,8 +660,16 @@ hm17_v110:
} }
} }
#endif
void IBEACON_loop() { void IBEACON_loop() {
#ifdef USE_IBEACON_ESP32
return;
#else
if (!IBEACON_Serial) return; if (!IBEACON_Serial) return;
uint32_t difftime=millis()-hm17_lastms; uint32_t difftime=millis()-hm17_lastms;
@ -464,6 +694,8 @@ uint32_t difftime=millis()-hm17_lastms;
} }
} }
#endif
} }
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
@ -523,7 +755,20 @@ bool xsns52_cmd(void) {
uint16_t len=XdrvMailbox.data_len; uint16_t len=XdrvMailbox.data_len;
if (len > 0) { if (len > 0) {
char *cp=XdrvMailbox.data; char *cp=XdrvMailbox.data;
if (*cp>='0' && *cp<='8') { if (*cp=='u') {
cp++;
if (*cp) IB_UPDATE_TIME=atoi(cp);
Response_P(S_JSON_IBEACON, XSNS_52,"uintv",IB_UPDATE_TIME);
} else if (*cp=='t') {
cp++;
if (*cp) IB_TIMEOUT_TIME=atoi(cp);
Response_P(S_JSON_IBEACON, XSNS_52,"lintv",IB_TIMEOUT_TIME);
} else if (*cp=='c') {
for (uint32_t cnt=0;cnt<MAX_IBEACONS;cnt++) ibeacons[cnt].FLAGS=0;
Response_P(S_JSON_IBEACON1, XSNS_52,"clr list","");
}
#ifndef USE_IBEACON_ESP32
else if (*cp>='0' && *cp<='8') {
hm17_sendcmd(*cp&7); hm17_sendcmd(*cp&7);
Response_P(S_JSON_IBEACON, XSNS_52,"hm17cmd",*cp&7); Response_P(S_JSON_IBEACON, XSNS_52,"hm17cmd",*cp&7);
} else if (*cp=='s') { } else if (*cp=='s') {
@ -536,18 +781,8 @@ bool xsns52_cmd(void) {
IBEACON_Serial->write((uint8_t*)cp,len); IBEACON_Serial->write((uint8_t*)cp,len);
hm17_cmd=99; hm17_cmd=99;
Response_P(S_JSON_IBEACON1, XSNS_52,"hm17cmd",cp); Response_P(S_JSON_IBEACON1, XSNS_52,"hm17cmd",cp);
} else if (*cp=='u') {
cp++;
if (*cp) IB_UPDATE_TIME=atoi(cp);
Response_P(S_JSON_IBEACON, XSNS_52,"uintv",IB_UPDATE_TIME);
} else if (*cp=='t') {
cp++;
if (*cp) IB_TIMEOUT_TIME=atoi(cp);
Response_P(S_JSON_IBEACON, XSNS_52,"lintv",IB_TIMEOUT_TIME);
} else if (*cp=='c') {
for (uint32_t cnt=0;cnt<MAX_IBEACONS;cnt++) ibeacons[cnt].FLAGS=0;
Response_P(S_JSON_IBEACON1, XSNS_52,"clr list","");
} }
#endif
#ifdef IBEACON_DEBUG #ifdef IBEACON_DEBUG
else if (*cp=='d') { else if (*cp=='d') {
cp++; cp++;
@ -562,6 +797,8 @@ bool xsns52_cmd(void) {
} }
#define D_CMND_IBEACON "IBEACON" #define D_CMND_IBEACON "IBEACON"
#ifndef USE_IBEACON_ESP32
//"IBEACON_FFFF3D1B1E9D_RSSI", Data "99" causes TAG to beep //"IBEACON_FFFF3D1B1E9D_RSSI", Data "99" causes TAG to beep
bool ibeacon_cmd(void) { bool ibeacon_cmd(void) {
ib_mac[0]=0; ib_mac[0]=0;
@ -592,6 +829,8 @@ void ib_sendbeep(void) {
hm17_sendcmd(HM17_CON); hm17_sendcmd(HM17_CON);
} }
#endif
void ibeacon_mqtt(const char *mac,const char *rssi,const char *uid,const char *major,const char *minor) { void ibeacon_mqtt(const char *mac,const char *rssi,const char *uid,const char *major,const char *minor) {
char s_mac[14]; char s_mac[14];
char s_uid[34]; char s_uid[34];
@ -636,19 +875,29 @@ bool Xsns52(byte function)
IBEACON_loop(); IBEACON_loop();
break; break;
case FUNC_EVERY_SECOND: case FUNC_EVERY_SECOND:
#ifdef USE_IBEACON_ESP32
esp32_every_second();
#else
hm17_every_second(); hm17_every_second();
#endif
break; break;
case FUNC_COMMAND_SENSOR: case FUNC_COMMAND_SENSOR:
if (XSNS_52 == XdrvMailbox.index) { if (XSNS_52 == XdrvMailbox.index) {
result = xsns52_cmd(); result = xsns52_cmd();
} }
break; break;
#ifndef USE_IBEACON_ESP32
case FUNC_COMMAND: case FUNC_COMMAND:
result=ibeacon_cmd(); result=ibeacon_cmd();
break; break;
#endif
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR: case FUNC_WEB_SENSOR:
#ifndef USE_IBEACON_ESP32
if (hm17_found) IBEACON_Show(); if (hm17_found) IBEACON_Show();
#else
IBEACON_Show();
#endif
break; break;
#endif // USE_WEBSERVER #endif // USE_WEBSERVER
} }

View File

@ -294,27 +294,27 @@ bool Xsns68Cmnd(void)
char sub_string[XdrvMailbox.data_len +1]; char sub_string[XdrvMailbox.data_len +1];
switch (XdrvMailbox.payload) { switch (XdrvMailbox.payload) {
case 1: case 1:
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.windmeter_radius = (uint16_t)strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.windmeter_radius = (uint16_t)strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
} }
break; break;
case 2: case 2:
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.windmeter_pulses_x_rot = (uint8_t)strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.windmeter_pulses_x_rot = (uint8_t)strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
} }
break; break;
case 3: case 3:
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.windmeter_pulse_debounce = (uint16_t)strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.windmeter_pulse_debounce = (uint16_t)strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
} }
break; break;
case 4: case 4:
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.windmeter_speed_factor = (int16_t)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 2)) * 1000); Settings.windmeter_speed_factor = (int16_t)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 2)) * 1000);
} }
break; break;
case 5: case 5:
if (strstr(XdrvMailbox.data, ",") != nullptr) { if (strchr(XdrvMailbox.data, ',') != nullptr) {
Settings.windmeter_tele_pchange = (uint8_t)strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.windmeter_tele_pchange = (uint8_t)strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
} }
break; break;

View File

@ -168,7 +168,7 @@ a_setoption = [[
"Use friendly name in zigbee topic (use with SetOption89)", "Use friendly name in zigbee topic (use with SetOption89)",
"Set dimmer low on rotary dial after power off" "Set dimmer low on rotary dial after power off"
],[ ],[
"Detach Swiches from Relays and enable MQTT action state for all the SwitchModes", "Detach Switches from Relays and enable MQTT action state for all the SwitchModes",
"","","", "","","",
"","","","", "","","","",
"","","","", "","","","",