Use Thinger for persistance?

Hi, Alvaro,
could yo please tell me what would your expert way be, to use Thinger for persistance?
I mean being able to have in my device some long-term integration values, that will survive a reboot.
(I have to deal with some bugs the prevents me to use EEPROM locally).

Should-I write them to a bucket and define an endpoint to read the bucket back?
Can it be done easier?
I’d love to get your advice.
Thank you.

Hello @rin67630,

Please take a look to the new device properties feature: https://docs.thinger.io/devices-administration#device-properties

best

I love you Jorge !

:yum:

That is really great!

I’m afraid I have to come back to that topic again:
I tried to follow your instructions but were not successful:

In loop() running every minute I wrote:

pson data;
data[“temperature”] = outdoor_temperature;
data[“humidity”] = outdoor_humidity;
data[“pressure”] = outdoor_pressure;
data[“wind”] = outdoor_wind_speed;
data[“direction”] = outdoor_wind_direction;
data[“summary”] = weather_summary;
data[“last_update”] = SecondOfDay;

thing.set_property(“persistance”, data, true);

That worked well and I could see the values in the device properties.

Then I wrote in setup() the symmetric instructions:

pson data;
outdoor_temperature = data[“temperature”];
outdoor_humidity = data[“humidity”];
outdoor_pressure = data[“pressure”];
outdoor_wind_speed = data[“wind”];
outdoor_wind_direction = data[“direction”];
weather_summary = data[“summary”];
LastUpdate = data[“last_update”];

thing.get_property(“persistance”, data);

a) “weather_summary” is a String and the compiler had thrown an error:

exit status 1
ambiguous overload for ‘operator=’ (operand types are ‘String’ and ‘protoson::pson’)

b) nothing was retrieved: apparently I don’t use the right syntax.???

Could you please write the example in your manual in the same way: from variable to variable?
It would have been easier to learn the syntax that way.
Thank you.

That would make it easier to undersatand.

Hello @rin67630,

great! glad to see this is going forward. I think that the problem with the compiler could be solved by declaring the pson data as global variable.

best

Hi Jorge,
thank you for replying.
The compiler error is just a marginal remark.
I am however stuck at the code to get property which does not work.
The syntax is not clear to me and my code is surely wrong.

Is

pson data;

a declaration that needs to be placed before setup()?

I tried to declare it globally and got

a_Declarations:195:1: error: ‘data’ does not name a type

Could you please provide, (at best in GitHub) a complete working example on how to store and retrieve successfully a couple of variables?

Thank you.

Can I hope for a working example?
I am still stuck and cannot get the properties to be retrieved.
I spend hours trying pretty much everything that would compile, and nothing works…
Thank you.

Hello @rin67630,

Yes, please let me check and write you back. I will also update the documentation to prevent future problems.

Best

Thank you very much.
Currently I have within loop()

pson persistance;
persistance["temperature"]  = outdoor_temperature;
persistance["humidity"]     = outdoor_humidity;
persistance["pressure"]     = outdoor_pressure;
thing.set_property("persistance", persistance, true);

and I would expect to be able to get the info back into my variables upon setup()
That way it did not work:

pson persistance;
thing.get_property(“persistance”, persistance);
outdoor_temperature = persistance[“temperature”];
outdoor_humidity = persistance[“humidity”];
outdoor_pressure = persistance[“pressure”];

nor that way:

pson persistance;
outdoor_temperature = persistance[“temperature”];
outdoor_humidity = persistance[“humidity”];
outdoor_pressure = persistance[“pressure”];
thing.get_property(“persistance”, persistance);

Defining the pson outside loop() or setup() was rejected by the compiler.
I hope you will find a solution.
Thanks again.

hello @rin67630,

don’t know where is the problem, the next code is working properly for me:

#define _DEBUG_
#include <ClimaStick.h>

#define USERNAME " "
#define DEVICE_ID " "
#define DEVICE_CREDENTIAL " "

#define SSID " "
#define SSID_PASSWORD " "

 
ClimaStick thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);

Environmental clima; 
pson data;
int previous_button_status;

   
void setup() {
  thing.add_wifi(SSID, SSID_PASSWORD);
  thing.init_sensors();
  
}


