How to fix arduino program to blink LED based on mqtt message - arduino

I am doing program on Arduino IDE with goal to blink LED on breadboard with NodeMCU whenever it receives ON message from MQTT topic.I have done the program but the LED is not blinking. If I do the program removing MQTT portion, things are fine. Might be I am doing something wrong in loop().
I created MQTT topic using Node-Red.When I tested publish-subscription on Node Red, the flow is working as expected. But when I am trying to read the message from arduino, I dont see LED changing it's state.
Copying relevant portion of the code-
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "NET";
const char* password = "xx";
const char* mqtt_server = "192.x.x.x";
const int lamp = 4;
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
messageTemp += (char)payload[i];
}
Serial.println();
Serial.println("messageTemp-"+messageTemp);
if (topic=="room/lamp") {
Serial.print("Changing Room lamp to ");
if (messageTemp == "on") {
digitalWrite(lamp, LOW);
Serial.print("On");
}
else if (messageTemp == "off") {
digitalWrite(lamp, HIGH);
Serial.print("Off");
}
}
Serial.println();
}
void setup() {
pinMode(lamp, OUTPUT);
Serial.begin(9600);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
I expect whenever I am pushing ON and OFF messages on the topic 'room/lamp' from nodered, the LED should get turned on and off.But it is not happening now.I am new to Arduino.Please advise.

Related

Feather Huzzah MQTT

I'm attempting to connect my Feather Huzzah to a local MQTT server but the program keeps blowing up and throwing a stack trace. When I attempt to decode the stack trace it's just empty, more frequently I only get part of the stack trace. Here's the code that I'm running, most of it is pretty similar to the pub/sub client example code for Arduino. I've tried erasing the flash on the device, that didn't seem to help.
Even stranger is that it worked once, but as soon as I tried it again adding the callback the code stopped working and blows up. If I try removing the callback nothing changes. I've tried stripping out a lot of the code just to see if I can get a consistent connection to MQTT, but that doesn't seem to be working either. The MQTT server is the latest Mosquitto from Ubuntu 18.04.
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <PubSubClient.h>
const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxxxx";
const int hallPin = 14;
const int ledPin = 0;
const char* mqtt_server = "mosquitto.localdomain";
long lastMsg = 0;
char msg[100];
int value = 0;
int hallState = 0;
WiFiClient espClient;
PubSubClient client(espClient);
WiFiUDP ntpUDP;
// By default 'time.nist.gov' is used with 60 seconds update interval and
// no offset
NTPClient timeClient(ntpUDP);
// Setup and connect to the wifi
void setup_wifi() {
delay(100);
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());
Serial.println("Gateway: ");
Serial.println(WiFi.gatewayIP());
}
//Reconnect to the MQTT broker
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("/homeassistant/devices/doorbell", "hello world");
// ... and resubscribe
client.subscribe("/homeassistant/doorbell/receiver");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
//Process messages incoming from the broker
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]);
}
}
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(hallPin, INPUT);
Serial.begin(115200);
setup_wifi();
timeClient.begin();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) {
setup_wifi();
}
if (!client.connected()) {
reconnect();
}
hallState = digitalRead(hallPin);
if (hallState == LOW) {
digitalWrite(ledPin, HIGH);
generateAndSendMessage();
delay(1000); //Add in a delay so it doesn't send messages extremely rapidly
} else {
digitalWrite(ledPin, LOW);
}
}
void generateAndSendMessage() {
timeClient.update();
StaticJsonBuffer<100> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "doorbell";
root["time"] = timeClient.getEpochTime();
root["value"] = 1;
root.printTo(msg);
Serial.println(msg);
client.publish("/homeassistant/devices/doorbell", msg);
}
Looking at the generateAndSendMessage function, I believe you are having an issue due to the size of the MQTT buffer.
The MQTT buffer is by default set to 128 bytes. This includes the length of the channel name along with the message.
The length of you channel is 32 bytes, and the json buffer you used to make the message is 100 bytes long. So you might just be exceeding the 128 byte mark.
Just declare this before including the PubSubClient.h
#define MQTT_MAX_PACKET_SIZE 200
This macro defines the buffer size of the PubSubClient to 200. You can change it to whatever you believe is required.
I hope this helps.

