[SOLVED] Get multiple variables from Ubidots at the same time

I am working with an esp8266, with the ubidots.h library and the http protocol, I use two devices, in one I send data to the server and in the other I receive and process them, in general I send 18 variables to the server and they take 2 seconds to arrive , but when requesting them in the other device it takes an average of 40 seconds, (2 or 3 seconds per variable), I am something new working with ubidots, I understand how multiple variables are sent at the same time, is there a way to receive all variables at the same time?
I send the variables with ubidots.add and ubidots.send, and to receive with ubidots.get (DEVICE_LABEL, LAB_SEND11), I do not pretend that it is in real time but for the project in which I work 40 seconds is a long time. thanks for your help

Good day @YesidGarcia

Thank you for reaching out to Ubidots, we’re glad that you are building an application with us.

To answer your questions:

If you use the HTTP protocol with the Ubidots library, it is normal that reading the 18 variables from the second ESP8266 takes up to 40 seconds because it is sequential, and each GET query might take anywhere between 1 to 3 seconds. On top of that, as you have a STEM account, this type of account only allows 1 request per second. In addition to this, the ESP8266 HTTP’s library doesn’t include a method to retrieve multiple variable’s last value at once.

With this being clear, I’d like to recommend using the MQTT protocol in the second device (the one that receive the values from Ubidots), that way, you could subscribe to all the variables and get the updates almost instantaneously. Makes sense?

NOTE: Please refer to this link to know how to use the MQTT protocol with your ESP8266. Also, You must include the UbitosESPMQTT library, please download it here. If you need to know anything else about how to use the MQTT protocol with Ubidots, please refer to this link.

However, the next week we’d share a code example of the MQTT subscription.

All the best,
Ángela

1 Like

Hello @YesidGarcia

Here’s the code example of the MQTT subscription for your second device. This way, you’ll be able to receive all variables at the same time.

//Include Libraries
#include "UbidotsESPMQTT.h"

//Define Constants
#define TOKEN "YOUR-UBIDOTS-TOKEN"   
#define WIFINAME "YOUR-WIFI" 
#define WIFIPASS "YOUR-WIFI-PASSWORD"  
#define DEVICE_LABEL "YOUR-DEVICE-LABEL"
char *var_labels[] = {
  "YOUR-VARIABLE-LABEL-1",
  "YOUR-VARIABLE-LABEL-2",
  "YOUR-VARIABLE-LABEL-3",
  "YOUR-VARIABLE-LABEL-4"
  // Add more variable labels here. Do not forget the comma ;)
};

#define DIMENSION_OF(x) (sizeof(x)/sizeof(x[0]))

float var_last_values[DIMENSION_OF(var_labels)] = {};
Ubidots client(TOKEN);

//Callback function
void callback(char* topic, byte* payload, unsigned int length) {
  // Limitations: Variable label must not be the same as device label
  
  char *topic_cpy = strdup(topic);
  char *payload_str = (char *) malloc(length + sizeof(""));
  char *topic_item = strtok(topic_cpy, "/");
  char *label = NULL;
  float value = NAN;
  size_t index = DIMENSION_OF(var_labels);
  size_t i;

  memcpy(payload_str, payload, length);
  payload_str[length] = '\0';
  
  while ((NULL != topic_item) && (NULL == label)) {
    for (i = 0; i < DIMENSION_OF(var_labels); i++) {
      if (0 == strcmp(var_labels[i], topic_item)) {
        label = topic_item;
        value = atof((char *) payload);
        index = i;
        break;
      }
    }
    topic_item = strtok(NULL, "/");
  }

  if (index < DIMENSION_OF(var_labels)) {
    var_last_values[index] = value;

    Serial.print(label);
    Serial.print(": ");
    Serial.println(value);
  }

  free(topic_cpy);
  free(payload_str);
}

