How to send simple MQTT message using an ESP-01?

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...

For PubSubClient, before you connect, it needs the host, port, and client

PubSubClient mqtt_client(mqtt_host, mqtt_port, espClient);

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.

Thanks a lot!

I do have this in my code...

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.

Here is a sketch that uses MQTT on an ESP-01

#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.
:grin: :cowboy_hat_face:
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.....

Don't all ESP-01s come with the AT software pe-installed?

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 don't know

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

They may ... until you load an Arduino sketch into it. That overwrites the AT code.

Thank you.

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.

How do you poll the reset pin on an ESP8266.
Do you have code?

We're not using GPIO16. . . not good.
Maybe you can RC that for him.

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.

Why do you suggest a solution when you have no idea if it will work or not.