AutoConnect with more than one ThingSpeak field

Hi,

I'm using AutoConnect, with the following sketch :

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#define GET_CHIPID()  (ESP.getChipId())
#include <FS.h>
#include <PubSubClient.h>
#include <AutoConnect.h>

#include "DHT.h"

#define DHTPIN D6          // D3 was 0, was D2 on WeMos

#define DHTTYPE DHT11     // DHT 11

DHT dht(DHTPIN, DHTTYPE);

String t, h;

#define PARAM_FILE      "/param.json"
#define AUX_MQTTSETTING "/mqtt_setting"
#define AUX_MQTTSAVE    "/mqtt_save"
#define AUX_MQTTCLEAR   "/mqtt_clear"


typedef ESP8266WebServer  WiFiWebServer;

AutoConnect  portal;
AutoConnectConfig config;
WiFiClient   wifiClient;
PubSubClient mqttClient(wifiClient);

String  serverName;
String  channelId;
String  userKey;
String  apiKey;
String  apid;
String  hostName;
unsigned int  updateInterval = 0;
unsigned long lastPub = 0;

#define MQTT_USER_ID  "anyone"

bool mqttConnect() {
  static const char alphanum[] = "0123456789"
                                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                 "abcdefghijklmnopqrstuvwxyz";  // For random generation of client ID.
  char    clientId[9];

  uint8_t retry = 3;
  while (!mqttClient.connected()) {
    if (serverName.length() <= 0)
      break;

    mqttClient.setServer(serverName.c_str(), 1883);
    Serial.println(String("Attempting MQTT broker:") + serverName);

    for (uint8_t i = 0; i < 8; i++) {
      clientId[i] = alphanum[random(62)];
    }
    clientId[8] = '\0';

    if (mqttClient.connect(clientId, MQTT_USER_ID, userKey.c_str())) {
      Serial.println("Established:" + String(clientId));
      return true;
    } else {
      Serial.println("Connection failed:" + String(mqttClient.state()));
      if (!--retry)
        break;
      delay(3000);
    }
  }
  return false;
}


void mqttPublish(String msg) {
String path = String("channels/") + channelId + String("/publish/") + apiKey;
mqttClient.publish(path.c_str(), msg.c_str());
}



int getStrength(uint8_t points) {
  uint8_t sc = points;
  long    rssi = 0;

  while (sc--) {
    rssi += WiFi.RSSI();
    delay(20);
  }
  return points ? static_cast<int>(rssi / points) : 0;
}

String loadParams(AutoConnectAux& aux, PageArgument& args) {
  (void)(args);
  File param = SPIFFS.open(PARAM_FILE, "r");
  if (param) {
    aux.loadElement(param);
    param.close();
  }
  else
    Serial.println(PARAM_FILE " open failed");
  return String("");
}

String saveParams(AutoConnectAux& aux, PageArgument& args) {
  serverName = args.arg("mqttserver");
  serverName.trim();

  channelId = args.arg("channelid");
  channelId.trim();
  
  userKey = args.arg("userkey");
  userKey.trim();
  
  apiKey = args.arg("apikey");
  apiKey.trim();
  
  String upd = args.arg("period");
  updateInterval = upd.substring(0, 2).toInt() * 1000;

  String uniqueid = args.arg("uniqueid");

  hostName = args.arg("hostname");
  hostName.trim();
  
  // The entered value is owned by AutoConnectAux of /mqtt_setting.
  // To retrieve the elements of /mqtt_setting, it is necessary to get
  // the AutoConnectAux object of /mqtt_setting.
  File param = SPIFFS.open(PARAM_FILE, "w");
  portal.aux("/mqtt_setting")->saveElement(param, { "mqttserver", "channelid", "userkey", "apikey", "period", "uniqueid", "hostname" });
  param.close();

  // Echo back saved parameters to AutoConnectAux page.
  AutoConnectText&  echo = aux["parameters"].as<AutoConnectText>();
  echo.value = "Server: " + serverName + "
";
  echo.value += "Channel ID: " + channelId + "
";
  echo.value += "User Key: " + userKey + "
";
  echo.value += "API Key: " + apiKey + "
";
  echo.value += "Update period: " + String(updateInterval / 1000) + " sec.
";
  echo.value += "Use APID unique: " + uniqueid + "
";
  echo.value += "ESP host name: " + hostName + "
";

  return String("");
}

void handleRoot() {
  String  content =
    "<html>"
    "<head>"
    "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
    "</head>"
    "<body>"
    "<iframe width=\"450\" height=\"260\" style=\"transform:scale(0.79);-o-transform:scale(0.79);-webkit-transform:scale(0.79);-moz-transform:scale(0.79);-ms-transform:scale(0.79);transform-origin:0 0;-o-transform-origin:0 0;-webkit-transform-origin:0 0;-moz-transform-origin:0 0;-ms-transform-origin:0 0;border: 1px solid #cccccc;\" src=\"https://thingspeak.com/channels/454951/charts/1?bgcolor=%23ffffff&color=%23d62020&dynamic=true&type=line\"></iframe>"
    "<p style=\"padding-top:10px;text-align:center\">" AUTOCONNECT_LINK(COG_24) "</p>"
    "</body>"
    "</html>";

  WiFiWebServer&  webServer = portal.host();
  webServer.send(200, "text/html", content);
}

// Clear channel using Thingspeak's API.
void handleClearChannel() {
  HTTPClient  httpClient;
  WiFiClient  client;
  String  endpoint = serverName;
  endpoint.replace("mqtt", "api");
  String  delUrl = "http://" + endpoint + "/channels/" + channelId + "/feeds.json?api_key=" + userKey;

  Serial.print("DELETE " + delUrl);
  if (httpClient.begin(client, delUrl)) {
    Serial.print(":");
    int resCode = httpClient.sendRequest("DELETE");
    String  res = httpClient.getString();
    httpClient.end();
    Serial.println(String(resCode) + "," + res);
  }
  else
    Serial.println(" failed");

  // Returns the redirect response. The page is reloaded and its contents
  // are updated to the state after deletion.
  WiFiWebServer&  webServer = portal.host();
  webServer.sendHeader("Location", String("http://") + webServer.client().localIP().toString() + String("/"));
  webServer.send(302, "text/plain", "");
  webServer.client().flush();
  webServer.client().stop();
}

// Load AutoConnectAux JSON from SPIFFS.
bool loadAux(const String auxName) {
  bool  rc = false;
  String  fn = auxName + ".json";
  File fs = SPIFFS.open(fn.c_str(), "r");
  if (fs) {
    rc = portal.load(fs);
    fs.close();
  }
  else
    Serial.println("SPIFFS open failed: " + fn);
  return rc;
}

void setup() {
  delay(1000);
  Serial.begin(9600);
  Serial.println("Started DHT");
  dht.begin();
  Serial.println("API Key: " + String(apiKey));
  delay(1000);
  Serial.println();
  SPIFFS.begin();

  loadAux(AUX_MQTTSETTING);
  loadAux(AUX_MQTTSAVE);

  AutoConnectAux* setting = portal.aux(AUX_MQTTSETTING);
  if (setting) {
    PageArgument  args;
    AutoConnectAux& mqtt_setting = *setting;
    loadParams(mqtt_setting, args);
    AutoConnectCheckbox&  uniqueidElm = mqtt_setting["uniqueid"].as<AutoConnectCheckbox>();
    AutoConnectInput&     hostnameElm = mqtt_setting["hostname"].as<AutoConnectInput>();
    if (uniqueidElm.checked) {
      config.apid = String("ESP") + "-" + String(GET_CHIPID(), HEX);
      Serial.println("apid set to " + config.apid);
    }
    if (hostnameElm.value.length()) {
      config.hostName = hostnameElm.value;
      Serial.println("hostname set to " + config.hostName);
    }
    config.homeUri = "/";
    portal.config(config);

    portal.on(AUX_MQTTSETTING, loadParams);
    portal.on(AUX_MQTTSAVE, saveParams);
  }
  else
    Serial.println("aux. load error");

  Serial.print("WiFi ");
  if (portal.begin()) {
    config.bootUri = AC_ONBOOTURI_HOME;
    Serial.println("connected:" + WiFi.SSID());
    Serial.println("IP:" + WiFi.localIP().toString());
  } else {
    Serial.println("connection failed:" + String(WiFi.status()));
    while (1) {
      delay(100);
      yield();
    }
  }

  WiFiWebServer&  webServer = portal.host();
  webServer.on("/", handleRoot);
  webServer.on(AUX_MQTTCLEAR, handleClearChannel);
}

