Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split Interlock mode of 4 channel in 2 groups #824

Closed
lobocobra opened this issue Sep 2, 2017 · 91 comments
Closed

Split Interlock mode of 4 channel in 2 groups #824

lobocobra opened this issue Sep 2, 2017 · 91 comments
Assignees
Labels
enhancement Type - Enhancement that will be worked on

Comments

@lobocobra
Copy link
Contributor

lobocobra commented Sep 2, 2017

Hi all

I wanted to use two 4CH Pro to control centrally 4 rollos. In consequence I needed to split the interlock mode of a 4CH/pro into 2 groups of 2 channels, in order to prevent, that the up/down motors can be activated the same time.

If somebody is interested my quick an dirty solution, you find it below. I tested it and it works like a charm. I combine it with PulseTime, which prevents, that the motors run by mistake forever.

You will need to add one variable and to replace two procedures in the code. In the answer section you will see the code. As this is quick an dirty, I doubt that it will make the way into the official code, but I would be ready to invest more time, so that it gets into the code.

!!! the current code only works with 4 CH devices and is not prepared for any hypothetical 3 or 6 Channel devices. For 2 Channels just use the Interlock function.

UPDATE 24.08.2018
The code evolved and you can find the solution now under:

@lobocobra
Copy link
Contributor Author

lobocobra commented Sep 2, 2017

As promised, find here the solution. you need to replace 2 procedures in the SONOFF tab and to activate it you add a new variable in user_config_override.h. Uncomment it, if you do not need it and the original code is active:

In user_config_overide.h add the following:
#define Sonoff4CH_Interlock_SPLIT 0

