Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When trying to ReInit/ReStart HAMqtt service via Web Interface ESP8266 Reboots #244

Closed
PhySix66 opened this issue Mar 27, 2024 · 2 comments

Comments

@PhySix66
Copy link

Win7x64 Arduino 1.8.19
HA-intergration 2.1.0
ESP8266-Olimex-Dev 2MB

I've made a WebInterface for the ESP8266, includeing the MQTT.

On startup everything is fine, but when I try to restart the Service the ESP8266 reboots.
On the Web Page there is a Enable button which then is sent to the mqtt_flags register.
If flag i set, then the mqtt startup initiates.

On the first start, it works. However when I change it fron Enabled to Disabled it seem to work.
Even HAMqtt::isConnected() returns false.

After I've enabled #define ARDUINOHA_DEBUG in the ArduinoHADefines.h library I've got some clues via Serial Debug lines:

On the first run, from setting Disabled to Enabled I got his:

AHA: MQTT state changed to -5, previous state: -1
AHA: MQTT connecting, client ID: 18fe34f5da56
AHA: MQTT state changed to 0, previous state: -5
AHA: MQTT connected

But when I set is from Enabled to Disabled I've never recive this line:

AHA: MQTT state changed to -1, previous state: 0
AHA: MQTT disconnected

So it seem that it never truly disconnects or just some mqtt status flags never get set to the proper state.

I've even tried to add change bool HAMqtt::disconnect() like so:

bool HAMqtt::disconnect()
{
    if (!_initialized) {
        return false;
    }

    ARDUINOHA_DEBUG_PRINTLN(F("AHA: disconnecting"))

    _initialized = false;
    _lastConnectionAttemptAt = 0;
    _mqtt->disconnect();
	
	// added code
	if (!isConnected()) {
        setState(StateDisconnected);
	}
	// added code
    return true;
}

With the resultin Serial:

AHA: disconnecting
AHA: MQTT state changed to -1, previous state: 0
AHA: MQTT disconnected

But still, the same thing happens after ReEnabling the Service, the ESP8266 reboots.

PhySix66

@PhySix66
Copy link
Author

PhySix66 commented Apr 2, 2024

Some additional info.
I've done some testing to trace the source of the problem.
With some Serial.print()-s I've come to the conclusion:

In HAMqtt.cpp

void HAMqtt::loop()
{
	...
	bool result = _mqtt->loop();	// error here -> PubSubClient::loop() 
	...
}

In PubSubClient.cpp

boolean PubSubClient::loop()
{
	if (connected()) {		// error here -> PubSubClient::connected()
	...
	}
}

boolean PubSubClient::connected() 
{
	...
	else {	
		rc = (int)_client->connected(); // ERROR Here If ReConnecting ->(?) Client::connected()
		// this is the code where it crashes
		
		//Fix Test 1 
		// rc = (int)_client[0].connected(); // Tryed this as well, not good
		//Fix Test 2							// Not good, fails
		/*
		if((int)_client->connected() > 0){
			rc = true;
			//Serial.println(F("_client[0].connected() == true"));
		}else{
			rc = false;
			//Serial.println(F("_client[0].connected() == false"));
		}*/
	...
	}
	return rc;
}

In Client.h

class Client: public Stream {
	public:
	...
	virtual uint8_t connected() = 0;	//	No idea where this points to
	// this is the end for my rabithole
	...

};

I only asume, that Client.h somehow points to WiFiClient.cpp

In WiFiClient.cpp

uint8_t WiFiClient::connected()
{
    //Serial.print(F("WiFiClient::connected()"));
	if (!_client || _client->state() == CLOSED)
	{	//Serial.println(F(" == false"));
        return 0;
	}
    return _client->state() == ESTABLISHED || available();
}

@PhySix66
Copy link
Author

Problem Solved!
Problem Source: USER (a.k.a ME)

I've made a bad, untested/unverified assumption based from the Arduinos Examples, namely:
example/home-assistaint-integration/multi-switch

From this as the basis:

void setup() {
    // you don't need to verify return status
    Ethernet.begin(mac);

    switch1.setName("Pretty label 1");
    switch1.setIcon("mdi:lightbulb");
    switch1.onCommand(onSwitchCommand);

    switch2.setName("Pretty label 2");
    switch2.setIcon("mdi:lightbulb");
    switch2.onCommand(onSwitchCommand);    

    mqtt.begin(BROKER_ADDR);
}

I made these Foo()-s:

