Arduino based relay controller using Relay8 boards

@kriznik
Couldn’t work out how to split the topic so I just made a new one
now that im home,

This is the code i currently have,

Relay Controller MQTT Code

#include <SPI.h>
#include “Ethernet.h”
#include “Wire.h”
#include <PubSubClient.h>
#include <stdlib.h>

#define SHIELD_1_I2C_ADDRESS 0x20 // 0x20 is the address with all jumpers removed
#define SHIELD_2_I2C_ADDRESS 0x21 // 0x21 is the address with a jumper on position A0

#define MAC_I2C_ADDRESS 0x50 // Microchip 24AA125E48 I2C ROM address

/* If channelInterlocks is set to true, the channels are grouped into

  • pairs starting at 1 (ie: channels 1 & 2, 3 & 4, etc) and only one
  • channel in each pair can be on at any time. For example, if channel
  • 1 is on and 2 is set to on, channel 1 will be turned off first and
  • vice versa. This is to allow control of dual-active devices such as
  • electric curtain motors which must only be driven in one direction
  • at a time. */
    const byte channelInterlocks = false;

/* CHANGE THIS TO YOUR OWN UNIQUE VALUE. The MAC number should be

  • different from any other devices on your network or you’ll have
  • problems receiving packets. Can be replaced automatically below
  • using a MAC address ROM. */
    static uint8_t mac[] = { 0xDE, 0xA7, 0x0E, 0xEF, 0xFE, 0xED };

/* CHANGE THIS TO MATCH YOUR HOST NETWORK. Most home networks are in

  • the 192.168.0.XXX or 192.168.1.XXX subrange. Pick an address
  • that’s not in use and isn’t going to be automatically allocated by
  • DHCP from your router. Can be replaced automatically using DHCP. */
    static uint8_t ip[] = { 192, 168, 1, 182 };

static uint8_t serverIP[] = { 192, 168, 1, 108 };

char* outputTopic="/output";
char topic[37];
char message[22];

byte shield1BankA = 0; // Current status of all outputs on first shield, one bit per output
byte shield2BankA = 0; // Current status of all outputs on second shield, one bit per output
EthernetClient ethClient;
PubSubClient client(serverIP, 1883, ethClient);

// New message receive
void callback(char* topic, byte* payload, unsigned int length) {
String strPayload= String((char*)payload).substring(0,length);

Serial.print(“Receive message”);
Serial.println(strPayload);

// topic will be something like /relay/power/1/01

char channel[]=" ";
channel[0]= *(topic+13);
channel[1]= *(topic+14);

unsigned short int relay = atoi(channel);

if (strPayload.equals(“on”))
{
setLatchChannelOn( relay );
publishState(atoi(channel),1,outputTopic);
Serial.print("Turning on ");
Serial.println(channel);
}

  if (strPayload.equals("off"))

  {
    setLatchChannelOff( relay );
    publishState(atoi(channel),0,outputTopic);
            Serial.print("Turning off ");
             Serial.println(channel);
  }

}

void setup()
{
Wire.begin(); // Wake up I2C bus
Serial.begin( 38400 );
Serial.println(“Strting MQTT Relay 8 board”);

Serial.print("Getting MAC address from ROM: ");
// mac[0] = readRegister(0xFA);
// mac[1] = readRegister(0xFB);
// mac[2] = readRegister(0xFC);
// mac[3] = readRegister(0xFD);
// mac[4] = readRegister(0xFE);
// mac[5] = readRegister(0xFF);
char tmpBuf[17];
sprintf(tmpBuf, “%02X:%02X:%02X:%02X:%02X:%02X”, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.println(tmpBuf);

// setup the Ethernet library to talk to the Wiznet board
Ethernet.begin(mac, ip); // Use static address defined above
//Ethernet.begin(mac); // Use DHCP

// Print IP address:
Serial.print(“My IP: “);
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.localIP()[thisByte], DEC);
if( thisByte < 3 )
{
Serial.print(”.”);
}
}