In sonoff, replace the procedure setRelay with below code:
void setRelay(uint8_t rpower)
{
uint8_t state;

if (4 == sysCfg.poweronstate) { // All on and stay on
power = (1 << Maxdevice) -1;
rpower = power;
}
#ifdef Sonoff4CH_Interlock_SPLIT 0 // split your channels into 2 groups, each group allows one active channel only
// ---- changes by lobocobra ----
if (sysCfg.flag.interlock) { // Allow only one or no relay set
uint8_t mask = 0x01;
uint8_t count = 0;
byte result1 =0;
byte result2 =0;
for (byte i = 0; i < Maxdevice; 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;
}
if ((result1) >1 && (result2 >1)) {power = 0; rpower = 0;}
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 // use original code, only one channel allowed
// ---- changes by lobocobra
if (sysCfg.flag.interlock) { // Allow only one or no relay set
uint8_t mask = 0x01;
uint8_t count = 0;
for (byte i = 0; i < Maxdevice; i++) {
if (rpower & mask) {
count++;
}
mask <<= 1;
}
if (count > 1) {
power = 0;
rpower = 0;
}
}
#endif
// --- end of modification by lobocobra

In sonoff also replace the procedure do_cmnd_power with my below code
void do_cmnd_power(byte device, byte state)
{
// device = Relay number 1 and up
// state 0 = Relay Off
// state 1 = Relay On (turn off after sysCfg.pulsetime * 100 mSec if enabled)
// state 2 = Toggle relay
// state 3 = Blink relay
// state 4 = Stop blinking relay
// state 6 = Relay Off and no publishPowerState
// state 7 = Relay On and no publishPowerState
// state 9 = Show power state

uint8_t publishPower = 1;
if ((6 == state) || (7 == state)) {
state &= 1;
publishPower = 0;
}
if ((device < 1) || (device > Maxdevice)) {
device = 1;
}
byte mask = 0x01 << (device -1);
pulse_timer[(device -1)&3] = 0;
if (state <= 2) {
if ((blink_mask & mask)) {
blink_mask &= (0xFF ^ mask); // Clear device mask
mqtt_publishPowerBlinkState(device);
}

#ifdef Sonoff4CH_Interlock_SPLIT 0 // split your channels into 2 groups, each group allows one active channel only
// ---- modifications by lobocobra ----

// find out if channel 1/2 or 3/4 are to be changed
if (device < 3 ) { // channel 1/2 are now changed
// we are on 1/2
if (sysCfg.flag.interlock && !interlockmutex) { // Clear all but masked relay
interlockmutex = 1;
for (byte i = 0; i < 2; i++) {
byte imask = 0x01 << i;
if ((power & imask) && (mask != imask)) {
do_cmnd_power(i +1, 0);
}
}
interlockmutex = 0;
}
} else {
// channel 3/4 are changed
if (sysCfg.flag.interlock && !interlockmutex) { // Clear all but masked relay
interlockmutex = 1;
for (byte i = 2; i < Maxdevice; i++) {
byte imask = 0x01 << i;
if ((power & imask) && (mask != imask)) {
do_cmnd_power(i +1, 0);
}
}
interlockmutex = 0;
}
}
#else // original code where only 1 active channel is allowed
if (sysCfg.flag.interlock && !interlockmutex) { // Clear all but masked relay
interlockmutex = 1;
for (byte i = 0; i < Maxdevice; i++) {
byte imask = 0x01 << i;
if ((power & imask) && (mask != imask)) {
do_cmnd_power(i +1, 0);
}
}
interlockmutex = 0;
}
#endif //end of modification of lobocobra
switch (state) {
case 0: { // Off
power &= (0xFF ^ mask);
break; }
case 1: // On
power |= mask;
break;
case 2: // Toggle
power ^= mask;
}
setRelay(power);
#ifdef USE_DOMOTICZ
domoticz_updatePowerState(device);
#endif // USE_DOMOTICZ
pulse_timer[(device -1)&3] = (power & mask) ? sysCfg.pulsetime[(device -1)&3] : 0;
}
else if (3 == state) { // Blink
if (!(blink_mask & mask)) {
blink_powersave = (blink_powersave & (0xFF ^ mask)) | (power & mask); // Save state
blink_power = (power >> (device -1))&1; // Prep to Toggle
}
blink_timer = 1;
blink_counter = ((!sysCfg.blinkcount) ? 64000 : (sysCfg.blinkcount *2)) +1;
blink_mask |= mask; // Set device mask
mqtt_publishPowerBlinkState(device);
return;
}
else if (4 == state) { // No Blink
byte flag = (blink_mask & mask);
blink_mask &= (0xFF ^ mask); // Clear device mask
mqtt_publishPowerBlinkState(device);
if (flag) {
do_cmnd_power(device, (blink_powersave >> (device -1))&1); // Restore state
}
return;
}
if (publishPower) {
mqtt_publishPowerState(device);
}
}

@ionciubotaru
Copy link

Another solution:
Backlog power1 0; delay 20;power2 1
and reverse:
Backlog power2 0; delay 20;power1 1
Also use PulseTime to prevent one relay remaining ON for long time

@lobocobra
Copy link
Contributor Author

lobocobra commented Sep 3, 2017

Unfortunately the backlog solution does not work for the buttons and the webpage. And a long-press would not work like this either. In such a scenario I would prefer to solve it with MQTT as you would get a confirmation for each task.
But this is not idiotic proof and as we know.... all that can go wrong will go wrong, I wanted to have a way that works in each case.

Of course it would be even cooler, if there would be a possibility to run small scripts on the SONOFF like on esayesp 2.0.
Not much is needed but things like....

  • timer based scheduling (on at x:xx for x sec || all off once a day at 24:00)
  • simple dependencies (if trigger x then // if relay x on then // if mqtt command x then backlog ...//
    => but only things that make sonoff failproof if the server is offline, because once deployed a sonoff device must always do the same 2-3 things, even if any central logic is down.

I want to avoid to explain to my wife, why she can not turn on the light, because an update on a mqtt server or openhab went wrong .... haha

BTW.... there is a bug in the codes, which can cause that a power cut leads to a permament on relay, if you want to work with MQTT.
I opened an issue and proposed a quick and dirty fix. The problem is that the pulsetime value is loaded to late in the boot sequence, which can lead to the situation that a relay is turned on and pulsetime is ignored (as pulsetime is loaded after the relay status.
=> there is a simple hack to have pulsetime at 1 instead of 0 at boot time. Because if Pulsetime is >0 in config, you never want a permanent on relay and prefer after a reboot in anycase an relay that is off.

@stefanbode
Copy link
Contributor

Your enhancement makes absolute sense because not only shutter requires this behaviour. My irrigation pumps also need 2 relays to open and close and should never be ON both. I solved this with the pulsetimer, but as you already mentioned this is just a workaround. I do not need a configuration what relays belong to the group. This can be hardwired. E.g. Relay 1 and 3 one group and 2 and 4 the other. In the GPIO definition, you just add two new definitions RelaysGroup1 and RelaysGroup2 and assign them to both GPIO. The rest should be easy to implement. In this case, you don't break the original functions. I will check if I can implement this in my fork of TASMOTA.

@lobocobra
Copy link
Contributor Author

This would be even better! I will check your fork, as currently I need to apply the changes to each upgrade manually :)

I like your Idea with 2 new GPIO definitions. Unfortunately I am not yet enough in the Tasmota code nor Arduino programming, to test your proposal.

@alakdae
Copy link

alakdae commented Dec 23, 2017

@lobocobra Could you help me out with a solution for this case? I think it will be similar to what you did.
#1423

@alakdae
Copy link

alakdae commented Dec 23, 2017

Never mind, did it. Solution is dirty, but working great. If anyone is interested let me know.

@strongset
Copy link

strongset commented Feb 25, 2018

I modified the patch to the 5.12 version:

void SetDevicePower(power_t rpower)
{
uint8_t state;

if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { // All on and stay on
power = (1 << devices_present) -1;
rpower = power;
}

#ifdef Sonoff4CH_Interlock_SPLIT 0 // split your channels into 2 groups, each group allows one active channel only
// ---- changes by lobocobra ----
if (Settings.flag.interlock) { // Allow only one or no relay set
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;
}
if ((result1) >1 && (result2 >1)) {power = 0; rpower = 0;}
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 // use original code, only one channel allowed

if (Settings.flag.interlock) { // Allow only one or no relay set
power_t mask = 1;
uint8_t count = 0;
for (byte i = 0; i < devices_present; i++) {
if (rpower & mask) {
count++;
}
mask <<= 1;
}
if (count > 1) {
power = 0;
rpower = 0;
}
}
#endif
// --- end of modification by lobocobra
XdrvSetPower(rpower);

if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
Serial.write(0xA0);
Serial.write(0x04);
Serial.write(rpower &0xFF);
Serial.write(0xA1);
Serial.write('\n');
Serial.flush();
}
else if (EXS_RELAY == Settings.module) {
SetLatchingRelay(rpower, 1);
}
else {
for (byte i = 0; i < devices_present; i++) {
state = rpower &1;
if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) {
digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? !state : state);
}
rpower >>= 1;
}
}
}

