Converting types from ArduinoJSON to PubSubClient library parameters (MQTT)

I’m using an ESP8266 with the ArduinoJSON and PubSubClient libraries. Basically, I’m trying to read a JSON file and use its values to connect to an MQTT server. However, there are some typing issues that I can’t figure out. In the two lines I’ve marked below (66 and 145), the char arrays aren’t working as parameters for the functions to the MQTT library. There is no error, but the library doesn’t connect to the server. Placing actual values in those places (not variables) causes it to work perfectly. The variables from ArduinoJSON work fine for connecting to the WiFi, but not MQTT.

garage.ino:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include "FS.h"
#include <ArduinoJson.h>
#include <PubSubClient.h>

#define CONFIG_FILEPATH  "/config.json"

/* ************************************
 * DON'T TOUCH ANYTHING PAST THIS LINE!
 * ************************************
*/

const char* wifi_ssid;
const char* wifi_password;
const char* mqtt_host;
const char* mqtt_port;
const char* mqtt_clientname;
const char* mqtt_username;
const char* mqtt_password;
const char* mqtt_topic;
const char* mqtt_route_door1;
const char* mqtt_route_door2;
const char* mqtt_route_car1;
const char* mqtt_route_car2;
const char* mqtt_route_calibrate;

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  
  Serial.begin (115200);
  Serial.println();
  Serial.println("[Sys]  Booting...");

  if (!SPIFFS.begin()) {
    Serial.println("[Sys]  Failed to mount file system");
    return;
  }
  if (!loadConfig()) {
    Serial.println("[Sys]  Failed to load config");
  } else {
    Serial.println("[Sys]  Config loaded");
  }
//  if (!saveConfig()) {
//    Serial.println("[Sys]  Failed to save config");
//  } else {
//    Serial.println("[Sys]  Config saved");
//  }
  SPIFFS.end();
  
  WiFi.begin(wifi_ssid, wifi_password);
  Serial.print("[WiFi] Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("connected");
  Serial.print("[WiFi] IP address: ");
  Serial.println(WiFi.localIP());
  Serial.print("[MQTT] Setting up: ");
  Serial.println((String) mqtt_host);
  // *********************************************************************** ISSUE HERE
  client.setServer((uint8_t*) mqtt_host, (int) mqtt_port); // CAN'T GET THESE VARIABLES TO WORK
  client.setCallback(mqttCallback);
  mqttConnect();
}

void loop() {
  if (!client.connected()) {
    Serial.println("[MQTT] Not connected!");
    mqttConnect();
  }
  client.loop();
}

/* functions for loading/saving config 
 * https://github.com/esp8266/Arduino/blob/master/libraries/esp8266/examples/ConfigFile/ConfigFile.ino
*/
bool loadConfig() {
  File configFile = SPIFFS.open(CONFIG_FILEPATH, "r");
  if (!configFile) {
    Serial.println("[Sys]  Failed to open config file");
    return false;
  }
  size_t size = configFile.size();
  if (size > 1024) {
    Serial.println("[Sys]  Config file size is too large");
    return false;
  }
  std::unique_ptr<char[]> buf(new char[size]);
  configFile.readBytes(buf.get(), size);
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& json = jsonBuffer.parseObject(buf.get());
  if (!json.success()) {
    Serial.println("[Sys]  Failed to parse config file");
    return false;
  }
  wifi_ssid = json["wifi_ssid"];
  wifi_password = json["wifi_password"];
  mqtt_host = json["mqtt_host"];
  mqtt_port = json["mqtt_port"];
  mqtt_clientname = json["mqtt_clientname"];
  mqtt_username = json["mqtt_username"];
  mqtt_password = json["mqtt_password"];
  mqtt_route_door1 = json["mqtt_route_door1"];
  mqtt_route_door2 = json["mqtt_route_door2"];
  mqtt_route_car1 = json["mqtt_route_car1"];
  mqtt_route_car2 = json["mqtt_route_car2"];
  mqtt_route_calibrate = json["mqtt_route_calibrate"];
  return true;
}
bool saveConfig() {
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& json = jsonBuffer.createObject();
  json["wifi_ssid"] = wifi_ssid;
  json["wifi_password"] = wifi_password;
  json["mqtt_host"] = mqtt_host;
  json["mqtt_port"] = mqtt_port;
  json["mqtt_clientname"] = mqtt_clientname;
  json["mqtt_username"] = mqtt_username;
  json["mqtt_password"] = mqtt_password;
  json["mqtt_topic"] = mqtt_topic;
  json["mqtt_route_door1"] = mqtt_route_door1;
  json["mqtt_route_door2"] = mqtt_route_door2;
  json["mqtt_route_car1"] = mqtt_route_car1;
  json["mqtt_route_car2"] = mqtt_route_car2;
  json["mqtt_route_calibrate"] = mqtt_route_calibrate;
  File configFile = SPIFFS.open(CONFIG_FILEPATH, "w");
  if (!configFile) {
    Serial.println("[Sys]  Failed to open config file for writing");
    return false;
  }
  json.printTo(configFile);
  return true;
}

/* MQTT functions */
void mqttConnect() {
  while (!client.connected()) {
    Serial.print("[MQTT] Connecting...");
    // *********************************************************************** ISSUE HERE
    if (client.connect(mqtt_clientname, mqtt_username, mqtt_password)) {  // CAN'T GET THESE VARIABLES TO WORK
      Serial.println("connected");
      //client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe(mqtt_route_door1);
      client.subscribe(mqtt_route_door2);
      client.subscribe(mqtt_route_calibrate);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("[MQTT] Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String message = "";
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
    Serial.print((char)payload[i]);
  }
  Serial.println();
  Serial.println(message);
}

config.json:

{
  "wifi_ssid": "ssid",
  "wifi_password": "pass",
  "mqtt_host": "192.168.0.100",
  "mqtt_port": 1883,
  "mqtt_clientname": "myclient",
  "mqtt_username": "user",
  "mqtt_password": "pass",
  "mqtt_route_door1": "garage/door1",
  "mqtt_route_door2": "garage/door2",
  "mqtt_route_car1": "garage/car1",
  "mqtt_route_car2": "garage/car2",
  "mqtt_route_calibrate": "garage/calibrate"
}

I know there’s an ESP8266 forum, but I’ve been given fantastic advice here, this is more of a C question, and all of these libraries work on standard Arduinos.

Thanks!

I think You should strdup() your Strings in char pointers because you are pointing to information that is transient and local to the loadConfig() function

Thanks for your quick reply.

J-M-L:
I think You should strdup() your Strings in char pointers because you are pointing to information that is transient and local to the loadConfig() function

Where exactly and how do I use strdup()?
Should I do this:

mqtt_host = strdup(json["mqtt_host"]);

or this:

client.setServer(strdup(mqtt_host), (int) mqtt_port);

Should I do this:

Yes.

or this:

NEVER call strdup() without saving the returned value. If you do, you have just wasted memory that you can not recover.

Be sure to free() the dup-ed memory when you are done with it.

Well that worked! Thank you! However, I've decided just to use a config.h file instead. Instead, the JSON file will only hold some calibration values, which are integers. Uploading to the filesystem from a computer actually takes way too long, as it has to create an image of the FS and upload the entire thing. This way I can store only the non-human-interacted values on the FS.

Thanks!

Good to know it was this pb - then indeed a choice for performance versus flexibility