ESP8266 MQTT 8 way relay - some help required

Hi guys,

Firstly can i thank Erick Joaquin and ItKindaWorks for the sketch, this is a my take on the 4 way relay but amended to suit an 8 way board with some tweaks that i think are possibly making it not as stable as i would like.

Please excuse the bullet points, but i feel it’s a clear way to seaprate the issues i have.

  • I’m unsure on how to power the relay board and the NodeMCU, i have power drop issues using my current AC-DC converter - which is a ipad charger so capable of delivering 2 amps. If i try and power the relay board and the NodeMCU it causes power to drop on the NodeMCU and become unresponsive.

  • I have no way to check what the NodeMCU is doing without a web interface, so i’ve been powering the NodeMCU from my laptop and looking at the serial outputs - this isn’t ideal.

  • I have to be perticular about how i turn on the relay and the NodeMCU otherwise it causes the NodeMCU to crash, even if using separate power for each component. power can be kept constant to the relay board, i then have to unplug the GPIO leads from each relay, then turn NodeMCU on, wait for a few moments for it to connect to WIFI then i can plug the GPIO leads in. This will fire each relay to turn on as this seems to be the default state within the Script

  • I do not want the relays to default to on when it’s turned on, although i could wire it up the other way around this would mean the relay is drawing 0.46 amps and i do not want this. I want the relays to be off at start up, and for the device that is wired to each relay to also be off in this state. Can you help with the code?

I think fixing the last issue will actually fix the crashing of the NodeMCU as well, If i lose power to the setup, i do not want to have manually unplug and go through a power up cycle - this would make it really not useful. If the code needs some tweaks could someone kind enough show me what needs doing. I had to change some output states so that when the board is showing in Home Assistant is the device was turned off, the relay LED would also be off - could this be an issue and what can i do to make it better?

Many thanks in advance, i will also keep looking at other projects to see if a similar problem has already been posted.

Jacko.

//EJ: 4 Relay Switch over WIFI using MQTT and Home Assistant with OTA Support
//EJ: The only way I know how to contribute to the HASS Community… you guys ROCK!!!
//EJ: Erick Joaquin :slight_smile: Australia

// Original sketch courtesy of ItKindaWorks
//ItKindaWorks - Creative Commons 2016
//github.com/ItKindaWorks
//
//Requires PubSubClient found here: GitHub - knolleary/pubsubclient: A client library for the Arduino Ethernet Shield that provides support for MQTT.
//
//ESP8266 Simple MQTT switch controller

#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>

// Mapping NodeMCU Ports to Arduino GPIO Pins
// Allows use of NodeMCU Port nomenclature in config.h
#define D0 16
#define D1 5
#define D2 4
#define D3 0
#define D4 2
#define D5 14
#define D6 12
#define D7 13
#define D8 15

void callback(char* topic, byte* payload, unsigned int length);

//EDIT THESE LINES TO MATCH YOUR SETUP
#define MQTT_SERVER “192.168.168.168” //you MQTT IP Address
const char* ssid = “SSID”;
const char* password = “PASSWORD”;

//EJ: Data PIN Assignment on WEMOS D1 R2 https://www.wemos.cc/product/d1.html
// if you are using Arduino UNO, you will need to change the “D1 ~ D4” with the corresponding UNO DATA pin number

const int switchPin1 = D1;
const int switchPin2 = D2;
const int switchPin3 = D3;
const int switchPin4 = D4;
const int switchPin5 = D5;
const int switchPin6 = D6;
const int switchPin7 = D7;
const int switchPin8 = D8;

//EJ: These are the MQTT Topic that will be used to manage the state of Relays 1 ~ 8
//EJ: Refer to my YAML component entry
//EJ: feel free to replicate the line if you have more relay switch to control, but dont forget to increment the number suffix so as increase switch logics in loop()

char const* switchTopic1 = “/house/switch1/”;
char const* switchTopic2 = “/house/switch2/”;
char const* switchTopic3 = “/house/switch3/”;
char const* switchTopic4 = “/house/switch4/”;
char const* switchTopic5 = “/house/switch5/”;
char const* switchTopic6 = “/house/switch6/”;
char const* switchTopic7 = “/house/switch7/”;
char const* switchTopic8 = “/house/switch8/”;

WiFiClient wifiClient;
PubSubClient client(MQTT_SERVER, 1883, callback, wifiClient);

