Relay8's and EtherTens

Okay bit of a weird one here,

I currently have 4 Relay8 boards working with an etherMega.

yesterday i got my EtherTens and tried to switch over to them but i cant get the blue LED to turn on.

coming off the IOREF i get 5v but on the Relay8 IOREF i dont get anything. i suspected the cable so replaced that still nothing. tried the same cable with the etherMega works perfectly fine. ive tried disabling the Pullups but still nada.

for now i might stick with the EtherMegas, but id like to pull the $120 boards out and replace them with the cheaper alternative, i have great plans for these Mega :sunglasses:

Hi Bedrock,

You are reading my mind, I started my draft about the same issue yesterday but didn’t submit the topic, was about to do that but noticed yours.

So same or similar issue here.

I got 2 EtherTen and 3 Relay8 boards, all unboxed yesterday (but purchased few month ago).

I started from the basics:

  1. Picked one arduino and one relay board on top, all out of the box.
  2. Uploaded the sketch from freetronics (just to monitor serial port and send signals to relays)
  3. Sketch uploaded, serial monitor works fine, but relays LEDs did not turn on/off.
  4. Realized that blue power LED should be turned on on the relay board but it wasn’t
  5. Played with all possible combinations with both EtherTens and all 3 relay boards, cut pullups on 2 of them but no luck.
  6. Then I put Relay board on my 6 year old arduino uno and blue power led turned on, but I was not able to turn on/off the relay through serial monitor, maybe because it’s an old arduino board or maybe there is something else not setup properly.

I have EtherMega so will test later today.

Out of topic - how do you control your relays? Are you using MQTT? Jon is using Web server to control the relays in his video and promised to share the updated code with MQTT, but I believe he is very busy.

Thanks.

1 Like

Hey @Serg

Using Mqtt

Here’s a link to my other topic for that side of things if you need it

Help with Arduino Mega With Relay8 Boards

After work I have a few ideas to try so hopefully I can get it working
I’ll update with any new news

1 Like

@Serg

Got mine working,

Im using one of the Relay carrier boards that @jon designed, so my setup might vary from yours a bit.

i had an issue where my IORef pin on all 3 of my ethertens wasn’t giving me a voltage,
the Relay8 board links the ioref lines with the 5v rail anyways so i just moved my jumper cable over to the 5v rail and bam, Blue led came on and everything is working,

Unsure as to why that isnt working but eh, its working now aha

Hopefully yours is as simple as mine. if you have jumper cable try using those to see if you can get similar results

1 Like

Got mine working as well.

What I had to do is just to read through the manual which came with the relay shield. Online Quickstart Guide on freetronics/superhouse is outdated, but printed version with the shield is Quick Start Guide v2 and there is a bit more information there.

In the online version it mentions all power supply options for the shield which is fine, but printed version also says that IORef pin is NOT connected to 5V which could be done by soldering 2 pins on the bottom or just using a jumper wire to connect IORef to 5V. Same as you said :slight_smile:

Thanks Bedrock for your help.

Just a bit more details if someone is facing the same issue - make sure you have enough power from Arduino to operate your relays. In my case I have 12v relays which cannot be turned on/off by 5v from Arduino powered by micro usb. External power supply to the shield worked, as well as 12v power supply to arduino (2.1mm power jack). POE will probably be the best option for this.

1 Like

To add further to this for reference.
In my testing POE works okay if the supply is there but in my case im using it with a switchmode psu
A strong 12v power supply(something like 5-6amps if your planning on running a number of relays like in my case I have 7 Relay8 on 1 ethermega.
And power that via the sheild or relay carrier board.

Nice work folks. I’m following close behind.

I’ve started creating some code that currently works for a proof-of-concept. I wanted to publish my progress in case it helps someone else, and to get some opinions.

Currently, the code

  • Connects to the MQTT broker
  • Sets a single callback function
  • Publishes a connected event to the event topic
  • Subscribes to the command topic for the controller
  • Triggers relays
  • Publishes a status event to the status topic

The MQTT command topic is house/switchboard/relay/+/command and the MQTT status topic is house/switchboard/relay/1/status (where 1 is the relay number).

Now the code is currently using 70% of program storage space and 75% of dynamic memory so it is getting quite big on the EtherTen and I am thinking of changing my direction.

Here is my current code:

/*
* Home Automation Relay Controller
* 
* This project aims to use an Arduino to trigger relay drivers
* attached via I2C by messages received from MQTT
* 
* Written by 
* Jon Oxer - Copyright 2015-2017 SuperHouse Automation Pty Ltd <info@superhouse.tv>
* Alex Ferrara <alex@receptiveit.com.au>
* Bedrock from Superhouse.tv Forums
* 
* 4th September 2019
* 
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*/

 // TODO: Add watchdog support

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


/*--------------------------- Configuration ------------------------------*/
/* Core Settings */
#define SERIAL_SPEED            57600   // Serial port speed

/* Network Settings */
#define ENABLE_DHCP             true    // true/false
#define ENABLE_MAC_ADDRESS_ROM  true    // true/false
#define MAC_I2C_ADDR            0x50    // Microchip 24AA125E48 I2C ROM address
static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };    // Set if no MAC ROM
IPAddress ip(192,168,1,35);             // Default if DHCP is not used

