diff --git a/sonoff/settings.h b/sonoff/settings.h index 618cc03f2..714dee800 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -76,7 +76,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t sleep_normal : 1; // bit 10 (v6.3.0.15) - SetOption60 - Enable normal sleep instead of dynamic sleep uint32_t button_switch_force_local : 1;// bit 11 (v6.3.0.16) - SetOption61 - Force local operation when button/switch topic is set uint32_t no_pullup : 1; // bit 12 (v6.4.1.7) - SetOption62 - Force no pull-up (0 = (no)pull-up, 1 = no pull-up) - uint32_t spare13 : 1; + uint32_t split_interlock : 1; // bit 13 (v6.4.1.8) - SetOption63 - Split interlock on CH4 uint32_t spare14 : 1; uint32_t spare15 : 1; uint32_t spare16 : 1; diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 404403d5a..16239e046 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -319,6 +319,23 @@ void SetDevicePower(power_t rpower, int source) power = (1 << devices_present) -1; rpower = power; } + if (Settings.flag3.split_interlock) { + Settings.flag.interlock = 1; // prevent the situation where interlock is off and split-interlock is on + uint8_t mask = 0x01; + uint8_t count = 0; + byte result1 = 0; + byte result2 = 0; + for (byte i = 0; i < devices_present; i++) { + if (rpower & mask) { + if (i <2) { result1++;}//increment if low part is ON + if (i >1) { result2++;}//increment if high part is ON + } + mask <<= 1; // shift the bitmask one left (1,2,4,8) to find out what is on + } + if ((result1) >1 && (result2 >1)) {power = 0; rpower = 0;} // all 4 switch are on, something is wrong, so we turn all off + if ((result1) >1 && (result2 <2)) {power = power & 0x0C; rpower = power;} // 1/2 are both on and 3/4 max one is on + if ((result1) <2 && (result2 >1)) {power = power & 0x03; rpower = power;} // 1/2 max one is on and 3/4 both are on + } else { if (Settings.flag.interlock) { // Allow only one or no relay set power_t mask = 1; uint8_t count = 0; @@ -331,6 +348,7 @@ void SetDevicePower(power_t rpower, int source) rpower = 0; } } + } XdrvMailbox.index = rpower; XdrvCall(FUNC_SET_POWER); // Signal power state @@ -1389,7 +1407,28 @@ void ExecuteCommandPower(byte device, byte state, int source) blink_mask &= (POWER_MASK ^ mask); // Clear device mask MqttPublishPowerBlinkState(device); } - if (Settings.flag.interlock && !interlock_mutex) { // Clear all but masked relay + if (Settings.flag3.split_interlock && !Settings.flag.interlock ) Settings.flag.interlock=1; // ensure interlock is on, in case split_interlock is on + // check if channel 1/2 or 3/4 are to be changed + if (device <= 2 && Settings.flag3.split_interlock ) { // channel 1/2 are changed + if (Settings.flag3.split_interlock && !interlock_mutex) { // Clear all but masked relay, but only if we are not already doing something + interlock_mutex = 1; + for (byte i = 0; i < 2; i++) { + byte imask = 0x01 << i; + if ((power & imask) && (mask != imask)) { ExecuteCommandPower(i +1, POWER_OFF, SRC_IGNORE); delay(50); }// example, first power is ON but the pushed button is not the first, then powerOFF the first one + } + interlock_mutex = 0; // avoid infinite loop due to recursive requests + } + } else { // channel 3/4 are changed + if (Settings.flag3.split_interlock && !interlock_mutex) { // only start if we are on interlock split and have no re-call + interlock_mutex = 1; + for (byte i = 2; i < devices_present; i++) { + byte imask = 0x01 << i; + if ((power & imask) && (mask != imask)) ExecuteCommandPower(i +1, POWER_OFF, SRC_IGNORE); + } + interlock_mutex = 0; + } + } + if ( Settings.flag.interlock && !interlock_mutex && !Settings.flag3.split_interlock) { //execute regular interlock-mode as interlock-split is off interlock_mutex = 1; for (byte i = 0; i < devices_present; i++) { power_t imask = 1 << i;