I have a Raspberry Pi running a C++ program and I recently integraded the Linux-Client code to be able to send just three parameters to Thinger.io, but it seems that the value is never updated.
First, I have a global array of Devices (50 elements):
Device devices[50];
The setup code is:
void setup() {
for (static int i = 0; i < 50; i ++) { // can't pass captures to lambda function... so the static (global also valid)
if(!devices[i].name.empty()) {
thing[devices[i].name.c_str()] >> [] (pson &out) {
out["temperature"] = devices[i].getTemperature();
out["humidity"] = devices[i].getHumidity();
out["luminosity"] = devices[i].getLumos();
out["timestamp"] = []() {
struct timeval tp;
gettimeofday(&tp, NULL);
long int ms = tp.tv_sec * 1000 + tp.tv_usec / 1000;
return ms;
}();
};
}
}
}
Then, in a timer event (libev) I’m executing the following code (which works and sends the data, but temperature, luminosity and humidity are set to 0 always):
void sendDeviceData (EV_P_ ev_timer *w, int revents)
{
thing.handle();
LOG_INFO << "Sending data to thinger.io";
for (int i = 0; i < 50; i ++) {
if(!devices[i].name.empty()) {
LOG_INFO << "Device: " << devices[i].name;
LOG_INFO << "Temperature: " << devices[i].temperature;
LOG_INFO << "Humidity: " << devices[i].humidity;
LOG_INFO << "Luminosity: " << devices[i].luminosity;
thing.stream(thing[devices[i].name.c_str()]);
}
}
ev_timer_again(EV_A_ w);
}
The values that I see for each device (devices[i].name.c_str()) in the dashboard are always 0 (the initialization value). The timestamp works as expected because is calculated “in situ”. The device array is updated elsewhere in the code and it works perfectly fine because I can see the values changing in the program’s ouput.
What can be the problem? Surely it has to be with the devices[] array.
Thank you
Well if I use global variables like:
float tem = 0;
float lum = 0;
float hum = 0;
And modify the sendDeviceData() function:
void sendDeviceData(EV_P_ ev_timer *w, int revents)
{
thing.handle();
LOG_INFO << "Sending data to thinger.io";
for (int i = 0; i < 50; i ++) {
if(!devices[i].name.empty()) {
LOG_INFO << "Device: " << devices[i].name;
LOG_INFO << "Temperature: " << devices[i].temperature;
LOG_INFO << "Humidity: " << devices[i].humidity;
LOG_INFO << "Luminosity: " << devices[i].luminosity;
tem = devices[i].temperature;
lum = devices[i].luminosity;
hum = devices[i].humidity;
thing.stream(thing[devices[i].name.c_str()]);
}
}
ev_timer_again(EV_A_ w);
}
It works!! I don’t understand it well, because the devices array is also global… It makes an initial copy of the data and sends every time the same thing instead of updating the values.
1 Like
Hi!, in the setup you posted in your fist approach, the i
is captured in the lambda, but every resource will have the same value when called, as the i will have a final value (50), so you will be always streaming the device 50. Notice that each resource is like defining a callback, and the i is evaluated just when the resource is called (i.e., streamed to the platform). A solution could be something like defining a global i
to be streamed and just use that index when streaming the data. Similar to just copying the values you got. With some little modifications in the library using (std::function instead of function pointers), it is possible to use lambdas capturing values.
Device devices[50];
int deviceToStream = 0;
void setup() {
for (int i = 0; i < 50; i ++) {
if(!devices[i].name.empty()) {
thing[devices[i].name.c_str()] >> [] (pson &out) {
out["temperature"] = devices[deviceToStream].getTemperature();
out["humidity"] = devices[deviceToStream].getHumidity();
out["luminosity"] = devices[deviceToStream].getLumos();
out["timestamp"] = []() {
struct timeval tp;
gettimeofday(&tp, NULL);
long int ms = tp.tv_sec * 1000 + tp.tv_usec / 1000;
return ms;
}();
};
}
}
}
void sendDeviceData(EV_P_ ev_timer *w, int revents)
{
thing.handle();
LOG_INFO << "Sending data to thinger.io";
for (int i = 0; i < 50; i ++) {
if(!devices[i].name.empty()) {
LOG_INFO << "Device: " << devices[i].name;
LOG_INFO << "Temperature: " << devices[i].temperature;
LOG_INFO << "Humidity: " << devices[i].humidity;
LOG_INFO << "Luminosity: " << devices[i].luminosity;
deviceToStream = i;
thing.stream(thing[devices[i].name.c_str()]);
}
}
ev_timer_again(EV_A_ w);
}
Hope that helps!
Hello,
Can you please elaborate a little more on how to modify the library to allow capturing variables in lamba function for resources. I am trying the following:-
thinger_device thing(USER_ID, DEVICE_ID, DEVICE_CREDENTIAL);
BluetoothDevice *waterlevel_sensor = NULL;
BluetoothManager *manager = nullptr;
thing["rssi"] >> [waterlevel_sensor](pson& out){ out = get_rssi_val(waterlevel_sensor); };
try
{
manager = BluetoothManager::get_bluetooth_manager();
}
catch(const std::runtime_error& e)
{
std::cerr << "Error while initializing libtinyb: " << e.what() << std::endl;
exit(1);
}
discover_devices(&waterlevel_sensor, manager);
if (waterlevel_sensor == nullptr)
{
std::cout << "Could not find WaterLevel_sensor "<< std::endl;
return 1;
}