/* Set up the Relay8 shields */
initialiseShield(SHIELD_1_I2C_ADDRESS);
sendRawValueToLatch1(0); // If we don’t do this, channel 6 turns on! I don’t know why

initialiseShield(SHIELD_2_I2C_ADDRESS);
sendRawValueToLatch2(0); // If we don’t do this, channel 6 turns on! I don’t know why

Serial.println(“Ready.”);
}

void connect() {
if (client.connect(“arduinoClient”, “openhabian”, “bedrock”)) {
Serial.println(“Connected”);
client.subscribe("/relay/power/1/#");
}
}

void loop()
{
if (!client.connected()) {
connect();
}

client.loop();
}

void publishState(int channel,int state,char* theTopic) {
sprintf(topic,theTopic,channel);
sprintf(message,"{channel:%1d,state:%1d}",channel,state);
client.publish(topic,message);
}

void initialiseShield(int shieldAddress)
{
// Set addressing style
Wire.beginTransmission(shieldAddress);
Wire.write(0x12);
Wire.write(0x20); // use table 1.4 addressing
Wire.endTransmission();

// Set I/O bank A to outputs
Wire.beginTransmission(shieldAddress);
Wire.write(0x00); // IODIRA register
Wire.write(0x00); // Set all of bank A to outputs
Wire.endTransmission();
}

/**
*/
void toggleLatchChannel(byte channelId)
{
if( channelId >= 1 && channelId <= 8 )
{
byte shieldOutput = channelId;
byte channelMask = 1 << (shieldOutput - 1);
shield1BankA = shield1BankA ^ channelMask;
sendRawValueToLatch1(shield1BankA);
}
else if( channelId >= 9 && channelId <= 16 )
{
byte shieldOutput = channelId - 8;
byte channelMask = 1 << (shieldOutput - 1);
shield2BankA = shield2BankA ^ channelMask;
sendRawValueToLatch2(shield2BankA);
}
}

/**
*/
void setLatchChannelOn (byte channelId)
{
if( channelInterlocks == true )
{
if ( (channelId % 2) == 0) // This is an even number channel, so turn off the channel before it
{
setLatchChannelOff( channelId - 1 );
} else { // This is an odd number channel, so turn off the channel after it
setLatchChannelOff( channelId + 1 );
}
}

if( channelId >= 1 && channelId <= 8 )
{
byte shieldOutput = channelId;
byte channelMask = 1 << (shieldOutput - 1);
shield1BankA = shield1BankA | channelMask;
sendRawValueToLatch1(shield1BankA);
}
else if( channelId >= 9 && channelId <= 16 )
{
byte shieldOutput = channelId - 8;
byte channelMask = 1 << (shieldOutput - 1);
shield2BankA = shield2BankA | channelMask;
sendRawValueToLatch2(shield2BankA);
}
}

/**
*/
void setLatchChannelOff (byte channelId)
{
if( channelId >= 1 && channelId <= 8 )
{
byte shieldOutput = channelId;
byte channelMask = 255 - ( 1 << (shieldOutput - 1));
shield1BankA = shield1BankA & channelMask;
sendRawValueToLatch1(shield1BankA);
}
else if( channelId >= 9 && channelId <= 16 )
{
byte shieldOutput = channelId - 8;
byte channelMask = 255 - ( 1 << (shieldOutput - 1));
shield2BankA = shield2BankA & channelMask;
sendRawValueToLatch2(shield2BankA);
}
}

/**
*/
void sendRawValueToLatch1(byte rawValue)
{
Wire.beginTransmission(SHIELD_1_I2C_ADDRESS);
Wire.write(0x12); // Select GPIOA
Wire.write(rawValue); // Send value to bank A
shield1BankA = rawValue;
Wire.endTransmission();
}

/**
*/
void sendRawValueToLatch2(byte rawValue)
{
Wire.beginTransmission(SHIELD_2_I2C_ADDRESS);
Wire.write(0x12); // Select GPIOA
Wire.write(rawValue); // Send value to bank A
shield2BankA = rawValue;
Wire.endTransmission();
}