void ExecuteCommandPower(byte device, byte state)
{
// device = Relay number 1 and up
// state 0 = Relay Off
// state 1 = Relay On (turn off after Settings.pulse_timer * 100 mSec if enabled)
// state 2 = Toggle relay
// state 3 = Blink relay
// state 4 = Stop blinking relay
// state 6 = Relay Off and no publishPowerState
// state 7 = Relay On and no publishPowerState
// state 9 = Show power state

uint8_t publish_power = 1;
if ((POWER_OFF_NO_STATE == state) || (POWER_ON_NO_STATE == state)) {
state &= 1;
publish_power = 0;
}
if ((device < 1) || (device > devices_present)) {
device = 1;
}
if (device <= MAX_PULSETIMERS) {
pulse_timer[(device -1)] = 0;
}
power_t mask = 1 << (device -1);
if (state <= POWER_TOGGLE) {
if ((blink_mask & mask)) {
blink_mask &= (POWER_MASK ^ mask); // Clear device mask
MqttPublishPowerBlinkState(device);
}

#ifdef Sonoff4CH_Interlock_SPLIT 0 // split your channels into 2 groups, each group allows one active channel only
// ---- modifications by lobocobra ----

// find out if channel 1/2 or 3/4 are to be changed
if (device < 3 ) { // channel 1/2 are now changed
// we are on 1/2
if (Settings.flag.interlock && !interlock_mutex) { // Clear all but masked relay
interlock_mutex = 1;
for (byte i = 0; i < 2; i++) {
byte imask = 0x01 << i;
if ((power & imask) && (mask != imask)) {
ExecuteCommandPower(i +1, 0);
}
}
interlock_mutex = 0;
}
} else {
// channel 3/4 are changed
if (Settings.flag.interlock && !interlock_mutex) { // Clear all but masked relay
interlock_mutex = 1;
for (byte i = 2; i < devices_present; i++) {
byte imask = 0x01 << i;
if ((power & imask) && (mask != imask)) {
ExecuteCommandPower(i +1, 0);
}
}
interlock_mutex = 0;
}
}
#else // original code where only 1 active channel is allowed
if (Settings.flag.interlock && !interlock_mutex) { // Clear all but masked relay
interlock_mutex = 1;
for (byte i = 0; i < devices_present; i++) {
power_t imask = 1 << i;
if ((power & imask) && (mask != imask)) {
ExecuteCommandPower(i +1, POWER_OFF);
}
}
interlock_mutex = 0;
}
#endif //end of modification of lobocobra

switch (state) {
case POWER_OFF: {
  power &= (POWER_MASK ^ mask);
  break; }
case POWER_ON:
  power |= mask;
  break;
case POWER_TOGGLE:
  power ^= mask;
}
SetDevicePower(power);

#ifdef USE_DOMOTICZ
DomoticzUpdatePowerState(device);
#endif // USE_DOMOTICZ
if (device <= MAX_PULSETIMERS) {
// pulse_timer[(device -1)] = (power & mask) ? Settings.pulse_timer[(device -1)] : 0;
pulse_timer[(device -1)] = (((POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate) ? ~power : power) & mask) ? Settings.pulse_timer[(device -1)] : 0;
}
}
else if (POWER_BLINK == state) {
if (!(blink_mask & mask)) {
blink_powersave = (blink_powersave & (POWER_MASK ^ mask)) | (power & mask); // Save state
blink_power = (power >> (device -1))&1; // Prep to Toggle
}
blink_timer = 1;
blink_counter = ((!Settings.blinkcount) ? 64000 : (Settings.blinkcount *2)) +1;
blink_mask |= mask; // Set device mask
MqttPublishPowerBlinkState(device);
return;
}
else if (POWER_BLINK_STOP == state) {
byte flag = (blink_mask & mask);
blink_mask &= (POWER_MASK ^ mask); // Clear device mask
MqttPublishPowerBlinkState(device);
if (flag) {
ExecuteCommandPower(device, (blink_powersave >> (device -1))&1); // Restore state
}
return;
}
if (publish_power) {
MqttPublishPowerState(device);
}
}

