Bump version v13.4.0.4

- Add command ``PowerLock`` to disable power control of selected outputs (#21081)
This commit is contained in:
Theo Arends 2024-04-03 11:47:38 +02:00
parent fbe83585bd
commit fe89774fe0
8 changed files with 63 additions and 23 deletions

View File

@ -3,7 +3,19 @@ All notable changes to this project will be documented in this file.
## [Unreleased] - Development
## [13.4.0.3]
## [13.4.0.4]
### Added
- Command ``PowerLock`` to disable power control of selected outputs (#21081)
### Breaking Changed
### Changed
### Fixed
### Removed
## [13.4.0.3] 20240402
### Added
- Zigbee support for attributes of type `uint48` used by energy monitoring (#20992)
- Support for single channel EU863-870 LoRaWanBridge (#17790)

View File

@ -116,8 +116,9 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
[Complete list](BUILDS.md) of available feature and sensors.
## Changelog v13.4.0.3
## Changelog v13.4.0.4
### Added
- Command ``PowerLock`` to disable power control of selected outputs [#21081](https://github.com/arendst/Tasmota/issues/21081)
- Support for calculated heat index if temperature and humidity is available with ``#define USE_HEAT_INDEX`` [#4771](https://github.com/arendst/Tasmota/issues/4771)
- Support for LoRa and single channel EU863-870 LoRaWanBridge [#17790](https://github.com/arendst/Tasmota/issues/17790)
- Support for AMS5915/AMS6915 temperature and pressure sensors [#20814](https://github.com/arendst/Tasmota/issues/20814)

View File

@ -286,6 +286,7 @@
#define D_CMND_STATE "State"
#define D_CMND_POWER "Power"
#define D_CMND_TIMEDPOWER "TimedPower"
#define D_CMND_POWERLOCK "PowerLock"
#define D_CMND_FANSPEED "FanSpeed"
#define D_CMND_POWERONSTATE "PowerOnState"
#define D_CMND_PULSETIME "PulseTime"

View File

@ -857,9 +857,7 @@ typedef struct {
uint16_t flowratemeter_calibration[2];// F78
int32_t energy_kWhexport_ph[3]; // F7C
uint32_t eth_ipv4_address[5]; // F88
uint32_t ex_energy_kWhtotal; // F9C
uint32_t power_lock; // F9C
SBitfield1 sbflag1; // FA0
TeleinfoCfg teleinfo; // FA4
uint64_t rf_protocol_mask; // FA8

View File

@ -22,6 +22,6 @@
#define TASMOTA_SHA_SHORT // Filled by Github sed
const uint32_t TASMOTA_VERSION = 0x0D040003; // 13.4.0.3
const uint32_t TASMOTA_VERSION = 0x0D040004; // 13.4.0.4
#endif // _TASMOTA_VERSION_H_

View File

@ -46,7 +46,7 @@ void RtcSettingsSave(void) {
memset(&RtcSettings, 0, sizeof(RtcSettings));
RtcSettings.valid = RTC_MEM_VALID;
// RtcSettings.ex_energy_kWhtoday = Settings->energy_power_calibration2; // = ex_energy_kWhtoday
// RtcSettings.ex_energy_kWhtotal = Settings->ex_energy_kWhtotal;
// RtcSettings.ex_energy_kWhtotal = Settings->power_lock;
for (uint32_t i = 0; i < 3; i++) {
RtcSettings.energy_kWhtoday_ph[i] = Settings->energy_kWhtoday_ph[i];
RtcSettings.energy_kWhtotal_ph[i] = Settings->energy_kWhtotal_ph[i];
@ -1639,7 +1639,7 @@ void SettingsDelta(void) {
memset(&Settings->sensors, 0xFF, 16); // Enable all possible sensors
}
if (Settings->version < 0x09050004) {
Settings->ex_energy_kWhtotal = Settings->ipv4_address[4];
Settings->power_lock = Settings->ipv4_address[4];
ParseIPv4(&Settings->ipv4_address[4], PSTR(WIFI_DNS2));
}
if (Settings->version < 0x09050005) {
@ -1664,7 +1664,7 @@ void SettingsDelta(void) {
if (Settings->version < 0x09050009) { // 9.5.0.9
memset(&Settings->energy_kWhtoday_ph, 0, 36);
memset(&RtcSettings.energy_kWhtoday_ph, 0, 24);
Settings->energy_kWhtotal_ph[0] = Settings->ex_energy_kWhtotal;
Settings->energy_kWhtotal_ph[0] = Settings->power_lock;
Settings->energy_kWhtoday_ph[0] = Settings->energy_power_calibration2; // = ex_energy_kWhtoday
Settings->energy_kWhyesterday_ph[0] = Settings->energy_voltage_calibration2; // = ex_energy_kWhyesterday
RtcSettings.energy_kWhtoday_ph[0] = RtcSettings.ex_energy_kWhtoday;
@ -1773,6 +1773,9 @@ void SettingsDelta(void) {
}
#endif
*/
if (Settings->version < 0x0D040004) { // 13.4.0.4
Settings->power_lock = 0;
}
Settings->version = TASMOTA_VERSION;
SettingsSave(1);

View File

@ -23,7 +23,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix
// Other commands
D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_RESTART "|"
#ifndef FIRMWARE_MINIMAL_ONLY
D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_TIMEDPOWER "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_SLEEP "|"
D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_POWERLOCK "|" D_CMND_TIMEDPOWER "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_SLEEP "|"
D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|" D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SAVEDATA "|"
D_CMND_SO "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|" D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|"
D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_FREQUENCY_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_WEIGHT_RESOLUTION "|"
@ -63,7 +63,7 @@ SO_SYNONYMS(kTasmotaSynonyms,
void (* const TasmotaCommand[])(void) PROGMEM = {
&CmndUpgrade, &CmndUpgrade, &CmndOtaUrl, &CmndSeriallog, &CmndRestart,
#ifndef FIRMWARE_MINIMAL_ONLY
&CmndBacklog, &CmndDelay, &CmndPower, &CmndTimedPower, &CmndStatus, &CmndState, &CmndSleep,
&CmndBacklog, &CmndDelay, &CmndPower, &CmndPowerLock, &CmndTimedPower, &CmndStatus, &CmndState, &CmndSleep,
&CmndPowerOnState, &CmndPulsetime, &CmndBlinktime, &CmndBlinkcount, &CmndSavedata,
&CmndSetoption, &CmndSetoption, &CmndTemperatureResolution, &CmndHumidityResolution, &CmndPressureResolution, &CmndPowerResolution,
&CmndVoltageResolution, &CmndFrequencyResolution, &CmndCurrentResolution, &CmndEnergyResolution, &CmndWeightResolution,
@ -658,6 +658,26 @@ void CmndPower(void)
}
}
void CmndPowerLock(void) {
// PowerLock - Show current state
// PowerLock0 0 - Reset all power locks
// PowerLock0 1 - Set all power locks
// PowerLock1 1 - Set Power1 lock
if (XdrvMailbox.index <= TasmotaGlobal.devices_present) {
if (XdrvMailbox.payload >= 0) {
XdrvMailbox.payload &= 1;
if (0 == XdrvMailbox.index) { // Control all bits
Settings->power_lock = (XdrvMailbox.payload) ? (1 << TasmotaGlobal.devices_present) -1 : 0;
} else { // Control individual bits
bitWrite(Settings->power_lock, XdrvMailbox.index -1, XdrvMailbox.payload & 1);
}
}
char stemp1[33];
ext_snprintf_P(stemp1, sizeof(stemp1), PSTR("%*_b"), TasmotaGlobal.devices_present, Settings->power_lock);
ResponseCmndChar(stemp1);
}
}
/********************************************************************************************/
typedef struct {

View File

@ -693,9 +693,9 @@ void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
#ifdef USE_SONOFF_IFAN
if (IsModuleIfan()) {
TasmotaGlobal.blink_mask &= 1; // No blinking on the fan relays
Settings->flag.interlock = 0; // No interlock mode as it is already done by the microcontroller - CMND_INTERLOCK - Enable/disable interlock
Settings->pulse_timer[1] = 0; // No pulsetimers on the fan relays
TasmotaGlobal.blink_mask &= 1; // No blinking on the fan relays
Settings->flag.interlock = 0; // No interlock mode as it is already done by the microcontroller - CMND_INTERLOCK - Enable/disable interlock
Settings->pulse_timer[1] = 0; // No pulsetimers on the fan relays
Settings->pulse_timer[2] = 0;
Settings->pulse_timer[3] = 0;
}
@ -703,7 +703,7 @@ void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
bool publish_power = true;
if ((state >= POWER_OFF_NO_STATE) && (state <= POWER_TOGGLE_NO_STATE)) {
state &= 3; // POWER_OFF, POWER_ON or POWER_TOGGLE
state &= 3; // POWER_OFF, POWER_ON or POWER_TOGGLE
publish_power = false;
}
@ -712,26 +712,31 @@ void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
}
TasmotaGlobal.active_device = device;
if (bitRead(Settings->power_lock, device -1)) {
AddLog(LOG_LEVEL_INFO, PSTR("CMD: Power%d is LOCKED"), device);
state = POWER_SHOW_STATE; // Only show state. Make no change
}
if (state != POWER_SHOW_STATE) {
SetPulseTimer((device -1) % MAX_PULSETIMERS, 0);
}
static bool interlock_mutex = false; // Interlock power command pending
power_t mask = 1 << (device -1); // Device to control
static bool interlock_mutex = false; // Interlock power command pending
power_t mask = 1 << (device -1); // Device to control
if (state <= POWER_TOGGLE) {
if ((TasmotaGlobal.blink_mask & mask)) {
TasmotaGlobal.blink_mask &= (POWER_MASK ^ mask); // Clear device mask
MqttPublishPowerBlinkState(device);
}
if (Settings->flag.interlock && // CMND_INTERLOCK - Enable/disable interlock
if (Settings->flag.interlock && // CMND_INTERLOCK - Enable/disable interlock
!interlock_mutex &&
((POWER_ON == state) || ((POWER_TOGGLE == state) && !(TasmotaGlobal.power & mask)))
) {
interlock_mutex = true; // Clear all but masked relay in interlock group if new set requested
interlock_mutex = true; // Clear all but masked relay in interlock group if new set requested
bool perform_interlock_delay = false;
for (uint32_t i = 0; i < MAX_INTERLOCKS; i++) {
if (Settings->interlock[i] & mask) { // Find interlock group
if (Settings->interlock[i] & mask) { // Find interlock group
for (uint32_t j = 0; j < TasmotaGlobal.devices_present; j++) {
power_t imask = 1 << j;
if ((Settings->interlock[i] & imask) && (TasmotaGlobal.power & imask) && (mask != imask)) {
@ -739,11 +744,11 @@ void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
perform_interlock_delay = true;
}
}
break; // An interlocked relay is only present in one group so quit
break; // An interlocked relay is only present in one group so quit
}
}
if (perform_interlock_delay) {
delay(50); // Add some delay to make sure never have more than one relay on
delay(50); // Add some delay to make sure never have more than one relay on
}
interlock_mutex = false;
}
@ -791,7 +796,7 @@ void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
}
TasmotaGlobal.blink_timer = millis() + 100;
TasmotaGlobal.blink_counter = ((!Settings->blinkcount) ? 64000 : (Settings->blinkcount *2)) +1;
TasmotaGlobal.blink_mask |= mask; // Set device mask
TasmotaGlobal.blink_mask |= mask; // Set device mask
MqttPublishPowerBlinkState(device);
return;
}