MQTT code stops working after a couple of hours

Made some code for a NodeMCU in the Arduino IDE to push a button using MQTT. The code works perfectly fine for some time, but after a couple of hours it will not respond anymore.
The code is very frankenstein, since I am a mega rookie, and is as follows:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Servo.h>
const char* ssid = "ap_name"; //change
const char* password = "ap_pw"; //change
const char* mqttServer = "server_ip"; //change
const int mqttPort = 1883;
const char* mqttUser = "server_name"; //change
const char* mqttPassword = "server_pw"; //change
WiFiClient espClient;
PubSubClient client(espClient);
Servo servo;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
servo.attach(D4);
servo.write(70);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the WiFi network");
client.setServer(mqttServer, mqttPort);
client.setCallback(callback);
while (!client.connected()) {
Serial.println("Connecting to MQTT...");
if (client.connect("ESP8266Client", mqttUser, mqttPassword )) {
Serial.println("connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
client.publish("esp/test", "Hello from ESP8266");
client.subscribe("esp/test");
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
if(*payload == 49){
rotServo();
Serial.println();
Serial.print("Roterar servo");
delay(3000);
client.publish("esp/test", "0");
}
Serial.println();
Serial.println("-----------------------");
}
void rotServo(){
servo.attach(D4);
servo.write(70);
delay(1000);
servo.write(175);
delay(2000);
servo.write(70);
delay(3000);
servo.detach();
}
void loop() {
client.loop();
}
Anyone that would know what might be causing it to stop working?
It could be because, you never reconnect if your client ever gets disconnected.
See the example here for more details, but here is the reconnect function from the example and how it is called in the loop. You would need to tailor it to suite your application.
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
// ... and resubscribe
client.subscribe("inTopic");
} 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();
...
}
On another note, while I don't think it would cause your specific problem, in your callback, you just compare the contents of the payload to the number 49.
if(*payload == 49){
...
}
You should check that the topic is the actual topic you are interested in and that the length is also what you expect, before you start looking at the payload.

Why does VirtualWire seem to receive transmission twice?

I have a simple setup with two Arduinos and a 433MHz transmitter and a receiver module.
The transmitter is set to transmit a string on button press, that side works correctly.
On the receiver end I have a simple program that's just writing whatever it's receiving to serial:
#include "VirtualWire.h"
int rx_pin = 2;
void setup(){
Serial.begin(9600);
Serial.println("serial ready");
vw_set_rx_pin(rx_pin);
vw_setup(2000);
vw_rx_start();
Serial.println("receiver ready");
}
void loop(){
uint8_t msg[VW_MAX_MESSAGE_LEN];
uint8_t msglen = VW_MAX_MESSAGE_LEN;
vw_wait_rx();
if(vw_get_message(msg, &msglen)){
Serial.print("Got: ");
for (int i = 0; i < msglen; i++)
{
Serial.print(char(msg[i]));
}
Serial.println();
}
}
When I then monitor serial, the receiving Arduino seems to receive the message twice each time it's sent. I used an oscilloscope to verify (to the best of my knowledge) that the transmitter is only sending the message once, I also tried wiring the two Arduinos together to make sure the issue is not with the RF modules, I got the same results.
This makes me think there is an issue with my code or with VirtualWire itself.
I'm thinking that I should somehow check if I've received the same message already or I should clear VirtualWire's buffer, how would I do either of those?
EDIT:
Here is the transmitter code:
#include "VirtualWire.h"
int tx_pin =2;
int interruptPin = 3;
volatile bool transmitBool = false;
void setup(){
vw_set_tx_pin(tx_pin);
vw_setup(2000);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), transmit, LOW);
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
transmitBool = false;
}
void loop(){
if(transmitBool) {
transmitBool = false;
digitalWrite(13, HIGH);
vw_send((uint8_t *)"abc", 4);
vw_wait_tx();
delay(500);
digitalWrite(13, LOW);
}
}
void transmit() {
transmitBool = true;
}