/* MQTT Settings */
IPAddress broker(192,168,1,125);            // MQTT broker
#define MQTT_USER         "mqtt"          // Username presented to the MQTT broker
#define MQTT_PASSWD       "Secret"      // Password presented to the MQTT broker
#define MQTT_TOPIC_BUFFER  40
char clientBuffer[40];                    // Maximum clientID length
char messageBuffer[100];  // TODO: unused ATM
char topicBuffer[35];                     // Maximum topic length
const char* mqttClientID      = "ArduinoClient"; // Client ID presented to the MQTT broker
const char* mqttEventTopic    = "events";        // MQTT logging topic
const char* mqttTopicPrefix   = "house/switchboard/relay"; // MQTT topic prefix
const char* mqttCmdTopic      = "command";       // MQTT command topic suffix
const char* mqttStatusTopic   = "status";        // MQTT status topic suffix

/* Relay 8 Modules */
const int RLY8_I2C_ADDR[4] = {0x20, 0x21, 0x22, 0x23};
byte BankA[4] = {0, 0, 0, 0}; // Current status of all outputs on first shield, one bit per output

/*------------------------------------------------------------------------*/

// Instantiate MQTT client
EthernetClient ethclient;
PubSubClient client(ethclient);

void setup() {
  Serial.begin( SERIAL_SPEED );
  Serial.println("Home Automation Relay Controller");
  Serial.println("--------------------------------");
  Serial.println("Starting up.");

  Wire.begin();

  if( ENABLE_MAC_ADDRESS_ROM == true )
  {
    Serial.print(F("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);
  } else {
    Serial.print(F("Using static MAC address: "));
  }
  // Print the MAC address
  char macAddr[17];
  sprintf(macAddr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  Serial.println(macAddr);

  // Set up the Ethernet library to talk to the Wiznet board
  if( ENABLE_DHCP == true )
  {
    Ethernet.begin(mac);      // Use DHCP
  } else {
    Ethernet.begin(mac, ip);  // Use static address defined above
  }
  
  // Print IP address:
  Serial.print(F("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(".");
    }
  }
  Serial.println();
  
  // Initialise Relay8 modules
  // TODO: support multiple shields
  initRelay8(RLY8_I2C_ADDR[0]);

  // Set MQTT broker settings
  Serial.println("MQTT broker settings...");
  client.setServer(broker, 1883);
  client.setCallback(mqttCallback);

  Serial.println("Ready.");

}

void loop() {
  // Stay connected to MQTT
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection: ");
    // Attempt to connect
    if (client.connect(mqttClientID, MQTT_USER, MQTT_PASSWD)) {
      Serial.println("Connected");

      // Construct MQTT Client ID
      sprintf(clientBuffer, "%s Connected %02X%02X%02X%02X%02X%02X", mqttClientID, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
      Serial.println(sizeof(clientBuffer));
      client.publish(mqttEventTopic, clientBuffer);

      // Construct MQTT topic
      sprintf(topicBuffer, "%s/+/%s", mqttTopicPrefix, mqttCmdTopic);

      Serial.print("Subscribing to MQTT topic: ");
      Serial.println(topicBuffer);
      
      client.subscribe(topicBuffer);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void initRelay8(int i2c_addr) {
  // Set I/O bank A to outputs
  Wire.beginTransmission(i2c_addr);
  Wire.write(0x00);
  Wire.write(0x00);
  Wire.endTransmission();
}

byte readRegister(byte r)
{
  unsigned char v;
  Wire.beginTransmission(MAC_I2C_ADDR);
  Wire.write(r);  // Register to read
  Wire.endTransmission();

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

void setLatchChannelOn (byte channelId)
{
  if ( channelId >= 1 && channelId <= 8 )
  {
    byte shieldOutput = channelId;
    byte channelMask = 1 << (shieldOutput - 1);
    BankA[0] = BankA[0] | channelMask;
    sendRawValueToLatch(BankA[0], RLY8_I2C_ADDR[0]);
  }
  else if ( channelId >= 9 && channelId <= 16 )
  {
    byte shieldOutput = channelId - 8;
    byte channelMask = 1 << (shieldOutput - 1);
    BankA[1] = BankA[1] | channelMask;
    sendRawValueToLatch(BankA[1], RLY8_I2C_ADDR[1]);
  }
}

void setLatchChannelOff (byte channelId)
{
  if( channelId >= 1 && channelId <= 8 )
  {
    byte shieldOutput = channelId;
    byte channelMask = 255 - ( 1 << (shieldOutput - 1));
    BankA[0] = BankA[0] & channelMask;
    sendRawValueToLatch(BankA[0], RLY8_I2C_ADDR[0]);
  }
  else if( channelId >= 9 && channelId <= 16 )
  {
    byte shieldOutput = channelId - 8;
    byte channelMask = 255 - ( 1 << (shieldOutput - 1));
    BankA[1] = BankA[1] & channelMask;
    sendRawValueToLatch(BankA[1], RLY8_I2C_ADDR[1]);  // TODO: This looks redundant and could be better
  }
}

void sendRawValueToLatch(byte rawValue, int i2cAddress)
{
  Wire.beginTransmission(i2cAddress);
  Wire.write(0x12);        // Select GPIOA
  Wire.write(rawValue);    // Send value to bank A
  Wire.endTransmission();
}

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

  // TODO: This should be more generic and awesome

  String tmpBuf = topic;
  Serial.println(tmpBuf);
  Serial.println(String(mqttTopicPrefix).length());
  //if (strcmp(topic, "relay1") == 0) {
  if (true) {
    Serial.println("Matched");
    if ((char)payload[0] == '1')
    {
      setLatchChannelOn(2);
      delay(100);   // not actually needed, but i added this in here for how my lights work
      Serial.println("Relay 2 triggered ON");
      client.publish(mqttStatusTopic, '1');
      
    }
    else if ((char)payload[0] == '0')
    {
      setLatchChannelOff(2);
      Serial.println("Relay 2 triggered OFF");
      client.publish(mqttStatusTopic, '0');
    }
  }
}

What I am thinking of doing is simplifying the Arduino sketch so each Relay8 has a unique subscription to MQTT and a unique callback function. The callback function effectively receiving the entire 8 bit register as the MQTT message and writing it to the relay8.

I am by no way a developer with much experience in C, so I could be completely wrong in my approach, but I would be interested in others thoughts.

1 Like

I love it, <3
@jon Might be interested too

ill have a bit more look at it tomorrow

@professor_alex

ive made a github repository for this, to help keep track for changes
also added watchdog support and switchboardID

1 Like

Hi guys,

I think it should be a bit more universal and a single cycle for all relays.

I understand the logic but still playing with the right syntax. In my understanding it should be something like:

if (strcmp(topic, “relay[i]”) == 0) {
if (true) {
Serial.println(“Trigger relay[i]”);
if ((char)payload[0] == ‘1’)
{
setLatchChannelOn(i);

I am building a solution for 32 relays so if I put IF condition per relay - I wont have enough space for it.

Will be happy to test your sketch, as have all hardware assembled but working on a sketch takes long time for me.

Hey @Serg

I currently have if for each relay all 32 of them and it just fits. 86% used.

Have a look at my github link we are working on a new code to unifi the code base. Feel free to add a pull request. And add yourself in the author section

I’m away for work this weekend. So hopefully I can do some more work on the code once I’m home

I’d generally do something like this:

if (strncmp(topic, “relay[”, 6) == 0) {
    char *endptr;
    unsigned long int relay = strtoul(topic+6, &endptr, 10);
    if (strcmp(endptr, "]") == 0 && relay < 32) {
        // do your thing
    }
}

strtoul is good because it returns the first non-numberic character in endptr… so you can check that it is really the end of the number before you accept it, or continue parsing whatever follows (in this case, the closing bracket).

2 Likes

That looks quite good @Fredderic.

It’s kind of what I had in mind and looks to tick the “This should be more generic and awesome” box.