I am trying to put together a simple ESP-01 based monitoring device and I want it to simply send a MQTT message to my MQTT broker every time a reed switch closes.
The closures are about 50-100 ms in duration and happen very widely spaced in time (minutes-hours-even days apart).
The device will be battery powered so to increase operating time I will use this scheme:
Connect the reed switch between the RST pin and GND with a pull-up of 10K.
When the switch operates the ESP-01 will be reset
On startup:
connect WiFi
connect the MQTT broker (is this needed for a posting?)
send a message using a specific topic and containing just a 1 as data
close the MQTT connection
close the WiFi connection
start deep-sleep
The code should be as simple as possible and I have tried to figure out how to deal with the MQTT part but the how-tos I found are doing too much....
What is the bare minimum needed code-wise in order to do the MQTT part outlined above?
Right now I have this after reading around a bit:
PubSubClient mqtt_client(espClient);
// MQTT connection parameters:
const char *mqtt_host = "192.168.xxx.yyy"; // broker endpoint
const char *mqtt_topic_rain = "aspo/doorpulse"; // MQTT topic
const int mqtt_port = 1883; // MQTT port (TCP)
void setup() {
StartWiFi(); //Will connect to my WiFi
mqtt_client.connect(mqtt_host , "", "") //No user/password in use
send_mqtt_message(mqtt_topic, "1"); //What to do here
// Close MQTT (how?)
// Close WiFi
ESP.deepSleep(0); //Wake up on reed closure via RST
}
void send_mqtt_message(const char *topic, char *payload)
{
bool result = mqtt_client.publish(topic, payload, false);
}
I do not have an ESP-01 device yet (delayed in the postal system) so I don't know if this will work, but I suspect that I have missed something in the MQTT part...
To connect, you need a client ID, which is arbitrary, but has to be unique. With no username or password, a blank or empty string is not "nothing enough". Use the function signature without them, or pass nullptr.
Check the bool result from calling publish. If true, that's as good as you can get. This library only supports QoS 0 when publishing, so it does not wait for an acknowledgement from the broker. At that point, you should be able to go to sleep. You could disconnect as a courtesy; shouldn't take much more time.
I am not sure I get it, do you mean that the connect call should be changed?
Right now I have this (where mqtt_topic, mqtt_broker and mqtt_port are defined constant strings):
// * Initiate MQTT client
WiFiClient espClient;
PubSubClient mqtt_client(mqtt_broker, mqtt_port, espClient);
// * Send a message to a broker topic
bool send_mqtt_message(const char *topic, char *payload)
{
bool result = mqtt_client.publish(topic, payload, false);
return (result);
}
void setup() {
// put your setup code here, to run once:
Start_WiFi();
mqtt_client.setServer(mqtt_broker, mqtt_port);
mqtt_client.connect(mqtt_broker , "", ""); //No user/password login needed
send_mqtt_message(mqtt_topic, "1"); //What to do more here?
mqtt_client.disconnect();
End_WiFi();
//Finished so go to deep sleep
ESP.deepSleep(0); //Wake up on reed closure via RST
}
When I use MQTT on a Linux prototyping system I use this type of command in my sccripts to publish a message and it "just works" towards my local broker on a Linux server: mosquitto_pub -h 192.168.xxx.yyy -t "topicstring" -m "message"
No need for a user/password login or anything like that....
When subscribing I use this in a bash script:
MQTTID="UBU-$RANDOM" #Make a unique subscription ID
mosquitto_sub -h 192.168.xxx.yyy-i "$MQTTID" -F '@Y-@m-@d @H:@M:@S ; %t ; %p' -t '#'
The MQTTID item makes the subscription unique on the server so multiple subscriptions from the same device (IP address) can be handled.
Don't need to setServer since those are passed in the constructor at top.
This is reusing the broker host name as the client ID. This is technically allowable, but not a good idea since the ID is supposed to be unique. You are already using random IDs to subscribe. The way this API works, you specify your ID when you connect, and then publish and/or subscribe. And with no user/pass, once you come up with a client ID -- which could also be random to publish -- you can try
mqtt_client.connect(mqtt_clientid);
If that doesn't work, then the username and password are actually empty strings, different than nullptr. A minor detail.
You're now returning the result, but not checking it. Not that there's much to do besides logging it somewhere else, in case things start to act up.
I'm not sure about the MQTT part but that code will not work with an ESP-01, it uses AT commands.
Also, why don't you connect the reed switch to the controller board?
Resetting the ESP does not make sense.
#include <ESP8266WiFi.h>
#include "secret.h"
#include <PubSubClient.h>
WiFiClient client;
PubSubClient mqttClient(client);
const char* server = "192.168.1.112"; //MQTT on Pi 4
char clientID[20];
char* reportTopic = "BBB";
char* requestTopic = "BBB";
void setup()
{
Serial.begin(115200);
Serial.setTimeout(2000);
while (!Serial) {}
connectWiFi();
for (int c = 0; c < 8; c++) //create random(ish) ID
{
clientID[c] = random('A', 'Z' + 1);
clientID[c + 1] = '\0';
}
Serial.printf("clientID : %s\n", clientID);
connectMqtt();
}
void loop()
{
if (!mqttClient.connected())
{
connectMqtt();
}
mqttClient.loop();
}
void connectWiFi()
{
Serial.println("Setting up WiFi connection");
WiFi.begin(mySSID, myPASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void connectMqtt()
{
mqttClient.setServer(server, 1883);
if (mqttClient.connect(clientID))
{
Serial.print("Connection has been established with ");
Serial.println(server);
mqttClient.subscribe(requestTopic);
}
else
{
Serial.println("The MQTT server connection failed...");
}
mqttClient.setCallback(callback);
}
void sendTemp()
{
float tempC = random(0, 100);
char buffer[40];
sprintf(buffer, "%s/%.2f", "room temp", tempC);
mqttClient.publish(reportTopic, buffer);
Serial.printf("publishing %s to %s\n\r", buffer, reportTopic);
}
void callback(char* requestTopic, byte* payload, unsigned int length)
{
char messageBuffer[30];
memcpy(messageBuffer, payload, length);
messageBuffer[length] = '\0';
Serial.printf("%s\n", messageBuffer);
if (strcmp(messageBuffer, "send temp") == 0)
{
sendTemp();
}
}
It connects to my local Pi running Mosquitto.
When the broker receives a message in the BBB topic (I use MQTT Explorer) the sketch receives it and tests whether it is "send temp". If it is then it publishes the temperature back to the same topic with some added text
The sketch is a cut down version of a larger one but works as it is.
Thanks to you all!
Much appreciated.
I will adjust my sketch now accordingly and when I receive the ESP-01 in the mail (hopefully on Monday) I will try to hook it up for a test. A bit hard when I am at the summer home away from my home workshop, parts store and tools.....
Who has said I don't connect the reed switch?
Of course I do, it is the state of that reed switch I want the ESP-01 to transfer via MQTT when it changes.
The problem is that I cannot connect it by wire to the end processor because of logistics of where it is and reluctance to drill holes in my house.
So I figured that a battery powered ESP-01 with deep-sleep would make it possible to run for maybe 6 months on 2 AA batteries.
The switch is connected to the ESP-01 in this scenario and the "end user" of the data will get it by subscribing to the topic on the MQTT broker.
And the AT firmware on the ESP-01 will be erased when a new sketch is uploaded, I believe.
The reset is used to start the ESP-01 when it is in deep-sleep mode since the ESP8266 pin for that is not exposed on an ESP-01 device.
Was not sure how you planned to use the ESP-01, of course you can upload new software.
However I would include some debouncing hardware on the reed switch or you may have problems with the board receiving multiple resets
I bought the ESP-01 at least 2 years ago, probably more. I obviously experimented with it because when I dug it out today and powered it up it was running the Blink sketch with asymmetrical periods
When I tried to program it today, initially I couldn't upload code to it, but I found my notes describing the magic of how to do it, uploaded the code and off it went
Yes, I am putting a 10K pull-up on that RST pin and I will also put a capacitor on it, say 10-100 nF or so to ground. The reed will immediately discharge the capacitor and since it is charged through the 10K pull-up I guess I will get a good enough debounce.
The bounce occurs when it opens and closes.
However Espressif recommends using CHIP_EN (CH_PD on the ESP-01 module) to reset the IC and not EXT_RSTB (RST)
If the activity is initiated on first contact and the reed switch isn't polled during the period when it's bouncing (ephemeral) then it doesn't matter.
But if it rattles for a while - it's resetting several times - it doesn't boot all the way till it settles, it's not up and running instantly anyway. If there's a delay(1000) in setup(), nothing goes till it goes.
@BosseB If there are problems later, make full disclosure.