void loop() { 
  thing.handle();


   if((millis()%5000)==0){ // store data each 5 seconds
       clima = thing.get_clima(); //retrieving data from sensors
       
       pson out;
       out["temperature"]=clima.temperature;
       out["humidity"]=clima.humidity;
       
       thing.set_property("environment",out,false);
    }
 
   if(digitalRead(0)==0 && previous_button_status==1){ //if usr button is pressed, print property values 
     
     Serial.println("reading property...");
     
     thing.get_property("environment", data);
     float temp=data["temperature"];
     float hum=data["humidity"];
     
     Serial.print("temp: ");
     Serial.println(temp);
     
  }
       previous_button_status=digitalRead(0);
  
}

I’m sending data to a property each 5s, then, when the usr button is pressed I retrieve data from the property and print it via serial. The instructions has been copied from the docu and it’s working fine ¿what is the difference between this an your requirements?

best

The first difference i notice, is

thing.set_property(“environment”,out,false);

What is the meaning of the last parameter true/false?

The most important difference is that my read procedure is in another scope: setup:().
Will your code work, if the

 thing.get_property("environment", data);
 float temp=data["temperature"];
 float hum=data["humidity"];
 
 Serial.print("temp: ");
 Serial.println(temp);

were located in setup()?
This is the very purpose of a persistence feature: to work across resets.

Regards and thank you for considering.

P.S: I have done the following:
in Setup I wrote:

getPersistance = true;

In loop() I wrote:

if (getPersistance)
{
getPersistance = false;
pson persistance;
thing.get_property(“persistance”, persistance);
outdoor_temperature = persistance[“temperature”];
outdoor_humidity = persistance[“humidity”];
outdoor_pressure = persistance[“pressure”];
}

I can’t explain why, but it seems to work that way, I will be sure after an overnight run.
Anyhow, thing.get_property() should work in setup() with uninitialised variables, before a thing.set_property() has run, as well.

Regards

hy @rin67630,

OK now I understand the problem! you can’t place the set/get property directly into the setup because these features require device connection with Thinger.io server, which will be created in the first loop execution. So to solve this, you can place it into a resource (then will be executed according to server configuration) or implement a clientListener (take a look to this post), but your solution is maybe the best option.

And, the bool attribute is just to obtain property writing confirmation.

best!

So if I have understood well, most (when not all)

thing.xxx();

methods are requiring

thing.handle();

to have run at least once?
that is at least not obvious and should be documented.

So the probably better way to start with is:

ThingerWifi thing(“username”, “deviceId”, “deviceCredential”);

void setup() {
// put here pson definitions e.g:
thing[“battery”] >> (pson & out)
{
out[“mAh”] = battery_mAh;
};

thing.handle();
delay(1000);
// put here interactions with Thinger that must run once a the beginning e.g.
pson persistance;
thing.get_property(“persistance”, persistance);
battery_mAh = persistance[“mAh”];
// put here initial stream methods:
thing.stream(“battery”);
}

void loop() {
thing.handle();
// periodical stuff e.g…
integrate.battery(mAh);
if (SecondOfDay % 3600 == 10)
{
thing.stream(“battery”); // every hour stream the values
pson persistance;
persistance[“mAh”] = battery_mAh ;
thing.set_property(“persistance”, persistance, true);
}
}

By putting the first

thing.handle();

right in the setup(); method, you can start properly and get historical values and begin re-streaming data to Thinger right after a reboot, without need to wait for the next hour to be chimed.

This procedure is required when your sketch is processing long-time integrating values, that must persist behind resets.

1 Like

Hello, I’m interested to this topic, and I have an alternative idea instead of call thing.handle() at setup.

You could use flag for indicating that you want to get some data once at the loop. After the condition was met, set the flag to completed. Microcontroller will not bother that function anymore until reset the microcontroller.

It goes like this:

void loop() {
  thing.handle();
  if (flagGetPersistanceOnce == 0) { // if the MCU is not getting the data for the first time
    pson persistance;
    thing.get_property(“persistance”, persistance);
    battery_mAh = persistance[“mAh”];
    // put here initial stream methods:
    thing.stream(“battery”);
    flagGetPersistanceOnce = 1; // this will make sure MCU will not enter this condition anymore
  }
  .....// some code right here
}

hope it helps the others too. (Apparently, I’m making something that have similar concept with this problem)

ah… I misread the thread… I’m so sorry to everyone.
the OP has made an solution that similar to my alternative.
Sure enough, thing.handle() must be called if we want to interact to Thinger.io server.

But, I could say the code format will be depends to everyone objective then.

Thank you for the understanding XD…