void setup() {
//initialize the switch as an output and set to LOW (off)
pinMode(switchPin1, OUTPUT); // Relay Switch 1
digitalWrite(switchPin1, LOW);

pinMode(switchPin2, OUTPUT); // Relay Switch 2
digitalWrite(switchPin2, LOW);

pinMode(switchPin3, OUTPUT); // Relay Switch 3
digitalWrite(switchPin3, LOW);

pinMode(switchPin4, OUTPUT); // Relay Switch 4
digitalWrite(switchPin4, LOW);

pinMode(switchPin5, OUTPUT); // Relay Switch 5
digitalWrite(switchPin5, LOW);

pinMode(switchPin6, OUTPUT); // Relay Switch 6
digitalWrite(switchPin6, LOW);

pinMode(switchPin7, OUTPUT); // Relay Switch 7
digitalWrite(switchPin7, LOW);

pinMode(switchPin8, OUTPUT); // Relay Switch 8
digitalWrite(switchPin8, LOW);

ArduinoOTA.setHostname(“Garage_Control”); // A name given to your ESP8266 module when discovering it as a port in ARDUINO IDE
ArduinoOTA.begin(); // OTA initialization

//start the serial line for debugging
Serial.begin(115200);
delay(100);

//start wifi subsystem
WiFi.begin(ssid, password);
//attempt to connect to the WIFI network and then connect to the MQTT server
reconnect();

//wait a bit before starting the main loop
delay(2000);
}

void loop(){

//reconnect if connection is lost
if (!client.connected() && WiFi.status() == 3) {reconnect();}

//maintain MQTT connection
client.loop();

//MUST delay to allow ESP8266 WIFI functions to run
delay(10);
ArduinoOTA.handle();
}

void callback(char* topic, byte* payload, unsigned int length) {

//convert topic to string to make it easier to work with
String topicStr = topic;
//EJ: Note: the “topic” value gets overwritten everytime it receives confirmation (callback) message from MQTT

//Print out some debugging info
Serial.println(“Callback update.”);
Serial.print("Topic: ");
Serial.println(topicStr);

if (topicStr == “/house/switch1/”)
{

 //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message
 if(payload[0] == '0'){
   digitalWrite(switchPin1, HIGH);
   client.publish("/house/switchConfirm1/", "0");
   }

  //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message
 else if (payload[0] == '1'){
   digitalWrite(switchPin1, LOW);
   client.publish("/house/switchConfirm1/", "1");
   }
 }

 // EJ: copy and paste this whole else-if block, should you need to control more switches
 else if (topicStr == "/house/switch2/") 
 {
 //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message
 if(payload[0] == '0'){
   digitalWrite(switchPin2, HIGH);
   client.publish("/house/switchConfirm2/", "0");
   }

  //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message
 else if (payload[0] == '1'){
   digitalWrite(switchPin2, LOW);
   client.publish("/house/switchConfirm2/", "1");
   }
 }
 else if (topicStr == "/house/switch3/") 
 {
 //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message
 if(payload[0] == '0'){
   digitalWrite(switchPin3, HIGH);
   client.publish("/house/switchConfirm3/", "0");
   }

  //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message
 else if (payload[0] == '1'){
   digitalWrite(switchPin3, LOW);
   client.publish("/house/switchConfirm3/", "1");
   }
 }
 else if (topicStr == "/house/switch4/") 
 {
 //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message
 if(payload[0] == '0'){
   digitalWrite(switchPin4, HIGH);
   client.publish("/house/switchConfirm4/", "0");
   }

  //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message
 else if (payload[0] == '1'){
   digitalWrite(switchPin4, LOW);
   client.publish("/house/switchConfirm4/", "1");
   }
 }
 else if (topicStr == "/house/switch5/") 
 {
 //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message
 if(payload[0] == '0'){
   digitalWrite(switchPin5, HIGH);
   client.publish("/house/switchConfirm5/", "0");
   }

  //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message
 else if (payload[0] == '1'){
   digitalWrite(switchPin5, LOW);
   client.publish("/house/switchConfirm5/", "1");
   }
 }
 else if (topicStr == "/house/switch6/") 
 {
 //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message
 if(payload[0] == '0'){
   digitalWrite(switchPin6, HIGH);
   client.publish("/house/switchConfirm6/", "0");
   }

  //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message
 else if (payload[0] == '1'){
   digitalWrite(switchPin6, LOW);
   client.publish("/house/switchConfirm6/", "1");
   }
 }
 else if (topicStr == "/house/switch7/") 
 {
 //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message
 if(payload[0] == '0'){
   digitalWrite(switchPin7, HIGH);
   client.publish("/house/switchConfirm7/", "0");
   }

  //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message
 else if (payload[0] == '1'){
   digitalWrite(switchPin7, LOW);
   client.publish("/house/switchConfirm7/", "1");
   }                            
 }
 else if (topicStr == "/house/switch8/") 
 {
 //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message
 if(payload[0] == '0'){
   digitalWrite(switchPin8, HIGH);
   client.publish("/house/switchConfirm8/", "0");
   }

  //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message
 else if (payload[0] == '1'){
   digitalWrite(switchPin8, LOW);
   client.publish("/house/switchConfirm8/", "1");
   }
 }

}