Wemos D1 reset when setting pins mode

I'm building a little car, remote controlled by a Wemos D1 board, in order to set the WiFi connection and the control logic I'm running this script:
#include <ESP8266WiFi.h>
const char* pass = "**********";
const char* ssid = "**********";
IPAddress ip(192,168,1,91);
IPAddress gat(192,168,1,1);
IPAddress dns(192,168,1,1);
IPAddress sub(255,255,255,0);
WiFiServer s(2000);
int inA1 = 1;
int inA2 = 2;
int enA = 3;
int inB1 = 4;
int inB2 = 5;
int enB = 6;
int trigger = 7;
int echo = 8;
double vSuono = 343; //Unità di misura: m/s
int speed = 255;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
WiFi.config(ip,gat,sub,dns);
WiFi.begin(ssid,pass);
delay(500);
while(WiFi.status() != WL_CONNECTED){
delay(500);
Serial.println(".");
}
Serial.println("Connected!");
delay(30);
s.begin();
Serial.println("Server running!");
delay(30);
//Here starts the problems
pinMode(inA1,OUTPUT);
pinMode(inA2,OUTPUT);
pinMode(enA,OUTPUT);
pinMode(inB1,OUTPUT);
pinMode(inB2,OUTPUT);
pinMode(enB,OUTPUT);
pinMode(trigger,OUTPUT);
pinMode(echo,INPUT);
delay(500);
}
void loop() {
// put your main code here, to run repeatedly:
WiFiClient c = s.available();
delay(30);
if(c){
Serial.println("New client connected!");
delay(3);
while(c.connected()){
if(c.available()){
String command = c.readStringUntil('\n');
if(command == "forward"){
Serial.println("forward");
forward(speed);
}else if(command == "right"){
Serial.println("right");
right(speed);
}else if(command == "left"){
Serial.println("left");
left(speed);
}else{
Serial.println("back");
back(speed);
}
}
delay(30);
}
c.stop();
}
}
void forward(int velocita){
digitalWrite(inA1,HIGH);
digitalWrite(inA2,LOW);
digitalWrite(inB1,HIGH);
digitalWrite(inB2,LOW);
analogWrite(enA,velocita);
analogWrite(enB,velocita);
}
void left(int velocita){
digitalWrite(inA1,HIGH);
digitalWrite(inA2,LOW);
digitalWrite(inB1,LOW);
digitalWrite(inB2,HIGH);
analogWrite(enA,velocita);
analogWrite(enB,velocita);
}
void right(int velocita){
digitalWrite(inA1,LOW);
digitalWrite(inA2,HIGH);
digitalWrite(inB1,HIGH);
digitalWrite(inB2,LOW);
analogWrite(enA,velocita);
analogWrite(enB,velocita);
}
void back(int velocita){
digitalWrite(inA1,LOW);
digitalWrite(inA2,HIGH);
digitalWrite(inB1,LOW);
digitalWrite(inB2,HIGH);
analogWrite(enA,velocita);
analogWrite(enB,velocita);
}
void stop(){
digitalWrite(inA1,LOW);
digitalWrite(inA2,LOW);
digitalWrite(inB1,LOW);
digitalWrite(inB2,LOW);
}
The problem is that when the board execute the pinMode function in the setup() block, the board stop the execution, crash and restart, and I'm not able to ping the board.
If I comment all the portion of the setup() block, with the pinMode calls, the program starts to work but obviously I can't use the pins.
On the serial monitor when the board crash appears this messages:
ets Jan 8 2013,rst cause:4, boot mode:(3,6)
wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v09f0c112
~ld
What could be the problem?
I don't know the pin mapping by heart, but you should stick to the GPIO pins named D1, D2...D8. You've named them 1, 2...8 which are different pins. You likely used a pin which is used by something else (like serial or reset).
int inA1 = D1;
int inA2 = D2;
int enA = D3;
int inB1 = D4;
int inB2 = D5;
int enB = D6;
int trigger = D7;
int echo = D8;
I was getting the same wdt reset error while trying to use pinMode with digitalWrite() function.
I solved it by figuring out how the Wemos Pin mapping works.
Actually, you need to refer the pin in 'Dx' notation.
e.g
digitalWrite(D15,LOW);
or
pinMode(D15, OUTPUT);
Also, make sure to select "Wemos D1 R1" in Tools > Boards so that Dx constants will match
the labels.
Have a look at the conversation here on Arduino FOrum to understand more about wemos pin mapping:
https://forum.arduino.cc/index.php?topic=545113.0