/**

  • Required to read the MAC address ROM
    */
    byte readRegister(byte r)
    {
    unsigned char v;
    Wire.beginTransmission(MAC_I2C_ADDRESS);
    Wire.write®; // Register to read
    Wire.endTransmission();

Wire.requestFrom(MAC_I2C_ADDRESS, 1); // Read a byte
while(!Wire.available())
{
// Wait
}
v = Wire.read();
return v;
}

not all of it is mine so im trying to piece this together. i should be able to publish into /relay/power/1/01 ‘on’ or ‘off’ and that should trigger the relay. am i missing something here?

Thanks again for your help

To answer your question

Currently it connects to mqtt. But I can’t seam to get it to pickup status changes. I’m sorta hoping I have just made a mistake somewhere but can’t figure it out.

you said your 2 relays are working, but another two are not… so which one is what and what you define as “working” and “non-working”
but you are talking about 8 relayboard … so … kind of dunno what is what :wink:

that code is bit of mess, so I would like to know which parts are ok and which are not.

btw is that some special relay board? why you just can’t send PIN number 1/0 to switch it on/off as it’s done on kind of every relay board i’ve seen ?

If you re having problems with the Arduino code then you might have better luck posting to an Arduino forum.

But if I can guess a bit about your setup, I’m guessing you have a relay board attached to this Arduino. The Arduino subscribes to MQTT topics to receive commands.

Have you verified that what ever you are sending the MQTT messages is working in the first place?

It would be a lot easier to read the code if it were in How to use code fences.

A quick scan through the code doesn’t show where you connect the subscription to call your callback function, but I don’t know this library so maybe that’s handled for you?

there is subscribtion on line 122 in connect function (yes … well)
and there is a calback function on line 45 which is kind of not called by anything …which I suppose is wrong indeed
where should be something like

client.on_message(){
   callback(data)
}

it does not matter if it is arduino or not, it’s simple C++ which we should help him with :slight_smile:
question really is, what does he mean by “2 relays are working, 2 are not”

edit, as am reading thru the script, I would suggest to start from scratch as there are parts which you’ll never use in combination with mqtt, unless this relayboard is somehow super special and need hex commands to operate

Took some advice from above and rewrote most of it, Here is the revised code


// This subscribes to MQTT IOT get the PIR sensor states //

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Wire.h>

#define SHIELD_1_I2C_ADDRESS  0x20  // 0x20 is the address with all jumpers removed
#define SHIELD_2_I2C_ADDRESS  0x21  // 0x21 is the address with a jumper on position A0
#define MAC_I2C_ADDRESS       0x50  // Microchip 24AA125E48 I2C ROM address

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 67);
IPAddress server(192, 168, 1, 108);

byte shield1BankA = 0; // Current status of all outputs on first shield, one bit per output
byte shield2BankA = 0; // Current status of all outputs on second shield, one bit per output

void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();


  if (strcmp(topic, "relay1") == 0) {
    if ((char)payload[0] == '1')
    {
      setLatchChannelOn(1);
      delay(100);
      Serial.println("Relay 1 triggered ON");
      
    }
    else if ((char)payload[0] == '0')
    {
      setLatchChannelOff(1);
     Serial.println("Relay 1 triggered OFF");
    }
  }
}



EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);

void setup()
{
  Serial.begin(38400);
  Ethernet.begin(mac, ip);
 
}