@B1G1
Copy link

B1G1 commented Mar 25, 2018

very good, I'm using a sonoff 4ch to control 2 roller shutters, and i need a interlocking mode working with group of two channels.
@diasarmando can you explain better what I need to replace in the original code?

@strongset
Copy link

you need to edit the SONOFF file and replace the SetDevicePower(power_t rpower) and ExecuteCommandPower(byte device, byte state) code for the suggested above methods.

@B1G1
Copy link

B1G1 commented Mar 26, 2018

No need to ad this?

In user_config_overide.h add the following:
#define Sonoff4CH_Interlock_SPLIT 0

@strongset
Copy link

strongset commented Mar 26, 2018 via email

@B1G1
Copy link

B1G1 commented Mar 27, 2018

Ok, can i update it from the administration page or i have to flash directly throug the serial?

@strongset
Copy link

strongset commented Mar 27, 2018 via email

@B1G1
Copy link

B1G1 commented Apr 4, 2018

Hi, when i try to upload the compiled bin I get this error
Upload Failed

Upload buffer miscompare

I read in other threads that the problem is a bad configuration of flash option, either 512 flash or no or to much spiffs, but in my Arduino ide is 1M (no SPIFFS) and it should be correct.

What's the problem?

@lobocobra
Copy link
Contributor Author

Did you try this?
#1539

Assuming that you double checked your settings with the wiki.... load a minimal version first, and then your patched one...

@B1G1
Copy link

B1G1 commented Apr 24, 2018

Yes! It worked!
thank you very much.

@localhost61
Copy link
Contributor

localhost61 commented Jun 13, 2018

@lobocobra
I already use 8 Sonoff Dual R2 to control my roller shutters and they work great in Tasmota v6.00a. I also bought two CH4 R2 to control the remaining 4 roller shutters but I'm missing the GPIO pins of the Dual R2 to connect my wall switches for a good WAF ;-) .

  • Did you connect manual switches on your CH4 (not Pro) to operate the shutters?
  • Did you convert the 4 buttons into switches for that purpose?
    I want to use your mod to be able to operate both shutters together, but still protecting the motors with the interlock feature.

Regarding your problems for flashing, I experimented that with CH4 R2 and Dual R2 (both are ESP8285) you don't have to enter Programming Mode like other ESP8266 but keep GPIO0 at Gnd during flashing.

@lobocobra
Copy link
Contributor Author

lobocobra commented Jun 22, 2018

As I had some requests to update the function see here the working update for version 6.00a.
If you want to use it on CH4-Pro then you need to set the switches on the board 👍
=> S6 on position 1
=> K5 all switch position ON
=> K6 all position OFF
=> Setoption14 need to be ON
The mod works on CH4 and CH4-pro (see switch settings above).

To implement the mod you need to download version 6.0.0a and to replace 2 functions completely with the code below and add one statement:

In user_config_overide.h add the following:

// start modification lobocobra
#define Sonoff4CH_Interlock_SPLIT 0
// end modification lobocobra 

In sonoff, replace the procedure SetDevicePower with below code:


void SetDevicePower(power_t rpower, int source)
{
  uint8_t state;

  ShowSource(source);

  if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) {  // All on and stay on
    power = (1 << devices_present) -1;
    rpower = power;
  }

#ifdef Sonoff4CH_Interlock_SPLIT 0 // split your channels into 2 groups, each group allows one active channel only
// ---- changes by lobocobra ----
if (Settings.flag.interlock) { // Allow only one or no relay set
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;
}
if ((result1) >1 && (result2 >1)) {power = 0; rpower = 0;}
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 // use original code, only one channel allowed
  
  if (Settings.flag.interlock) {     // Allow only one or no relay set
    power_t mask = 1;
    uint8_t count = 0;
    for (byte i = 0; i < devices_present; i++) {
      if (rpower & mask) count++;
      mask <<= 1;
    }
    if (count > 1) {
      power = 0;
      rpower = 0;
    }
  }
