16 relay with arduino. Change many at the same time


  • Hero Member

    I'm working on a node with 16 relays controlled by Vera.
    I use shift registers and opto couplers to connect the relays to the arduino board. This is system is apparently a bit slow, so if you try to change a few of the relays at the same time, most of them will fail.

    I've been working on a solution adding a buffer to the system, both at Vera's end and node end. If you are interested, you can read about it here:

    http://forum.mysensors.org/topic/131/scene-too-fast-for-gateway/4

    What come next is a addition to that system.
    This sketch allows to operate the relays as before (1 relay at a time), but also allows to receive a message that changes many or all o f the relays at the same time, with only one message sent by Vera.

    First of all I created a function in the startup Lua to make it easier to send messages to the node.

    -- send to multiple relays Mysensor.org
    function updateRelays(parent, child, msg)
        local newRadioId=tostring(child)..";100"
        luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand",
        {radioId=newRadioId, variableId="LIGHT", value=msg}, parent)
        end
    

    Then I use this code to send the message from a scene or Pleg

    -- order: (first......last)
    -- 1: relay ON, 0: relay OFF
    -- guide       1234567812345678
    local relays="b1100100000000100"
    updateRelays(130, 3, relays)
    

    In my case, 130 is the parent node id, 3 is the relay node id, and relays contains a binary representation of every relay, 1 mening ON and 0 meaning OFF.

    This is all you need to do to turn a buch of the relays in any way you need, all at the same time. The rest is taken care by the sketch (decoding the binary message, sending back the ack's to the gw, etc)

    
    // This  will remember relay state even after power failure.
    
    
    #include <MySensor.h>
    #include <SPI.h>
    #include <MyBuffer.h>
    
    #define RELAY_1  0  // number for first relay (second on pin+1 etc)
    #define NUMBER_OF_RELAYS 16 // Total number of attached relays
    #define RELAY_ON HIGH  // GPIO value to write to turn on attached relay
    #define RELAY_OFF LOW // GPIO value to write to turn off attached relay
    
    int dataPin  = 6;//11;        //Define which pins will be used for the Shift Register control
    int latchPin = 4;//8;
    int clockPin = 7;//12;
    
    boolean registers[16];//={HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH};
    
    long previousMillis = 0;        // will store last time buffer was processed
    long interval = 1000;           // interval at which to check buffer
    
    MyBuffer buffer;                // define a new buffer
    MySensor gw;
    MyMessage msgRelay(0,V_LIGHT);  //message for akc multiple relays back to gw
    
    void setup()  
    {   
        // Then set relay pins in output mode 
        pinMode(dataPin, OUTPUT); 
        pinMode(latchPin, OUTPUT);
        pinMode(clockPin, OUTPUT);
        
        writeReg(false); //reset all relays to off at boot
        
        // Initialize library and add callback for incoming messages
        gw.begin(incomingMessage, AUTO);
        
        // Send the sketch version information to the gateway and Controller
        gw.sendSketchInfo("HomeRelay_1", "1.1");
        
        //loop through the relays
        for (int sensor=RELAY_1; sensor<NUMBER_OF_RELAYS; sensor++) 
            {
            // Register all sensors to gw (they will be created as child devices)
            gw.present(sensor, S_LIGHT);
         
            // Set relays array to last known state (using eeprom storage) 
            registers[sensor] = gw.loadState(sensor)?RELAY_ON:RELAY_OFF;
            }
    
        //set relays
        writeReg(true);
    }
    
    
    void loop() 
    {
      // Alway process incoming messages whenever possible
      gw.process();
      
      //check for buffer items one in a while
      checkTime();
    }
    
    void incomingMessage(const MyMessage &message) {
      buffer.push(message.sensor,message.type,message.getString());
    }
    
    void checkTime(){
       unsigned long currentMillis = millis();
       if(currentMillis - previousMillis > interval) {
            previousMillis = currentMillis;  
            processBuffer();    
          }
    }
    
    //gets message from buffer if exists
    void processBuffer(){
        if(!buffer.isEmpty()){
            String msg=buffer.pop();
            
            int mIndex = msg.indexOf(';');
            int secondmIndex = msg.indexOf(';', mIndex+1);
      
            String firstValue = msg.substring(0, mIndex);
            String secondValue = msg.substring(mIndex+1, secondmIndex);
            String thirdValue = msg.substring(secondmIndex+1);
            
            int sensor = firstValue.toInt();
            int type = secondValue.toInt();
            String data = thirdValue;
      
            Serial.println("    >> Process MSG: s:"+ firstValue +", t:"+secondValue+", d:"+thirdValue);
            
            processMsg(sensor, type, data);
        }
    }
    
    void processMsg(int sensor, int type, String data){
         boolean msg;
    
        // We only expect one type of message from controller. But we better check anyway.
        if (type==V_LIGHT) {
       
           if(sensor==100){ //command for all relays
            for (int i = 16; i>=1; i--)
                {
                
                msg=data.substring(i,i+1).toInt()?RELAY_OFF:RELAY_ON;
               
                registers[i-1]=msg;
                gw.saveState(i-1, msg);
                
                //send message back to gw to change child devices accordingly
                gw.send(msgRelay.setSensor(i-1).set(msg?RELAY_OFF:RELAY_ON));
                }
           }else{ //command for one relay
               //my relays need LOW to activate. Others might be different
               msg=data.toInt()?RELAY_OFF:RELAY_ON;
               
               registers[sensor]=msg;
             
               // Store state in eeprom
               gw.saveState(sensor, msg);
               }
    
           //set relays
           writeReg(true);
         } 
    }
    
    void writeReg(boolean rst){
      int loc_reg;
      digitalWrite(latchPin, LOW);
      for (int i = 15; i>=0; i--)
        {
        loc_reg=rst?registers[i]:HIGH;
        digitalWrite(clockPin, LOW);
        digitalWrite(dataPin, loc_reg );
        digitalWrite(clockPin, HIGH);
        }
      digitalWrite(latchPin, HIGH);
    
    }
    
    


  • @ferpando Hi, I am installing your HomeRelay_1 program (16 relay with Arduino) and would like the MyBuffer.h and MyBuffer.cpp. The only ones I have found have (sensor, type) for buffer.push where you actually have (sensor, type,string data). The program will not compile on v1.6.5.
    Thank you for all that you do for the community!


 

335
Online

7.8k
Users

8.7k
Topics

93.0k
Posts