void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
  Serial.print("Attempting MQTT connection...");
  // Attempt to connect
  if (client.connect("arduinoClient", "openhabian", "bedrock")) {
    Serial.println("connected");
    client.subscribe("relay1");
  } else {
    Serial.print("failed, rc=");
    Serial.print(client.state());
    Serial.println(" try again in 5 seconds");
    // Wait 5 seconds before retrying
    delay(5000);
   }
 }
}
void loop()
{
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

void setLatchChannelOn (byte channelId)
{
  if ( channelId >= 1 && channelId <= 8 )
  {
    byte shieldOutput = channelId;
    byte channelMask = 1 << (shieldOutput - 1);
    shield1BankA = shield1BankA | channelMask;
    sendRawValueToLatch1(shield1BankA);
  }
  else if ( channelId >= 9 && channelId <= 16 )
  {
    byte shieldOutput = channelId - 8;
    byte channelMask = 1 << (shieldOutput - 1);
    shield2BankA = shield2BankA | channelMask;
    sendRawValueToLatch2(shield2BankA);
  }
}

void setLatchChannelOff (byte channelId)
{
  if( channelId >= 1 && channelId <= 8 )
  {
    byte shieldOutput = channelId;
    byte channelMask = 255 - ( 1 << (shieldOutput - 1));
    shield1BankA = shield1BankA & channelMask;
    sendRawValueToLatch1(shield1BankA);
  }
  else if( channelId >= 9 && channelId <= 16 )
  {
    byte shieldOutput = channelId - 8;
    byte channelMask = 255 - ( 1 << (shieldOutput - 1));
    shield2BankA = shield2BankA & channelMask;
    sendRawValueToLatch2(shield2BankA);
  }
}

void sendRawValueToLatch1(byte rawValue)
{
  Wire.beginTransmission(SHIELD_1_I2C_ADDRESS);
  Wire.write(0x12);        // Select GPIOA
  Wire.write(rawValue);    // Send value to bank A
  shield1BankA = rawValue;
  Wire.endTransmission();
}

void sendRawValueToLatch2(byte rawValue)
{
  Wire.beginTransmission(SHIELD_2_I2C_ADDRESS);
  Wire.write(0x12);        // Select GPIOA
  Wire.write(rawValue);    // Send value to bank A
  shield2BankA = rawValue;
  Wire.endTransmission();
}

/** Required to read the MAC address ROM */
byte readRegister(byte r)
{
  unsigned char v;
  Wire.beginTransmission(MAC_I2C_ADDRESS);
  Wire.write(r);  // Register to read
  Wire.endTransmission();

  Wire.requestFrom(MAC_I2C_ADDRESS, 1); // Read a byte
  while (!Wire.available())
  {
    // Wait
  }
  v = Wire.read();
  return v;
}

In this i subscribe to the topic of relay1 if it sees a “1” it turns the relay on if it sees a “0” it turns off.

Currently when i publish into relay1 with a 1 i get this in the serial monitor

23:43:24.626 -> Attempting MQTT connection...connected
23:43:29.035 -> Message arrived [relay1] 1
23:43:29.137 -> Relay 1 triggered

But its not updating the status of the relay itself. it seams like its compleatly ignoring the setLatchChannelOn(1)

Pulled this info from the Freetronics Store Page


Addr 0	Addr 1	Addr 2	        Shield Address
    0	   0	   0	               0x20
    1      0	   0	               0x21
    0	   1       0	               0x22
    1	   1	   0	               0x23
    0      0	   1	               0x24
    1	   0	   1                   0x25
    0	   1	   1	               0x26
    1      1	   1	               0x27

This sets the Address of the Shield via pin headers and depending on which ones have jumpers over them

The example sketch below uses the Wire library (included with the Arduino IDE) to communicate with the 8-Channel Relay Driver Shield. The bank of 8 relay outputs corresponds to a single byte (8-bit value from 0 to 255) with each output matching one of the 8 bits. Each relay channel therefore has the following corresponding value:

Relay	Decimal	         Binary
1	       1	         00000001
2	       2	         00000010
3	       4	         00000100
4	       8        	 00001000
5	       16	         00010000
6	       32	         00100000
7	       64	         01000000
8	       128	         10000000

To activate one specific relay, send the value that corresponds to that relay: to turn on relay 5, send the value “16”. To turn on relay 7, send the value “64”, and so on.

To activate multiple relays, add the values of those relays together. For example, to activate relays 5 and 7 at the same time, send “80” (16 + 64).

The example sketch provides a very simplistic approach to controlling the relays, allowing one relay to be turned on at a time. This makes it easy to understand and will help you get started with your own projects, but a more complete solution would use a single byte to represent the current state of the outputs and then apply “bitwise operators” to turn individual relays on or off without altering the state of any other relay.

  1. Copy and paste the sketch into the Arduino IDE.

  2. Compile and upload the sketch to your Arduino.

  3. Open the serial console in the Arduino IDE, make sure the speed is set to 38400, and type “0” then to turn off all relays or the number of a relay channel followed by to activate that relay.

/*
 * Example sketch to control the RELAY8 8-Channel Relay
 * Driver Shield. Open serial console at 38400bps, and
 * send value "0" to reset all relays, or a channel number
 * to activate that relay. Requires Arduino IDE v1.0.1
 * or newer.
 */

#include "Wire.h"

#define I2C_ADDR  0x20  // 0x20 is the address with all jumpers removed

void setup()
{
  Serial.begin( 38400 );
  Serial.println("RELAY8 demonstration starting up");

  Wire.begin(); // Wake up I2C bus

  // Set I/O bank A to outputs
  Wire.beginTransmission(I2C_ADDR);
  Wire.write(0x00); // IODIRA register
  Wire.write(0x00); // Set all of bank A to outputs
  Wire.endTransmission();
  
  Serial.println("Ready. Type 0 to turn off relays, 1 - 8 to activate a relay.");
}

void loop()
{
   int command = 0;
   if (Serial.available()) {
    command = Serial.read();
    if( command == '0' )
    {
      sendValueToLatch(0);
      Serial.println("Resetting all relays");
    }
    if( command == '1' )
    {
      sendValueToLatch(1);
      Serial.println("Activating relay 1");
    }
    if( command == '2' )
    {
      sendValueToLatch(2);
      Serial.println("Activating relay 2");
    }
    if( command == '3' )
    {
      sendValueToLatch(4);
      Serial.println("Activating relay 3");
    }
    if( command == '4' )
    {
      sendValueToLatch(8);
      Serial.println("Activating relay 4");
    }
    if( command == '5' )
    {
      sendValueToLatch(16);
      Serial.println("Activating relay 5");
    }
    if( command == '6' )
    {
      sendValueToLatch(32);
      Serial.println("Activating relay 6");
    }
    if( command == '7' )
    {
      sendValueToLatch(64);
      Serial.println("Activating relay 7");
    }
    if( command == '8' )
    {
      sendValueToLatch(128);
      Serial.println("Activating relay 8");
    }
  }
}

void sendValueToLatch(int latchValue)
{
  Wire.beginTransmission(I2C_ADDR);
  Wire.write(0x12);        // Select GPIOA
  Wire.write(latchValue);  // Send value to bank A
  Wire.endTransmission();
}

Hopefully this makes a bit more sense

Well, they say after you hit your head against a wall enough youll figure out the issue

Might actually help if i added Wire.begin(); // Wake up the I2C Bus

into
void setup()


// This subscribes to MQTT IOT get the PIR sensor states //

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Wire.h>

#define SHIELD_1_I2C_ADDRESS  0x20  // 0x20 is the address with all jumpers removed
#define SHIELD_2_I2C_ADDRESS  0x21  // 0x21 is the address with a jumper on position A0
#define MAC_I2C_ADDRESS       0x50  // Microchip 24AA125E48 I2C ROM address

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 67);
IPAddress server(192, 168, 1, 108);

