Linknode R4 Wifi 4 Ch Relay Board

Hopefully a stupid question: Are you trying to upload the zip file or its contents to the Arduino IDE workspace? Have you opened the zip file and looked inside? Should you be uploading the contents?

I went to the Git page for this data and downloaded as a zip.
Now trying to use Arduino to use the data in the Zip file to build the code to upload into my esp8266 relay board but struggling as no files that Arduino can read etc…

So all help gratefully received.

Alan,

Are you referring to the github page in the second post of this thread?

Trying to load this code via Arduino into my relay board.

Some progress finding each .H file as it fails and loading them manually into the sketch folder but that cant be the correct way to do this.

No actual sketch file in the zip that Arduino recognises but found something under the ‘check external ip’ by martins picture on the git page above…

I have been hoping someone with some esp8266 experience would point you in the right direction, not only to help you on your way, but to also confirm or dismiss my own suspicions. I am not that familiar with esp8266 so please do not assume I know what I’m talking about here as I may be way off.

I think the firmware @Martin_Harizanov has written uses the expressif SDK toolchain rather than the Arduino IDE, I do not know if these methods of compilation are interchangeable or if they can be altered to be so, but as far as I can make out “it’s not that easy” or maybe it is soooooo easy that it doesn’t warrant documenting anywhere and it is just you and I that are a bit slow on the uptake :slight_smile:

A guide to uploading firmware to the shop bought relay using the the same firmeware can be found here which does not use the same method as the emonESP which is here, That guide for the emonESP firmware offers 2 options 1.PlatformIO or 2. Arduino IDE and they both use the “ESP8266 core for Arduino”.

Back in stock at Amazon so for the £9.90 thought I’d try one. It can always be backup for my home brewed heat bank controller.

Paul, I would have jumped in but haven’t a clue what Martin’s code looks like or what tool chain he uses although I’d hazard a guess that he didn’t use the arduino environment which means the OP will have to use the SDK tool chain which is not as easy as the arduino toolchain.

Alan, can you see a .ino file in the zip you have downloaded? If not then Martin must have used the SDK and you’ll have to install the environment.

Simon

No .ino file that makes sense i’m afraid.

Will locate the SDK you mention and try that one.

The official OPen firmware update is a binary file that a working unit will use to load via http. I’m using the linmknode R4 which works with all basic examples but not the full suite inc web server and MQT. Will post more later today…

This link on Martin’s page says: Also see the ESP8266 WiKi for more details on uploading code. The Wiki mentions the Espressif ESP8266 SDK, the toolchain PB66 mentioned a few posts above this one.

Yes, my code uses the Espressif SDK. The Arduino IDE was not so flexible/reliable at the time I published that project. Probably things have improved significantly now.

Well just to prove I’m no slouch, I have loaded EmonTX V3.4 firmware onto two TX3 units that had gone intermittent so I’m very happy.

Just that ESPTool and Python stuff to overcome…

So nearly completed with all 4 relays switchable from node red and a single line entry in emoncms for the last change of any one of the 4 relays.

Struggling to see how to have 4 entries in emoncms, one for each relay as the next change overrides the previous entry even if I turn on retain in the publish message.

No WEB screens required here just ability to use emoncms to turn relay on/off based upon a temp from emoncms emontx for example and to be able to see status of all 4 relays for LED widgets.

Code

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

const char* ssid = "id";
const char* password = "password";

//const char* mqtt_server = "test.mosquitto.org";
//const char* mqtt_server = "iot.eclipse.org";
const char* mqtt_server = "172.1x.xx.xx";

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  
  pinMode(12,OUTPUT), pinMode(13,OUTPUT),pinMode(14,OUTPUT),pinMode(16,OUTPUT);
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  reconnect();
}

void setup_wifi(){

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(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]);
  }
  
  if((char)payload[0] == 'R' && (char)payload[1] == '1' && (char)payload[2] == '1') //R1 on
    digitalWrite(12,HIGH),client.publish("emon/ESP8266/R1", "1");
  else if((char)payload[0] == 'R' && (char)payload[1] == '1' && (char)payload[2] == '0') //R1 off
    digitalWrite(12,LOW),client.publish("emon/ESP8266/R1", "0");
  else if((char)payload[0] == 'R' && (char)payload[1] == '2' && (char)payload[2] == '1') //R2 on
    digitalWrite(13,HIGH),client.publish("emon/ESP8266/R2", "1");
  else if((char)payload[0] == 'R' && (char)payload[1] == '2' && (char)payload[2] == '0') //R2 off
    digitalWrite(13,LOW),client.publish("emon/ESP8266/R2", "0");
    
  Serial.println();
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client","emonpi","emonpimqtt2016")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("emon/ESP8266/connection status", "Connected!");
      // ... and resubscribe
      client.subscribe("ESP8266/#");
    } 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();
}

Would be great if someone could shed some light on this last piece of the puzzle.

:pager:

Alan,

To get 4 entries you need to send 4 bits of data with each send in the same way the emonTx sends several pieces of data with each send. If you only send one piece then it will overwrite the last data. Check out the documentation for emonhub and how to structure the data you are sending.

But given you are sending via MQTT and node red, you should be able to collect the data in node red and send all 4 states based on their current values.

