Timestamped data


#1

My device makes multiple measurements available with each sample. It also generates a timestamp for the group of measurements. When I send the data to Cayenne I have to slit up the group into separate MQTT messages. How do I send data to Cayenne with the timestamp info so that the group appears in Cayenne charts at the sampling time, not the time Cayenne received the MQTT message? Is there any way to send the entire group of readings with one timestamp? Maybe a JSON message with everything?


#2

@eptak tagging for this.


#3

Yes:

v1/USERNAME/things/THING_ID/data/json
payload is of this format

[
     {"channel":100,"type":"rssi","unit":"dbm","value":10,"name":"RSSI"},
     {"channel":101,"type":"snr","unit":"db","value":10,"name":"SNR"},
     {"channel":1,"type":"temp","unit":"c","value":10,"name":"Temperature"},
     {"channel":2,"type":"rel_hum","unit":"p","value":10,"name":"Humidity"},
     {"channel":4,"type":"lum","unit":"lux","value":10,"name":"Luminosity"},
     {"channel":5,"type":"motion","unit":"d","value":motion,"name":"Motion"}, 
     {"channel":6,"type":"co2","unit":"ppm","value":10,"name":"CO2"},
     {"channel":107,"type":"voltage","unit":"v","value":8,"name":"VDD"}
  ]

#4

I have pondered this question, and notwithstanding the database clog problems before and slightly after April 12, the data moves quite quickly through the internet and into the database within 1 second, and is timestamped when it arrives. And since this is usually 15 second data, the “within a second” is probably adequate.

This is an 8266 series, that goes through wifi, then fiber internet Canadian phone company to the server in LaLa Land (I’m guessing), with the Cayenne server time on the left, and my 8266 time on the right, and they are usually within a second.

If there is bad internet on either end, or other problems, they could diverge.

On your response adam with v1/USERNAME/things/THING_ID/data/json, is that a mqtt command that can send a multi-item update to the server? I assume if I am using the mqtt arduino library with the virtualwrite command, I am sending each datapoint separately. Is there a virtualwrite for multiple points? Or do I have to build my own json, and send it through the http post/get/etc system and bypass the cayenne mqtt library?

As an aside, I would be interested in the secret document all all the REST and MQTT interactions that your servers can accommodate, and are legal and kosher. I have been bypassing the summary database to get some non-summarized data, now and then, but have to reverse engineer it from the commands my browser is sending. :grinning:


#5

You will have to send the payload manually. I still have a project here that is not using the Cayenne library (instead uses paho), you can get an idea of how to send the data there.

topic = "v1/" + username + "/things/" + clientid + "/data/json"
payload = '[{"channel":100,"type":"rssi","unit":"dbm","value":10,"name":"RSSI"},{"channel":101,"type":"snr","unit":"db","value":10,"name":"SNR"},{"channel":1,"type":"temp","unit":"c","value":10,"name":"Temperature"},{"channel":2,"type":"rel_hum","unit":"p","value":10,"name":"Humidity"},{"channel":4,"type":"lum","unit":"lux","value":10,"name":"Luminosity"},{"channel":5,"type":"motion","unit":"d","value":motion,"name":"Motion"}, {"channel":6,"type":"co2","unit":"ppm","value":10,"name":"CO2"},{"channel":107,"type":"voltage","unit":"v","value":8,"name":"VDD"}]'
mqttc.publish(topic, payload=payload , retain=True)

*I didn’t test the format of the payload varaible in Python. It’s been a long time since I did any Python programming so take that as a hint rather than copy this and it will work


#6

I got that format from @ecoqba on Slack. Maybe he can help if you have any other questions.


#7

Thanks for the great JSON syntax. Now all the widgets appear at once, very nice! All the data gets the same timestamp.

Is there any way to set the timestamp used by Cayenne? I understand the Internet speeds can be quick, but my full network is not. For example, timestamped data may get queued up while a modem comes online and connects. I send the data to a time indexed database, and to Cayenne, and sometimes other sites. I need the time values to correspond to those in the data, not when it showed up at Cayenne, so it can be synchronized with the database and other sites.

Maybe a valid “type” could be a timestamp? Or could one of the JSON fields on each channel be “timestamp”?


#8

For everyone trying to use any of the LPWAN technologies and only connecting to the network at periodic times, this can be real problem. Some way to capture the time that the sample was taken would be great.


#9

You can send your own time with extra virtualwrite’s.

Just note the time when you read your sensor, and the delay in internet travel and the variance in delay are avoided. Conceivably they could add a “time” field, just like a “unit” field, which would be better.

Here is some code (arduino code for 8266)

// ~~~~~ declarations ~~~~~
#include <time.h>

int timezone = -6; // -6 for daylight savings, -7 regular mountain
struct tm * timeinfo;
time_t boottime;
time_t now;

// ~~~~~ setup ~~~~~

configTime(timezone * 3600, 0, “pool.ntp.org”, “time.nist.gov”);
Serial.println("\nWaiting for time");
while (!time(nullptr)) {
Serial.print(".");
delay(1000);
}
Serial.println("");
now = time(nullptr);
Serial.println(ctime(&now));
boottime = now;

// ~~~~~ CAYENNE_OUT_DEFAULT ~~~~~
now = time(nullptr);
// Cayenne.virtualWrite(1, now, “UnixTime”, “Seconds”); // not UTC
long seconds = now - boottime;
hours = seconds / 3600.0;
Cayenne.virtualWrite(0, hours, “Uptime”, “Hours”);
time_t now = time(nullptr);
Serial.print(ctime(&now));
timeinfo = localtime (&now);
float timefloat = timeinfo->tm_hour*100 + timeinfo->tm_min + timeinfo->tm_sec/100.0;
Cayenne.virtualWrite(2, timefloat, “Time”, “HHMM.SS”);


Reading Data from Device in every 30 minutes
#10

That will just create a new Cayenne datapoint with time information, and it will be timestamped by Cayenne when it receives the message. I am trying to associate a timestamp with the data being sent, so when it is shown in a chart, the time information on the X axis is the time the data was collected, not the time when Cayenne receives the message.


#11

I agree – not a perfect solution, but … not bad. :grinning:


#12

Im building a Beer Fermentation Chamber Temperature checker and want to timestamp when the last Temperature sent to cayenne. with this Code

#include <Arduino.h>
#include <CountUpDownTimer.h>
#include <time.h>

// This example shows how to connect to Cayenne using an ESP8266 and send/receive sample data.
// Make sure you install the ESP8266 Board Package via the Arduino IDE Board Manager and select the correct ESP8266 board before compiling. 
//#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>

//Countdown Settings
CountUpDownTimer T(DOWN, HIGH); // DOWN / UP

//Timestamp settings
int timezone = 3;
int dst = 0;

const double VCC = 3.3;             // NodeMCU on board 3.3v vcc
const double R2 = 10000;            // 10k ohm series resistor
const double adc_resolution = 1023; // 10-bit adc

const double A = 0.001129148;   // thermistor equation parameters
const double B = 0.000234125;
const double C = 0.0000000876741; 
// WiFi network info.
char ssid[] = "xxx";
char wifiPassword[] = "xxx";

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
char username[] = "xxx";
char password[] = "xxx";
char clientID[] = "xxx";

unsigned long lastMillis = 0;


void setup() {
  Serial.begin(9600);
  Cayenne.begin(username, password, clientID, ssid, wifiPassword);
 
//Countdown settings
   T.SetTimer(0,0,10);  // H-M-S  //start at 1 minute (USE FOR: DOWN ONLY)
// T.SetStopTime(0,0,30); // stop at 10 seconds (USE FOR: UP/DOWN)
  T.StartTimer();
  
configTime(timezone * 3600, dst * 0, "tr.pool.ntp.org", "time.nist.gov");
 Serial.println("\nWaiting for time");
 while (!time(nullptr)) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println("");

}
void loop() {
 Cayenne.loop();
  T.Timer();
  //time stamp settings
  time_t now;
  struct tm * timeinfo;
  time(&now);
  timeinfo = localtime(&now);  

  //Serial.println(timeinfo->tm_hour);
  //Serial.println(timeinfo->tm_min);
  //Serial.println(timeinfo->tm_sec);
  //Serial.println(timeinfo->tm_mday);
  //Serial.println(timeinfo->tm_mon);
  //Serial.println(timeinfo->tm_year);
  
 float timefloat = timeinfo->tm_hour*100 + timeinfo->tm_min + timeinfo->tm_sec/100.0;
 
 double Vout, Rth, temperature, adc_value; 

  adc_value = analogRead(A0);
  Vout = (adc_value * VCC) / adc_resolution;
  Rth = (VCC * R2 / Vout) - R2;

/*  Steinhart-Hart Thermistor Equation:
 *  Temperature in Kelvin = 1 / (A + B[ln(R)] + C[ln(R)]^3)
 *  where A = 0.001129148, B = 0.000234125 and C = 8.76741*10^-8  */
  temperature = (1 / (A + (B * log(Rth)) + (C * pow((log(Rth)),3))));   // Temperature in kelvin

  temperature = temperature - 273.15;

  if (T.TimeHasChanged() ) // this prevents the time from being constantly shown.
  {
//Cayenne.virtualWrite(2, timefloat, "counter", "null");


   Serial.print(T.ShowMinutes());
   Serial.print(" - Timecheck:");
   Serial.println(T.TimeCheck());
    
    // This DOES NOT format the time to 0:0x when seconds is less than 10.
    // if you need to format the time to standard format, use the sprintf() function.
if (T.TimeCheck() > 0) {
   Cayenne.virtualWrite(1, temperature, TYPE_TEMPERATURE, UNIT_CELSIUS);
   Cayenne.virtualWrite(2, timefloat, "Time", "null");
    Serial.println(" - Sıcaklık Girildi ");
    Serial.println(timefloat);
    T.ResetTimer();
}
  }

// 1 minutes 60000
//10 minutes 600000
//30 minutes = 1800000 
//60 minutes 3600000 


} // loop bitis

// Default function for sending sensor data at intervals to Cayenne.
// You can also use functions for specific channels, e.g CAYENNE_OUT(1) for sending channel 1 data.
CAYENNE_OUT_DEFAULT()
{

  // Write data to Cayenne here. This example just sends the current uptime in milliseconds on virtual channel 0.
  Cayenne.virtualWrite(0, millis());
  // Some examples of other functions you can use to send data.
  //Cayenne.celsiusWrite(1, 22.0);
  //Cayenne.luxWrite(2, 700);
  //Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
 
}

Cayenne.virtualWrite(2, timefloat, “Time”, “HHMM.SS”);

gives output like below on dashboard

Is there Any way to Let Cayenne write this data Like 03:32:56

Thanks


#13

As of right now, no. What others have done is create 3 separate widgets (one for hour, one for minute, one for second) that make up the time.