Close

Fixing connection issues

A project log for Old Roomba, new tricks

Add mapping & MQTT-interfacing with ESP8266 and an IMU

simon-jansenSimon Jansen 04/06/2022 at 20:170 Comments

short update 2022-04-10:

All this research and effort. Could it be solved by adding a WiFi antenna‽

My MQTT-LED-floorlamp will have to go without stable internet till I get some new antenna's in the mail. I had to scavenge around, because I didn't have the patience to wait for tomorrows mail delivery. 

It's also much easier to fumble around with some software than to disassemble the roomba so I kept stalling...

I was suspecting the hardware to be a source of my problems for a while now. I can imagine the electrical environment when docked and charging being quite noisy. I could also see the signal strength of the ESP8266 dropping on my routers info page, when docked. 

I could also see the MQTT connection being timed out on the mosquitto broker running on a Pi when reviewing the logs.

When I used some debug values in the code, I could see the WiFi connection would not drop completely and reconnect, but the MQTT-clients reconnect would fail with a socket error.

And the most important is that the MQTT connection is stable so the roomba can listen when it is time to clean. This still is it's primary function.

First few hours the problem seemed fixed. But then .. *sad trombone noises* .. The WiFi connection is more robust, but the MQTT connection still drops. Well, now I know what's NOT the problem. 

Next suspect on the list is the TCP-connection/MQTT-session. I now have the MQTT-broker running in -verbose mode for debugging. And all other connected appliances are down so I'm not being overwhelmed by all the info. To be continued.. once again.. 

Adding the antenna did not completely solve the wonky OTA though. It updates, but fails the check. This doesn't bother me for now because it behaves when I undock it. 

---


I've had connection issues for quite some time wich are VERY difficult to track down.

Symptoms:

I discovered the PubSub MQTT reconnect function is blocking. So I switched libraries to a non-blocking one:

https://github.com/marvinroger/async-mqtt-client

It has a dependency which is not included:

https://github.com/me-no-dev/ESPAsyncTCP

Using the example, this made my sketch into:

#include <ESP8266WiFi.h>    //For ESP8266
#include <ESP8266mDNS.h>    //For OTA
#include <WiFiUdp.h>        //For OTA
#include <Ticker.h>         //For MQTT
#include <AsyncMqttClient.h>//For MQTT
#include <ArduinoOTA.h>     //For OTA
#include <ArduinoJson.h>
#include <Extras.h>
Extras SketchExtras;
#include <Roomba632.h>
Roomba632 roomba;

// WIFI configuration
#define WIFI_SSID "***"
#define WIFI_PASSWORD "***"

//OTA configuration
const char* host = "Roomba632"; //84ed23
//const char* host = "ESP8285_Testplatform"; //80e74a
const char * sketchpass = "**";

// MQTT configuration
#define MQTT_HOST IPAddress(192, 168, 1, 100)
#define MQTT_PORT 1883
#define MQTT_USER "***"
#define MQTT_PASSWORD "***"
#define MQTT_SUB_TOPIC "homeassistant/device/roomba/set"
#define MQTT_PUB_TOPIC "homeassistant/device/roomba/state"
#define MQTT_STREAM_TOPIC "homeassistant/device/roomba/stream"
#define MQTT_PUB_MESSAGE "MQTT-reconnected"
String mqtt_client_id = host;  //This text is concatenated with ChipId to get unique client_id
//unsigned long lastReconnectAttempt = 0;

unsigned long streamTimer = 0;
//#define STREAMINTERVAL 300000
#define STREAMINTERVAL 30000
//#define STREAMINTERVAL 1000

#define SERIAL_SIZE_RX  1024

AsyncMqttClient mqttClient;
Ticker mqttReconnectTimer;

WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
Ticker wifiReconnectTimer;

//Connecting to Wi-Fi...
void connectToWifi() {
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

//Connecting to MQTT...
void connectToMqtt() {
  mqttClient.connect();
}

//Connected to Wi-Fi
void onWifiConnect(const WiFiEventStationModeGotIP& event) {
  connectToMqtt();
}

//Disconnected from Wi-Fi
void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
  mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
  wifiReconnectTimer.once(2, connectToWifi);
}

void onMqttConnect(bool sessionPresent) {
  mqttClient.subscribe(MQTT_SUB_TOPIC, 0);
  mqttClient.publish(MQTT_PUB_TOPIC, 0, true, "MQTT-Reconnected");
}

//Disconnected from MQTT
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  if (WiFi.isConnected()) {
    mqttReconnectTimer.once(2, connectToMqtt);
  }
}

void onMqttSubscribe(uint16_t packetId, uint8_t qos) {}
void onMqttUnsubscribe(uint16_t packetId) {}

void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
  char command = payload[0];
  // Switch case for commands only uses first char
  switch (command) {
    case 'C': { //Clean
      roomba.clean();
      break;
    }
    case 'D': { //Dock
      roomba.dock();
      break;
    }
    case 'S': { //Spot
      roomba.spot();
      break;
    }
    case 'X': { //Stop command
      roomba.stop();
      break;
    }
    default: 
      roomba.stop();
      break;
  }
}

void onMqttPublish(uint16_t packetId) {}

void setup() {
  //Serial.begin(115200);
  //Serial.setRxBufferSize(SERIAL_SIZE_RX);

  wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
  wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);

  ArduinoOTA.onStart([]() { //Make sure device is in a safe mode
    //store params to EEPROM?
  });
  ArduinoOTA.onEnd([]() { //Device will reboot

  });
  ArduinoOTA.onError([](ota_error_t error) {
    (void)error;
    ESP.restart();
  });
  ArduinoOTA.begin();
  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.onSubscribe(onMqttSubscribe);
  mqttClient.onUnsubscribe(onMqttUnsubscribe);
  mqttClient.onMessage(onMqttMessage);
  mqttClient.onPublish(onMqttPublish);
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  mqttClient.setCredentials(MQTT_USER, MQTT_PASSWORD);

  connectToWifi();
  //mqttClient.publish(MQTT_PUB_TOPIC, 0, true, "ESP8266-Reset");
}

void loop() {
  ArduinoOTA.handle();
  roomba.handler();
  SketchExtras.Update();    
  if (millis() > streamTimer){
    streamTimer =  millis() + STREAMINTERVAL;
    char buffer[280];
    StaticJsonDocument<384> doc;
    doc["loops"] = SketchExtras.LoopsPerSec;
    doc["debug"] = roomba.debugVal;
    doc["data"] = roomba.dataState;
    doc["rS"] = roomba.roombaState;
    doc["dS"] = roomba.docked;
    doc["cS"] = roomba.chargingState;
    doc["bV"] = roomba.batteryVoltage;
    doc["bA"] = roomba.current;
    doc["bT"] = roomba.batteryTemp;
    doc["bC"] = roomba.batteryCharge;
    doc["bCap"] = roomba.batteryCapacity;
    doc["OI"] = roomba.OImode;
    doc["serA"] = Serial.available();
    doc["Song"] = roomba.songPlaying;
    doc["dD"] = roomba.dirtDetect;
    doc["mEL"] = roomba.encoderLeft;
    doc["mER"] = roomba.encoderRight;
    doc["rA"] = roomba.angle;
    doc["rD"] = roomba.distance;
    serializeJson(doc, buffer);
    mqttClient.publish(MQTT_STREAM_TOPIC, 0, true, buffer);
  } 
}

Aaaaaaand... it doesn't help :(

It's more efficient. So spending a few evenings wasn't entirely for nothing. Running at ~26000 main loops a second now instead of ~21000. But the reconnect issues are the same. AAArgh... 

To be continued...

Discussions