[SOLVED] ESP8266 publishes four topics but not 5

Admittedly, I’m not a true programmer. I have my 8266 arduino programmed to publish over MQTT the state of two switches and the indoor temperature and humidity. I also have the data for outside temperature and humidity but cannot get the 8266 to publish more than 4 topics. I have added a delay but that didn’t help. The relevant code is:

char fan1_state_topic; // defines topic as char type
char louver_state_topic; // defines topic as char type
char indoor_temp_topic; // defines topic as char type
char indoor_humidity_topic; // defines topic as char type
char outside_temp_topic;
char outside_humidity_topic;

if (Fan1Status == 0)
{
client.publish(“fan1_state_topic”, “OFF”);
delay (100);
}
if (Fan1Status == 1)
{
client.publish(“fan1_state_topic”, “ON”);
delay (100);
}

if (LouverStatus == 0)
{
client.publish(“louver_state_topic”, “OFF”);
delay (100);
}
if (LouverStatus == 1)
{
client.publish(“louver_state_topic”, “ON”);
delay (100);
}

char OutTemp [2];
dtostrf (OutdoorTemp,2,0,OutTemp);

char OutHumidity [2];
dtostrf (OutdoorHumidity,2,0,OutHumidity);
delay (100);

char IndoorTemp [2]; // defines IndoorTemp as character type
dtostrf (PoolIndoorTemp,2,0,IndoorTemp); // This converts digital to string

char IndoorHumidity [2]; // Defines IndoorHumidity as character type
dtostrf (PoolIndoorHumidity,2,0,IndoorHumidity); // This converts digital to string

client.publish(“indoor_temp_topic”, IndoorTemp);
client.publish(“indoor_humidity_topic”, IndoorHumidity);

client.publish(“outside_temp_topic”, OutTemp);
client.publish(“outside_humidity_topic”, OutHumidity);

When I move the client.publish topics around, it changes the topics that get published but I still only see 4 topics (in MQTT.fm). I feel like there must be a limitation that I haven’t seen in my limited documentation for MQTT.

Which ones?
Do you ever see the “louver_state_topic” and the “fan1_state_topic” being published?

Yes the Fan1 and Louver states are published as are two of the next 4 topics. Should be simple, but I cannot figure it out.

And which mqtt library are you using?

I call these libraries:

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include “DHT.h”
#include <PubSubClient.h>

Have you tried a small delay between each publish?
Can you show the whole code, please?

Please use the code fences:

Yes, I did try a delay of 100, but that didn’t seem to matter. Here’s the entire block of code:

// August 17, 2018
//

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include “DHT.h”
#include <PubSubClient.h>

/************ WIFI and MQTT INFORMATION (CHANGE THESE FOR YOUR SETUP) ******************/
#define wifi_ssid " [SSID] " //type your WIFI information inside the quotes
#define wifi_password "[PSWD] "
#define mqtt_server “192.168.50.153” // this is the ip address for the openhab Pi server
#define mqtt_user " [User] "
#define mqtt_password " [Pswd] "
#define mqtt_port 1883

/****************** Manually set MQTT packet size **************/

#define MQTT_MAX_PACKET_SIZE 512

/*************** Define Sensor types and data pins ************/

DHT dht(D7,DHT22);
DHT dht1(D6,DHT22);

/**************** needed for WiFi and MQTT???*****************/

WiFiClient espClient;
PubSubClient client(espClient);

/******************* Declare variables **********************/

float PoolIndoorTemp;
float PoolIndoorHumidity;
float OutdoorTemp;
float OutdoorHumidity;

int IndoorTempAdjustment = 0; // Adjustments are used to calibrate the temperature and
int IndoorHumidityAdjustment = 0; // humidity readings for accuracy and comparability
int OutdoorTempAdjustment = 1;
int OutdoorHumidityAdjustment = 2;

int PoolIndoorHumiditySetPoint = 34;
int PoolIndoorHumidityBuffer = 2; // buffer is used to separate on and off by the number
int OutdoorTempSetPoint = 45; // degrees indicated. The idea is to prevent short cycling
int OutdoorTempBuffer = 2;

int Fan1Status; // = 0;
int LouverStatus; // = 0;

char message_buff[100];

void setup()

{
Serial.begin(115200);

setup_wifi();

client.setServer(mqtt_server, mqtt_port);
boolean rt = client.connect(mqtt_server, mqtt_user, mqtt_password);

// client.setCallback(callback);

// reconnect();

Serial.println(WiFi.localIP());

}
void callback(char* topic, byte* payload, unsigned int length)
{
Serial.print(“Message arrived [”);
Serial.print(topic);
Serial.print("] ");
int i=0;
for (i=0;i<length;i++) {
Serial.print((char)payload[i]);
message_buff[i] = payload[i];
}
message_buff[i] = ‘\0’;
String msgString = String(message_buff);
if (msgString.equals(“OFF”))
{
client.publish(“openhab/himitsu/command”,“acknowedging OFF”);
}
else if(msgString.equals(“ON”))
{
client.publish(“openhab/himitsu/command”,“acknowedging ON”);
}
Serial.println();
}

/*************************** START SETUP WIFI*****************/

void setup_wifi()
{

delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(wifi_ssid);

WiFi.mode(WIFI_STA);
WiFi.begin(wifi_ssid, wifi_password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(“connecting to wifi”);
}

Serial.println("");
Serial.println(“WiFi connected”);
Serial.println("IP address: ");
// Serial.println(WiFi.localIP());
}

void loop()

{

/************* check for sensor reading errors and print if found ***/

/*************Read Sensors and adjust for accuracy (manually set adjustment above) **************/

PoolIndoorTemp = (dht.readTemperature(true)*5/9+32 + IndoorTempAdjustment); // read and convert to Fahrenheit
PoolIndoorHumidity = (dht.readHumidity()+ IndoorHumidityAdjustment);
OutdoorTemp = (dht1.readTemperature(true)*5/9+32 + OutdoorTempAdjustment); // read and convert to Fahrenheit
OutdoorHumidity = (dht1.readHumidity()+ OutdoorHumidityAdjustment);

/************* Print Indoor Sensor readings - use for display **************/

Serial.print (“Indoor Temperature: “); // prints the words
Serial.print(PoolIndoorTemp,0); //reads temp
Serial.print(”\xC2\xB0”); // this adds the degree symbol. I don’t know how, but it does.
Serial.println (“F”); // adds the F after the degree symbol
Serial.print(“Indoor - Relative Humidity: “); // prints RH: with a space but no carriage return
Serial.print(PoolIndoorHumidity,0);
Serial.println(”%”); // adds the % symbol;

/*************Read and Print outdoor Sensor - use for display **************/
Serial.print (“Outdoor Temperature: “); // prints the words
Serial.print((OutdoorTemp),0); //converts to Fahrenheit
Serial.print(”\xC2\xB0”); // this adds the degree symbol. I don’t know how, but it does.
Serial.println (“F”);
Serial.print(“Outdoor - Relative Humidity: “); // prints RH: with a space but no carriage return
Serial.print(OutdoorHumidity,0);
Serial.println(”%”); // adds the % symbol
Serial.println();

/************** Determine whether change Fan and Louver Status ****************/

// If Fan is off, set Fan variable to “on” if humidity is too high.

if ((Fan1Status == 0) and (PoolIndoorHumidity > PoolIndoorHumiditySetPoint))
{
Fan1Status = 1;
delay (100);
// Serial.print ("Fan Status = ");
// Serial.println (Fan1Status);
Serial.println (“Turning on Fan 1.”);
// Serial.println ();

      // If fan is on but louver is closed, change louver status to open if not too cold out 
      // this is a nested loop. It should only run if the first "if" is satisfied

    if ((LouverStatus == 0) and (OutdoorTemp > OutdoorTempSetPoint))                    
    {
        LouverStatus = 1; 
        delay (100);                                                        
        //  Serial.print ("Louver status = ");
        //  Serial.println (LouverStatus);
        Serial.println ("Opening Louvers.");
        //  Serial.println ();
    }   
}

// If fan is on and louver is open but it gets too cold out, close louver, leave fan on.

if (((Fan1Status == 1) and (LouverStatus == 1)) and (OutdoorTemp < (OutdoorTempSetPoint - OutdoorTempBuffer)))

{
  LouverStatus = 0;                                          
  delay (100);  
  //  Serial.print ("louver status = ");
  //  Serial.println (LouverStatus);
  Serial.println ("Too cold outside; closing louvers");
}

// If fan is on and indoor humidity drops below set point munus the buffer, then turn off and close.

if ((Fan1Status == 1) and (PoolIndoorHumidity < (PoolIndoorHumiditySetPoint - PoolIndoorHumidityBuffer)))
{
delay (100);
Fan1Status = 0;
LouverStatus = 0;
Serial.println (“Humidity is low enough, turning off Fan 1 and closing the Louvers.”);
}

/**************** Publish data over MQTT *************/

client.setServer(“192.168.50.153”,1883);
client.setCallback(callback);

char fan1_state_topic; // defines topic as char type
char louver_state_topic; // defines topic as char type
char indoor_temp_topic; // defines topic as char type
char indoor_humidity_topic; // defines topic as char type
//char outside_temp_topic;
//char outside_humidity_topic;

// The following reads the state of Fan1Status and LouverStatus and publishes it over MQTT
if (Fan1Status == 0)
{
client.publish(“fan1_state_topic”, “OFF”);
delay (100);
}
if (Fan1Status == 1)
{
client.publish(“fan1_state_topic”, “ON”);
delay (100);
}

if (LouverStatus == 0)
{
client.publish(“louver_state_topic”, “OFF”);
delay (100);
}
if (LouverStatus == 1)
{
client.publish(“louver_state_topic”, “ON”);
delay (100);
}

char OutTemp [2];
dtostrf (OutdoorTemp,2,0,OutTemp);
char OutHumidity [2];
dtostrf (OutdoorHumidity,2,0,OutHumidity);

char IndoorTemp [2]; // defines IndoorTemp as character type
dtostrf (PoolIndoorTemp,2,0,IndoorTemp); // This converts digital to string
char IndoorHumidity [2]; // Defines IndoorHumidity as character type
dtostrf (PoolIndoorHumidity,2,0,IndoorHumidity); // This converts digital to string

client.publish(“indoor_temp_topic”, IndoorTemp);
client.publish(“indoor_humidity_topic”, IndoorHumidity);

client.publish(“outside_temp_topic”, OutTemp);
client.publish(“outside_humidity_topic”, OutHumidity);

delay (100);

delay(10000); // The delay between the repeat of everything below void loop()

}

I know this could be improved. Suggestions would be appreciated.

Remove these two lines from your loop
They are already part on your setup function.

We’ll debug the rest after

I commented those two lines out. Now I only see indoor_humidity_topic and the other three temperature/humidity topics are blank in MQTT.fm. I cannot see why the small change affected everything. So, I removed the comment and re-flashed and now I have both states and the indoor temp/humidity topics showing up in MQTT.fm.

So I also tried commenting only “client.setServer(“192.168.50.153”,1883);” out and the same result, both states are published as is the indoor temp/humidity topics, not the outdoor. But if I comment out:

client.setCallback(callback);

I lose the indoor_temp_topic, but MQTT.fm still is able to subscribe to:

fan1_state_topic
louver_state_topic
indoor_humidity_topic

Pretty odd.

Just for grins, I also tried inserting

client.setCallback(callback);

a second time, below the
fan1_state_topic
louver_state topic

  • no difference. I also tried inserting it lower and removing it from its original location no net change. If it is in, I see the two state topics and two of the four temp/humidity topics, if it is out, I see the two state topics and only one of the temp/humidity topics.

I know for sure that those two lines should not be in your main loop.
Have you tried the ESP arduino forum?

No, I wasn’t aware of that forum. My issue probably is more arduino than openhab. I was just hoping someone might flip the light switch for me. Which forum would you recommend?

tried out

#define MQTT_MAX_PACKET_SIZE 1000

also in PubSubClient.h

Changing to

#define MQTT_MAX_PACKET_SIZE 1024

or to 1000 from 512 didn’t make a difference.

I also tried increasing the message buffer declaration from

char message_buff[100];

to 150. That also didn’t make a difference.

There is one other clue. I have well down in my void loop() these two lines:

client.setServer(“192.168.50.153”,1883);
client.setCallback(callback)

This is apparently the wrong place. I commented them both out and when I did, only three topics were published. If I un-commented only the client.setCallback(callback) then immediately I’m back to 4 topics being published. I already had the same line in my void setup(), so i shouldn’t need it in the void loop().

No better feeling than fixing your code. :smiley:

An alternative could be to use Esp Easy firmware. I have a few ESP8266’s that I flashed using ATOM IDE and they work well.

Well, trying to debug my code, I inserted some Serial.print commands. They detected an error “call of overloaded ‘println(char[4], int)’ is ambiguous” so I changed the char declarations from 2 to 3 and that appears to remove the overload and now all six topics publish. Thanks to all for attempting to help.

*originally it was [4] and the dtostrf was also 4, I changed to 2 and 2 and then 3 and 2 to get it to work. The earlier response was confusing.

Glad you found your solution. Please mark as solved. Publish the code that works.
Your code needs work.
These two line should not be in the main loop.
The 10s delay in the main loop is bad practice and causes your esp to loose connection and that’s why you need these two lines to reconnect
I’ll try to do a bit of a clean up after you publish your working code

I found that I needed to increase the declarations to 4 and 3 to permit higher temperatures and 100% humidity. Here’s the current working code:

// Reads two DHT22 sensors and connects to wifi
// sends correct information (state of Fan 1, Louver status, and indoor
// and outdoor temperature and humidity to the Openhab broker via MQTT
// August 18, 2018
//

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>

#include “DHT.h”

#include <PubSubClient.h>

/************ WIFI and MQTT INFORMATION (CHANGE THESE FOR YOUR SETUP) ******************/
#define wifi_ssid “[SSID]” //type your WIFI information inside the quotes
#define wifi_password “[PSWD]”
#define mqtt_server “192.168.50.153” // this is the ip address for the openhab Pi server
#define mqtt_user “[user name]”
#define mqtt_password “[user password]”
#define mqtt_port 1883

/****************** Manually set MQTT packet size **************/

#define MQTT_MAX_PACKET_SIZE 512

/*************** Define Sensor types and data pins ************/

DHT dht(D7,DHT22);
DHT dht1(D6,DHT22);

/**************** needed for WiFi and MQTT???*****************/

WiFiClient espClient;
PubSubClient client(espClient);

/******************* Declare variables **********************/

float PoolIndoorTemp;
float PoolIndoorHumidity;
float OutdoorTemp;
float OutdoorHumidity;

int IndoorTempAdjustment = 0; // Adjustments are used to calibrate the temperature and
int IndoorHumidityAdjustment = 0; // humidity readings for accuracy and comparability
int OutdoorTempAdjustment = 1;
int OutdoorHumidityAdjustment = 2;

int PoolIndoorHumiditySetPoint = 34;
int PoolIndoorHumidityBuffer = 2; // buffer is used to separate on and off by the number
int OutdoorTempSetPoint = 45; // degrees indicated. The idea is to prevent short cycling
int OutdoorTempBuffer = 2;

int Fan1Status;
int LouverStatus;

char message_buff[100];

void setup()

{
Serial.begin(115200);

setup_wifi();

client.setServer(mqtt_server, mqtt_port);
boolean rt = client.connect(mqtt_server, mqtt_user, mqtt_password);

client.setCallback(callback);
Serial.println(WiFi.localIP());

}
void callback(char* topic, byte* payload, unsigned int length)
{
Serial.print(“Message arrived [”);
Serial.print(topic);
Serial.print("] ");
int i=0;
for (i=0;i<length;i++) {
Serial.print((char)payload[i]);
message_buff[i] = payload[i];
}
message_buff[i] = ‘\0’;
String msgString = String(message_buff);
if (msgString.equals(“OFF”))
{
client.publish(“openhab/himitsu/command”,“acknowedging OFF”);
}
else if(msgString.equals(“ON”))
{
client.publish(“openhab/himitsu/command”,“acknowedging ON”);
}
Serial.println();
}

/*************************** START SETUP WIFI*****************/

void setup_wifi()
{

delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(wifi_ssid);

WiFi.mode(WIFI_STA);
WiFi.begin(wifi_ssid, wifi_password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(“connecting to wifi”);
}

Serial.println("");
Serial.println(“WiFi connected”);
Serial.println("IP address: ");
// Serial.println(WiFi.localIP());
}

void loop()

{

/************* check for sensor reading errors and print if found ***/

/*************Read Sensors and adjust for accuracy (manually set adjustment above) **************/

PoolIndoorTemp = (dht.readTemperature(true)*5/9+32 + IndoorTempAdjustment); // read and convert to Fahrenheit
PoolIndoorHumidity = (dht.readHumidity()+ IndoorHumidityAdjustment);
OutdoorTemp = (dht1.readTemperature(true)*5/9+32 + OutdoorTempAdjustment); // read and convert to Fahrenheit
OutdoorHumidity = (dht1.readHumidity()+ OutdoorHumidityAdjustment);

/************* Print Indoor Sensor readings - use for display **************/

Serial.print (“Indoor Temperature: “); // prints the words
Serial.print(PoolIndoorTemp,0); //reads temp
Serial.print(”\xC2\xB0”); // this adds the degree symbol. I don’t know how, but it does.
Serial.println (“F”); // adds the F after the degree symbol
Serial.print(“Indoor - Relative Humidity: “); // prints RH: with a space but no carriage return
Serial.print(PoolIndoorHumidity,0);
Serial.println(”%”); // adds the % symbol;

/*************Read and Print outdoor Sensor - use for display **************/
Serial.print (“Outdoor Temperature: “); // prints the words
Serial.print((OutdoorTemp),0); //converts to Fahrenheit
Serial.print(”\xC2\xB0”); // this adds the degree symbol. I don’t know how, but it does.
Serial.println (“F”);
Serial.print(“Outdoor - Relative Humidity: “); // prints RH: with a space but no carriage return
Serial.print(OutdoorHumidity,0);
Serial.println(”%”); // adds the % symbol
Serial.println();

/************** Determine whether change Fan and Louver Status ****************/

// If Fan is off, set Fan variable to “on” if humidity is too high.

if ((Fan1Status == 0) and (PoolIndoorHumidity > PoolIndoorHumiditySetPoint))
{
Fan1Status = 1;
delay (100);
Serial.println (“Turning on Fan 1.”);

      // If fan is on but louver is closed, change louver status to open if not too cold out 
      // this is a nested loop. It should only run if the first "if" is satisfied

    if ((LouverStatus == 0) and (OutdoorTemp > OutdoorTempSetPoint))                    
    {
        LouverStatus = 1; 
        delay (100);                                                        
        Serial.println ("Opening Louvers.");
    }   
}

// If fan is on and louver is open but it gets too cold out, close louver, leave fan on.

if (((Fan1Status == 1) and (LouverStatus == 1)) and (OutdoorTemp < (OutdoorTempSetPoint - OutdoorTempBuffer)))
{
LouverStatus = 0;
delay (100);
Serial.println (“Too cold outside; closing louvers”);
}

// If fan is on and indoor humidity drops below set point munus the buffer, then turn off and close.

if ((Fan1Status == 1) and (PoolIndoorHumidity < (PoolIndoorHumiditySetPoint - PoolIndoorHumidityBuffer)))
{
delay (100);
Fan1Status = 0;
LouverStatus = 0;
Serial.println (“Humidity is low enough, turning off Fan 1 and closing the Louvers.”);
}

/**************** Confirm MQTT is connected **********/

/**************** Publish data over MQTT *************/

char fan1_state_topic; // defines topic as char type
char louver_state_topic; // defines topic as char type
char indoor_temp_topic; // defines topic as char type
char indoor_humidity_topic; // defines topic as char type
char outside_temp_topic;
char outside_humidity_topic;

// The following reads the state of Fan1Status and LouverStatus and publishes it over MQTT
if (Fan1Status == 0)
{
client.publish(“fan1_state_topic”, “OFF”);
delay (100);
}
if (Fan1Status == 1)
{
client.publish(“fan1_state_topic”, “ON”);
delay (100);
}

if (LouverStatus == 0)
{
client.publish(“louver_state_topic”, “OFF”);
delay (100);
}
if (LouverStatus == 1)
{
client.publish(“louver_state_topic”, “ON”);
delay (100);
}

char OutTemp [4];
dtostrf (OutdoorTemp,3,0,OutTemp);

char OutHumidity [4];
dtostrf (OutdoorHumidity,3,0,OutHumidity);

char IndoorTemp [4]; // defines IndoorTemp as character type
dtostrf (PoolIndoorTemp,3,0,IndoorTemp); // This converts digital to string

char IndoorHumidity [4]; // Defines IndoorHumidity as character type
dtostrf (PoolIndoorHumidity,3,0,IndoorHumidity); // This converts digital to string

client.publish(“indoor_temp_topic”, IndoorTemp);
client.publish(“indoor_humidity_topic”, IndoorHumidity);
client.publish(“outside_temp_topic”, OutTemp);
client.publish(“outside_humidity_topic”, OutHumidity);

delay(10000); // The delay between the repeat of everything below void loop()

}

My next steps:
1.name the esp 8266 a unique name
2. insert the correct mqtt reconnect loop to assure reconnection if connection is lost
3. Add OTA updating
4. add the ability to change the set points remotely
5. log the temperature and humidity data for graphing
6. add error detection

That is much tidier than before!!

You don’t need these as you are using string constants in your publish function calls

char fan1_state_topic; // defines topic as char type
char louver_state_topic; // defines topic as char type
char indoor_temp_topic; // defines topic as char type
char indoor_humidity_topic; // defines topic as char type
char outside_temp_topic;
char outside_humidity_topic;

So remove them from the loop

In the loop replase the delay(10000) with:

https://playground.arduino.cc/Code/AvoidDelay

The problem with the delay command is that your ESP “freezes” for 10s and can and will loose connection.
So you replace the delay with a set of instruction that check that 10 seconds has passed and then execute the instruction. So your loop is running all the time, Your ESP is happy. Every 10 seconds the reading of pins and publishing of topics happens, you are happy.