//Suscribe function
void subscribe_to_vars(char **labels, size_t n_labels) {
  size_t i;
  for (i = 0; i < n_labels; i++) {
    char *label = labels[i];
    client.ubidotsSubscribe(DEVICE_LABEL, label);
  }
}

//Print last values function
void print_last_values(void) {
  char str_buff[64] = "";
  size_t i;

  for (i = 0; i < DIMENSION_OF(var_labels); i++) {
    snprintf(str_buff, sizeof(str_buff), "%s: %f", var_labels[i], var_last_values[i]);
    Serial.println(str_buff);
  }
}

//Main functions
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  client.setDebug(true);  // Pass a true or false bool value to activate debug messages
  client.wifiConnection(WIFINAME, WIFIPASS);
  client.begin(callback);
  subscribe_to_vars(var_labels, DIMENSION_OF(var_labels));
}

void loop() {
  // put your main code here, to run repeatedly:
  if (!client.connected()) {
    client.reconnect();
    subscribe_to_vars(var_labels, DIMENSION_OF(var_labels));
  }
  client.loop();
}

Please be aware that firstly, you need to define the constants of your code with your account information (in the below segment):

//Define Constants
#define TOKEN "YOUR-UBIDOTS-TOKEN"   
#define WIFINAME "YOUR-WIFI" 
#define WIFIPASS "YOUR-WIFI-PASSWORD"  
#define DEVICE_LABEL "YOUR-DEVICE-LABEL"
char *var_labels[] = {
  "YOUR-VARIABLE-LABEL-1",
  "YOUR-VARIABLE-LABEL-2",
  "YOUR-VARIABLE-LABEL-3",
  "YOUR-VARIABLE-LABEL-4"
  // Add more variable labels here. Do not forget the comma ;)
};

NOTE: Bear in mind that the Ubidots library only supports the ESP8266 platform version v.2.7.4. Please, when installing this platform, make sure that you’re using the correct version.
Let me know if you need anything else!

All the best,
Ángela

We want to read multiple variable last value using HTTP/REST API. Please suggest efficient single call API.

regards,
Sunand

Hello Sunand and everyone,

To get the last value for multiple variables in a single call, you could use the Get Device Last Values Endpoint or the Raw Series Endpoint, however, it’s important to know that each has it’s own scope: the Device Last Values Endpoint gets the Last Values for each variable within a Device, while the Raw Series Endpoint gets the values for a list of variables (independent of which Device it comes from).

Device Last Values

GET https://industrial.api.ubidots.com/api/v2.0/devices/<device_key>/_/values/last

Where <device_key> is replaced with the ID or label (prefix the label with ~) of the Device.

Raw Series

To make sure you only get the last value of each variable, you need to:

  1. Not specify the start or end keys
  2. Include the limit key with a value of 1

In that sense, your request would look something like this:

Endpoint
POST https://industrial.api.ubidots.com/api/v1.6/data/raw/series

Body

{
  "variables": [
    "62c4877hh8975656ccd7aa11",
    "62c48886gj0866tg5f858c452",
    "628j08y788768251dc355e15"
  ],
  "columns": [
    "value.value",
    "timestamp"
  ],
  "join_dataframes": "false",
  "limit": 1
}

Where in the variables object you specify the IDs of the variables that you want to get the data from, and in the columns object you specify what data you’d like to get from the last Dot. In this example you’d get the value and the timestamp. If you also wanted to get the Dot’s context, then you would add the “value.context” element

Best regards,
SebastiĂĄn

Dear @Sebastian
Thanks for prompt reply. With this API, the problem that I see that we need to pass variable IDs

As I mentioned earlier, we don’t have variable IDs available in custom HTML. We work only with API labels (from our device). We want somewhat generic dashboard with customer HTML across devices. We can manage to change device token when we move dashboard. But, keeping track of 16 variable IDs for each device is a challenge.

We use v2.0 API to fetch all variable information. And then filter out relevant variable’s last values using API labels. It should be ok for us.

thanks,
Sunand

1 Like