16 relay with arduino. Change many at the same time
-
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!