#endif
// --- end of modification by lobocobra
  XdrvSetPower(rpower);

  if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
    Serial.write(0xA0);
    Serial.write(0x04);
    Serial.write(rpower &0xFF);
    Serial.write(0xA1);
    Serial.write('\n');
    Serial.flush();
  }
  else if (EXS_RELAY == Settings.module) {
    SetLatchingRelay(rpower, 1);
  }
  else {
    for (byte i = 0; i < devices_present; i++) {
      state = rpower &1;
      if ((i < MAX_RELAYS) && (pin[GPIO_REL1 +i] < 99)) {
        digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? !state : state);
      }
      rpower >>= 1;
    }
  }
}

In sonoff replace ExecuteCommandPower with:

void ExecuteCommandPower(byte device, byte state, int source)
{
// device  = Relay number 1 and up
// state 0 = Relay Off
// state 1 = Relay On (turn off after Settings.pulse_timer * 100 mSec if enabled)
// state 2 = Toggle relay
// state 3 = Blink relay
// state 4 = Stop blinking relay
// state 6 = Relay Off and no publishPowerState
// state 7 = Relay On and no publishPowerState
// state 9 = Show power state

//  ShowSource(source);

  uint8_t publish_power = 1;
  if ((POWER_OFF_NO_STATE == state) || (POWER_ON_NO_STATE == state)) {
    state &= 1;
    publish_power = 0;
  }
  if ((device < 1) || (device > devices_present)) device = 1;
  if (device <= MAX_PULSETIMERS) pulse_timer[(device -1)] = 0;
  power_t mask = 1 << (device -1);
  if (state <= POWER_TOGGLE) {
    if ((blink_mask & mask)) {
      blink_mask &= (POWER_MASK ^ mask);  // Clear device mask
      MqttPublishPowerBlinkState(device);
    }
#ifdef Sonoff4CH_Interlock_SPLIT 0 // split your channels into 2 groups, each group allows one active channel only
// ---- modifications by lobocobra ----

// find out if channel 1/2 or 3/4 are to be changed
if (device < 3 ) { // channel 1/2 are now changed
// we are on 1/2
if (Settings.flag.interlock && !interlock_mutex) { // Clear all but masked relay
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);
}
}
interlock_mutex = 0;
}
} else {
// channel 3/4 are changed
if (Settings.flag.interlock && !interlock_mutex) { // Clear all but masked relay
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;
}
}
#else // original code where only 1 active channel is allowed
    if (Settings.flag.interlock && !interlock_mutex) {  // Clear all but masked relay
      interlock_mutex = 1;
      for (byte i = 0; i < devices_present; i++) {
        power_t imask = 1 << i;
        if ((power & imask) && (mask != imask)) ExecuteCommandPower(i +1, POWER_OFF, SRC_IGNORE);
      }
      interlock_mutex = 0;
    }
#endif //end of modification of lobocobra    
    switch (state) {
    case POWER_OFF: {
      power &= (POWER_MASK ^ mask);
      break; }
    case POWER_ON:
      power |= mask;
      break;
    case POWER_TOGGLE:
      power ^= mask;
    }
    SetDevicePower(power, source);
#ifdef USE_DOMOTICZ
    DomoticzUpdatePowerState(device);
#endif  // USE_DOMOTICZ
#ifdef USE_KNX
    KnxUpdatePowerState(device, power);
#endif  // USE_KNX
    if (device <= MAX_PULSETIMERS) {
//      pulse_timer[(device -1)] = (power & mask) ? Settings.pulse_timer[(device -1)] : 0;
      pulse_timer[(device -1)] = (((POWER_ALL_OFF_PULSETIME_ON == Settings.poweronstate) ? ~power : power) & mask) ? Settings.pulse_timer[(device -1)] : 0;
    }
  }
  else if (POWER_BLINK == state) {
    if (!(blink_mask & mask)) {
      blink_powersave = (blink_powersave & (POWER_MASK ^ mask)) | (power & mask);  // Save state
      blink_power = (power >> (device -1))&1;  // Prep to Toggle
    }
    blink_timer = 1;
    blink_counter = ((!Settings.blinkcount) ? 64000 : (Settings.blinkcount *2)) +1;
    blink_mask |= mask;  // Set device mask
    MqttPublishPowerBlinkState(device);
    return;
  }
  else if (POWER_BLINK_STOP == state) {
    byte flag = (blink_mask & mask);
    blink_mask &= (POWER_MASK ^ mask);  // Clear device mask
    MqttPublishPowerBlinkState(device);
    if (flag) ExecuteCommandPower(device, (blink_powersave >> (device -1))&1, SRC_IGNORE);  // Restore state
    return;
  }
  if (publish_power) MqttPublishPowerState(device);
}

Btw... I disabled all sensors that I do not need an knx and similar. So the bin has a size of 484k.
=> If someone needs the full code or a bin, then let me know and I compile it for you.

