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:


    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)

    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;
    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
    void loop() 
      // Alway process incoming messages whenever possible
      //check for buffer items one in a while
    void incomingMessage(const MyMessage &message) {
    void checkTime(){
       unsigned long currentMillis = millis();
       if(currentMillis - previousMillis > interval) {
            previousMillis = currentMillis;  
    //gets message from buffer if exists
    void processBuffer(){
            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--)
                gw.saveState(i-1, msg);
                //send message back to gw to change child devices accordingly
           }else{ //command for one relay
               //my relays need LOW to activate. Others might be different
               // Store state in eeprom
               gw.saveState(sensor, msg);
           //set relays
    void writeReg(boolean rst){
      int loc_reg;
      digitalWrite(latchPin, LOW);
      for (int i = 15; i>=0; i--)
        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!