Also not sure why you would want to use emoncms as the tool to do the decision making about turning things on and off at your set points. I would do that in nodered and send the status to emoncms if you want it in a dashboard. Also have you looked at the UI nodes for nodered. you could maybe use those instead of emoncms.

Simon

So I managed to overcome this little blocker by turning nodevar_format_enable = 1 to nodevar_format_enable = 0. Send the values with a state change for all 4 realys and emoncms detected them.

I then put nodevar_format_enable = 1 as per original setting and it remembers the settings and any state changes are now logged.

So the LinkNode R4 now can be controlled via MQTT and send its state to emoncms via MQTT.

Next step is to add an update on status every 5 min to emoncms.

Basic code available if anyone would like to share my learnings.

Hi Alan
I have a relay board to play with when I get some time, it would be handy to post our working config to assist.

Regards
Dave


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

const char* ssid = "Your SSID Here";
const char* password = "Your SSID Password Here";

//const char* mqtt_server = "test.mosquitto.org";
//const char* mqtt_server = "iot.eclipse.org";
const char* mqtt_server = "Your broker IP Address Here";

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  
  pinMode(12,OUTPUT), pinMode(13,OUTPUT),pinMode(14,OUTPUT),pinMode(16,OUTPUT);
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  reconnect();
}

void setup_wifi(){

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(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]);
  }
  
  if((char)payload[0] == 'R' && (char)payload[1] == '1' && (char)payload[2] == '1') //R1 on with R11
    digitalWrite(12,HIGH),client.publish("emon/ESP8266/Relay1/", "1");
  else if((char)payload[0] == 'R' && (char)payload[1] == '1' && (char)payload[2] == '0') //R1 off with R10
    digitalWrite(12,LOW),client.publish("emon/ESP8266/Relay1/", "0");
  else if((char)payload[0] == 'R' && (char)payload[1] == '2' && (char)payload[2] == '1') //R2 on with R21
    digitalWrite(13,HIGH),client.publish("emon/ESP8266/Relay2/", "1");
  else if((char)payload[0] == 'R' && (char)payload[1] == '2' && (char)payload[2] == '0') //R2 off with R20
    digitalWrite(13,LOW),client.publish("emon/ESP8266/Relay2/", "0");
  else if((char)payload[0] == 'R' && (char)payload[1] == '3' && (char)payload[2] == '1') //R3 on with R31
    digitalWrite(14,HIGH),client.publish("emon/ESP8266/Relay3/", "1");
  else if((char)payload[0] == 'R' && (char)payload[1] == '3' && (char)payload[2] == '0') //R3 off with R30
    digitalWrite(14,LOW),client.publish("emon/ESP8266/Relay3/", "0");
  else if((char)payload[0] == 'R' && (char)payload[1] == '4' && (char)payload[2] == '1') //R4 on with R41
    digitalWrite(16,HIGH),client.publish("emon/ESP8266/Relay4/", "1");
  else if((char)payload[0] == 'R' && (char)payload[1] == '4' && (char)payload[2] == '0') //R4 off with R40
    digitalWrite(16,LOW),client.publish("emon/ESP8266/Relay4/", "0");
    
    
  Serial.println();
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client","emonpi","emonpimqtt2016")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("emon/ESP8266/Status", "1");
      // ... and resubscribe
      client.subscribe("ESP8266/Status");
      client.subscribe("ESP8266/Relay1");
      client.subscribe("ESP8266/Relay2");
      client.subscribe("ESP8266/Relay3");
      client.subscribe("ESP8266/Relay4");
    } 
    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();
}

Very basic but works and happy to take any feedback with better options.

No GUI just add your SSID details, broker IP address and user details (I use Emonpi) and off you go…

1 Like

Hi @powerman, Used this code as a basis for my own version and it has really helped. My C++ knowledge is extremely low ATM.

However, I’d like to know if the relay goes off line as I’d need node-red to reset them all. I’d like the relay to send a regular heartbeat but cannot for the life of me work out how! I just want to send it as an MQTT message at a regular interval. I suspect it is because I do not really understand the void loop() construct properly!

The alternative is for Node-Red to resend the state regularly.

Brian - I am not sure if you looking for a node-red solution or something else. If it is node-red…

Alan’s code above does send out a heartbeat via MQTT to a broker. This device sends (publishes) a status of 1 to a topic named emon/ESP8266/Status every 5 seconds.

client.publish(“emon/ESP8266/Status”, “1”);

With node-red it is easy to subscribe to that heartbeat and react to the absence of the heartbeat. Is that what you are looking for?

As @borpin has eluded, I think we need a ‘dead mans switch’ so in the absence of no heartbeat being received from node-red, the relay independently defaults to off after a certain period.
The relay is the last link in the chain, so it’s important that it retains some logic if the rest of the system fails.

Paul

@Jon, Unless I am reading the code incorrectly, that status is sent out once each time a reconnection to the broker occurs. The 5 sec is a delay between retrys. I am certainly not seeing it updated more than that.

I’m happy with connecting to it in Node-Red - it will be the fact that there is a new message rather than what the message is. Probably best for the message not to be retained as well.

My C++ is very limited, so I suspect it is the builtin loop() function I need to use - just not sure how :slight_smile: