Hi all, I am using a Wemos D1 mini that is connected to an external LiPo battery. I have it hooked up to a transistor (BC548) and my intention here is that I pull the transistor's pin HIGH and tun on an LED strip that is also connected to the same battery.
The reason I do that instead of controlling the LED strip directly from the Wemos is that I want the ability to put the Wemos to sleep and still leave the LED strip on. Or at least this is what I expect .
The behaviour I am seeing is that this all works if I don't sleep the Wemos. I can control things using PubSub but as soon as I put it to sleep, it seems the Wemos will only consume the last message it was initialised with and never take any other messages into consideration. I think I am messing up on the sleep here.
The reason I use Sleep is I want to preserve battery because I will have the LED strip turned on for about 15-30 minutes at a time, so sleeping would be ideal while the LED strip is on. The Wemos will just wake up and check if I have not sent another command for the time being.
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "arduino_secrets.h"
const char* ssid = SECRET_SSID;
const char* password = SECRET_PASS;
const char* mqtt_server = "192.168.1.32";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
// sleep for this many seconds
const int sleepSeconds = 10;
void setup() {
 // Set the output for the transistor
 pinMode(D7, OUTPUT);
Â
 // Connect D0 to RST to wake up
 pinMode(D0, WAKEUP_PULLUP);
Â
 Serial.begin(9600);
 setup_wifi();
 client.setServer(mqtt_server, 1883);
 client.setCallback(callback);
 if (!client.connected()) {
  reconnect();
 }
 client.loop();
Â
 // Sleep after turning the LED strip on or off
 Serial.println("going to sleep");
 ESP.deepSleep(sleepSeconds * 1000000);
}
void setup_wifi() {
 delay(2);
 // We start by connecting to a WiFi network
 Serial.println();
 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]);
 }
 Serial.println();
 // Switch on the LED Strip if an 1 was received as first character
 int val;
 if ((char)payload[0] == '1') {
  digitalWrite(D7, HIGH);
 } else {
  digitalWrite(D7, LOW);
 }
}
void reconnect() {
 // Loop until we're reconnected
 while (!client.connected()) {
  Serial.print("Attempting MQTT connection...");
  // Attempt to connect
  byte willQoS = 1;
  const char* willTopic = "switch/sign/state";
  const char* willMessage = "disconnected";
  boolean willRetain = 0;
  boolean cleanSession = 0;
  if (client.connect("onAirClient", "", "", willTopic, willQoS, willRetain, willMessage, cleanSession)) {
   Serial.println("connected");
   // Once connected, publish an announcement...
   client.publish("switch/sign/state", "connected");
   // ... and resubscribe
   client.subscribe("switch/sign/switch", 1);
  } 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();
}
Many thanks in advance and please let me know if I can clarify anything else.
Unless there's some way to wake your Wemos on network activity, I can't see how you can use a pubSub mechanism and sleep effectively together.
I'd also be concerned that I'd drop some of the message while the Wemos was waking up, but obviously that's only a problem to check if you actually can wake it this way.
I suppose you could set the retain flag on your messages and wake frequently and reconnect as a subscriber and you would then get the latest message. There would still be a risk that you missed messages though.
You don't say which LED strip or what your battery capacity or how long between charges, but the Wemos will draw much less current than the LEDs, so is sleep even necessary?
wildbill:
Unless there's some way to wake your Wemos on network activity, I can't see how you can use a pubSub mechanism and sleep effectively together.
I'd also be concerned that I'd drop some of the message while the Wemos was waking up, but obviously that's only a problem to check if you actually can wake it this way.
I suppose you could set the retain flag on your messages and wake frequently and reconnect as a subscriber and you would then get the latest message. There would still be a risk that you missed messages though.
I don't mind not having it wake up when a new message is received. I want it to wake up (say after a few minutes), check if there is a new message and act upon. I'm OK with the delay.
mplacona:
I don't mind not having it wake up when a new message is received. I want it to wake up (say after a few minutes), check if there is a new message and act upon. I'm OK with the delay.
I think it would work for you then. For switching on an LED strip, I expect that all you care about is the last command and retain will give you that. It's of little importance if you missed a message to turn the strip on if you've overridden that with 'turn it off'.
Thanks, but I have it working from the beginning. My issue as I described but perhaps failed to clarify is:
The behaviour I am seeing is that this all works if I don't sleep the Wemos. I can control things using PubSub but as soon as I put it to sleep, it seems the Wemos will only consume the last message it was initialised with and never take any other messages into consideration. I think I am messing up on the sleep here.
What I am trying to say here is that it consumes the message over and over again. The same message regardless of any new message that I send.
Also, the fact that I don't think my sleep is in the right place because the LED strip flashes every time the Wemos wakes up.
So when it turns on it should turn on the LED strip, and it does. I then see the following:
.......
WiFi connected
IP address:
192.168.1.36
Attempting MQTT connection...connected
going to sleep
⸮dGI⸮K⸮JY⸮⸮hBk⸮
LukeWifiWalker-2G
..........
WiFi connected
IP address:
192.168.1.36
Attempting MQTT connection...connected
going to sleep
⸮Hl⸮G⸮⸮L⸮X⸮⸮⸮
LukeWifiWalker-2G
.........
WiFi connected
IP address:
192.168.1.36
Attempting MQTT connection...connected
going to sleep
⸮H⸮G⸮⸮lE⸮i⸮h⸮
LukeWifiWalker-2G
..........
WiFi connected
IP address:
192.168.1.36
Attempting MQTT connection...connected
going to sleep
⸮$OX⸮,⸮⸮X⸮⸮CX⸮⸮
LukeWifiWalker-2G
..........
WiFi connected
IP address:
192.168.1.36
Attempting MQTT connection...connected
going to sleep
As you can see it never seems to fall into the callback bit upon restart though, and even if I then send it another MQTT command it gets ignored or not acted upon because I don't see the LED strip update its state.
Tried that and checked that the retain worked by running a subscriber locally nd checking I always get the correct message. It still seems to never go through the callback upon waking up.
I'm no MQTT expert, but I'll guess that you're going back to sleep before the MQTT server does anything. You're sleeping for ten seconds, so the keep alive won't have timed you out so the server is probably still trying to send you a retry message periodically. So it may be that you woke, reconnected, it's waiting before sending again and by the time it does you're sleeping again. Can you tell how long you're awake?
The bit I'm unsure about is if you actually need to subscribe again when you wake. On the ESP end, clearly you do so you can get the callback set up, but I'm not sure if that gets you a brand new session on the MQTT end or if it reconnects you to the one you had.
As you drop into sleep/reset very quickly after connecting to MQTT and only perform a single client.loop() then maybe a potential message is not being acted on correctly. QOS 1 message reception expects the client to reply to the broker that it has received the message okay. If your sleeping before the reply is sent (client.loop does this) then the broker may keep trying the same message.
A table in this write-up implies that using QOS 0 and retain should keep the message on the broker until picked up by the client and because it's QOS 0 then maybe it will not care about a reply.
Another option is to allow client.loop to run for a couple of seconds before sleeping.
EDIT:
wildbill beat me to it but I was not prepared to scrap my message after investing the time in the reply.
wildbill:
I'm no MQTT expert, but I'll guess that you're going back to sleep before the MQTT server does anything. You're sleeping for ten seconds, so the keep alive won't have timed you out so the server is probably still trying to send you a retry message periodically. So it may be that you woke, reconnected, it's waiting before sending again and by the time it does you're sleeping again. Can you tell how long you're awake?
The bit I'm unsure about is if you actually need to subscribe again when you wake. On the ESP end, clearly you do so you can get the callback set up, but I'm not sure if that gets you a brand new session on the MQTT end or if it reconnects you to the one you had.
Riva:
As you drop into sleep/reset very quickly after connecting to MQTT and only perform a single client.loop() then maybe a potential message is not being acted on correctly. QOS 1 message reception expects the client to reply to the broker that it has received the message okay. If your sleeping before the reply is sent (client.loop does this) then the broker may keep trying the same message.
A table in this write-up implies that using QOS 0 and retain should keep the message on the broker until picked up by the client and because it's QOS 0 then maybe it will not care about a reply.
Another option is to allow client.loop to run for a couple of seconds before sleeping.
EDIT:
wildbill beat me to it but I was not prepared to scrap my message after investing the time in the reply.
Thank you you two! To clarify, when you say allow client.loop to run for a few seconds, do you mean something like this?
void setup() {
/*
// Set the output for the transistor
pinMode(D7, OUTPUT);
*/
// Connect D0 to RST to wake up
pinMode(D0, WAKEUP_PULLUP);
Serial.begin(9600);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
if (!client.connected()) {
reconnect();
}
client.loop();
delay(10000);
// Sleep after turning the LED strip on or off
Serial.println("going to sleep");
ESP.deepSleep(sleepSeconds * 1000000);
}
Adding the delay hasn't fixed it, but I did start seeing an intermittent error on my serial log. Not every time, but some times
WiFi connected
IP address:
192.168.1.36
Attempting MQTT connection...connected
going to sleep
Attempting MQTT connection...failed, rc=-2 try again in 5 seconds
8 ⸮⸮I⸮h⸮D⸮@x:A⸮⸮
Let your actual loop function get some action, as you have it now, it will never be called. Put the sleep in there, but use millis to stay awake for a while.
You might consider adding something that sleeps immediately once the callback gets and deals with a message from the server.
Hey, so I modified the code to look like this because I am not sure how to force the loop function to be used.
// wait a few seconds
 unsigned long starttime = millis();
 unsigned long endtime = starttime;
 int loopcount = 0;
 while ((endtime - starttime) <=10000) // do this loop for up to 1000mS
 {
 Â
  if (!client.connected()) {
   reconnect();
  }
 Â
  client.loop();
  loopcount = loopcount+1;
  endtime = millis();
 }
Â
 // Sleep after turning the LED strip on or off
 Serial.println("going to sleep");
 ESP.deepSleep(sleepSeconds * 1000000);
And that waits for 10 seconds (I haven't tweaked the time yet) and reads the correct message regardless of whether I am using a retained message or not, though retained will be best in this case.
However, it seems the Wemos (unlike Arduino apparently) does not keep the state of the pin upon sleep as you can see here. So basically as soon as it sleeps, Pin 7 goes low (or floats) and my transistor is deactivated
It seems like a latching relay may solve this but I really wanted to keep that state some other way. Seems like I could get one of these though I have never used them before.
Would appreciate any tips here, but also thank you so much for all the support!