@diasarmando, thanks for adapting it to v5.12.

@ascillato2 ascillato2 added the enhancement Type - Enhancement that will be worked on label Jun 22, 2018
@ascillato2 ascillato2 reopened this Jun 22, 2018
@lobocobra
Copy link
Contributor Author

lobocobra commented Jun 22, 2018

@localhost61

about your questions....

Did you connect manual switches on your CH4 (not Pro) to operate the shutters?

  • No, I did not use any GPIO to connect manual switches, nor did I manipulate the CH4 switches.
  • I mounted two CH4-pro in an electric box to the wall in my garage, where I could operate the shutters, but I never do that directly on the CH4-pro.
  • I use the 433khz capabilities of the CH4-pro and bought four Intertechno Funk-Wandsender YWT-8500 and programmed the CH4-pro 433mhz to them. Now I have the Intertechno switches next to the window where the shutters are and they send a signal to the ch4-pro in the garage.
  • I have in addition tablets on the wall and openhab-panel running to command the shutter.
  • I have rules in openhab that close / open the shutter depending on rain, wind and sun elevation.

Did you convert the 4 buttons into switches for that purpose?

  • I wanted a clean installation and bought Intertechno switches, which I put to the corresponding windows.
  • Openhab rules do the main job and react on wind, rain, sun elevation. I seldom have to interfer. The ch4/pro are too ugly to have them somewhere visible.

I want to use your mod to be able to operate both shutters together, but still protecting the motors with the interlock feature.

  • Great to hear, you probably want to set PULSETIME1-4 to something like 15 seconds, so if anything goes wrong, your motors stop after 15 seconds.

My flashing issues

  • I solved them now completely with adding a 12v source the first time I have to program them. The issue was that an USB port has not enough ampere. Since I do that, flashing goes easy.

@stefanbode
Copy link
Contributor

stefanbode commented Jun 22, 2018

I make a proposal how to support the shutter usecase, without changing adding to much code to it. The functionality is already added to my branch. See stefanbode mod.

Idea:
Added SetOption31 to enhance the interlock mode (SetOption14 must also be ON) to a paired version. This pairs ALL relays in groups of two. After using the option only relay 1,3,5,7... can be actively switched. Relay 2,4,6,... will be switched as a slave with the opposite of the corresponding relay.

Main change below in the interlock. PulseTime still works and set the corresponding relay after period

  //STB mode
  if (Settings.flag.interlock) {
    if (Settings.flag.paired_interlock) {
      for (byte i = 0; i < devices_present; i=i+2) {
        bitWrite(rpower, i+1, !bitRead(rpower, i));
      }
      power = rpower;
    } else {
      power_t mask = 1;
      uint8_t count = 0;
      for (byte i = 0; i < devices_present; i++) {
        if (rpower & mask) count++;
        mask <<= 1;
      }
      if (count > 1) {
        power = 0;
        rpower = 0;
      }
    }
  }
//end

@localhost61
Copy link
Contributor

@lobocobra
Many thanks for you update, I'll give it a try for sure !
@stefanbode
In my mind, shutters are 3-state: UP/DN/OFF
If I understand properly, your mod only allow UP/DN, isn't it?
OFF may be achieved with Pulstime, but it wouldn't allow open at 20%, for instance.

@stefanbode
Copy link
Contributor

stefanbode commented Jun 26, 2018

Yes, I was already thinking about this. The problem is not doing it, the problem is doing it in a smart way without adding to much code. Therefore using something that already exist is a good idea. A three state switch is nothing already be there. Just preventing two relays on is also something that you currently can simulate quite nice with the pulsetime, as long as you do not decide to switch during this period like my wife did. As far as I cann see the problem of the interlock is that you need to remember the old state to decide to switch off wich relay if in a request both are ON. If we solve this on the UI and the API that’s fine , too. I’m intrested to get this solved because I have some valves and a shutter to operate.

@stefanbode
Copy link
Contributor

stefanbode commented Jun 26, 2018

Let me propose a simple solution. All,working in the group. If both relay OFF, all fine do nothing. If relay 1 or 2 ON also finen do nothing. If relay 1 and 2 are ON always switch OFF the second relay. Therefore you prevent mess but you cannot just move in the opposite direction by switching relay 2 to ON. You have to switch relay 1 OFF upfront manually or by a pulsetimer. If ok i can give it a try in my code and share results

@stefanbode
Copy link
Contributor

stefanbode commented Jun 26, 2018

ok, done and checked in into my branch. Changes are small and smart. Here is how I did it. Honestly, easy way is just use my branch :-).