Broker messages that recurs with nodeMCU

I’m having some problem with a home automation project of mine. I bought a nodeMCU v3 from aliexpress that i want to control my blinds with.
This is the code I’m using on it. I use the Arduino IDE to push this code in to the nodeMCU.
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <SimpleTimer.h>
// MQTT Server
const char* ssid = "****";
const char* password = "****";
const char* mqtt_server = "****";
char message_buff[100];
int photoValue = 0;
int rainValue = 0;
int photo = A0;
int rain = D6;
int relayUp = D7;
int relayDown= D8;
long interval = 10000;
long previousMillis = 0;
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void setup() {
pinMode(photo, INPUT);
pinMode(rain, INPUT);
pinMode(relayUp, OUTPUT);
pinMode(relayDown, OUTPUT);
digitalWrite(relayUp ,LOW);
digitalWrite(relayDown, LOW);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
if (client.connect("ESP8266Client")) {
client.subscribe("home/relayBlinds");
} else {
delay(5000);
}
}
}
void loop() {
if (!client.connected()) {
// Connect (or reconnect) to mqtt broker on the openhab server
reconnect();
}
// Read Photo- and Rain-sensors
photoValue = analogRead(photo);
rainValue = analogRead(rain);
// publish Temperature reading every 10 seconds
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
// publish Photo
String pubStringPhoto = String(photoValue);
pubStringPhoto.toCharArray(message_buff, pubStringPhoto.length()+1);
client.publish("home/photo", message_buff);
// publish Rain
String pubStringRain = String(rainValue);
pubStringRain.toCharArray(message_buff, pubStringRain.length()+1);
client.publish("home/rain", message_buff);
}
client.loop();
}
void callback(char* topic, byte* payload, unsigned int length) {
// MQTT inbound Messaging
int i = 0;
// create character buffer with ending null terminator (string)
for(i=0; i<length; i++) {
message_buff[i] = payload[i];
}
message_buff[i] = '\0';
String msgString = String(message_buff);
if (msgString == "BLINDSUP") {
digitalWrite(relayUp ,HIGH);
delay(5000);
digitalWrite(relayUp ,LOW);
} else if (msgString == "BLINDSDOWN") {
digitalWrite(relayDown ,HIGH);
delay(5000);
digitalWrite(relayDown ,LOW);
}
}
The plan was to have a Raspberry Pi with openHAB as a controller. I have used several guides to setup mosquitto and openHAB and i always get the same result.
So this is what happens: the nodeMCU connects to my Wifi and publishes both the rain and photo values. I can read them in the openHAB GUI without problems.
When i press the activation button in openHAB to publish BLINDSUP or BLINDSDOWN the messages arrives without any problems and i can see the message on my mosquitto terminal. Now is when the unexpected result starts happening. The same message gets delivered multiple times to my nodeMCU without it showing up in the mosquitto terminal.
I have been trying to find out why it would act this way and I think it is because the line:
if (!client.connected()) {
is false and the nodeMCU reconnects and gets the same message somehow. But it is always the first message. If I send BLINDSUP and then BLINDSDOWN it will only register BLINDSUP forever.
I'm really out of ideas how to fix this and would appreciate any help, thanks.
URL to the nodeMCU if that helps anyhow: nodeMCU
Try connecting to MQTT broker with a clean session. Probably you published the topic with the retain flag set to true.
If you do like this, the broker will deliver the last retained message when the nodeMCU connects to the broker and subscribes to the retained topic.

Resources