void loop() {

  h = (String)dht.readHumidity();
  t = (String)dht.readTemperature();

 
  
  portal.handleClient();
  if (updateInterval > 0) {
    if (millis() - lastPub > updateInterval) {
      if (!mqttClient.connected()) {
        mqttConnect();
      }

     
      String item = String("field1=") + String(getStrength(7));
      // String item1 = String("field2=") + String(t);
      // String item2 = String("field3=") + String(h);
      mqttPublish(item);
      // mqttPublish(item1);
      // mqttPublish(item2);

      
      mqttClient.loop();
      lastPub = millis();
    }
  }

Serial.println("API Key: " + String(apiKey));
Serial.println("Temperature: " + String(t));
Serial.println("Humidity: " + String(h));
delay(5000);
  
}

I want to publish temperature and humidity from the DHT sensor in addition to the WiFi strength, but I am unable to currently achieve this. With the current code, only one field is published.
Any ideas ?

The first post had a 9000 character limit, so I'd like to add the following :

If I uncomment the additional items 1 and 2 that I created, as follows, only the item string related to field1 is published to Thingspeak :

String item = String("field1=") + String(getStrength(7));
      String item1 = String("field2=") + String(t);
      String item2 = String("field3=") + String(h);
      mqttPublish(item);
      mqttPublish(item1);
      mqttPublish(item2);

Also, the following doesn't work either :

String item = String("field1=") + String(getStrength(7) + String("field2=") + String(t) + String("field3=") + String(h) );
      mqttPublish(item);
     ;

I also came across this : Remote Sensor Control Using Secure MQTT Publish and Subscribe - MATLAB & Simulink , which I used to start reworking the code above, but things got messy.

I'm a newbie and suspect someone has already achieved what I'm trying to do.

P.S. I have got AutoConnect working with some other type of "well known" Thingspeak code, such as follows:

void postDataToThingspeak(float DHT_humidity, float DHT_temperature){
  if (wifiClient.connect(host,80)) {
    
    String postStr = apiKey;
    postStr +="&field1=";
    postStr += String(DHT_temperature);
    postStr +="&field2=";
    postStr += String(DHT_humidity);
    wifiClient.print("POST /update HTTP/1.1\n");
    wifiClient.print("Host: api.thingspeak.com\n");
    wifiClient.print("Connection: close\n");
    wifiClient.print("X-THINGSPEAKAPIKEY: "+apiKey+"\n"); //taken from SPIFF Auto Connect
    wifiClient.print("Content-Type: application/x-www-form-urlencoded\n");
    wifiClient.print("Content-Length: ");
    wifiClient.print(postStr.length());
    wifiClient.print("\n\n");
    wifiClient.print(postStr);



    
  }
  wifiClient.stop(); 
}

But this above code is specific to Thingspeak. Ideally I'd like to use the MQTT code with AutoConnect because if I can get it working with multiple fields, it would work for both other MQTT servers and Thingspeak :slight_smile:

I'm just reporting back, as this may help someone else like me who had issues.
I resolved them as follows :

I created a string (called payload) as shown below, then I simply used mqttpublish(payload);

String payload="field1=";
payload+=(getStrength(7));
payload+="&field2=";
payload+=t;
payload+="&field3=";
payload+=h;

portal.handleClient();
if (updateInterval > 0) {
if (millis() - lastPub > updateInterval) {
if (!mqttClient.connected()) {
mqttConnect();
}

// String item = String("field1=") + String(getStrength(7));
// String item1 = String("field2=") + String(t);
// String item2 = String("field3=") + String(h);
// mqttPublish(item);
mqttPublish(payload);
// mqttPublish(item1);
// mqttPublish(item2);