Ensure Shuttermotorstop even on direct relay operation (#18329)

* Ensure motorstoptime also on direct relay change

When relay is triggered with button or switches it did not take the motorstoptime into account

* Ensure motorstoptime also on direct relay change

When relay is triggered with button or switches it did not take the motorstoptime into account

* Ensure motorstoptime also on direct relay change

When relay is triggered with button or switches it did not take the motorstoptime into account
This commit is contained in:
stefanbode 2023-04-04 16:17:12 +02:00 committed by GitHub
parent 9993061c1a
commit f109d6ff72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 42 deletions

View File

@ -167,6 +167,7 @@ struct SHUTTERGLOBAL {
power_t RelayShutterMask = 0; // bit mask with 11 at the position of relays that belong to at least ONE shutter
power_t RelayOldMask = 0; // bitmatrix that contain the last known state of all relays. Required to detemine the manual changed relay.
power_t RelayCurrentMask = 0; // bitmatrix that contain the current state of all relays
uint8_t LastChangedRelay = 0; // Relay 1..32, 0 no change
uint8_t position_mode = 0; // how to calculate actual position: SHT_TIME, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME
uint8_t skip_relay_change; // avoid overrun at endstops
uint8_t start_reported = 0; // indicates of the shutter start was reported through MQTT JSON
@ -306,6 +307,16 @@ void ShutterSettingsSave(void) {
}
}
uint8_t ShutterGetRelayNoFromBitfield(power_t number) {
int position = 0;
while (number != 0) {
position++;
if (number & 1) return position;
number >>= 1;
}
return 0; // return 0 if no relay found
}
bool ShutterStatus(void) {
if (Settings->flag3.shutter_mode) { // SetOption80 - (Shutter) Enable shutter support (1)
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS13_SHUTTER "\":{"));
@ -802,15 +813,15 @@ void ShutterPowerOff(uint8_t i)
Shutter[i].last_stop_time = millis();
}
void ShutterWaitForMotorStop(uint8_t index)
void ShutterWaitForMotorStop(uint8_t i)
{
Shutter[index-1].last_stop_time = millis();
ShutterWaitForMotorStart(index);
Shutter[i].last_stop_time = millis();
ShutterWaitForMotorStart(i);
}
void ShutterWaitForMotorStart(uint8_t index)
void ShutterWaitForMotorStart(uint8_t i)
{
while (millis() < Shutter[index-1].last_stop_time + ShutterSettings.shutter_motorstop) {
while (millis() < Shutter[i].last_stop_time + ShutterSettings.shutter_motorstop) {
loop();
}
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Stoptime done"));
@ -906,7 +917,7 @@ void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos)
ShutterGlobal.skip_relay_change = 1;
} else {
Shutter[i].pwm_velocity = 0;
ShutterWaitForMotorStart(i+1);
ShutterWaitForMotorStart(i);
switch (ShutterGlobal.position_mode) {
#ifdef SHUTTER_STEPPER
case SHT_COUNTER:
@ -1040,6 +1051,7 @@ void ShutterRelayChanged(void)
default:
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i);
Shutter[i].target_position = Shutter[i].real_position;
Shutter[i].last_stop_time = millis();
}
break;
case SHT_TIME:
@ -1051,8 +1063,9 @@ void ShutterRelayChanged(void)
ShutterStartInit(i, -1, 0);
break;
default:
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i);
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i+1);
Shutter[i].target_position = Shutter[i].real_position;
Shutter[i].last_stop_time = millis();
}
break;
case SHT_TIME_GARAGE:
@ -2024,6 +2037,8 @@ bool Xdrv27(uint32_t function)
uint8_t counterend = XdrvMailbox.index==0?TasmotaGlobal.shutters_present:XdrvMailbox.index;
int32_t rescue_payload = XdrvMailbox.payload;
uint32_t rescue_data_len = XdrvMailbox.data_len;
char stemp1[10];
power_t save_powermatrix;
switch (function) {
case FUNC_SAVE_SETTINGS:
ShutterSettingsSave();
@ -2062,32 +2077,36 @@ bool Xdrv27(uint32_t function)
}
break;
case FUNC_SET_POWER:
char stemp1[10];
// extract the number of the relay that was switched and save for later in Update Position.
ShutterGlobal.RelayCurrentMask = XdrvMailbox.index ^ ShutterGlobal.RelayOldMask;
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Switched relay %d by %s"), ShutterGlobal.RelayCurrentMask,GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource));
ShutterRelayChanged();
ShutterGlobal.RelayOldMask = XdrvMailbox.index;
ShutterGlobal.LastChangedRelay = ShutterGetRelayNoFromBitfield(XdrvMailbox.index ^ ShutterGlobal.RelayOldMask);
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_POWER Relaymask %d SwitchedRelay:%d by %s, payload %d, powermask %d"), ShutterGlobal.RelayOldMask, ShutterGlobal.LastChangedRelay,GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource),XdrvMailbox.payload, TasmotaGlobal.power);
save_powermatrix = TasmotaGlobal.power; // can be changed in ShutterRelayChanged
if (!ShutterGlobal.LastChangedRelay) {
ShutterGlobal.skip_relay_change = 1;
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("INVALID REQUEST"));
} else {
ShutterRelayChanged();
ShutterGlobal.RelayOldMask = XdrvMailbox.index; // may be changed and now revert
TasmotaGlobal.power = save_powermatrix;
}
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_POWER end. powermask %d"), TasmotaGlobal.power);
break;
case FUNC_SET_DEVICE_POWER:
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_DEVICE_POWER Skipping:%d, Source %s"), ShutterGlobal.skip_relay_change,GetTextIndexed(stemp1, sizeof(stemp1), XdrvMailbox.payload, kCommandSource));
if (ShutterGlobal.skip_relay_change ) {
uint8_t i;
for (i = 0; i < TasmotaGlobal.devices_present; i++) {
if (ShutterGlobal.RelayCurrentMask &1) {
break;
}
ShutterGlobal.RelayCurrentMask >>= 1;
}
//AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Skip relay change %d"), i+1);
result = true;
ShutterGlobal.skip_relay_change = 0;
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Skipping switch off relay %d"), i);
ExecuteCommandPowerShutter(i+1, 0, SRC_SHUTTER);
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Skipping switch off relay %d"), ShutterGlobal.LastChangedRelay);
//ExecuteCommandPowerShutter(i+1, 0, SRC_SHUTTER); // should not required anymore. check for bugs
if (ShutterGlobal.LastChangedRelay) ShutterGlobal.RelayOldMask = TasmotaGlobal.power ^= 1<<(ShutterGlobal.LastChangedRelay-1);
}
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_DEVICE_POWER end. powermask %ld, current rel: %ld"), TasmotaGlobal.power, ShutterGlobal.RelayOldMask);
break;
case FUNC_BUTTON_MULTI_PRESSED:
if (XdrvMailbox.index < MAX_SHUTTERS_ESP32*2 && ShutterSettings.shutter_button[XdrvMailbox.index].enabled) {
result = ShutterButtonHandlerMulti();
}
break;

