Raspberry Pi code to send some custom parameters

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;
}