void InitMQTT_Device()
{
          device.setUniqueId(esp_mac.b, sizeof(esp_mac));
          Serial.print(F("MQTT UniqueID :")); Serial.println(device.getUniqueId());
          
          // set device's details (optional)
          //device.setName(ESP_HostName.c_str());
          device.setName(ESP_HostName);
          Serial.print(F("ESP_HostName :")); Serial.println(ESP_HostName);
          device.setManufacturer("PhySix66");
          device.setModel(esp_model_name);
          device.setSoftwareVersion("0.0.1");
          
          // This method enables availability for all device types registered on the device.
          // For example, if you have 5 sensors on the same device, you can enable
          // shared availability and change availability state of all sensors using
          // single method call "device.setAvailability(false|true)"
          //device.enableSharedAvailability();
      
          // Optionally, you can enable MQTT LWT feature. If device will lose connection
          // to the broker, all device types related to it will be marked as offline in
          // the Home Assistant Panel.
          //device.enableLastWill();
}

void InitMQTT_Switches()
{        
          // handle switch state (multi-switch) - OutPut via MCP23x17
          switch0.setName("Switch0");
          //switch0.setIcon("mdi:lightbulb");
          switch0.setIcon("mdi:toggle-switch");
          //switch0.setRetain(true);              //  Sets retain flag for the switch command. If set to true the command produced by Home Assistant will be retained.
          switch0.onCommand(onSwitchCommand);
          
          switch1.setName("Switch1");
          switch1.setIcon("mdi:toggle-switch");
          switch1.onCommand(onSwitchCommand);    
          //....
          switch7.setName("Switch7");
          switch7.setIcon("mdi:toggle-switch");
          switch7.onCommand(onSwitchCommand);
}

void startMQTT()
{
     if(mqtt_flags & MQTT_FLAG_EN)
     {      
       if(!(AreBitSet(mqtt_flags, (MQTT_FLAG_SERVER_AV | MQTT_FLAG_INIT))))
       {
         Serial.println(F("mqtt.h: startMQTT() Not Inited()"));
         
         IPAddress tempIP(0,0,0,0);
         if(!WiFi.hostByName(BROKER_ADDR, tempIP, 800)) { // Get the IP address of the NTP server
          Serial.print(F("MQTT Req DNS lookup failed for "));   Serial.println(BROKER_ADDR);
          mqtt_flags &= ~MQTT_FLAG_SERVER_AV;
         }
         else
         {
            Serial.print(F("MQTT Req DNS lookup Success for "));   Serial.println(BROKER_ADDR);
            Serial.print(F("IP Addr is "));                        Serial.println(tempIP);
            mqtt_flags |= MQTT_FLAG_SERVER_AV;
         }
  
        if(mqtt_flags & MQTT_FLAG_SERVER_AV)
        {        
		  InitMQTT_Device();	// <<-	One of these caused the ERROR.
		  InitMQTT_Switches();	// <<-	One of these caused the ERROR.
		  
		  if(mqtt_flags & MQTT_FLAG_USE_CREDENTIALS)
          {
            // use this for mqtt-with-credentials
            mqtt.begin(MQTT_ServerName, mqtt_port, mqtt_server_user_name, mqtt_server_password);
          }
          else
          {
            if(mqtt.begin(MQTT_ServerName) == true)
            {
              Serial.println(F("mqtt.begin == true"));
            }
            else
            {
              Serial.println(F("mqtt.begin == false"));
            }
          }
     
          mqtt_flags |= MQTT_FLAG_INIT;
          Serial.print(F("mqtt_flags: "));    Serial.println(mqtt_flags);
          Serial.println(F("MQTT is Inited"));
        }
      }
    }
    else if(mqtt.isConnected())
    {
      mqtt_flags &= ~(MQTT_FLAG_SERVER_AV | MQTT_FLAG_INIT);
      mqtt.disconnect();
      Serial.println(F("MQTT DisConnected"));
    }
}

And every time, when I reenabled the MQTT via startMQTT(), then I've also "reinitialized" it's device and switches... Or so I thought.
Not sure about the details of what's happening, but I only assume, that during the second call of InitMQTT_Device() and InitMQTT_Switches() some memory allocation/curroption occurs, that messed up the _Client* client (var/pointer?) in the PubSubClient.cpp.

Note to noobs like me:
To find the problem, I did a reinstall of the librarys where I poked arround (added some extra code): home-assistant-integration and the pubsubclient, and went back to square one. After the reflashing, with basicly the same code as in the exmaple, it still crashed. This got me thinking and lead me to the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants