How to send multiple variables for one device - with a single Timestamp?


#1

I am sending a large payload with 18 variables to Ubidots from Particle using a Webhook. I would like to supply a Timestamp for all of these variables and see that it could be accomplished using the approach outlined here:

However, this would have me sending the same 32-bit Timestamp number 18 times which seems wasteful. Is there a way - using the Device API - to provide a single Timestamp for all the variables provided in the Webhook?

Thanks,

Chip


#2

Greetings @chipmc, as our HTTP REST API does not support global timestamps, if you use TCP you can send an unique timestamp for all your variables, the packet structure can be referenced at our hw docs and should look like the one below:

{USER_AGENT}|POST|{TOKEN}|{DEVICE_LABEL}:{DEVICE_NAME}@{GLOBAL_TIMESTAMP}=>{VARIABLE_LABEL}:{VALUE}${CONTEXT_KEY_1}={CONTEXT_VALUE}${CONTEXT_KEY_2}={CONTEXT_VALUE}|end

If TCP is not suitable for you, you may also send your own customized http request to an Ubifunction, with this architecture you will be able to manage the data coming from your devices just as you wish to fit your needs, this is the most flexible option.

Let me know if you have any additional doubt


#3

@jotathebest,

OK, understand this is not possible via the Api. TCP is not an option for me.

I do, however have access to Ubifunctions and would like to learn more about their use. Can you please validate this approach and point me to any examples / docs I could use to learn this?

Scenario. Device collects data from sensors every 15 minutes at 15, 30, 45 minutes after the hour. At the top of the hour, another data set is collected and the device connects to Particle. At that time, it sends the four data sets using web hooks.

Here is the Webhook I am currently using: https://business.api.ubidots.com/api/v1.6/devices/{{PARTICLE_DEVICE_ID}}/?token={{My Token}}

The JSON payload is:
{
“TimeStamp”: “{{TimeStamp}}”,
“Soilmoisture1”: “{{Soilmoisture1}}”,
“Soilmoisture2”: “{{Soilmoisture2}}”,
“Soilmoisture3”: “{{Soilmoisture3}}”,
“Soilmoisture4”: “{{Soilmoisture4}}”,
“Soilmoisture5”: “{{Soilmoisture5}}”,
“Soilmoisture6”: “{{Soilmoisture6}}”,
“Precipitation”: “{{Precipitation}}”,
“Soiltemp”: “{{Soiltemp}}”,
“Humidity”: “{{Humidity}}”,
“Temperature”: “{{Paneltemperature}}”,
“Panelhumidity”: “{{Panelhumidity}}”,
“Paneltemperature”: “{{Temperature}}”,
“Battery”: “{{Battery}}”,
“Radiotech”: “{{Radiotech}}”,
“Signal”: “{{Signal}}”,
“Quality”: “{{Quality}}”,
“Resets”: “{{Resets}}”,
“Alerts”: “{{Alerts}}”
}

The first field is the Unix Time for all the variables in the payload. I am assuming that I would need to point the Webhook to an endpoint associated with a Ubifunction which would, in turn, add the variable data points to the desired device. Correct?

Any help on next steps would be appreciated.

Thanks,

Chip


#4

hi @chipmc

here is how I do it via https api and I supply timestamp for each variable
{
“ext_analog3”: {
“value”: 0,
“timestamp”: 1563105576846
},
“ext_analog4”: {
“value”: 0,
“timestamp”: 1563105576846
},
“rssi”: {
“value”: -88,
“timestamp”: 1563105576846

}

}


#5

@tom,

Yes, that is the correct way to add the timestamp and is the apparently the only way supported by the API. The problem for me is that I have 18 variables for each device. Sending a 32-bit timestamp for each variable means that I am sending over 500 bytes in redundant time code information. As my device is cellular and battery powered, and there are limitations (I believe?) on the length of a Particle Webhook / Ubidots API call, I was looking for a way to send that time code once for each API call.

It may be that the Ubifunction gives me a way to append the timecode once the web hook reached Ubidots. If I get this working, I will share my results.

Thanks for your reply

Chip


#6

Hi there @chipmc, I will advise two ways that come to my mind to solve your problem:

1. Using Particle Webhooks

Let’s create a simple script to send 8 variables using Particle Webhooks. Notice that we will also send an unique timestamp.

const int ARRAY_LENGTH = 8;
long values[ARRAY_LENGTH];
char *labels[ARRAY_LENGTH] = {"t0","t1","t2","t3","t4","t5","t6","t7"};
char timestamp_ubi[13];
char payload[700];

void setup() {
  Serial.begin(115200);
}

void loop() {
  unsigned long timestamp_seconds = Time.now();
  sprintf(timestamp_ubi, "%lu000", timestamp_seconds);

  readValues(values);
  buildPayload(payload);
  Serial.println(payload);
  //Particle.Publish("ubidots", payload, PRIVATE);
  delay(5000);
}

void readValues(long values[]){
  for (uint8_t i = 0; i < ARRAY_LENGTH; i++){
    values[i] = analogRead(i + 10);
  }
}

void buildPayload(char payload[]) {
  sprintf(payload, "%s", "");
  sprintf(payload, "{");
  for (uint8_t i = 0; i < ARRAY_LENGTH;) {
    sprintf(payload, "%s\"%s\":%d", payload, labels[i], values[i]);
    i++;
    if (i < ARRAY_LENGTH) {
      sprintf(payload, "%s,", payload);
    } else {
      sprintf(payload, "%s,\"timestamp\":%s}", payload, timestamp_ubi);
    }
  }
}

The payload that will be sent will look like the one below:

{"t0": 1000, "t1": 1000, .... , "t7": 1000, "timestamp": 1568213275000}

Now, let’s create a webhook that will add the timestamp key to every value:

Settings:

Advanced settings: Add the timestamp to every key-value pair

Headers:

2. Ubifunctions:

This is the most flexible way, and there are multiple solutions that may fit your needs, I will write just one as example. Let’s create the format below for your values stream:

{"values": "value_1,value_2,...,value_n,timestamp"}

Note: You will need to implement in your firmware the routine to create the json above.

The Ubifunction code (in python) to decode the string above would look like:


def main(args):
    '''
    Main function - runs every time the function is executed.
    "args" is a dictionary containing both the URL params and the HTTP body (for POST requests).
    '''
    stream = args.get("values")
    payload = decoder(stream)

   # Add here the logic to send
   send_to_ubidots(payload)

def send_to_ubidots(payload):
    '''
    Define the function to send data, not written here to make the post short, please guide yourself from the 
    basic Ubifunction example
    '''
    pass

def decoder(stream):
    '''
    Decodes the custom stream
    '''
    counter = 0 
    values = values.split(",") 
    timestamp = values[len(values)-1]
    for value in values[0:len(values)-1]:
        payload[f"value-{counter}"] = {"value": value, "timestamp": timestamp}
        counter += 1
    return payload

Notice that the Ubifunction script is implemented to decode an already custom data buffer. It is important to mention here that Ubifunctions receives just json type data as arguments.

I hope that these examples may serve you as reference, if you have any further doubt, just let me know.