New code added
In a previous post I discussed the use of an old ENC28J60 ethernetshield for an MQTT node. The biggest setback of the ENC28J60 shield is that it uses a lot of memory. When using the newer W5100 Ethernetshield, there is a bit more room to play with. So here is a simple framework for an MQTT node that doesnt’t only publish, but also reacts to simple commands that come in with a subscription.
/* Arduino UNO with W5100 Ethernetshield or W5100 Ethernet module, used as MQTT client It will connect over Wifi to the MQTT broker and controls a digital output (LED, relay) and gives the Temperature and Humidity, as well as the state of some switches The topics have the format "home/br/sb" for southbound messages and "home/nb" for northbound messages Southbound are messages going to the client, northbound are messages coming from the client As the available memory of a UNO with Ethernetcard is limited, I have kept the topics short Also, the payloads are kept short The Northbound topics are home/br/nb/temp for temperature home/br/nb/humid for humidity home/br/nb/deur for a door switch home/br/nb/l for the lightintensity home/br/nb/pr for the status of a PIR sensor home/br/nb/ip showing the IP number of the client home/br/nb/relay showing the relaystate There is only one southbound topic: home/br/sb The payload here determines the action: 0 -Switch the relay off 1-Switch the relay on 2-Publish the IP number of the client 3 Ask for the relaystate REMOVED On Startup, the Client publishes the IP number */ #include "Ethernet.h" #include "PubSubClient.h" #include "DHT.h" //kennelijk geeft update van DHT sensor library boven 1.2.1 een fout #define CLIENT_ID "Hal" //#define TOPIC "temp" #define PUBLISH_DELAY 3000 #define PUB_TOPIC "my_username/f/temperature" //Adafruit dashboard #define PUB_TOPIC_h "my_username/f/humidity" //Adafruit dashboard #define DHTPIN 3 #define DHTTYPE DHT11 #define ledPin 13 #define relayPin 8 String ip = ""; bool statusKD = HIGH; bool statusBD = HIGH; bool statusGD = HIGH; bool relaystate = LOW; bool pir = LOW; bool startsend = HIGH; int lichtstatus; uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x06}; EthernetClient ethClient; PubSubClient mqttClient; DHT dht(DHTPIN, DHTTYPE); long previousMillis; void setup() { pinMode(4, INPUT_PULLUP); pinMode(5, INPUT_PULLUP); pinMode(6, INPUT_PULLUP); pinMode(7, INPUT); pinMode(LED_BUILTIN, OUTPUT); pinMode(relayPin, OUTPUT); // setup serial communication Serial.begin(9600); while (!Serial) {}; Serial.println(F("MQTT Arduino Demo")); Serial.println(); // setup ethernet communication using DHCP if (Ethernet.begin(mac) == 0) { //Serial.println(F("Unable to configure Ethernet using DHCP")); for (;;); } Serial.println(F("Ethernet configured via DHCP")); Serial.print("IP address: "); Serial.println(Ethernet.localIP()); Serial.println(); /* Serial.println(Ethernet.localIP()[0]); Serial.println(Ethernet.localIP()[1]); Serial.println(Ethernet.localIP()[2]); Serial.println(Ethernet.localIP()[3]); */ ip = String (Ethernet.localIP()[0]); ip = ip + "."; ip = ip + String (Ethernet.localIP()[1]); ip = ip + "."; ip = ip + String (Ethernet.localIP()[2]); ip = ip + "."; ip = ip + String (Ethernet.localIP()[3]); //Serial.println(ip); // setup mqtt client mqttClient.setClient(ethClient); //mqttClient.setServer(mqttServer, 1883); // mqttClient.setServer("test.mosquitto.org", 1883); // mqttClient.setServer( "raspberrypi.local",1883); //mqttClient.setServer("io.adafruit.com",1883); mqttClient.setServer( "192.168.1.102", 1883); //Serial.println(F("MQTT client configured")); mqttClient.setCallback(callback); // setup DHT sensor dht.begin(); Serial.println(F("DHT sensor initialized")); Serial.println(); Serial.println(F("Ready to send data")); previousMillis = millis(); mqttClient.publish("home/br/nb/ip", ip.c_str()); } void loop() { statusBD = digitalRead(4);// FrontdoorSwitch statusGD = digitalRead(5);// Garagedoor Switch statusKD = (digitalRead(6));//LivingRoom Switch lichtstatus = analogRead(A0);//Reads an LDR pir = digitalRead(7);//Reads a PIR sensor relaystate = digitalRead(relayPin);// Reads the state of a relay // it's time to send new data? if (millis() - previousMillis > PUBLISH_DELAY) { sendData(); previousMillis = millis(); } mqttClient.loop(); } void sendData() { char msgBuffer[20]; float h = dht.readHumidity(); float t = dht.readTemperature(); Serial.print("Temperature: "); Serial.print(t); Serial.println("oC"); Serial.print("Humidity: "); Serial.print(h); Serial.println("%"); Serial.print("Relay is: "); Serial.println((relaystate == LOW) ? "OPEN" : "CLOSED"); if (mqttClient.connect(CLIENT_ID)) { mqttClient.publish("home/br/nb/temp", dtostrf(t, 6, 2, msgBuffer)); mqttClient.publish("home/br/nb/humid", dtostrf(h, 6, 2, msgBuffer)); mqttClient.publish("home/br/nb/deur", (statusBD == HIGH) ? "OPEN" : "CLOSED"); mqttClient.publish("home/br/nb/garage", (statusGD == HIGH) ? "OPEN" : "DICHT"); mqttClient.publish("home/br/nb/bel", (statusKD == HIGH) ? "OPEN" : "CLOSED"); mqttClient.publish("home/br/nb/l", dtostrf(lichtstatus, 4, 0, msgBuffer)); mqttClient.publish("home/br/nb/p", (pir == HIGH) ? "OPEN" : "CLOSED"); mqttClient.publish("home/br/nb/relay", (relaystate == LOW) ? "OPEN" : "CLOSED"); mqttClient.subscribe("home/br/sb"); if (startsend) { // mqttClient.publish("home/br/nb/relay", (relaystate == LOW) ? "OPEN" : "CLOSED"); mqttClient.publish("home/br/nb/ip", ip.c_str()); startsend = LOW; } } } void callback(char* topic, byte* payload, unsigned int length) { char msgBuffer[20]; // I am only using one ascii character as command, so do not need to take an entire word as payload // However, if you want to send full word commands, uncomment the next line and use for string comparison //payload[length] = '\0'; // terminate string with '0' //String strPayload = String((char*)payload); // convert to string // Serial.println(strPayload); //can use this if using longer southbound topics Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] ");//MQTT_BROKER for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); Serial.println(payload[0]); // Examine only the first character of the message if (payload[0] == 49) // Message "1" in ASCII (turn output ON) { digitalWrite(LED_BUILTIN, HIGH); // digitalWrite(relayPin, HIGH); } else if (payload[0] == 48) // Message "0" in ASCII (turn output OFF) { digitalWrite(relayPin, LOW); // digitalWrite(LED_BUILTIN, LOW); } else if (payload[0] == 50) { mqttClient.publish("home/br/nb/ip", ip.c_str());// publish IP nr } else { Serial.println("Unknown value"); mqttClient.publish("home/br/nb", "Syntax Error"); } }
You will find the full code for download here.
Edit
I altered the above code a bit so it takes ON/OFF/READ commands rather than just numbers.
It now looks like this:
/* Arduino UNO with W5100 Ethernetshield or W5100 Ethernet module, used as MQTT client It will connect over Wifi to the MQTT broker and controls a digital output (LED, relay) and gives the Temperature and Humidity, as well as the state of some switches The topics have the format " home="" br="" sb"="" for="" southbound="" messages="" and="" "home="" nb"="" northbound="" are="" going="" tomq="" the="" client,="" coming="" from="" client="" as="" available="" memory="" of="" a="" uno="" with="" ethernetcard="" is="" limited,="" i="" have="" kept="" topics="" short="" also,="" payloads="" nb="" temp="" temperature="" humid="" humidity="" deur="" door="" switch="" l="" lightintensity="" pr="" status="" pir="" sensor="" ip="" showing="" number="" relay="" relaystate="" there="" only="" one="" topic:="" sb="" payload="" here="" determines="" action:="" off="" -switch="" on-switch="" on="" read="" ask="" *="" #include="" "ethernet.h"="" "pubsubclient.h"="" "dht.h"="" #define="" client_id="" "hal"="" publish_delay="" 30000="" dhtpin="" 3="" dhttype="" dht11="" ledpin="" 13="" relaypin="" 8="" string="" ;="" bool="" statuskd="HIGH;" statusbd="HIGH;" statusgd="HIGH;" startsend="HIGH;" int="" lichtstatus;="" uint8_t="" mac[6]="{0x00," 0x01,="" 0x02,="" 0x03,="" 0x04,="" 0x06};="" ethernetclient="" ethclient;="" pubsubclient="" mqttclient;="" dht="" dht(dhtpin,="" dhttype);="" long="" previousmillis;="" void="" setup()="" {="" pinmode(4,="" input_pullup);="" pinmode(5,="" pinmode(6,="" pinmode(7,="" input);="" pinmode(led_builtin,="" output);="" pinmode(relaypin,="" digitalwrite(relaypin,="" low);="" digitalwrite(led_builtin,high);="" setup="" serial="" communication="" serial.begin(9600);="" while="" (!serial)="" {};="" serial.println(f("mqtt="" arduino="" demo"));="" serial.println();="" ethernet="" using="" dhcp="" if="" (ethernet.begin(mac)="=" 0)="" serial.println(f("unable="" to="" configure="" dhcp"));="" (;;);="" }="" serial.println(f("ethernet="" configured="" via="" serial.print("ip="" address:="" ");="" serial.println(ethernet.localip());="" (ethernet.localip()[0]);="" +="" ".";="" (ethernet.localip()[1]);="" (ethernet.localip()[2]);="" (ethernet.localip()[3]);="" serial.println(ip);="" mqtt="" mqttclient.setclient(ethclient);="" mqttclient.setserver(="" "192.168.1.103",="" 1883);="" configured"));="" mqttclient.setcallback(callback);="" dht.begin();="" serial.println(f("dht="" initialized"));="" serial.println(f("ready="" send="" data"));="" previousmillis="millis();" mqttclient.publish("home="" ip",="" ip.c_str());="" loop()="" frontdoorswitch="" garagedoor="" lichtstatus="analogRead(A0);//Reads" an="" ldr="" reads="" state="" it's="" time="" new="" data?="" (millis()="" -="" >="" publish_delay)="" senddata();="" mqttclient.loop();="" senddata()="" char="" msgbuffer[20];="" float="" h="dht.readHumidity();" t="dht.readTemperature();" serial.print("temperature:="" serial.print(t);="" serial.println("oc");="" serial.print("humidity:="" serial.print(h);="" serial.println("%");="" serial.print("relay="" is:="" serial.println((relaystate="=" low)="" ?="" "open"="" :="" "closed");="" (mqttclient.connect(client_id))="" temp",="" dtostrf(t,="" 6,="" 2,="" msgbuffer));="" humid",="" dtostrf(h,="" deur",="" (statusbd="=" high)="" garage",="" (statusgd="=" "dicht");="" bel",="" (statuskd="=" l",="" dtostrf(lichtstatus,="" 4,="" 0,="" p",="" (pir="=" relay",="" (relaystate="=" mqttclient.subscribe("home="" relay");="" (startsend)="" callback(char*="" topic,="" byte*="" payload,="" unsigned="" length)="" serial.print("message="" arrived="" [");="" serial.print(topic);="" serial.print("]="" mqtt_broker="" (int="" <="" length;="" i++)="" serial.print((char)payload[i]);="" serial.println(payload[0]);="" (strncmp((const="" char*)payload,="" "on",="" 2)="=" digitalwrite(ledpin,="" high);="" "off",="" 3)="=" "read",="" 4)="="
Edit
I altered the above code a bit so it takes ON/OFF/READ commands rather than just numbers.
It now looks like this:
/* Arduino UNO with W5100 Ethernetshield or W5100 Ethernet module, used as MQTT client It will connect over Wifi to the MQTT broker and controls a digital output (LED, relay) and gives the Temperature and Humidity, as well as the state of some switches The topics have the format " home="" br="" sb"="" for="" southbound="" messages="" and="" "home="" nb"="" northbound="" are="" going="" tomq="" the="" client,="" coming="" from="" client="" as="" available="" memory="" of="" a="" uno="" with="" ethernetcard="" is="" limited,="" i="" have="" kept="" topics="" short="" also,="" payloads="" nb="" temp="" temperature="" humid="" humidity="" deur="" door="" switch="" l="" lightintensity="" pr="" status="" pir="" sensor="" ip="" showing="" number="" relay="" relaystate="" there="" only="" one="" topic:="" sb="" payload="" here="" determines="" action:="" off="" -switch="" on-switch="" on="" read="" ask="" *="" #include="" "ethernet.h"="" "pubsubclient.h"="" "dht.h"="" #define="" client_id="" "hal"="" publish_delay="" 30000="" dhtpin="" 3="" dhttype="" dht11="" ledpin="" 13="" relaypin="" 8="" string="" ;="" bool="" statuskd="HIGH;" statusbd="HIGH;" statusgd="HIGH;" startsend="HIGH;" int="" lichtstatus;="" uint8_t="" mac[6]="{0x00," 0x01,="" 0x02,="" 0x03,="" 0x04,="" 0x06};="" ethernetclient="" ethclient;="" pubsubclient="" mqttclient;="" dht="" dht(dhtpin,="" dhttype);="" long="" previousmillis;="" void="" setup()="" {="" pinmode(4,="" input_pullup);="" pinmode(5,="" pinmode(6,="" pinmode(7,="" input);="" pinmode(led_builtin,="" output);="" pinmode(relaypin,="" digitalwrite(relaypin,="" low);="" digitalwrite(led_builtin,high);="" setup="" serial="" communication="" serial.begin(9600);="" while="" (!serial)="" {};="" serial.println(f("mqtt="" arduino="" demo"));="" serial.println();="" ethernet="" using="" dhcp="" if="" (ethernet.begin(mac)="=" 0)="" serial.println(f("unable="" to="" configure="" dhcp"));="" (;;);="" }="" serial.println(f("ethernet="" configured="" via="" serial.print("ip="" address:="" ");="" serial.println(ethernet.localip());="" (ethernet.localip()[0]);="" +="" ".";="" (ethernet.localip()[1]);="" (ethernet.localip()[2]);="" (ethernet.localip()[3]);="" serial.println(ip);="" mqtt="" mqttclient.setclient(ethclient);="" mqttclient.setserver(="" "192.168.1.103",="" 1883);="" configured"));="" mqttclient.setcallback(callback);="" dht.begin();="" serial.println(f("dht="" initialized"));="" serial.println(f("ready="" send="" data"));="" previousmillis="millis();" mqttclient.publish("home="" ip",="" ip.c_str());="" loop()="" frontdoorswitch="" garagedoor="" lichtstatus="analogRead(A0);//Reads" an="" ldr="" reads="" state="" it's="" time="" new="" data?="" (millis()="" -="" >="" publish_delay)="" senddata();="" mqttclient.loop();="" senddata()="" char="" msgbuffer[20];="" float="" h="dht.readHumidity();" t="dht.readTemperature();" serial.print("temperature:="" serial.print(t);="" serial.println("oc");="" serial.print("humidity:="" serial.print(h);="" serial.println("%");="" serial.print("relay="" is:="" serial.println((relaystate="=" low)="" ?="" "open"="" :="" "closed");="" (mqttclient.connect(client_id))="" temp",="" dtostrf(t,="" 6,="" 2,="" msgbuffer));="" humid",="" dtostrf(h,="" deur",="" (statusbd="=" high)="" garage",="" (statusgd="=" "dicht");="" bel",="" (statuskd="=" l",="" dtostrf(lichtstatus,="" 4,="" 0,="" p",="" (pir="=" relay",="" (relaystate="=" mqttclient.subscribe("home="" relay");="" (startsend)="" callback(char*="" topic,="" byte*="" payload,="" unsigned="" length)="" serial.print("message="" arrived="" [");="" serial.print(topic);="" serial.print("]="" mqtt_broker="" (int="" <="" length;="" i++)="" serial.print((char)payload[i]);="" serial.println(payload[0]);="" (strncmp((const="" char*)payload,="" "on",="" 2)="=" digitalwrite(ledpin,="" high);="" "off",="" 3)="=" "read",="" 4)="=" It can be found here. Apparently the 1st code simple I had published sometimes didn't keep the relay state. New code does not have that problem. The code has a number of print statements. Once it is hooked up to the network it might not be very useful to have those anymore. Commenting them out will make more space available
Nice! If I can make one suggestion it would be to use the SimpleTimer library to handle the transmissions. That way, your code becomes more readable and more symmetrical for sending and receiving, but more importantly, you can add more time-triggered routines very transparently, avoiding the spaghetti monster.
Thanks Jeroen, I will look into that. Didnt know that library
Hi. I used your sketch and its working very well. I only have one issue, the relay doesnt stay on for some reason. When I trigger the relay, it opens for a couple of seconds, and then resets to off. Any ideas what i might be doing wrong?
What program do you use to send the MQTT command? Do you have more than 1 device sending the same MQTT command. Try setting the ‘retain’ value in your broker or sender. This is what it looks like in MQTTDash
i have successfully set up and used this sketch to run an 8 channel relay (well i am and can only use 6 relays with 1 DHT11 attached due to pin availability), and i am literally just starting to learn arduino (if i can figure this out it, it must be super simple and easy to learn). I have been able to add the relay state to all 6 relays, but i am more than a little confused with how to implement the sub topics with multiple relays and the call back function. I noticed in another post you had you referred to variables and i know that is the way to go i just cannot figure out how it actually goes in the code. any help with this would be greatly appreciated
I think I just addressed your question on instructables and referred you to this post.
If my explanation on instructables and the example in the link are still not clear, just ask again