In sonoff.ino
Change Function ExecuteCommandPower snipped below.

    if (Settings.flag.interlock && !interlock_mutex ) {  // Clear all but masked relay
      interlock_mutex = 1;
    //stb mod
      if (Settings.flag.paired_interlock) {
        byte  temp = 2* !(device%2);
        power_t imask = 1 << (device- temp);
        //snprintf_P(log_data, sizeof(log_data), PSTR("SRC0: device %d, state: %d, source %d, devicebin: %d, power: %ld, mask: %ld, imask %ld"),device,state,source, device%2 ,power, mask, imask);
        //AddLog(LOG_LEVEL_DEBUG);
        if (power & imask) ExecuteCommandPower(device +1-temp , POWER_OFF, SRC_IGNORE);
      } else {
        for (byte i = 0; i < devices_present; i++) {
          power_t imask = 1 << i;
          if ((power & imask) && (mask != imask)) ExecuteCommandPower(i +1, POWER_OFF, SRC_IGNORE);
        }
      }
      //end
      interlock_mutex = 0;
    }

Additionally the wiping of all relays must be more conditional: change SetDevicePower
replace condition:
if (Settings.flag.interlock) {
with
if (Settings.flag.interlock && !Settings.flag.paired_interlock) {

For the nerds; What am I doing in the procedure?
Depending on the device%2 result I know if it is an even or non even relay. Depending on this value I know if I need to check the relay before or after. I check if the corresponding relay is ON and set it to OFF.
Example: relay1=ON Toggle relay2 to ON automatically set relay1 to OFF. Attention: If setting relay1 to OFF, even if it is already OFF (not working in webgui, but with MQTT) then relay2 will change to OFF. In this case both are off. I accept this side effect currently to save an extra check if the switched relay will result in an ON state.

@lobocobra
Copy link
Contributor Author

lobocobra commented Jun 26, 2018

Hey stefanbode

I like your idea to change as little code as possible, but your solution is almost obsolet if you use an CH4pro, as each switch can be connected with 2 cables, where one is always switched on.
=> So using a CH4pro allows already already to attach 4 shutters and each is either set on UP or DOWN but there is no stop.
=> Now we could say that thus we simply change the wires and use 2 switches for each shutter.
- One to set the power ON/OFF
- The second to select UP/DOWN.
But how the heck could I explain that my wife?

For me this is no solution and I will extend my mod with the aim:

  • Ensure that by pushing the device buttons, it is not possible that up/down are on on the same time
  • SONOFF "knows" the position of the shutter anytime and answers at what % level down the shutter is
  • I can give the MQTT order 30% to let it go down 30%, while up/down means fully up/down.

If we want to have this mod added to arendst master, we would probably to have it programmed as a module. If not arendst will for sure not consider it (at least I would not in his place).

@speedymk1
Copy link

speedymk1 commented Aug 12, 2018 via email

@speedymk1
Copy link

Hi again,

With the new firmware I got both possibilities and the command

ShutterGoPercent1 50
ShutterGoPercent2 50

image

work perfect -> THANK YOU

@ascillato2 ascillato2 changed the title CH4 // Split Interlock mode of 4 channel in 2 groups Split Interlock mode of 4 channel in 2 groups Aug 23, 2018
@ascillato2
Copy link
Collaborator

Just for reference:
#3204
#719

@lobocobra
Copy link
Contributor Author

lobocobra commented Aug 24, 2018

For those who are interested, I made now a new version that can deal with SPRINKLER or devices where you would like to know how much time there were on and how much this costs in Euro/Dollar.
=> It is programmed as a driver and can be activated with SETOPTION and can split channels.
=> I will transform my SHUTTER MOD to this version and also my previous HEATING MOD

Example: I want to know how much water I use with my sprinkler and how much this costs.
=> Sprinkler: https://github.com/lobocobra/sonoff-shutter (USE THE ONoffCOUNTER BRANCH)
=> Shutter: https://github.com/lobocobra/sonoff-shutter (USE THE MASTER BRANCH)

@meingraham
Copy link
Collaborator

Cross-posting from #3709

The two and two grouping is one scenario. Logically one would group 1&2 and 3&4. But, for unforeseen reasons, one might select the channels in each group differently. I wouldn't, but someone might (say in a retrofit where they now want to take advantage of this new firmware feature but they had already wired something differently. Just surmising). One might want only one group and then the remaining channels ungrouped.

The real reason this occured to me was a group of three scenario. I have this scenario for my ceiling fans. Three channels are used to control the speed of the fan. The interlocking varies from manufacturer to manufacturer.

Full interlock:
A - Low
B - Medium
C - High

Hybrid interlock:
A - Low
A&B - Medium
C - High

I use the fourth channel to control the ceiling fan light. This channel operates independently from the other three.

A part of the group configuration would be to specify which channels make up the group. Thus, if one has the ability to specify which three channels to group, then this same capability could be used in the 2/2 grouping to specify which channels are in each group. One could extend this thinking to a 5Ch switch (still two groups at most).

@lobocobra
Copy link
Contributor Author

I like your idea and will implement it in the next version

@achillealb
Copy link

Hi Lobocobra
I have Sonoff 4CH Pro R2
1- Does your firmware work with Sonoff 4CH Pro R2?
2-Which of these patterns can you use with your firmware?
3- Do you have the firmware in the bin format?
sonoff_4ch_pro_pulsanti

@lobocobra
Copy link
Contributor Author

lobocobra commented Sep 29, 2018

@achillealb

1) Does your firmware work with Sonoff 4CH Pro R2? YES
On the picture above you have a SONOFF PRO R1, but I assume that you know this already and ordered a R2. I can tell you that there should be no issues a using R2 with my firmware. The differences are handled on lower level of the code by arendst.
=> But I will receive a R2 the next day and then I can tell for sure, but this should not stop you.
=> If there is an issue, let me know and we can fix it easily.

2) 2-Which of these patterns can you use with your firmware?
Looking at your picture above your shutter motor is simillar to mine and needs on one of the 2 phases
to be powered (never both) to go to either up or down. The firmware was build for that propose, if your motor works like this, then the answer is YES.
=> The small device on bottom right, seems only to be needed, if you do not use a sonoff or use the sonoff in the pulse mode. If you want to use pulse Switches you do not need this with my firmware.