View File

@ -135,6 +135,7 @@ struct SHUTTERGLOBAL {
power_t RelayShutterMask = 0; // bit mask with 11 at the position of relays that belong to at least ONE shutter
power_t RelayOldMask = 0; // bitmatrix that contain the last known state of all relays. Required to detemine the manual changed relay.
power_t RelayCurrentMask = 0; // bitmatrix that contain the current state of all relays
uint8_t LastChangedRelay = 0; // Relay 1..32, 0 no change
uint8_t position_mode = 0; // how to calculate actual position: SHT_TIME, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME
uint8_t skip_relay_change; // avoid overrun at endstops
uint8_t start_reported = 0; // indicates of the shutter start was reported through MQTT JSON
@ -143,6 +144,16 @@ struct SHUTTERGLOBAL {
#define SHT_DIV_ROUND(__A, __B) (((__A) + (__B)/2) / (__B))
uint8_t ShutterGetRelayNoFromBitfield(power_t number) {
int position = 0;
while (number != 0) {
position++;
if (number & 1) return position;
number >>= 1;
}
return 0; // return 0 if no relay found
}
bool ShutterStatus(void) {
if (Settings->flag3.shutter_mode) { // SetOption80 - (Shutter) Enable shutter support (1)
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS13_SHUTTER "\":{"));
@ -322,7 +333,6 @@ void ShutterInit(void)
}
for (uint32_t i = 0; i < MAX_SHUTTERS; i++) {
// set startrelay to 1 on first init, but only to shutter 1. 90% usecase
//Settings->shutter_startrelay[i] = (Settings->shutter_startrelay[i] == 0 && i == 0? 1 : Settings->shutter_startrelay[i]);
if (Settings->shutter_startrelay[i] && (Settings->shutter_startrelay[i] <= 32 )) {
bool relay_in_interlock = false;
TasmotaGlobal.shutters_present++;
@ -641,15 +651,15 @@ void ShutterPowerOff(uint8_t i)
Shutter[i].last_stop_time = millis();
}
void ShutterWaitForMotorStop(uint8_t index)
void ShutterWaitForMotorStop(uint8_t i)
{
Shutter[index-1].last_stop_time = millis();
ShutterWaitForMotorStart(index);
Shutter[i].last_stop_time = millis();
ShutterWaitForMotorStart(i);
}
void ShutterWaitForMotorStart(uint8_t index)
void ShutterWaitForMotorStart(uint8_t i)
{
while (millis() < Shutter[index-1].last_stop_time + Settings->shutter_motorstop) {
while (millis() < Shutter[i].last_stop_time + Settings->shutter_motorstop) {
loop();
}
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Stoptime done"));
@ -745,7 +755,7 @@ void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos)
ShutterGlobal.skip_relay_change = 1;
} else {
Shutter[i].pwm_velocity = 0;
ShutterWaitForMotorStart(i+1);
ShutterWaitForMotorStart(i);
switch (ShutterGlobal.position_mode) {
#ifdef SHUTTER_STEPPER
case SHT_COUNTER:
@ -879,6 +889,7 @@ void ShutterRelayChanged(void)
default:
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i);
Shutter[i].target_position = Shutter[i].real_position;
Shutter[i].last_stop_time = millis();
}
break;
case SHT_TIME:
@ -890,8 +901,9 @@ void ShutterRelayChanged(void)
ShutterStartInit(i, -1, 0);
break;
default:
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i);
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i+1);
Shutter[i].target_position = Shutter[i].real_position;
Shutter[i].last_stop_time = millis();
}
break;
case SHT_TIME_GARAGE:
@ -1885,6 +1897,8 @@ bool Xdrv27(uint32_t function)
uint8_t counterend = XdrvMailbox.index==0?TasmotaGlobal.shutters_present:XdrvMailbox.index;
int32_t rescue_payload = XdrvMailbox.payload;
uint32_t rescue_data_len = XdrvMailbox.data_len;
char stemp1[10];
power_t save_powermatrix;
switch (function) {
case FUNC_PRE_INIT:
ShutterInit();
@ -1919,27 +1933,31 @@ bool Xdrv27(uint32_t function)
}
break;
case FUNC_SET_POWER:
char stemp1[10];
// extract the number of the relay that was switched and save for later in Update Position.
ShutterGlobal.RelayCurrentMask = XdrvMailbox.index ^ ShutterGlobal.RelayOldMask;
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Switched relay %d by %s"), ShutterGlobal.RelayCurrentMask,GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource));
ShutterRelayChanged();
ShutterGlobal.RelayOldMask = XdrvMailbox.index;
ShutterGlobal.LastChangedRelay = ShutterGetRelayNoFromBitfield(XdrvMailbox.index ^ ShutterGlobal.RelayOldMask);
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_POWER Relaymask %d SwitchedRelay:%d by %s, payload %d, powermask %d"), ShutterGlobal.RelayOldMask, ShutterGlobal.LastChangedRelay,GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource),XdrvMailbox.payload, TasmotaGlobal.power);
save_powermatrix = TasmotaGlobal.power;
if (!ShutterGlobal.LastChangedRelay) {
ShutterGlobal.skip_relay_change = 1;
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("INVALID REQUEST"));
} else {
ShutterRelayChanged();
ShutterGlobal.RelayOldMask = XdrvMailbox.index;
TasmotaGlobal.power = save_powermatrix;
}
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_POWER end. powermask %d"), TasmotaGlobal.power);
break;
case FUNC_SET_DEVICE_POWER:
if (ShutterGlobal.skip_relay_change ) {
uint8_t i;
for (i = 0; i < TasmotaGlobal.devices_present; i++) {
if (ShutterGlobal.RelayCurrentMask &1) {
break;
}
ShutterGlobal.RelayCurrentMask >>= 1;
}
//AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Skip relay change %d"), i+1);
result = true;
ShutterGlobal.skip_relay_change = 0;
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Skipping switch off relay %d"), i);
ExecuteCommandPowerShutter(i+1, 0, SRC_SHUTTER);
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Skipping switch off relay %d"), ShutterGlobal.LastChangedRelay);
//ExecuteCommandPowerShutter(i+1, 0, SRC_SHUTTER);
if (ShutterGlobal.LastChangedRelay) ShutterGlobal.RelayOldMask = TasmotaGlobal.power ^= 1<<(ShutterGlobal.LastChangedRelay-1);
//ShutterGlobal.RelayOldMask ^= 1<<(ShutterGlobal.LastChangedRelay-1);
}
break;
case FUNC_BUTTON_PRESSED: