Thingy53: use of Bluetooth mesh sensor model

Dear community,

I am working on the Sensor Server bluetooth mesh model that I have implemented on the Thingy53.

Code is based on the existing sensor server sample available in nRF Connect SDK 3.2.99. i.e. github.com/.../

My questions concerns

(1) the sensor data that can be retrieved from the Thingy53 (for instance from bme680 sensor, or other existing sensor?)

(2) the number of sensor data readings that can be achieved with the sensor server model.

****************************************

Résumé of my problem

****************************************

(1) type of Sensor Data

Currently I manage to get the following 4 sensor readings from Thingy53 :

Temperature, Relative Humidity, air Pressure & presence (presence is actually detected not from a sensor, but with a button press). 

However I have difficulty to get the VOC concentration.

And I wonder also how to get readings from the light sensor (this reading does not come with BME680).

(2) Number of Sensor Data

I do not manage to read more than 4 sensor types/channels at a time. If I try to add & read a fifth one, it does not manage.

(1) type of sensor data

************************************************************

The Sensor Server model (sensor_srv) requires a list of bt_mesh_sensor pointers.

Here is the list of 5 sensor instances I am using.

Then each bt_mesh_sensor  is defined as such (example with Temperature), with a type and a get function to read data.

Each sensor type is assigned its own Device Property ID, as specified in the Bluetooth mesh device properties specification. Here bt_mesh_sensor_present_dev_op_temp corresp to the property ID 0x0054.

And each sensor type may consist of one or more channels. Sensor_channel_get() function enables to retrieve the data corresponding to the channel(s) of the sensor type.

The only channel corresponding to the type bt_mesh_sensor_present_dev_op_temp is SENSOR_CHAN_AMBIENT_TEMP

My first Question is about VOC concentration that should be read from bme680. Here is the corresponding table I use between the sensors pointers, the type and the channel attached.

This is working well except for VOC.

In nRF SDK documentation, for gas sensor, I see only two types = {bt_mesh_sensor_present_amb_voc_concentration; bt_mesh_sensor_present_amb_co2_concentration}

To try to get VOC, I am using the first one, i.e. bt_mesh_sensor_present_amb_voc_concentration.

As for channel, I try to use either SENSOR_CHAN_VOC or SENSOR_CHAN_GAS_RES.

The combination bt_mesh_sensor_present_amb_voc_concentration / SENSOR_CHAN_VOC provides me with empty result.

The combination bt_mesh_sensor_present_amb_voc_concentration / SENSOR_CHAN_GAS_RES provides me with FE FF result, which looks strange. No?

(It is worth mentionning that I read FE FF result from 3 different sensor clients, the nRF mesh app, and two others nodes/nRF5280DK programmed with sensor client model).

=> I am interested in knowing how to retrieve correct VOC values.

Also as Temperature, Relative Humidity, VOC relate to BME680 sensor.

=> I am also interested in knowing how to read data from other sensor(s) present on Thingy53? Would it be possible ot read data from the light sensor for instance?

(2) Number of data readings (limited to 4?)

************************************************************

I am surprised also that I manage to read (only) 4 sensors at a time. It means I can defined the sensors[] list with 4 sensors instances maximum.

Here with 5 instances, it will returns only the four first ones.

Would you know any reason for this?

Thank you very much for any tips on these observations !

  • Allright !

    I realize, I might not have been very clear above. Sorry for this.

    I did some more work and think I solve mostly all of it.

    As reminder, with Thingy53 and the use of the BLE MESH server model,

    I want to

    (1) send data of the gas sensor (in bme688 sensor),
    (2) send data regarding the light sensor (ie. BH1749)
    (3) send (if possible) more than 4 sensors instances at a time

    (1) data of the gas sensor (bme688 sensor).

    To retrieve gas sensor data I use sensor_channel_get(dev, SENSOR_CHAN_GAS_RES, rsp), where SENSOR_CHAN_GAS_RES is Gas sensor resistance in ohms.

    I used to retrieve erroneous data of gas (0xFEFF), because I was using bt_mesh_sensor_type bt_mesh_sensor_present_amb_voc_concentration, which is only encoded as 16 bit unsigned scalar.

    By using a 32 bit usigned scalar encoded bt_mesh_sensor_type (for instance bt_mesh_sensor_air_pressure) it works better, and now retrieve a result 0x07B300D6 (129171670), which sounds coherent with results displayed here https://www.hackster.io/mahmood-ul-hassan/how-to-read-nordic-thingy-53-onboard-bme688-sensor-003560.

    (It sounds coherent, but however value keeps constant, whatever the heavy smoking clouds I send to the sensor, but okay...)

    // BE 688 sensor
    #if DT_NODE_HAS_STATUS(DT_NODELABEL(bme680), okay)
    /** Thingy53 */
    #define SENSOR_NODE DT_NODELABEL(bme680)
    static const struct device *dev = DEVICE_DT_GET(SENSOR_NODE);
    
    // array of sensors instances
    static struct bt_mesh_sensor *const sensors[] = {
    	&chip_temp,
    	&humidity,
    	&color,
    	&gas,
    };
    
    // gas instance
    static struct bt_mesh_sensor gas = {
        .type = &bt_mesh_sensor_air_pressure,
        .get = gas_get,
    };
    
    static int gas_get(struct bt_mesh_sensor_srv *srv,
    			 struct bt_mesh_sensor *sensor,
    			 struct bt_mesh_msg_ctx *ctx,
    			 struct sensor_value *rsp)
    {
    	int err;
    	
    	sensor_sample_fetch(dev);
    	
    	err = sensor_channel_get(dev, SENSOR_CHAN_GAS_RES, rsp); // Get a reading from a sensor device. 
    	printk("G: %d.%06d\n", rsp->val1, rsp->val2);
    	
    	if (err) {
    		printk("Error getting gas sensor data (%d)\n", err);
    	}
    	
    	return err;
    }

    Two questions still stand:

    How to convert this value into VOC & eCO2 equivalent values ?

    I see the post  How to convert the gas resistance of bme680 sensor to IAQ in thingy53 , hope that this is feasible.

    It looks like no bt_mesh_sensor_type is yet available to manage correctly the gas resistance data, or did I miss something?

    (2) send data regarding the light sensor (ie. BH1749)

    Thanks to Nordic Academy course on SDK fundamentals (lesson6) & https://www.hackster.io/mahmood-ul-hassan/how-to-read-nordic-thingy-53-onboard-bh1749-light-sensor-bc591f, I manage now to get IR data that is of interest to me.

    I use the bt_mesh_sensor_type bt_mesh_sensor_present_amb_light_level (3 bytes).

    I still am interested in knowing why for the BME680 sensor, we can use sensor_channel_get(), but not for the bh1749 sensor, which requires I2C functions.

    #define BH1749_SYSTEM_CONTROL                           0x40
    #define BH1749_MODE_CONTROL1                            0x41
    #define BH1749_MODE_CONTROL2                            0x42
    #define BH1749_RED_DATA_LSB                             0x50
    #define BH1749_IR_DATA_LSB                             	0x58
    #define BH1749_MODE_CONTROL2_RGB_EN_ENABLE              BIT(4)
    #define BH1749_MODE_CONTROL1_DEFAULTS                   0x2A
    
    #define BH_NODE DT_NODELABEL(bh1749)
    static const struct i2c_dt_spec bh_i2c = I2C_DT_SPEC_GET(BH_NODE);
    
    uint8_t init_bh1749(void)
    {
    	int ret;
    
    	if (!device_is_ready(bh_i2c.bus)) {
    		printk("I2C bus %s is not ready!\n\r",bh_i2c.bus->name);
    		return 0;
    	}
    	printk("device is %p, name is %s\n", bh_i2c.bus, bh_i2c.bus->name); 
    
    	char buff1[] = {BH1749_MODE_CONTROL1,BH1749_MODE_CONTROL1_DEFAULTS};
    	ret = i2c_write_dt(&bh_i2c,buff1,sizeof(buff1));
    	if(ret != 0){
    		printk("1- Failed to write to I2C device address 0x%c at Reg. 0x%c\n",bh_i2c.addr,BH1749_MODE_CONTROL1);
    	}
    	
    	char buff2[] = {BH1749_MODE_CONTROL2,BH1749_MODE_CONTROL2_RGB_EN_ENABLE};
    	ret = i2c_write_dt(&bh_i2c,buff2,sizeof(buff2));
    	if(ret != 0){
    		printk("2- Failed to write to I2C device address 0x%c at Reg. 0x%c\n",bh_i2c.addr,BH1749_MODE_CONTROL2);
    	}
    	return 1;
    }
    
    static int color_get(struct bt_mesh_sensor_srv *srv,
    			 struct bt_mesh_sensor *sensor,
    			 struct bt_mesh_msg_ctx *ctx,
    			 struct sensor_value *rsp)
    {
    	int err;
    	uint8_t ir_value[10]= {0};
    	err = i2c_burst_read_dt(&bh_i2c, 0x50, ir_value, sizeof(ir_value));
    	rsp->val1 = ir_value[8] | ir_value[9] << 8;
    	rsp->val2 = 0;
    	printk("val1 %ld\n", rsp->val1);
    	printk("val2 %ld\n", rsp->val2);
    
    	if (err) {
    		printk("Error getting color sensor data (%d)\n", err);
    	}
    
    	return err;
    }
    
    static struct bt_mesh_sensor color = {
    	.type = &bt_mesh_sensor_present_amb_light_level, // 0x0076(118)) This property represents relative humidity measured by a humidity sensor. .
    	.get = color_get,
    };

    (3) send (if possible) more than 4 sensors instances at a time

    It is clear now

    #define BT_MESH_SENSOR_SRV_INIT(_sensors, _count)                              \
        {                                                                      \
            .sensor_array = _sensors,                                      \
            .sensor_count =                                                \
                MIN(CONFIG_BT_MESH_SENSOR_SRV_SENSORS_MAX, _count),    \
        }
    CONFIG_BT_MESH_SENSOR_SRV_SENSORS_MAX is 4, meaning no more than 4 sensor instances by Sensor server. I have built a second instance of server model, implemented on a second element in the node. That has solved my issue.
  • Hi BesbarJB,

    My apology for the late follow-up. My team is facing high loading due to some unavailability. Unless someone from the community had already helped you then, one our support engineer will be with you next week.

    Thank you for your patience.

    Hieu

  • Hi Hieu, 

    No worries, getting help (according to your timing) is already very precious.

    Good luck and speak to you soon! 

  • Hi BesbarJB,To my understanding, you have the following two questions left:

    BesbarJB said:
    It looks like no bt_mesh_sensor_type is yet available to manage correctly the gas resistance data, or did I miss something?

    I don't think you missed anything. I will send a feedback to our development team, as bt_mesh_sensor_type is a nRF library. However, I don't know when they can get to it.

    BesbarJB said:
    I still am interested in knowing why for the BME680 sensor, we can use sensor_channel_get(), but not for the bh1749 sensor, which requires I2C functions.

    I see that the API is implemented for the BH1749 driver here: https://github.com/nrfconnect/sdk-nrf/blob/v2.3.0/drivers/sensor/bh1749/bh1749.c#L102-L139.

    Do you have any trouble using the API?

    Once again, my apology for the late follow-up. Thank you very much for the patience.

    Hieu

  • Dear Hieu, thanks a lot.

    1. Regarding BH1749 driver, I have added CONFIG_BH1749=y in prj.conf - [looks like a rookie mistake, but I am a rookie Slight smile]. Now sensor_channel_get() is also working for bh1749.

    #include <zephyr/drivers/sensor.h>
    
    #define BH_NODE DT_NODELABEL(bh1749)
    static const struct device *bh1749rgbDev = DEVICE_DT_GET(BH_NODE);
    
    uint8_t init_bh1749(void)
    {
    	if (!device_is_ready(bh1749rgbDev)) 
    	{
    		printk("Sensor device not ready\n");
    	}
    	return 1;
    }
    
    static int color_get(struct bt_mesh_sensor_srv *srv,
    			 struct bt_mesh_sensor *sensor,
    			 struct bt_mesh_msg_ctx *ctx,
    			 struct sensor_value *rsp)
    {
    	sensor_sample_fetch(bh1749rgbDev);
    
    	int err = sensor_channel_get(bh1749rgbDev, SENSOR_CHAN_IR, rsp);
    	printk("IR: %d.%06d\n", rsp->val1, rsp->val2);
    	if (err) 
    	{
    		printk("sensor_channel_get failed err %d\n", err);
    	}
    }
    
    static struct bt_mesh_sensor color = {
    	//https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/libraries/bluetooth_services/mesh/sensor_types.html#ambient-temperature-sensor-types
    	.type = &bt_mesh_sensor_present_amb_light_level, // 0x0078(120) This property represents the light level as measured by a light sensor measuring illuminance (Lux).
    	.get = color_get,
    };
    
    

    2. Regarding bme680 gas data. Indeed if the Nordic Developer team could integrate a bt_mesh_sensor_type that would be appropriate to correctly retrieve VOC and eCO2 data, that would be excellent.

    I am already using Thingy52 as a BLE sensor in my network with all environmental data available incl. VOC and eCO2.

    And now I can use Thingy53 as a BLE MESH sensor, but I miss only VOC and eCO2 data.

    Last but not least, just a very minor suggestion, the Thingy53 sample Mesh_sensor_server v2.3.0 could actually be updated with possibly two sensors server model instances, that would allow retrieving full data from both sensors (bme680 and bh1749), as well as battery level => so that users may have a Thingy52 equivalent set of data sensor, but in mesh protocol.

    Anyway this is what I wanted to do, and thanks to your genuine help, I've managed.

    Thanks Nordic teams !

Related