[SOLVED] unable to get data into datasource's variables using MQTT

I am using Nick O’Leary’s Arduino Client for MQTT on the SparkFun Thing Dev (an ESP8266 microcontroller). I have used thee MQTT library on this board successfully in the past with other MQTT servers. But, I am unable to publish data to my datasource’s variables on Ubidots.

I am able to connect to Ubidots’ MQTT server successfully. Here are some code snippets:
char mqtt_server[] = “things.ubidots.com”; // the ubidots.com MQTT server
int mqtt_port = 1883; // the ubidots.com MQTT port

client.setServer(mqtt_server, mqtt_port); // configure the MQTT client with the MQTT server address:port

if (client.connect(“mqtt://things.ubidots.com”, “”, “”))
Serial.println(“connected”);

But when I view my datasource and variables in the dashboard after the microcontroller publishes data, there is no activity / data. The label for my datasource is “incubator”. I have four variables in that datasource with labels: ambienttemp, bottomtemp, toptemp, and heaterstatus.

Here is the code for publishing:
void sendToCloud()
{
// construct the JSON object
message[“ambienttemp”] = lm35Temperature;
message[“bottomtemp”] = temperature[0];
message[“toptemp”] = temperature[1];
if (heaterOn)
message[“heaterstatus”] = “on”;
else
message[“heaterStatus”] = “off”;

// convert JSON object to string
message.printTo(msg, sizeof(msg));

Serial.print(“Publish message: “);
Serial.println(msg);
client.publish(”/v1.6/devices/incubator”, msg);
}

I can’t figure out what I am doing wrong. I may be getting a little confused with Ubidots’ terminology. The dashboard is all about “datasources” while a lot of the documentation talks about “devices”. I was unable to create a “device” in the dashboard.

@peejster Could you paste here all of your code, i think that you are forgetting some parts of the code

Okay. Here is the entire sketch:

#include <OneWire.h>             // for reading data from DS18B20 sensors
#include <ESP8266WiFi.h>         // for WiFi connnectivity
#include <PubSubClient.h>        // for MQTT connectivity; documentation at http://pubsubclient.knolleary.net/api.html#PubSubClient1
#include <ArduinoJson.h>         // for JSON encoding of MQTT message

const int sensorCount = 2;       // define the number of DS18B20 sensors
const int tempPin = 2;           // DS18B20 temp sensors are connected to digital pin 2
const int lm35Pin = 0;           // LM35 temp sensor is connected to A0
const int heaterPin = 15;        // heater switched via digital pin 15

OneWire ds(tempPin);             // create an instance of the temp sensors
WiFiClient espClient;            // create an instance of the wifi client
PubSubClient client(espClient);  // create an ESP8266 compatible client instance of the MQTT client

float temperature[sensorCount];  // store the temp reading from each DS18B20 sensor
float lm35Temperature;           // store the temp reaing from the LM35 temp sensor

char ssid[] = "<my_wifi_network>";   // your network SSID (name)
char pass[] = "<my_password>";    // your network password (use for WPA, or use as key for WEP)
char mqtt_server[] = "things.ubidots.com"; // the ubidots.com MQTT server
int mqtt_port = 1883;            // the ubidots.com MQTT port

long lastMsg = 0;
char msg[100];
bool heaterOn = false;

StaticJsonBuffer<100> jsonBuffer;
JsonObject& message = jsonBuffer.createObject();

void setup()
{
  Serial.begin(115200);          // initialize the serial monitor

  connectWifi();                 // establish wifi connection
  client.setServer(mqtt_server, mqtt_port);  // configure the MQTT client with the MQTT server address and port

  pinMode(heaterPin, OUTPUT);    // initialize the heater pin
  digitalWrite(heaterPin, LOW);  // set heater pin to low (off)
}

void loop()
{
  // make sure you are connected to the wifi network
  if (WiFi.status() != WL_CONNECTED)
    connectWifi();

  // make sure you are connected to the MQTT server
  if (!client.connected())
  {
    reconnect();
  }
  client.loop();

  long now = millis();
  if (now - lastMsg > 60000)     // take temp readings and post to cloud every 60 seconds
  {
    lastMsg = now;
    
    // take reading from temperature sensors
    getDS18B20Temp();
    getLM35Temp();

    // check temperature in incubator
    if (temperature[0] < 31.0)
    {
      // turn on heater
      Serial.println("Turning heater on");
      digitalWrite(heaterPin, HIGH);
      heaterOn = true;
    }
    else if (temperature [0] > 33.0)
    {
      // turn off heater
      Serial.println("Turning heater off");
      digitalWrite(heaterPin, LOW);
      heaterOn = false;
    }

    sendToCloud();
  }
}

// connect to wifi network
void connectWifi()
{
  Serial.print("Attempting to connect to SSID: ");
  Serial.println(ssid);

  // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }

  Serial.println("Connected to wifi");
}

// record the temperature from all the DS18B20 sensors
void getDS18B20Temp()
{
  byte data[12];
  byte addr[sensorCount][8];
  
  // send a reset pulse
  ds.reset_search();
  
  // then receive presence pulse from the devices
  for (int i = 0; i < sensorCount; i++)
  {
    if ( !ds.search(addr[i]))
    {
      Serial.println("No devices.");
      ds.reset_search();
      temperature[i] = -1000;
      return;
    }
  }

  // get readings from the devices
  for (int i = 0; i < sensorCount; i++)
  {
    // verify the device's CRC
    if (OneWire::crc8(addr[i], 7) != addr[i][7])
    {
      Serial.println("CRC is not valid!");
      temperature[i] = -1000;
      return;
    }

    // check the device type
    // Serial.print("Device ");
    // Serial.print(i);

    if (!((addr[i][0] == 0x10) || (addr[i][0] == 0x28)))
    {
      Serial.print(" is not recognized: 0x");
      Serial.println(addr[i][0],HEX);
      temperature[i] = -1000;
      return;
    }

    // Initiate a conversion on the temp sensor  
    ds.reset();
    ds.select(addr[i]);
    ds.write(0x44,1);

    // Wait for the conversion to complete
    delay(850);

    // Read from the scratchpad
    ds.reset();
    ds.select(addr[i]);
    ds.write(0xBE);

    for (int j = 0; j < 9; j++)
    {
      data[j] = ds.read();
      // Serial.print(data[j], HEX);
      // Serial.print(" ");
    }

    // Serial.println("");

    // calculate temp
    temperature[i] = (((data[1] << 8) + data[0] )*0.0625);

    Serial.print("DS18B20 sensor ");
    Serial.print(i);
    Serial.print(": ");
    Serial.println(temperature[i]);
  }

  return;
}

void getLM35Temp()
{
  lm35Temperature = analogRead(lm35Pin) / 10.24;
  Serial.print("LM35 sensor: ");
  Serial.println(lm35Temperature);
}

void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    // Boolean connect(const char* clientId, const char* username, const char* password);
    if (client.connect("mqtt://things.ubidots.com", "<my_token>", ""))
    {
      Serial.println("connected");
      // Once connected, publish an announcement...
      // client.publish("/users/peejster/temp/ambient", "0");
      // ... and resubscribe
      //client.subscribe("inTopic");
    }
      else
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void sendToCloud()
{
  // construct the JSON object
  message["ambienttemp"] = lm35Temperature;
  message["bottomtemp"] = temperature[0];
  message["toptemp"] = temperature[1];
  if (heaterOn)
    message["heaterstatus"] = "on";
  else
    message["heaterStatus"] = "off";

  // convert JSON object to string
  message.printTo(msg, sizeof(msg));

  Serial.print("Publish message: ");
  Serial.println(msg);
  client.publish("/v1.6/devices/incubator", msg);
}

Solved.

I was sending a string instead of a float or integer for the value of my “heaterstatus” variable; the value can only be a float or integer. If I want to send a string, it needs to be a JSON object with metadata for the context key.

Since I just want to track off and on for the heater status, I just used 0 and 1 for the value.

One reason it took me so long to trouble shoot is that the client.connect call would always return true (I added code to what I posted above which printed out the return value from the client.connect call). I wonder why I would get a response of true from the Ubidots API if I was sending invalid type in my JSON message.

Here is the code change to make the above work:

  if (heaterOn)
    message["heat"] = 1;
  else
    message["heat"] = 0;