void reconnect() {

//attempt to connect to the wifi if connection is lost
if(WiFi.status() != WL_CONNECTED){
//debug printing
Serial.print("Connecting to ");
Serial.println(ssid);

//loop while we wait for connection
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}

//print out some more debug once connected
Serial.println("");
Serial.println("WiFi connected");  
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

}

//make sure we are connected to WIFI before attemping to reconnect to MQTT
if(WiFi.status() == WL_CONNECTED){
// Loop until we’re reconnected to the MQTT server
while (!client.connected()) {
Serial.print(“Attempting MQTT connection…”);

  // Generate client name based on MAC address and last 8 bits of microsecond counter
  String clientName;
  clientName += "esp8266-";
  uint8_t mac[6];
  WiFi.macAddress(mac);
  clientName += macToStr(mac);

  //if connected, subscribe to the topic(s) we want to be notified about
  //EJ: Delete "mqtt_username", and "mqtt_password" here if you are not using any 
  if (client.connect((char*) clientName.c_str(),"USERNAME", "PASSWORD")) {  //EJ: Update accordingly with your MQTT account 
    Serial.print("\tMQTT Connected");
    client.subscribe(switchTopic1);
    client.subscribe(switchTopic2);
    client.subscribe(switchTopic3);
    client.subscribe(switchTopic4);
    client.subscribe(switchTopic5);
    client.subscribe(switchTopic6);
    client.subscribe(switchTopic7);
    client.subscribe(switchTopic8);
    //EJ: Do not forget to replicate the above line if you will have more than the above number of relay switches
  }

  //otherwise print failed for debugging
  else{Serial.println("\tFailed."); abort();}
}

}
}

//generate unique name from MAC addr
String macToStr(const uint8_t* mac){

String result;

for (int i = 0; i < 6; ++i) {
result += String(mac[i], 16);

if (i < 10){
  result += ':';
}

}

return result;
}

Change the LOW to HIGH in the setup routine?

I did try that, but it doesn’t seem to work or just became even more unstable so i changed it back. Let me try again and report back the exact results.

Ok, i made some random HIGH / LOW changes, as below;