byte shield1BankA = 0; // Current status of all outputs on first shield, one bit per output
byte shield2BankA = 0; // Current status of all outputs on second shield, one bit per output

void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();


  if (strcmp(topic, "relay1") == 0) {
    if ((char)payload[0] == '1')
    {
      setLatchChannelOn(1);
      delay(100);
      Serial.println("Relay 1 triggered");
      
    }
    else if ((char)payload[0] == '0')
    {
      setLatchChannelOff(1);
    }
  }
}



EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);

void setup()
{
  Wire.begin(); // Wake up the I2C Bus
  Serial.begin(38400);
  Ethernet.begin(mac, ip);
  // Note - the default maximum packet size is 128 bytes. If the
  // combined length of clientId, username and password exceed this,
  // you will need to increase the value of MQTT_MAX_PACKET_SIZE in
  // PubSubClient.h

/* Set up the Relay8 shields */
  initialiseShield(SHIELD_1_I2C_ADDRESS);
  sendRawValueToLatch1(0);  // If we don't do this, channel 6 turns on! I don't know why
  
  initialiseShield(SHIELD_2_I2C_ADDRESS);
  sendRawValueToLatch2(0);  // If we don't do this, channel 6 turns on! I don't know why
 Serial.println("Ready.");
}

void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
  Serial.print("Attempting MQTT connection...");
  // Attempt to connect
  if (client.connect("arduinoClient", "openhabian", "bedrock")) {
    Serial.println("connected");
    client.subscribe("relay1");
    client.subscribe("sensor2");
    client.subscribe("sensor3");
    client.subscribe("sensor4");
  } else {
    Serial.print("failed, rc=");
    Serial.print(client.state());
    Serial.println(" try again in 5 seconds");
    // Wait 5 seconds before retrying
    delay(5000);
   }
 }
}
void loop()
{
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

void initialiseShield(int shieldAddress)
{
  // Set addressing style
  Wire.beginTransmission(shieldAddress);
  Wire.write(0x12);
  Wire.write(0x20); // use table 1.4 addressing
  Wire.endTransmission();

  // Set I/O bank A to outputs
  Wire.beginTransmission(shieldAddress);
  Wire.write(0x00); // IODIRA register
  Wire.write(0x00); // Set all of bank A to outputs
  Wire.endTransmission();
}

void setLatchChannelOn (byte channelId)
{
  if ( channelId >= 1 && channelId <= 8 )
  {
    byte shieldOutput = channelId;
    byte channelMask = 1 << (shieldOutput - 1);
    shield1BankA = shield1BankA | channelMask;
    sendRawValueToLatch1(shield1BankA);
  }
  else if ( channelId >= 9 && channelId <= 16 )
  {
    byte shieldOutput = channelId - 8;
    byte channelMask = 1 << (shieldOutput - 1);
    shield2BankA = shield2BankA | channelMask;
    sendRawValueToLatch2(shield2BankA);
  }
}

void setLatchChannelOff (byte channelId)
{
  if( channelId >= 1 && channelId <= 8 )
  {
    byte shieldOutput = channelId;
    byte channelMask = 255 - ( 1 << (shieldOutput - 1));
    shield1BankA = shield1BankA & channelMask;
    sendRawValueToLatch1(shield1BankA);
  }
  else if( channelId >= 9 && channelId <= 16 )
  {
    byte shieldOutput = channelId - 8;
    byte channelMask = 255 - ( 1 << (shieldOutput - 1));
    shield2BankA = shield2BankA & channelMask;
    sendRawValueToLatch2(shield2BankA);
  }
}

void sendRawValueToLatch1(byte rawValue)
{
  Wire.beginTransmission(SHIELD_1_I2C_ADDRESS);
  Wire.write(0x12);        // Select GPIOA
  Wire.write(rawValue);    // Send value to bank A
  shield1BankA = rawValue;
  Wire.endTransmission();
}

void sendRawValueToLatch2(byte rawValue)
{
  Wire.beginTransmission(SHIELD_2_I2C_ADDRESS);
  Wire.write(0x12);        // Select GPIOA
  Wire.write(rawValue);    // Send value to bank A
  shield2BankA = rawValue;
  Wire.endTransmission();
}

/** Required to read the MAC address ROM */
byte readRegister(byte r)
{
  unsigned char v;
  Wire.beginTransmission(MAC_I2C_ADDRESS);
  Wire.write(r);  // Register to read
  Wire.endTransmission();

  Wire.requestFrom(MAC_I2C_ADDRESS, 1); // Read a byte
  while (!Wire.available())
  {
    // Wait
  }
  v = Wire.read();
  return v;
}

Thanks for your help again @kriznik and @rlkoshak
if you need any help with stateless arduino stuff ive got it all worked out now :rofl::rofl::rofl::rofl:

no worries, glad it worked out.
rewriting code is usually good way to spot any mistakes which seems to be invisible