If you want to work with sonoff in pulse mode, then I recommend you the regular firmware, as all the add-on make no sense (with a pulse for start and a pulse for stop, you will never know the exact position of your shutter).

Personally I do use 2 433mhz pulse-switches ( intertechno ywt , just google it) which are connected to the ch4-pro by 433mhz, but you can also use any other switch with my firmware. But in all cases, sonoff is not in the pulse-mode, only the switches are.

3- Do you have the firmware in the bin format?
Yes I have and here it is... and its posted above in a ZIP file. 9 posts before this one.
LINK

=> let me know if you need support

@marksev1
Copy link

https://www.ebay.com/itm/1pc-DC12V-G3-4-Normally-Closed-Brass-Electric-Solenoid-Water-Valve-Fast-Install/323265864011?hash=item4b4425a14b:g:zkcAAOSw~RFa2Htu:rk:1:pf:0 Would such a valve be a good choice for use with the Sonoff 4ch or the R2 or the Pro versions of this hardware.

Thanks in advance for advice!

@localhost61
Copy link
Contributor

Do you have a 12V power supply for this application? Why not use a mains powered valve like the one used in a dish machine?

@stefanbode
Copy link
Contributor

Anyhow no problem here. Just some relays in front and you’re done. Standard installation

@ascillato2
Copy link
Collaborator

ascillato2 commented Dec 22, 2018

@lobocobra

Can you make a Pull Request with your Splitted Interlock Mode, please ?

Thanks

@GianCann
Copy link

GianCann commented Jan 2, 2019

I hope to see the "Interlock mask funcionality", written by @stefanbode, implemented in the master Tasmota code because is usefull for various scenario.
Thank you.

@ascillato2
Copy link
Collaborator

ascillato2 commented Jan 3, 2019

@GianCann

I already asked to both @lobocobra and @stefanbode for a PR to add that feature to Tasmota but there is no answer so far. They must be very busy.

@GianCann
Copy link

GianCann commented Jan 4, 2019

@lobocobra @stefanbode we trust in you ;)

@lobocobra
Copy link
Contributor Author

Ah sorry I was on vacation! I will do it :-)

@Pako75
Copy link

Pako75 commented Jan 12, 2019

Hi,
Do you think it would be possible to use the interlock option only on 2 channels of a t1 with 3 ch???
I think that changing something on this code this would be possible, can you help me???

@stefanbode
Copy link
Contributor

Hi gents. I’m still on holiday and can not commit a change he master branch until feb 2019. THe requested masking of specific relays is already implemented and tested. The code changes are quite a few. Not very complicated.

@lobocobra
Copy link
Contributor Author

lobocobra commented Jan 13, 2019

@ascillato2
Hi
I submitted the Pull Request and tested it. Sorry for the delay, I was away and then sick.
=> I submitted the version that is since 2 years in operation.

@Pako75
Can you please check? It should work on 3 channel as well. CH1/2 would be a group, CH3 alone

@ascillato2
Copy link
Collaborator

ascillato2 commented Jan 13, 2019

Added with PR #4910 from @lobocobra

@ascillato2
Copy link
Collaborator

Thanks a lot for sharing this and thanks everyone for sharing theirs ideas. Very appreciated. 👍

@Pako75
Copy link

Pako75 commented Jan 13, 2019

@lobocobra
Tomorrow i’ll try and let you know

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Type - Enhancement that will be worked on
Projects
None yet
Development

No branches or pull requests