Merge branch 'development' into pre-release-9.1.0

This commit is contained in:
Theo Arends 2020-11-03 16:45:17 +01:00
commit 68f8ea6f39
23 changed files with 258 additions and 115 deletions

View File

@ -142,6 +142,7 @@
| USE_EZOORP | - | - | - | - | - | - | - | | USE_EZOORP | - | - | - | - | - | - | - |
| USE_EZOPH | - | - | - | - | - | - | - | | USE_EZOPH | - | - | - | - | - | - | - |
| USE_EZOPRS | - | - | - | - | - | - | - | | USE_EZOPRS | - | - | - | - | - | - | - |
| USE_EZORGB | - | - | - | - | - | - | - |
| USE_EZORTD | - | - | - | - | - | - | - | | USE_EZORTD | - | - | - | - | - | - | - |
| | | | | | | | | | | | | | | | | |
| Feature or Sensor | minimal | lite | tasmota | knx | sensors | ir | display | Remarks | Feature or Sensor | minimal | lite | tasmota | knx | sensors | ir | display | Remarks

View File

@ -16,17 +16,20 @@ All notable changes to this project will be documented in this file.
- Support for EZO PRS sensors by Christopher Tremblay (#9659) - Support for EZO PRS sensors by Christopher Tremblay (#9659)
- Support for EZO FLO sensors by Christopher Tremblay (#9697) - Support for EZO FLO sensors by Christopher Tremblay (#9697)
- Support for EZO DO sensors by Christopher Tremblay (#9707) - Support for EZO DO sensors by Christopher Tremblay (#9707)
- Support for EZO RGB sensors by Christopher Tremblay (#9723)
- Zigbee reduce battery drain (#9642) - Zigbee reduce battery drain (#9642)
- Zigbee command ``ZbMap`` to describe Zigbee topology (#9651) - Zigbee command ``ZbMap`` to describe Zigbee topology (#9651)
- 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"}}`
- HM10 Beacon support and refactoring by Christian Baars (#9702) - HM10 Beacon support and refactoring by Christian Baars (#9702)
### Changed ### Changed
- 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
- When ``SetOption73 1`` JSON result from `{"ACTION":"SINGLE"}` to `{"Button1":{"Action":"SINGLE"}}`
### Fixed ### Fixed
- Rule Break not working as expected when ONCE is enabled (#9245) - Rule Break not working as expected when ONCE is enabled (#9245)

View File

@ -87,3 +87,4 @@ Index | Define | Driver | Device | Address(es) | Description
55 | USE_EZOPRS | xsns_78 | EZOPRS | 0x61 - 0x70 | Pressure sensor 55 | USE_EZOPRS | xsns_78 | EZOPRS | 0x61 - 0x70 | Pressure sensor
55 | USE_EZOFLO | xsns_78 | EZOFLO | 0x61 - 0x70 | Flow meter sensor 55 | USE_EZOFLO | xsns_78 | EZOFLO | 0x61 - 0x70 | Flow meter sensor
55 | USE_EZODO | xsns_78 | EZODO | 0x61 - 0x70 | Disolved Oxygen sensor 55 | USE_EZODO | xsns_78 | EZODO | 0x61 - 0x70 | Disolved Oxygen sensor
55 | USE_EZORGB | xsns_78 | EZORGB | 0x61 - 0x70 | Color sensor

View File

@ -61,9 +61,10 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
### Added ### Added
- Command ``Gpios 255`` to show all possible GPIO configurations - Command ``Gpios 255`` to show all possible GPIO configurations
- Command ``NoDelay`` for immediate backlog command execution by Erik Montnemery (#9544) - Command ``NoDelay`` for immediate backlog command execution by Erik Montnemery (#9544)
- Command ``SwitchMode 15`` sending only MQTT message on switch change (#9593)
- 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 ``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 ``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
@ -89,6 +90,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- TLS fingerprint ``#define MQTT_FINGERPRINT`` from string to hexnumbers (#9570) - TLS fingerprint ``#define MQTT_FINGERPRINT`` from string to hexnumbers (#9570)
- Command ``Status`` output for disabled status types now returns {"Command":"Error"} - Command ``Status`` output for disabled status types now returns {"Command":"Error"}
- MAX31865 driver to support up to 6 thermocouples selected by ``MX31865 CS`` instead of ``SSPI CS`` (#9103) - MAX31865 driver to support up to 6 thermocouples selected by ``MX31865 CS`` instead of ``SSPI CS`` (#9103)
- When ``SetOption73 1`` JSON result from `{"ACTION":"SINGLE"}` to `{"Button1":{"Action":"SINGLE"}}`
### Changed ### Changed
- Command ``Gpio17`` replaces command ``Adc`` - Command ``Gpio17`` replaces command ``Adc``

View File

@ -37,9 +37,11 @@
#define D_JSON_BAUDRATE "Baudrate" #define D_JSON_BAUDRATE "Baudrate"
#define D_JSON_BLINK "Blink" #define D_JSON_BLINK "Blink"
#define D_JSON_BLOCKED_LOOP "Blocked Loop" #define D_JSON_BLOCKED_LOOP "Blocked Loop"
#define D_JSON_BLUE "Blue"
#define D_JSON_BOOTVERSION "Boot" #define D_JSON_BOOTVERSION "Boot"
#define D_JSON_BOOTCOUNT "BootCount" #define D_JSON_BOOTCOUNT "BootCount"
#define D_JSON_BSSID "BSSId" #define D_JSON_BSSID "BSSId"
#define D_JSON_BUTTON "Button"
#define D_JSON_BUILDDATETIME "BuildDateTime" #define D_JSON_BUILDDATETIME "BuildDateTime"
#define D_JSON_CHANNEL "Channel" #define D_JSON_CHANNEL "Channel"
#define D_JSON_CO2 "CarbonDioxide" #define D_JSON_CO2 "CarbonDioxide"
@ -82,6 +84,7 @@
#define D_JSON_FROM "from" #define D_JSON_FROM "from"
#define D_JSON_GAS "Gas" #define D_JSON_GAS "Gas"
#define D_JSON_GATEWAY "Gateway" #define D_JSON_GATEWAY "Gateway"
#define D_JSON_GREEN "Green"
#define D_JSON_GROUPS "Groups" #define D_JSON_GROUPS "Groups"
#define D_JSON_HALTING "Halting" #define D_JSON_HALTING "Halting"
#define D_JSON_HEAPSIZE "Heap" #define D_JSON_HEAPSIZE "Heap"
@ -132,6 +135,7 @@
#define D_JSON_PROGRAMSIZE "ProgramSize" #define D_JSON_PROGRAMSIZE "ProgramSize"
#define D_JSON_PSRMAXMEMORY "PsrMax" #define D_JSON_PSRMAXMEMORY "PsrMax"
#define D_JSON_PSRFREEMEMORY "PsrFree" #define D_JSON_PSRFREEMEMORY "PsrFree"
#define D_JSON_RED "Red"
#define D_JSON_REFERENCETEMPERATURE "ReferenceTemperature" #define D_JSON_REFERENCETEMPERATURE "ReferenceTemperature"
#define D_JSON_REMAINING "Remaining" #define D_JSON_REMAINING "Remaining"
#define D_JSON_RESET "Reset" #define D_JSON_RESET "Reset"
@ -728,6 +732,8 @@ const char S_JSON_SENSOR_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_SENSO
const char S_JSON_DRIVER_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":%d}"; const char S_JSON_DRIVER_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":%d}";
const char S_JSON_DRIVER_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":\"%s\"}"; const char S_JSON_DRIVER_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_DRIVER "%d\":\"%s\"}";
const char S_JSON_SVALUE_ACTION_SVALUE[] PROGMEM = "{\"%s\":{\"Action\":\"%s\"}}";
const char JSON_SNS_TEMP[] PROGMEM = ",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"; const char JSON_SNS_TEMP[] PROGMEM = ",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}";
const char JSON_SNS_ILLUMINANCE[] PROGMEM = ",\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d}"; const char JSON_SNS_ILLUMINANCE[] PROGMEM = ",\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d}";
@ -787,6 +793,9 @@ const char HTTP_SNS_O2[] PROGMEM = "{s}%s " D_O2 "{
const char HTTP_SNS_LITERS[] PROGMEM = "{s}%s " D_VOLUME "{m}%s " D_UNIT_LITERS "{e}"; const char HTTP_SNS_LITERS[] PROGMEM = "{s}%s " D_VOLUME "{m}%s " D_UNIT_LITERS "{e}";
const char HTTP_SNS_LPM[] PROGMEM = "{s}%s " D_FLOW_RATE "{m}%s " D_UNIT_LITERS_PER_MIN "{e}"; const char HTTP_SNS_LPM[] PROGMEM = "{s}%s " D_FLOW_RATE "{m}%s " D_UNIT_LITERS_PER_MIN "{e}";
const char HTTP_SNS_DO[] PROGMEM = "{s}%s " D_DO "{m}%s " D_UNIT_PARTS_PER_MILLION "{e}"; const char HTTP_SNS_DO[] PROGMEM = "{s}%s " D_DO "{m}%s " D_UNIT_PARTS_PER_MILLION "{e}";
const char HTTP_SNS_COLOR_RED[] PROGMEM = "{s}%s " D_COLOR_RED "{m}%u " "{e}";
const char HTTP_SNS_COLOR_GREEN[] PROGMEM = "{s}%s " D_COLOR_GREEN "{m}%u " "{e}";
const char HTTP_SNS_COLOR_BLUE[] PROGMEM = "{s}%s " D_COLOR_BLUE "{m}%u " "{e}";
const char S_MAIN_MENU[] PROGMEM = D_MAIN_MENU; const char S_MAIN_MENU[] PROGMEM = D_MAIN_MENU;
const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION; const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION;

View File

@ -1,7 +1,7 @@
/* /*
it-IT.h - localization for Italian - Italy for Tasmota it-IT.h - localization for Italian - Italy for Tasmota
Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 30.10.2020 Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 02.11.2020
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -84,7 +84,7 @@
#define D_DISABLED "Disabilitato/a" #define D_DISABLED "Disabilitato/a"
#define D_DISTANCE "Distanza" #define D_DISTANCE "Distanza"
#define D_DNS_SERVER "Server DNS" #define D_DNS_SERVER "Server DNS"
#define D_DO "Disolved Oxygen" #define D_DO "Ossigeno dissolto"
#define D_DONE "Completato" #define D_DONE "Completato"
#define D_DST_TIME "DST" #define D_DST_TIME "DST"
#define D_EC "EC" #define D_EC "EC"

View File

@ -501,9 +501,9 @@
// xsns_27_apds9960.ino // xsns_27_apds9960.ino
#define D_GESTURE "Gesture" #define D_GESTURE "Gesture"
#define D_COLOR_RED "Red" #define D_COLOR_RED ""
#define D_COLOR_GREEN "Green" #define D_COLOR_GREEN "绿"
#define D_COLOR_BLUE "Blue" #define D_COLOR_BLUE ""
#define D_CCT "CCT" #define D_CCT "CCT"
#define D_PROXIMITY "Proximity" #define D_PROXIMITY "Proximity"

View File

@ -572,6 +572,7 @@
// #define USE_EZOPRS // [I2cDriver55] Enable support for EZO's PRS sensor (+0k7 code) - Shared EZO code required for any EZO device (+1k2 code) // #define USE_EZOPRS // [I2cDriver55] Enable support for EZO's PRS sensor (+0k7 code) - Shared EZO code required for any EZO device (+1k2 code)
// #define USE_EZOFLO // [I2cDriver55] Enable support for EZO's FLO sensor (+0k4 code) - Shared EZO code required for any EZO device (+1k2 code) // #define USE_EZOFLO // [I2cDriver55] Enable support for EZO's FLO sensor (+0k4 code) - Shared EZO code required for any EZO device (+1k2 code)
// #define USE_EZODO // [I2cDriver55] Enable support for EZO's DO sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) // #define USE_EZODO // [I2cDriver55] Enable support for EZO's DO sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code)
// #define USE_EZORGB // [I2cDriver55] Enable support for EZO's RGB sensor (+0k5 code) - Shared EZO code required for any EZO device (+1k2 code)
// #define USE_DISPLAY // Add I2C Display Support (+2k code) // #define USE_DISPLAY // Add I2C Display Support (+2k code)
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0

View File

@ -44,7 +44,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) - SetOption16 - Switch between clockwise or counter-clockwise uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) - SetOption16 - Switch between clockwise or counter-clockwise
uint32_t decimal_text : 1; // bit 17 (v5.8.1) - SetOption17 - Switch between decimal or hexadecimal output (0 = hexadecimal, 1 = decimal) uint32_t decimal_text : 1; // bit 17 (v5.8.1) - SetOption17 - Switch between decimal or hexadecimal output (0 = hexadecimal, 1 = decimal)
uint32_t light_signal : 1; // bit 18 (v5.10.0c) - SetOption18 - Pair light signal with CO2 sensor uint32_t light_signal : 1; // bit 18 (v5.10.0c) - SetOption18 - Pair light signal with CO2 sensor
uint32_t hass_discovery : 1; // bit 19 (v5.11.1a) - SetOption19 - Control Home Assistantautomatic discovery (See SetOption59) uint32_t hass_discovery : 1; // bit 19 (v5.11.1a) - SetOption19 - Control Home Assistant automatic discovery (See SetOption59)
uint32_t not_power_linked : 1; // bit 20 (v5.11.1f) - SetOption20 - Control power in relation to Dimmer/Color/Ct changes uint32_t not_power_linked : 1; // bit 20 (v5.11.1f) - SetOption20 - Control power in relation to Dimmer/Color/Ct changes
uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i) - SetOption21 - Show voltage even if powered off uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i) - SetOption21 - Show voltage even if powered off
uint32_t mqtt_serial : 1; // bit 22 (v5.12.0f) - CMND_SERIALSEND and CMND_SERIALLOG uint32_t mqtt_serial : 1; // bit 22 (v5.12.0f) - CMND_SERIALSEND and CMND_SERIALLOG
@ -139,7 +139,8 @@ 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 spare00 : 1; // bit 0 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 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
uint32_t spare03 : 1; // bit 3 uint32_t spare03 : 1; // bit 3

View File

@ -61,23 +61,21 @@ struct TOUCH_BUTTON {
/********************************************************************************************/ /********************************************************************************************/
void ButtonPullupFlag(uint8 button_bit) void ButtonPullupFlag(uint32_t button_bit) {
{
bitSet(Button.no_pullup_mask, button_bit); bitSet(Button.no_pullup_mask, button_bit);
} }
void ButtonInvertFlag(uint8 button_bit) void ButtonInvertFlag(uint32_t button_bit) {
{
bitSet(Button.inverted_mask, button_bit); bitSet(Button.inverted_mask, button_bit);
} }
#ifdef ESP32 #ifdef ESP32
void ButtonTouchFlag(uint8 button_bit) void ButtonTouchFlag(uint32_t button_bit) {
{
bitSet(Button.touch_mask, button_bit); bitSet(Button.touch_mask, button_bit);
} }
#endif // ESP32 #endif // ESP32
void ButtonInit(void)
{ void ButtonInit(void) {
Button.present = 0; Button.present = 0;
#ifdef ESP8266 #ifdef ESP8266
if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) {
@ -101,8 +99,7 @@ void ButtonInit(void)
} }
} }
uint8_t ButtonSerial(uint8_t serial_in_byte) uint8_t ButtonSerial(uint8_t serial_in_byte) {
{
if (Button.dual_receive_count) { if (Button.dual_receive_count) {
Button.dual_receive_count--; Button.dual_receive_count--;
if (Button.dual_receive_count) { if (Button.dual_receive_count) {
@ -133,8 +130,7 @@ uint8_t ButtonSerial(uint8_t serial_in_byte)
* SetOption73 (0) - Decouple button from relay and send just mqtt topic * SetOption73 (0) - Decouple button from relay and send just mqtt topic
\*********************************************************************************************/ \*********************************************************************************************/
void ButtonHandler(void) void ButtonHandler(void) {
{
if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit
uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command
@ -355,8 +351,8 @@ void ButtonHandler(void)
} }
} }
void MqttButtonTopic(uint8_t button_id, uint8_t action, uint8_t hold) /*
{ void MqttButtonTopic(uint8_t button_id, uint8_t action, uint8_t hold) {
char scommand[CMDSZ]; char scommand[CMDSZ];
char stopic[TOPSZ]; char stopic[TOPSZ];
char mqttstate[7]; char mqttstate[7];
@ -371,9 +367,21 @@ void MqttButtonTopic(uint8_t button_id, uint8_t action, uint8_t hold)
MqttPublish(stopic); MqttPublish(stopic);
} }
} }
*/
void ButtonLoop(void) void MqttButtonTopic(uint32_t button_id, uint32_t action, uint32_t hold) {
{ SendKey(KEY_BUTTON, button_id, (hold) ? 3 : action +9);
if (!Settings.flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59)
char scommand[10];
snprintf_P(scommand, sizeof(scommand), PSTR(D_JSON_BUTTON "%d"), button_id);
char mqttstate[7];
Response_P(S_JSON_SVALUE_ACTION_SVALUE, scommand, (hold) ? SettingsText(SET_STATE_TXT4) : GetTextIndexed(mqttstate, sizeof(mqttstate), action, kMultiPress));
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, scommand);
}
}
void ButtonLoop(void) {
if (Button.present) { if (Button.present) {
if (TimeReached(Button.debounce)) { if (TimeReached(Button.debounce)) {
SetNextTimeInterval(Button.debounce, Settings.button_debounce); // ButtonDebounce (50) SetNextTimeInterval(Button.debounce, Settings.button_debounce); // ButtonDebounce (50)

View File

@ -391,7 +391,7 @@ void CmndPower(void)
void CmndStatus(void) void CmndStatus(void)
{ {
uint32_t payload = XdrvMailbox.payload; int32_t payload = XdrvMailbox.payload;
if (payload > MAX_STATUS) { return; } // {"Command":"Error"} if (payload > MAX_STATUS) { return; } // {"Command":"Error"}
if (!Settings.flag.mqtt_enabled && (6 == payload)) { return; } // SetOption3 - Enable MQTT if (!Settings.flag.mqtt_enabled && (6 == payload)) { return; } // SetOption3 - Enable MQTT
@ -402,7 +402,7 @@ void CmndStatus(void)
char stemp[200]; char stemp[200];
char stemp2[TOPSZ]; char stemp2[TOPSZ];
if (0 == payload) { if ((0 == payload) || (-99 == payload)) {
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;
#ifdef USE_SONOFF_IFAN #ifdef USE_SONOFF_IFAN
if (IsModuleIfan()) { maxfn = 1; } if (IsModuleIfan()) { maxfn = 1; }

View File

@ -652,7 +652,9 @@ void ResponseAppendFeatures(void)
#if defined(USE_I2C) && defined(USE_EZODO) #if defined(USE_I2C) && defined(USE_EZODO)
feature7 |= 0x00000100; feature7 |= 0x00000100;
#endif #endif
// feature7 |= 0x00000200; #if defined(USE_I2C) && defined(USE_EZORGB)
feature7 |= 0x00000200;
#endif
// feature7 |= 0x00000400; // feature7 |= 0x00000400;
// feature7 |= 0x00000800; // feature7 |= 0x00000800;

View File

@ -34,6 +34,10 @@ const uint8_t AC_PERIOD = (20 + SWITCH_FAST_PROBE_INTERVAL - 1) / SWITCH_FAST_PR
#define SM_NO_TIMER_MASK 0xFF #define SM_NO_TIMER_MASK 0xFF
#define SM_FIRST_PRESS 0x40 #define SM_FIRST_PRESS 0x40
#define SM_SECOND_PRESS 0x80 #define SM_SECOND_PRESS 0x80
#define POWER_NONE 99
const char kSwitchPressStates[] PROGMEM =
"||||POWER_INCREMENT|POWER_INV|POWER_CLEAR|POWER_RELEASE|POWER_100|";
#include <Ticker.h> #include <Ticker.h>
@ -52,28 +56,23 @@ struct SWITCH {
/********************************************************************************************/ /********************************************************************************************/
void SwitchPullupFlag(uint16 switch_bit) void SwitchPullupFlag(uint32 switch_bit) {
{
bitSet(Switch.no_pullup_mask, switch_bit); bitSet(Switch.no_pullup_mask, switch_bit);
} }
void SwitchSetVirtual(uint32_t index, uint8_t state) void SwitchSetVirtual(uint32_t index, uint32_t state) {
{
Switch.virtual_state[index] = state; Switch.virtual_state[index] = state;
} }
uint8_t SwitchGetVirtual(uint32_t index) uint8_t SwitchGetVirtual(uint32_t index) {
{
return Switch.virtual_state[index]; return Switch.virtual_state[index];
} }
uint8_t SwitchLastState(uint32_t index) uint8_t SwitchLastState(uint32_t index) {
{
return Switch.last_state[index]; return Switch.last_state[index];
} }
bool SwitchState(uint32_t index) bool SwitchState(uint32_t index) {
{
uint32_t switchmode = Settings.switchmode[index]; uint32_t switchmode = Settings.switchmode[index];
return ((FOLLOW_INV == switchmode) || return ((FOLLOW_INV == switchmode) ||
(PUSHBUTTON_INV == switchmode) || (PUSHBUTTON_INV == switchmode) ||
@ -86,17 +85,16 @@ bool SwitchState(uint32_t index)
/*********************************************************************************************/ /*********************************************************************************************/
void SwitchProbe(void) void SwitchProbe(void) {
{ if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit
if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit
uint8_t state_filter; uint32_t state_filter;
uint8_t debounce_flags = Settings.switch_debounce % 10; uint32_t switch_probe_interval;
uint8_t force_high = debounce_flags &1; // 51, 101, 151 etc uint32_t first_change = Switch.first_change;
uint8_t force_low = debounce_flags &2; // 52, 102, 152 etc uint32_t debounce_flags = Settings.switch_debounce % 10;
uint8_t ac_detect = debounce_flags == 9; bool force_high = (debounce_flags &1); // 51, 101, 151 etc
uint8_t switch_probe_interval; bool force_low = (debounce_flags &2); // 52, 102, 152 etc
uint8_t first_change = Switch.first_change; bool ac_detect = (debounce_flags == 9);
if (ac_detect) { if (ac_detect) {
switch_probe_interval = SWITCH_FAST_PROBE_INTERVAL; switch_probe_interval = SWITCH_FAST_PROBE_INTERVAL;
@ -117,7 +115,7 @@ void SwitchProbe(void)
// Olimex user_switch2.c code to fix 50Hz induced pulses // Olimex user_switch2.c code to fix 50Hz induced pulses
if (1 == digitalRead(Pin(GPIO_SWT1, i))) { if (1 == digitalRead(Pin(GPIO_SWT1, i))) {
if (ac_detect) { // Enabled with SwitchDebounce x9 if (ac_detect) { // Enabled with SwitchDebounce x9
Switch.state[i] |= 0x80; Switch.state[i] |= 0x80;
if (Switch.state[i] > 0x80) { if (Switch.state[i] > 0x80) {
Switch.state[i]--; Switch.state[i]--;
@ -128,9 +126,9 @@ void SwitchProbe(void)
} }
} else { } else {
if (force_high) { // Enabled with SwitchDebounce x1 if (force_high) { // Enabled with SwitchDebounce x1
if (1 == Switch.virtual_state[i]) { if (1 == Switch.virtual_state[i]) {
Switch.state[i] = state_filter; // With noisy input keep current state 1 unless constant 0 Switch.state[i] = state_filter; // With noisy input keep current state 1 unless constant 0
} }
} }
@ -143,7 +141,7 @@ void SwitchProbe(void)
} }
} else { } else {
if (ac_detect) { // Enabled with SwitchDebounce x9 if (ac_detect) { // Enabled with SwitchDebounce x9
/* /*
* Moes MS-104B and similar devices using an AC detection circuitry * Moes MS-104B and similar devices using an AC detection circuitry
* on their switch inputs generating an ~4 ms long low pulse every * on their switch inputs generating an ~4 ms long low pulse every
@ -174,9 +172,9 @@ void SwitchProbe(void)
} }
} else { } else {
if (force_low) { // Enabled with SwitchDebounce x2 if (force_low) { // Enabled with SwitchDebounce x2
if (0 == Switch.virtual_state[i]) { if (0 == Switch.virtual_state[i]) {
Switch.state[i] = 0; // With noisy input keep current state 0 unless constant 1 Switch.state[i] = 0; // With noisy input keep current state 0 unless constant 1
} }
} }
@ -193,9 +191,8 @@ void SwitchProbe(void)
TickerSwitch.attach_ms(switch_probe_interval, SwitchProbe); // Re-arm as core 2.3.0 does only support ONCE mode TickerSwitch.attach_ms(switch_probe_interval, SwitchProbe); // Re-arm as core 2.3.0 does only support ONCE mode
} }
void SwitchInit(void) void SwitchInit(void) {
{ bool ac_detect = (Settings.switch_debounce % 10 == 9);
uint8_t ac_detect = Settings.switch_debounce % 10 == 9;
Switch.present = 0; Switch.present = 0;
for (uint32_t i = 0; i < MAX_SWITCHES; i++) { for (uint32_t i = 0; i < MAX_SWITCHES; i++) {
@ -230,58 +227,64 @@ void SwitchInit(void)
* Switch handler * Switch handler
\*********************************************************************************************/ \*********************************************************************************************/
void SwitchHandler(uint8_t mode) void SwitchHandler(uint32_t mode) {
{ if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit
if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit
uint16_t loops_per_second = 1000 / Settings.switch_debounce; uint32_t loops_per_second = 1000 / Settings.switch_debounce;
for (uint32_t i = 0; i < MAX_SWITCHES; i++) { for (uint32_t i = 0; i < MAX_SWITCHES; i++) {
if (PinUsed(GPIO_SWT1, i) || (mode)) { if (PinUsed(GPIO_SWT1, i) || (mode)) {
uint8_t button = Switch.virtual_state[i]; uint32_t button = Switch.virtual_state[i];
uint8_t switchflag = POWER_TOGGLE +1; uint32_t switchflag = POWER_TOGGLE +1;
uint32_t mqtt_action = POWER_NONE;
if (Switch.hold_timer[i] & (((Settings.switchmode[i] == PUSHHOLDMULTI) | (Settings.switchmode[i] == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK)) { if (Switch.hold_timer[i] & (((Settings.switchmode[i] == PUSHHOLDMULTI) | (Settings.switchmode[i] == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK)) {
Switch.hold_timer[i]--; Switch.hold_timer[i]--;
if ((Switch.hold_timer[i] & SM_TIMER_MASK) == loops_per_second * Settings.param[P_HOLD_TIME] / 25) { if ((Switch.hold_timer[i] & SM_TIMER_MASK) == loops_per_second * Settings.param[P_HOLD_TIME] / 25) {
if ((Settings.switchmode[i] == PUSHHOLDMULTI) & (NOT_PRESSED == Switch.last_state[i])) { if ((Settings.switchmode[i] == PUSHHOLDMULTI) & (NOT_PRESSED == Switch.last_state[i])) {
SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT
} }
if ((Settings.switchmode[i] == PUSHHOLDMULTI_INV) & (PRESSED == Switch.last_state[i])) { if ((Settings.switchmode[i] == PUSHHOLDMULTI_INV) & (PRESSED == Switch.last_state[i])) {
SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT
} }
} }
if (0 == (Switch.hold_timer[i] & (((Settings.switchmode[i] == PUSHHOLDMULTI) | (Settings.switchmode[i] == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK))) { if (0 == (Switch.hold_timer[i] & (((Settings.switchmode[i] == PUSHHOLDMULTI) | (Settings.switchmode[i] == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK))) {
switch (Settings.switchmode[i]) { switch (Settings.switchmode[i]) {
case TOGGLEMULTI: case TOGGLEMULTI:
switchflag = POWER_TOGGLE; // Toggle after hold switchflag = POWER_TOGGLE; // Toggle after hold
break; break;
case FOLLOWMULTI: case FOLLOWMULTI:
switchflag = button &1; // Follow wall switch state after hold switchflag = button &1; // Follow wall switch state after hold
break; break;
case FOLLOWMULTI_INV: case FOLLOWMULTI_INV:
switchflag = ~button &1; // Follow inverted wall switch state after hold switchflag = ~button &1; // Follow inverted wall switch state after hold
break; break;
case PUSHHOLDMULTI: case PUSHHOLDMULTI:
if (NOT_PRESSED == button) { if (NOT_PRESSED == button) {
Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 25; Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 25;
SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT
mqtt_action = POWER_INCREMENT;
} else { } else {
Switch.hold_timer[i]= 0; Switch.hold_timer[i]= 0;
SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT
mqtt_action = POWER_CLEAR;
} }
break; break;
case PUSHHOLDMULTI_INV: case PUSHHOLDMULTI_INV:
if (PRESSED == button) { if (PRESSED == button) {
Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 25; Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 25;
SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT
mqtt_action = POWER_INCREMENT;
} else { } else {
Switch.hold_timer[i]= 0; Switch.hold_timer[i]= 0;
SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT
mqtt_action = POWER_CLEAR;
} }
break; break;
default: default:
SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT
mqtt_action = POWER_HOLD;
break; break;
} }
} }
@ -291,22 +294,22 @@ void SwitchHandler(uint8_t mode)
switch (Settings.switchmode[i]) { switch (Settings.switchmode[i]) {
case TOGGLE: case TOGGLE:
case PUSHBUTTON_TOGGLE: case PUSHBUTTON_TOGGLE:
switchflag = POWER_TOGGLE; // Toggle switchflag = POWER_TOGGLE; // Toggle
break; break;
case FOLLOW: case FOLLOW:
switchflag = button &1; // Follow wall switch state switchflag = button &1; // Follow wall switch state
break; break;
case FOLLOW_INV: case FOLLOW_INV:
switchflag = ~button &1; // Follow inverted wall switch state switchflag = ~button &1; // Follow inverted wall switch state
break; break;
case PUSHBUTTON: case PUSHBUTTON:
if (PRESSED == button) { if (PRESSED == button) {
switchflag = POWER_TOGGLE; // Toggle with pushbutton to Gnd switchflag = POWER_TOGGLE; // Toggle with pushbutton to Gnd
} }
break; break;
case PUSHBUTTON_INV: case PUSHBUTTON_INV:
if (NOT_PRESSED == button) { if (NOT_PRESSED == button) {
switchflag = POWER_TOGGLE; // Toggle with releasing pushbutton from Gnd switchflag = POWER_TOGGLE; // Toggle with releasing pushbutton from Gnd
} }
break; break;
case PUSHBUTTONHOLD: case PUSHBUTTONHOLD:
@ -314,8 +317,8 @@ void SwitchHandler(uint8_t mode)
Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; // Start timer on button press Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; // Start timer on button press
} }
if ((NOT_PRESSED == button) && (Switch.hold_timer[i])) { if ((NOT_PRESSED == button) && (Switch.hold_timer[i])) {
Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer... Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer...
switchflag = POWER_TOGGLE; // ...and Toggle switchflag = POWER_TOGGLE; // ...and Toggle
} }
break; break;
case PUSHBUTTONHOLD_INV: case PUSHBUTTONHOLD_INV:
@ -323,8 +326,8 @@ void SwitchHandler(uint8_t mode)
Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; // Start timer on button press... Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; // Start timer on button press...
} }
if ((PRESSED == button) && (Switch.hold_timer[i])) { if ((PRESSED == button) && (Switch.hold_timer[i])) {
Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer. Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer.
switchflag = POWER_TOGGLE; // ...and Toggle switchflag = POWER_TOGGLE; // ...and Toggle
} }
break; break;
case TOGGLEMULTI: case TOGGLEMULTI:
@ -332,30 +335,34 @@ void SwitchHandler(uint8_t mode)
case FOLLOWMULTI_INV: case FOLLOWMULTI_INV:
if (Switch.hold_timer[i]) { if (Switch.hold_timer[i]) {
Switch.hold_timer[i] = 0; Switch.hold_timer[i] = 0;
SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT
mqtt_action = POWER_HOLD;
} else { } else {
Switch.hold_timer[i] = loops_per_second / 2; // 0.5 second multi press window Switch.hold_timer[i] = loops_per_second / 2; // 0.5 second multi press window
} }
break; break;
case PUSHHOLDMULTI: case PUSHHOLDMULTI:
if (NOT_PRESSED == button) { if (NOT_PRESSED == button) {
if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) {
Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0;
SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT
mqtt_action = POWER_INV;
} }
} else { } else {
if ((Switch.hold_timer[i] & SM_TIMER_MASK) > loops_per_second * Settings.param[P_HOLD_TIME] / 25) { if ((Switch.hold_timer[i] & SM_TIMER_MASK) > loops_per_second * Settings.param[P_HOLD_TIME] / 25) {
if((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { if((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) {
Switch.hold_timer[i]= SM_FIRST_PRESS; Switch.hold_timer[i]= SM_FIRST_PRESS;
switchflag = POWER_TOGGLE; // Toggle with pushbutton switchflag = POWER_TOGGLE; // Toggle with pushbutton
} }
else{ else{
SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT
mqtt_action = POWER_100;
Switch.hold_timer[i]= 0; Switch.hold_timer[i]= 0;
} }
} else { } else {
Switch.hold_timer[i]= 0; Switch.hold_timer[i]= 0;
SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT
mqtt_action = POWER_RELEASE;
} }
} }
Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings.param[P_HOLD_TIME] / 10; Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings.param[P_HOLD_TIME] / 10;
@ -364,33 +371,36 @@ void SwitchHandler(uint8_t mode)
if (PRESSED == button) { if (PRESSED == button) {
if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) {
Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0;
SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT
mqtt_action = POWER_INV;
} }
} else { } else {
if ((Switch.hold_timer[i] & SM_TIMER_MASK)> loops_per_second * Settings.param[P_HOLD_TIME] / 25) { if ((Switch.hold_timer[i] & SM_TIMER_MASK)> loops_per_second * Settings.param[P_HOLD_TIME] / 25) {
if((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { if((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) {
Switch.hold_timer[i]= SM_FIRST_PRESS; Switch.hold_timer[i]= SM_FIRST_PRESS;
switchflag = POWER_TOGGLE; // Toggle with pushbutton switchflag = POWER_TOGGLE; // Toggle with pushbutton
} }
else{ else{
SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT
mqtt_action = POWER_100;
Switch.hold_timer[i]= 0; Switch.hold_timer[i]= 0;
} }
} else { } else {
Switch.hold_timer[i]= 0; Switch.hold_timer[i]= 0;
SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT
mqtt_action = POWER_RELEASE;
} }
} }
Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings.param[P_HOLD_TIME] / 10; Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings.param[P_HOLD_TIME] / 10;
break; break;
case PUSHON: case PUSHON:
if (PRESSED == button) { if (PRESSED == button) {
switchflag = POWER_ON; // Power ON with pushbutton to Gnd switchflag = POWER_ON; // Power ON with pushbutton to Gnd
} }
break; break;
case PUSHON_INV: case PUSHON_INV:
if (NOT_PRESSED == button) { if (NOT_PRESSED == button) {
switchflag = POWER_ON; // Power ON with releasing pushbutton from Gnd switchflag = POWER_ON; // Power ON with releasing pushbutton from Gnd
} }
break; break;
case PUSH_IGNORE: case PUSH_IGNORE:
@ -400,16 +410,34 @@ void SwitchHandler(uint8_t mode)
Switch.last_state[i] = button; Switch.last_state[i] = button;
} }
if (switchflag <= POWER_TOGGLE) { if (switchflag <= POWER_TOGGLE) {
if (!SendKey(KEY_SWITCH, i +1, switchflag)) { // Execute command via MQTT if (!Settings.flag5.mqtt_switches) { // SetOption114 (0) - Detach Swiches from relays and enable MQTT action state for all the SwitchModes
ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < TasmotaGlobal.devices_present) 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)
}
} 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 (!Settings.flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59)
char mqtt_state_str[16];
char *mqtt_state = mqtt_state_str;
if (mqtt_action <= 3) {
if (mqtt_action != 3) { SendKey(KEY_SWITCH, i +1, mqtt_action); }
mqtt_state = SettingsText(SET_STATE_TXT1 + mqtt_action);
} else {
GetTextIndexed(mqtt_state_str, sizeof(mqtt_state_str), mqtt_action, kSwitchPressStates);
}
Response_P(S_JSON_SVALUE_ACTION_SVALUE, GetSwitchText(i).c_str(), mqtt_state);
char scommand[10];
snprintf_P(scommand, sizeof(scommand), PSTR(D_JSON_SWITCH "%d"), i +1);
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, scommand);
} }
mqtt_action = POWER_NONE;
} }
} }
} }
} }
void SwitchLoop(void) void SwitchLoop(void) {
{
if (Switch.present) { if (Switch.present) {
if (TimeReached(Switch.debounce)) { if (TimeReached(Switch.debounce)) {
SetNextTimeInterval(Switch.debounce, Settings.switch_debounce); SetNextTimeInterval(Switch.debounce, Settings.switch_debounce);

View File

@ -497,7 +497,7 @@ bool SendKey(uint32_t key, uint32_t device, uint32_t state)
XdrvCall(FUNC_ANY_KEY); XdrvCall(FUNC_ANY_KEY);
XdrvMailbox.payload = payload_save; XdrvMailbox.payload = payload_save;
#ifdef USE_PWM_DIMMER #ifdef USE_PWM_DIMMER
result = true; if (PWM_DIMMER == TasmotaGlobal.module_type) result = true;
} }
#endif // USE_PWM_DIMMER #endif // USE_PWM_DIMMER
return result; return result;

View File

@ -136,7 +136,8 @@
//#define USE_EZOO2 // [I2cDriver55] Enable support for EZO's O2 sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) //#define USE_EZOO2 // [I2cDriver55] Enable support for EZO's O2 sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code)
//#define USE_EZOPRS // [I2cDriver55] Enable support for EZO's PRS sensor (+0k7 code) - Shared EZO code required for any EZO device (+1k2 code) //#define USE_EZOPRS // [I2cDriver55] Enable support for EZO's PRS sensor (+0k7 code) - Shared EZO code required for any EZO device (+1k2 code)
//#define USE_EZOFLO // [I2cDriver55] Enable support for EZO's FLO sensor (+0k4 code) - Shared EZO code required for any EZO device (+1k2 code) //#define USE_EZOFLO // [I2cDriver55] Enable support for EZO's FLO sensor (+0k4 code) - Shared EZO code required for any EZO device (+1k2 code)
// #define USE_EZODO // [I2cDriver55] Enable support for EZO's DO sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) // #define USE_EZODO // [I2cDriver55] Enable support for EZO's DO sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code)
// #define USE_EZORGB // [I2cDriver55] Enable support for EZO's RGB sensor (+0k5 code) - Shared EZO code required for any EZO device (+1k2 code)
#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code) #define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code)
#define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code) #define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code)

View File

@ -352,13 +352,11 @@ void MqttPublishPrefixTopic_P(uint32_t prefix, const char* subtopic, bool retain
* prefix 6 = tele using subtopic or RESULT * prefix 6 = tele using subtopic or RESULT
*/ */
char romram[64]; char romram[64];
char stopic[TOPSZ];
snprintf_P(romram, sizeof(romram), ((prefix > 3) && !Settings.flag.mqtt_response) ? S_RSLT_RESULT : subtopic); // SetOption4 - Switch between MQTT RESULT or COMMAND snprintf_P(romram, sizeof(romram), ((prefix > 3) && !Settings.flag.mqtt_response) ? S_RSLT_RESULT : subtopic); // SetOption4 - Switch between MQTT RESULT or COMMAND
for (uint32_t i = 0; i < strlen(romram); i++) { UpperCase(romram, romram);
romram[i] = toupper(romram[i]);
}
prefix &= 3; prefix &= 3;
char stopic[TOPSZ];
GetTopic_P(stopic, prefix, TasmotaGlobal.mqtt_topic, romram); GetTopic_P(stopic, prefix, TasmotaGlobal.mqtt_topic, romram);
MqttPublish(stopic, retained); MqttPublish(stopic, retained);

View File

@ -1618,8 +1618,8 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) {
if ((0x0000 == profileid) && (0x00 == srcendpoint)) { if ((0x0000 == profileid) && (0x00 == srcendpoint)) {
// ZDO request // ZDO request
// Report LQI // Report LQI
Z_Device & device = zigbee_devices.getShortAddr(srcaddr);
if (srcaddr != localShortAddr) { if (srcaddr != localShortAddr) {
Z_Device & device = zigbee_devices.getShortAddr(srcaddr);
device.setLQI(linkquality); device.setLQI(linkquality);
device.setLastSeenNow(); device.setLastSeenNow();
} }

View File

@ -86,9 +86,6 @@ const char HTTP_SNS_GESTURE[] PROGMEM = "{s}%s " D_GESTURE "{m}%s{e}";
#endif // USE_APDS9960_GESTURE #endif // USE_APDS9960_GESTURE
#ifdef USE_APDS9960_COLOR #ifdef USE_APDS9960_COLOR
const char HTTP_SNS_COLOR_RED[] PROGMEM = "{s}%s " D_COLOR_RED "{m}%u{e}";
const char HTTP_SNS_COLOR_GREEN[] PROGMEM = "{s}%s " D_COLOR_GREEN "{m}%u{e}";
const char HTTP_SNS_COLOR_BLUE[] PROGMEM = "{s}%s " D_COLOR_BLUE "{m}%u{e}";
const char HTTP_SNS_CCT[] PROGMEM = "{s}%s " D_CCT "{m}%u " D_UNIT_KELVIN "{e}"; const char HTTP_SNS_CCT[] PROGMEM = "{s}%s " D_CCT "{m}%u " D_UNIT_KELVIN "{e}";
#endif // USE_APDS9960_COLOR #endif // USE_APDS9960_COLOR

View File

@ -373,6 +373,7 @@ class MI32SensorCallback : public NimBLEClientCallbacks {
} }
void onDisconnect(NimBLEClient* pclient) { void onDisconnect(NimBLEClient* pclient) {
MI32.mode.connected = 0; MI32.mode.connected = 0;
MI32.mode.willReadBatt = 0;
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("disconnected %s"), kMI32DeviceType[(MIBLEsensors[MI32.state.sensor].type)-1]); AddLog_P2(LOG_LEVEL_DEBUG,PSTR("disconnected %s"), kMI32DeviceType[(MIBLEsensors[MI32.state.sensor].type)-1]);
} }
bool onConnParamsUpdateRequest(NimBLEClient* MI32Client, const ble_gap_upd_params* params) { bool onConnParamsUpdateRequest(NimBLEClient* MI32Client, const ble_gap_upd_params* params) {
@ -859,7 +860,7 @@ void MI32StartScanTask(){
xTaskCreatePinnedToCore( xTaskCreatePinnedToCore(
MI32ScanTask, /* Function to implement the task */ MI32ScanTask, /* Function to implement the task */
"MI32ScanTask", /* Name of the task */ "MI32ScanTask", /* Name of the task */
4096, /* Stack size in words */ 2048, /* Stack size in words */
NULL, /* Task input parameter */ NULL, /* Task input parameter */
0, /* Priority of the task */ 0, /* Priority of the task */
NULL, /* Task handle. */ NULL, /* Task handle. */
@ -1660,7 +1661,7 @@ void MI32EverySecond(bool restart){
if(_beacon.active == false) continue; if(_beacon.active == false) continue;
_activeBeacons++; _activeBeacons++;
_beacon.time++; _beacon.time++;
Response_P(PSTR("{\"Beacon%u\":{\"Time\":%u}}"), _beacon.time); Response_P(PSTR("{\"Beacon%u\":{\"Time\":%u}}"), _idx, _beacon.time);
XdrvRulesProcess(); XdrvRulesProcess();
} }
if(_activeBeacons==0) MI32.mode.activeBeacon = 0; if(_activeBeacons==0) MI32.mode.activeBeacon = 0;
@ -1843,7 +1844,7 @@ bool MI32Cmd(void) {
switch(XdrvMailbox.index){ switch(XdrvMailbox.index){
case 0: case 0:
MI32.state.beaconScanCounter = 8; MI32.state.beaconScanCounter = 8;
Response_P(S_JSON_MI32_BCOMMAND_SVALUE, command, XdrvMailbox.index,PSTR("\"scanning\"")); Response_P(S_JSON_MI32_BCOMMAND_SVALUE, command, XdrvMailbox.index,PSTR("scanning"));
break; break;
case 1: case 2: case 3: case 4: case 1: case 2: case 3: case 4:
char _MAC[18]; char _MAC[18];
@ -1880,7 +1881,7 @@ bool MI32Cmd(void) {
* Presentation * Presentation
\*********************************************************************************************/ \*********************************************************************************************/
const char HTTP_MI32[] PROGMEM = "{s}MI ESP32 v0916{m}%u%s / %u{e}"; const char HTTP_MI32[] PROGMEM = "{s}MI ESP32 v0916a{m}%u%s / %u{e}";
const char HTTP_MI32_MAC[] PROGMEM = "{s}%s %s{m}%s{e}"; const char HTTP_MI32_MAC[] PROGMEM = "{s}%s %s{m}%s{e}";
const char HTTP_RSSI[] PROGMEM = "{s}%s " D_RSSI "{m}%d dBm{e}"; const char HTTP_RSSI[] PROGMEM = "{s}%s " D_RSSI "{m}%d dBm{e}";
const char HTTP_BATTERY[] PROGMEM = "{s}%s" " Battery" "{m}%u %%{e}"; const char HTTP_BATTERY[] PROGMEM = "{s}%s" " Battery" "{m}%u %%{e}";

View File

@ -18,13 +18,13 @@
*/ */
#ifdef USE_I2C #ifdef USE_I2C
#if defined(USE_EZOPH) || defined(USE_EZOORP) || defined(USE_EZORTD) || defined(USE_EZOHUM) || defined(USE_EZOEC) || defined(USE_EZOCO2) || defined(USE_EZOO2) || defined(USE_EZOPRS) || defined(USE_EZOFLO) || defined(USE_EZODO) #if defined(USE_EZOPH) || defined(USE_EZOORP) || defined(USE_EZORTD) || defined(USE_EZOHUM) || defined(USE_EZOEC) || defined(USE_EZOCO2) || defined(USE_EZOO2) || defined(USE_EZOPRS) || defined(USE_EZOFLO) || defined(USE_EZODO) || defined(USE_EZORGB)
#define USE_EZO #define USE_EZO
#endif #endif
#if defined(USE_EZO) #if defined(USE_EZO)
#define D_EZO_DELAY 300 // Minimum delay for any instruction #define D_EZO_DELAY 300 // Minimum delay for any instruction
#define D_EZO_MAX_BUF 40 // Maximum response #define D_EZO_MAX_BUF 52 // Maximum response
const char D_EZO_NAME[] PROGMEM = "EZO"; const char D_EZO_NAME[] PROGMEM = "EZO";

View File

@ -0,0 +1,82 @@
/*
xsns_78_ezorgb.ino - EZO RGB I2C RGB sensor support for Tasmota
Copyright (C) 2020 Christopher Tremblay
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_I2C
#ifdef USE_EZORGB
#define EZO_RGB_READ_LATENCY 400
struct EZORGB : public EZOStruct {
EZORGB(uint32_t addr) : EZOStruct(addr), R(-1), G(-1), B(-6), Lux(0), hasLux(false) {}
virtual void ProcessMeasurement(void)
{
char data[D_EZO_MAX_BUF];
char *next;
// R, G, B, Lux
EZOStruct::ProcessMeasurement(data, sizeof(data), EZO_RGB_READ_LATENCY);
R = atoi(data);
next = strchr(data, ',') + 1;
G = atoi(next);
next = strchr(next, ',') + 1;
B = atoi(next);
next = strstr_P(next, PSTR(",Lux"));
hasLux = (next != nullptr);
if (hasLux) {
Lux = atoi(next + sizeof(",Lux") - 1);
}
}
virtual void Show(bool json, const char *name)
{
if (json) {
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_RED "\":%d,\"" D_JSON_GREEN "\":%d,\"" D_JSON_BLUE "\":%d"), name, R, G, B);
if (hasLux) {
ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%d"), Lux);
}
ResponseJsonEnd();
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(HTTP_SNS_COLOR_RED, name, R);
WSContentSend_PD(HTTP_SNS_COLOR_GREEN, name, G);
WSContentSend_PD(HTTP_SNS_COLOR_BLUE, name, B);
if (hasLux) {
WSContentSend_PD(HTTP_SNS_ILLUMINANCE, name, Lux);
}
#endif
}
}
static const char id[] PROGMEM;
private:
uint16_t R, G, B;
uint16_t Lux;
bool hasLux;
};
const char EZORGB::id[] PROGMEM = "RGB";
#endif // USE_EZORGB
#endif // USE_I2C

View File

@ -106,7 +106,11 @@ const char *const EZOSupport[EZO_ADDR_n] PROGMEM = {
#else #else
EZOStruct::id, EZOStruct::id,
#endif #endif
EZOStruct::id, // "RGB" #ifdef USE_EZORGB
EZORGB::id,
#else
EZOStruct::id,
#endif
}; };
#define CREATE_EZO_CLASS(CLASS) \ #define CREATE_EZO_CLASS(CLASS) \
@ -267,6 +271,9 @@ private:
#endif #endif
#ifdef USE_EZOHUM #ifdef USE_EZOHUM
CREATE_EZO_CLASS(HUM) CREATE_EZO_CLASS(HUM)
#endif
#ifdef USE_EZORGB
CREATE_EZO_CLASS(RGB)
#endif #endif
} }
count++; count++;

View File

@ -168,7 +168,8 @@ 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",
"","","",
"","","","", "","","","",
"","","","", "","","","",
"","","","", "","","","",
@ -235,7 +236,7 @@ a_features = [[
],[ ],[
"USE_EZOORP","USE_EZORTD","USE_EZOHUM","USE_EZOEC", "USE_EZOORP","USE_EZORTD","USE_EZOHUM","USE_EZOEC",
"USE_EZOCO2","USE_EZOO2","USE_EZOPRS","USE_EZOFLO", "USE_EZOCO2","USE_EZOO2","USE_EZOPRS","USE_EZOFLO",
"USE_EZODO","","","", "USE_EZODO","USE_EZORGB","","",
"","","","", "","","","",
"","","","", "","","","",
"","","","", "","","","",