mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 10:46:31 +00:00
Add better support for bistable (latching) relays
Add support for bistable (latching) relays mixed with monostable relays using GPIO Relay_b or Relay_bi
This commit is contained in:
parent
554a49e520
commit
6031e5df98
@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
## [12.0.2.3]
|
## [12.0.2.3]
|
||||||
### Added
|
### Added
|
||||||
- Support for Sonoff POWR3xxD and THR3xxD (#15856)
|
- Support for Sonoff POWR3xxD and THR3xxD (#15856)
|
||||||
|
- Support for bistable (latching) relays mixed with monostable relays using GPIO Relay_b or Relay_bi
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Driver DHT v6 consolidation for both ESP8266 and ESP32 to support SI7021, THS01 and MS01 on ESP32 (#15856)
|
- Driver DHT v6 consolidation for both ESP8266 and ESP32 to support SI7021, THS01 and MS01 on ESP32 (#15856)
|
||||||
|
@ -114,6 +114,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
|
|||||||
- Command ``GlobalPress2 1..250`` to select Global Pressure source indexed from teleperiod occurance data [#15834](https://github.com/arendst/Tasmota/issues/15834)
|
- Command ``GlobalPress2 1..250`` to select Global Pressure source indexed from teleperiod occurance data [#15834](https://github.com/arendst/Tasmota/issues/15834)
|
||||||
- Support for 5-channel light dimmer driver SM2335 used in SwitchBot Color Bulbs [#15839](https://github.com/arendst/Tasmota/issues/15839)
|
- Support for 5-channel light dimmer driver SM2335 used in SwitchBot Color Bulbs [#15839](https://github.com/arendst/Tasmota/issues/15839)
|
||||||
- Support for Sonoff POWR3xxD and THR3xxD [#15856](https://github.com/arendst/Tasmota/issues/15856)
|
- Support for Sonoff POWR3xxD and THR3xxD [#15856](https://github.com/arendst/Tasmota/issues/15856)
|
||||||
|
- Support for bistable (latching) relays mixed with monostable relays using GPIO Relay_b or Relay_bi
|
||||||
|
|
||||||
### Breaking Changed
|
### Breaking Changed
|
||||||
|
|
||||||
|
@ -192,8 +192,12 @@ enum UserSelectablePins {
|
|||||||
GPIO_SM2335_CLK, GPIO_SM2335_DAT, // SM2335 PWM controller
|
GPIO_SM2335_CLK, GPIO_SM2335_DAT, // SM2335 PWM controller
|
||||||
GPIO_MP3_DFR562_BUSY, // RB-DFR-562, DFPlayer Mini MP3 Player busy flag
|
GPIO_MP3_DFR562_BUSY, // RB-DFR-562, DFPlayer Mini MP3 Player busy flag
|
||||||
GPIO_TM1621_CS, GPIO_TM1621_WR, GPIO_TM1621_RD, GPIO_TM1621_DAT, // Sonoff POWR3xxD and THR3xxD LCD display
|
GPIO_TM1621_CS, GPIO_TM1621_WR, GPIO_TM1621_RD, GPIO_TM1621_DAT, // Sonoff POWR3xxD and THR3xxD LCD display
|
||||||
|
GPIO_REL1_BI, GPIO_REL1_BI_INV, // 8 x Relays bistable
|
||||||
GPIO_SENSOR_END };
|
GPIO_SENSOR_END };
|
||||||
|
|
||||||
|
// Error as warning to rethink GPIO usage
|
||||||
|
static_assert(GPIO_SENSOR_END < 2000, "Too many UserSelectablePins");
|
||||||
|
|
||||||
enum ProgramSelectablePins {
|
enum ProgramSelectablePins {
|
||||||
GPIO_FIX_START = 2046,
|
GPIO_FIX_START = 2046,
|
||||||
GPIO_USER, // User configurable needs to be 2047
|
GPIO_USER, // User configurable needs to be 2047
|
||||||
@ -428,6 +432,7 @@ const char kSensorNames[] PROGMEM =
|
|||||||
D_SENSOR_SM2335_CLK "|" D_SENSOR_SM2335_DAT "|"
|
D_SENSOR_SM2335_CLK "|" D_SENSOR_SM2335_DAT "|"
|
||||||
D_SENSOR_DFR562_BUSY "|"
|
D_SENSOR_DFR562_BUSY "|"
|
||||||
D_GPIO_TM1621_CS "|" D_GPIO_TM1621_WR "|" D_GPIO_TM1621_RD "|" D_GPIO_TM1621_DAT "|"
|
D_GPIO_TM1621_CS "|" D_GPIO_TM1621_WR "|" D_GPIO_TM1621_RD "|" D_GPIO_TM1621_DAT "|"
|
||||||
|
D_SENSOR_RELAY "_b|" D_SENSOR_RELAY "_bi|"
|
||||||
;
|
;
|
||||||
|
|
||||||
const char kSensorNamesFixed[] PROGMEM =
|
const char kSensorNamesFixed[] PROGMEM =
|
||||||
@ -471,6 +476,12 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||||||
#endif
|
#endif
|
||||||
AGPIO(GPIO_REL1) + MAX_RELAYS, // Relays
|
AGPIO(GPIO_REL1) + MAX_RELAYS, // Relays
|
||||||
AGPIO(GPIO_REL1_INV) + MAX_RELAYS,
|
AGPIO(GPIO_REL1_INV) + MAX_RELAYS,
|
||||||
|
|
||||||
|
#ifdef USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
AGPIO(GPIO_REL1_BI) + MAX_RELAYS, // Bistable (Latching) two coil relays
|
||||||
|
AGPIO(GPIO_REL1_BI_INV) + MAX_RELAYS,
|
||||||
|
#endif
|
||||||
|
|
||||||
AGPIO(GPIO_LED1) + MAX_LEDS, // Leds
|
AGPIO(GPIO_LED1) + MAX_LEDS, // Leds
|
||||||
AGPIO(GPIO_LED1_INV) + MAX_LEDS,
|
AGPIO(GPIO_LED1_INV) + MAX_LEDS,
|
||||||
#ifdef USE_COUNTER
|
#ifdef USE_COUNTER
|
||||||
|
@ -397,6 +397,9 @@
|
|||||||
//#define MY_LANGUAGE zh_CN // Chinese (Simplified) in China
|
//#define MY_LANGUAGE zh_CN // Chinese (Simplified) in China
|
||||||
//#define MY_LANGUAGE zh_TW // Chinese (Traditional) in Taiwan
|
//#define MY_LANGUAGE zh_TW // Chinese (Traditional) in Taiwan
|
||||||
|
|
||||||
|
// -- Basic features ------------------------------
|
||||||
|
#define USE_BISTABLE_RELAY_SUPPORT // Add support for bistable (latching) relays using GPIO Relay_b or Relay_bi
|
||||||
|
|
||||||
// -- Wifi Config tools ---------------------------
|
// -- Wifi Config tools ---------------------------
|
||||||
#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 13 as used by Wi-Fi Manager web GUI
|
#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 13 as used by Wi-Fi Manager web GUI
|
||||||
#define USE_IMPROV // Add support for IMPROV serial protocol as used by esp-web-tools (+2k code)
|
#define USE_IMPROV // Add support for IMPROV serial protocol as used by esp-web-tools (+2k code)
|
||||||
|
@ -221,6 +221,9 @@ struct TasmotaGlobal_t {
|
|||||||
|
|
||||||
power_t power; // Current copy of Settings->power
|
power_t power; // Current copy of Settings->power
|
||||||
power_t rel_inverted; // Relay inverted flag (1 = (0 = On, 1 = Off))
|
power_t rel_inverted; // Relay inverted flag (1 = (0 = On, 1 = Off))
|
||||||
|
#ifdef USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
power_t rel_bistable; // Relay bistable bitmap
|
||||||
|
#endif // USE_BISTABLE_RELAY_SUPPORT
|
||||||
power_t last_power; // Last power set state
|
power_t last_power; // Last power set state
|
||||||
power_t blink_power; // Blink power state
|
power_t blink_power; // Blink power state
|
||||||
power_t blink_powersave; // Blink start power save state
|
power_t blink_powersave; // Blink start power save state
|
||||||
|
@ -221,8 +221,7 @@ void ZeroCrossInit(uint32_t offset) {
|
|||||||
|
|
||||||
/********************************************************************************************/
|
/********************************************************************************************/
|
||||||
|
|
||||||
void SetLatchingRelay(power_t lpower, uint32_t state)
|
void SetLatchingRelay(power_t lpower, uint32_t state) {
|
||||||
{
|
|
||||||
// TasmotaGlobal.power xx00 - toggle REL1 (Off) and REL3 (Off) - device 1 Off, device 2 Off
|
// TasmotaGlobal.power xx00 - toggle REL1 (Off) and REL3 (Off) - device 1 Off, device 2 Off
|
||||||
// TasmotaGlobal.power xx01 - toggle REL2 (On) and REL3 (Off) - device 1 On, device 2 Off
|
// TasmotaGlobal.power xx01 - toggle REL2 (On) and REL3 (Off) - device 1 On, device 2 Off
|
||||||
// TasmotaGlobal.power xx10 - toggle REL1 (Off) and REL4 (On) - device 1 Off, device 2 On
|
// TasmotaGlobal.power xx10 - toggle REL1 (Off) and REL4 (On) - device 1 Off, device 2 On
|
||||||
@ -240,8 +239,17 @@ void SetLatchingRelay(power_t lpower, uint32_t state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDevicePower(power_t rpower, uint32_t source)
|
#ifdef USE_BISTABLE_RELAY_SUPPORT
|
||||||
{
|
void ResetBistableRelays(void) {
|
||||||
|
for (uint32_t i = 0; i < MAX_RELAYS; i++) {
|
||||||
|
if (bitRead(TasmotaGlobal.rel_bistable, i)) {
|
||||||
|
DigitalWrite(GPIO_REL1, i, bitRead(TasmotaGlobal.rel_inverted, i) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
|
||||||
|
void SetDevicePower(power_t rpower, uint32_t source) {
|
||||||
ShowSource(source);
|
ShowSource(source);
|
||||||
TasmotaGlobal.last_source = source;
|
TasmotaGlobal.last_source = source;
|
||||||
|
|
||||||
@ -298,6 +306,26 @@ void SetDevicePower(power_t rpower, uint32_t source)
|
|||||||
{
|
{
|
||||||
ZeroCrossMomentStart();
|
ZeroCrossMomentStart();
|
||||||
|
|
||||||
|
#ifdef USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
uint32_t port = 0;
|
||||||
|
uint32_t port_next;
|
||||||
|
for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) {
|
||||||
|
power_t state = rpower &1;
|
||||||
|
|
||||||
|
port_next = 1; // Select next relay
|
||||||
|
if (bitRead(TasmotaGlobal.rel_bistable, port)) {
|
||||||
|
if (!state) { port_next = 2; } // Skip highest relay
|
||||||
|
TasmotaGlobal.latching_relay_pulse = 2; // max 200mS (initiated by stateloop())
|
||||||
|
port += state; // Relay<lowest> = Off, Relay<highest> = On
|
||||||
|
state = 1; // Set pulse
|
||||||
|
}
|
||||||
|
if (i < MAX_RELAYS) {
|
||||||
|
DigitalWrite(GPIO_REL1, port, bitRead(TasmotaGlobal.rel_inverted, port) ? !state : state);
|
||||||
|
}
|
||||||
|
port += port_next; // Select next relay
|
||||||
|
rpower >>= 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) {
|
for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) {
|
||||||
power_t state = rpower &1;
|
power_t state = rpower &1;
|
||||||
if (i < MAX_RELAYS) {
|
if (i < MAX_RELAYS) {
|
||||||
@ -305,6 +333,7 @@ void SetDevicePower(power_t rpower, uint32_t source)
|
|||||||
}
|
}
|
||||||
rpower >>= 1;
|
rpower >>= 1;
|
||||||
}
|
}
|
||||||
|
#endif // USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
|
||||||
ZeroCrossMomentEnd();
|
ZeroCrossMomentEnd();
|
||||||
}
|
}
|
||||||
@ -1125,7 +1154,16 @@ void Every100mSeconds(void)
|
|||||||
|
|
||||||
if (TasmotaGlobal.latching_relay_pulse) {
|
if (TasmotaGlobal.latching_relay_pulse) {
|
||||||
TasmotaGlobal.latching_relay_pulse--;
|
TasmotaGlobal.latching_relay_pulse--;
|
||||||
if (!TasmotaGlobal.latching_relay_pulse) SetLatchingRelay(0, 0);
|
if (!TasmotaGlobal.latching_relay_pulse) {
|
||||||
|
#ifdef ESP8266
|
||||||
|
if (EXS_RELAY == TasmotaGlobal.module_type) {
|
||||||
|
SetLatchingRelay(0, 0);
|
||||||
|
}
|
||||||
|
#endif // ESP8266
|
||||||
|
#ifdef USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
ResetBistableRelays();
|
||||||
|
#endif // USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TasmotaGlobal.skip_sleep) {
|
if (TasmotaGlobal.skip_sleep) {
|
||||||
@ -1969,6 +2007,19 @@ void GpioInit(void)
|
|||||||
bitSet(TasmotaGlobal.rel_inverted, mpin - AGPIO(GPIO_REL1_INV));
|
bitSet(TasmotaGlobal.rel_inverted, mpin - AGPIO(GPIO_REL1_INV));
|
||||||
mpin -= (AGPIO(GPIO_REL1_INV) - AGPIO(GPIO_REL1));
|
mpin -= (AGPIO(GPIO_REL1_INV) - AGPIO(GPIO_REL1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
else if ((mpin >= AGPIO(GPIO_REL1_BI)) && (mpin < (AGPIO(GPIO_REL1_BI) + MAX_RELAYS))) {
|
||||||
|
bitSet(TasmotaGlobal.rel_bistable, mpin - AGPIO(GPIO_REL1_BI));
|
||||||
|
mpin -= (AGPIO(GPIO_REL1_BI) - AGPIO(GPIO_REL1));
|
||||||
|
}
|
||||||
|
else if ((mpin >= AGPIO(GPIO_REL1_BI_INV)) && (mpin < (AGPIO(GPIO_REL1_BI_INV) + MAX_RELAYS))) {
|
||||||
|
bitSet(TasmotaGlobal.rel_bistable, mpin - AGPIO(GPIO_REL1_BI_INV));
|
||||||
|
bitSet(TasmotaGlobal.rel_inverted, mpin - AGPIO(GPIO_REL1_BI_INV));
|
||||||
|
mpin -= (AGPIO(GPIO_REL1_BI_INV) - AGPIO(GPIO_REL1));
|
||||||
|
}
|
||||||
|
#endif // USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
|
||||||
else if ((mpin >= AGPIO(GPIO_LED1_INV)) && (mpin < (AGPIO(GPIO_LED1_INV) + MAX_LEDS))) {
|
else if ((mpin >= AGPIO(GPIO_LED1_INV)) && (mpin < (AGPIO(GPIO_LED1_INV) + MAX_LEDS))) {
|
||||||
bitSet(TasmotaGlobal.led_inverted, mpin - AGPIO(GPIO_LED1_INV));
|
bitSet(TasmotaGlobal.led_inverted, mpin - AGPIO(GPIO_LED1_INV));
|
||||||
mpin -= (AGPIO(GPIO_LED1_INV) - AGPIO(GPIO_LED1));
|
mpin -= (AGPIO(GPIO_LED1_INV) - AGPIO(GPIO_LED1));
|
||||||
@ -2163,6 +2214,10 @@ void GpioInit(void)
|
|||||||
|
|
||||||
GpioInitPwm();
|
GpioInitPwm();
|
||||||
|
|
||||||
|
#ifdef USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
uint32_t bi_device = 0;
|
||||||
|
#endif // USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
|
||||||
for (uint32_t i = 0; i < MAX_RELAYS; i++) {
|
for (uint32_t i = 0; i < MAX_RELAYS; i++) {
|
||||||
if (PinUsed(GPIO_REL1, i)) {
|
if (PinUsed(GPIO_REL1, i)) {
|
||||||
TasmotaGlobal.devices_present++;
|
TasmotaGlobal.devices_present++;
|
||||||
@ -2171,6 +2226,14 @@ void GpioInit(void)
|
|||||||
if (i &1) { TasmotaGlobal.devices_present--; }
|
if (i &1) { TasmotaGlobal.devices_present--; }
|
||||||
}
|
}
|
||||||
#endif // ESP8266
|
#endif // ESP8266
|
||||||
|
|
||||||
|
#ifdef USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
if (bitRead(TasmotaGlobal.rel_bistable, i)) {
|
||||||
|
if (bi_device &1) { TasmotaGlobal.devices_present--; }
|
||||||
|
bi_device++;
|
||||||
|
}
|
||||||
|
#endif // USE_BISTABLE_RELAY_SUPPORT
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user