void setup() {
//initialize the switch as an output and set to LOW (off)
pinMode(switchPin1, OUTPUT); // Relay Switch 1
digitalWrite(switchPin1, HIGH);

pinMode(switchPin2, OUTPUT); // Relay Switch 2
digitalWrite(switchPin2, HIGH);

pinMode(switchPin3, OUTPUT); // Relay Switch 3
digitalWrite(switchPin3, HIGH);

pinMode(switchPin4, OUTPUT); // Relay Switch 4
digitalWrite(switchPin4, HIGH);

pinMode(switchPin5, OUTPUT); // Relay Switch 5
digitalWrite(switchPin5, LOW);

pinMode(switchPin6, OUTPUT); // Relay Switch 6
digitalWrite(switchPin6, HIGH);

pinMode(switchPin7, OUTPUT); // Relay Switch 7
digitalWrite(switchPin7, LOW);

pinMode(switchPin8, OUTPUT); // Relay Switch 8
digitalWrite(switchPin8, LOW);

This caused relay 5, 7 and 8 and the corrasponding LED to be illuminated, once GPIO pins have been connectede (i’m still having to unplug all GPIO cables in order to get the NodeMCU to boot.

When the NodeMCU is trying to update the stautus it seems to hang, sometimes at relay 5 (seems most often at relay 5) but sometimes at relay 6. Eventually it updates all relays and then they are accessesable via HA, untill each has been updated none of relays can be opperated via HA.

Once all relays status has been up dated i can then access via HA, each relay at this point is in an off state, dispite this not being the same within the script, so that’s quite odd?

I have the same issue with the relay state update when all relays state is set the same, it does seem to take far longer than i would expect for this to happen - could this be some issue with the code?

What are you using for hardware, what is your schematic? It is hard to gauge what is the problem without a schematic.

For power supply issues, try adding a capacitor (larger is probably better) near the nodeMCU Vin. If the relays are causing too much noise in the supply or two much of a current drop when turning on, then a capacitor may keep it online until the PSU stabilizes. However, you should add up all the power requirements of your devices and make sure 2A is enough (my hardware for 8 channels would be ~1.5A max)

If the relays are on by default, then it sounds like you either have the mains connected to NC, or you have your relays wired such that LOW on the nodeMCU applies power. I personally don’t use with either of those options. I always want my controllers to default to off when power is restored. This is how my relays are setup (except the LED and resistor in most cases)

As for remote monitoring, you may find this useful


It is my code for a generic 2-relay switch for in wall or whatever (and could very easily be extended to handle 8 channels). If you look at the code I have a wifi server open on port 23 which allows me to telnet in (using putty) and see what it is printing out to the serial.

Hi Nordlead2005,

Thanks for such a thorough responce. I’ve got to get some other jobs done around the house so i can’t get a diagram together that the moment but i certainly will do in a little while. I’m excited about getting this setup correctly so i can put it into production (so to speak)

Jacko.

Hi Nordlead2005,

I’m using a LoLin NodeMCU V3
I’m using a generic 8 way relay board

Power supply is a iPAD 5v 2.3A output max

I can power the NodeMCU and the relay board from the single supply, my issue with the power draw of the relay board is the same regardless of if i power the nMCU via the same source or if i power the nMCU via the laptop - so i can look at the serial output.

My wiring as as such, all grounds are common, if using PC to power nMCU.

Relay board
Ground (far left pin) to common ground
relay 1 - GPIO5 on nMCU
relay 2 - GPIO4 on nMCU
relay 3 - GPIO0 on nMCU
relay 4 - GPIO2 on nMCU
relay 5 - GPIO14 on nMCU
relay 6 - GPIO12 on nMCU
relay 7 - GPIO13 on nMCU
relay 8 - GPIO15 on nMCU
VCC - 5v from AC-DC supply

I’m powering the NodeMCU via a microUSB input and i had one of the ground pins connected to common ground.

On the 3 pin to the right of the board, i have connected ground to common ground and i’ve connect JC-VCC to 5v as well and i have not connected power to VCC here. I’ve tried it a few different ways, so it would be interesting to know if i should bridge VCC and JCVCC together and just supply power to VCC on the main header.

Sorry it’s not a diagram, if it’s unclear i can put something together.

I’ll take a look at your sketch now and see if i can doctor it to work, thanks very much for sharing.

With regard to adding a capacitor close to the nMCU i can see the logic in that, should help with noise and sudden drops in power. I though the nMCU boards where quite robust with a good power supply design to help suppress interference but it’s well worth me trying.

I actually want to control each relay via a push button as well, so i’m considering what my options my be here, i suspect an Arduino of sorts but i need to check into it, looks like your code already some buttons defined to making changes to this to work with 8 relays, each with a button will be very good.

My eventual plan is to have a 5v 2a AC-DC converter powering the lot, do you think that a cap at the nodeMCU input side would fix the serge issue? Just not sure why the board takes so long to update the relay state and publish it to MQTT, it seems that unless it can update all at the same time it will not update any at all.

Your reboot problems are probably due to GPIO0 and 15 as they are special pins needed for booting, I think they need a pull down and pull up resistor.

I’ll do some research on that, thanks. For what it’s worth, once all relay states have been updated the nMCU is stable and each relay works flawlessly.

You can also use Tasmota for control 8ch relay with NodeMCU 8266 etc.

Thanks Mudasar, i’ll have a look at this as an option. Problem i have is i’ve struggled to upload Tasmota onto my Sonoff devices. I’ve had to resort to using ESPeasy and Espurna which is annoying as i can’t make changes to the GPIO inputs which i need to do, so using Tasmota for all ESP8266 devices would be nice.

1 Like

I am using it with 4ch and 8ch relay+nodeMCU+5v 1amp adapter and its working like a charm.

I use a PCF8574 I2C IO expander with my ESP8266 and it works like a charm. The best part is you can do 8-bytes to control all 8 relays with one command. Very useful for christmas lights. The next upgrade to mechanical 8-way relays would be a 8-relay SSR to get blinking effect.

how about using Arduino IDE to program the ESP? That’s what I do and its great because you can code them in C.

You are probably right. GPIO2 must be high, GPIO15 must be low, and GPIO0 is high to run, low to flash via serial/usb.

I think it will only apply while you have it connected to your pc, tho’ maybe worth trying it stand alone for a few days and if it crashes see if it comes back up before adding resistors.

Guys, you have all been amazing at offering advice on a resolution, thank you very much for offering your time to this.

I’ve unfortunately been really busy with work and i don’t think i’ll get time to do much playing this week, but i’ll try and do some research in my downtime and formulate a plan.

With regard to GPIO2 and GPIO15 i’ll need to research how to wire this up, i have a NodeMCU working as my garage door controller using a slightly modified version of GarHAge without issue and without using pullup/down resistors so Keithh666, you may be right about powering from the PC and i’ll do some testing. My issue was that i couldn’t see the serial log unless connected to PC but nordlead2005 you provided some code for remote monitoring so i just need to get my head around it and add it to the sketch and upload.

I was looking at using an Arduino board with more GPIO to control this relay board, and possibly having some environmental inputs, and use physical buttons to control the relays as well. I just need to look at what option will be most cost effective for the requirement so i will research my options when i get a moment.

Lots to think about, i’ll keep you posted on progress. :slight_smile: