Additional Data Elements with Asset Tracker v2 on nRF9160 DK from SDK 1.8.0

For my project I need to do some local control using I2C devices, ADC, and GPIO. I then need to communicate to the cloud some of the variables from this control. I started development with Asset Tracker v2 in SDK v2.1.0 and was able to modify nrf_cloud_integration.c and sensor_module.c to have dummy data in .humidity .air_pressure .air_quality and .temperature and all were being properly sent and displayed on the nRF Cloud.

Unfortunately, I was never able to get any of the additional peripherals working in v2.x

So, I moved back to SDK v1.8.0 and SES and quickly got the peripherals up and running. I am more comfortable with the development environment and was able to find more examples that worked.

It would seem that this version of Asset Tracker v2 does not have all of the same hooks in it as the version I used previously. Natively it supports sending Temperature and Humidity, but Air Pressure and Air Quality don't seem to be 100% integrated into this version. I've made the following changes, but the additional environmental variables (Air Pressure and Air Quality) are not being sent up to the cloud. Is there a file/change that I'm missing?

asset_tracker_v2\src\modules\sensor_module.c line 212

#else

	/* This event must be sent even though environmental sensors are not
	 * available on the nRF9160DK. This is because the Data module expects
	 * responses from the different modules within a certain amounf of time
	 * after the APP_EVT_DATA_GET event has been emitted.
	 */
	LOG_DBG("No external sensors, submitting dummy sensor data");

	/* Set this entry to false signifying that the event carries no data.
	 * This makes sure that the entry is not stored in the circular buffer.
	 */
	sensor_module_event = new_sensor_module_event();
	sensor_module_event->type = SENSOR_EVT_ENVIRONMENTAL_NOT_SUPPORTED;

// begin change
// put dummy data into the nRF Cloud buckets to display on cards
    static double dummyDouble = 0.5;
    dummyDouble += 1.1;
    static int dummyInt = 0;
    dummyInt++;
	sensor_module_event->data.sensors.timestamp = k_uptime_get() ;
    sensor_module_event->data.sensors.temperature = dummyDouble ;
	sensor_module_event->data.sensors.humidity = dummyDouble ;
	sensor_module_event->data.sensors.pressure = dummyDouble ;
	sensor_module_event->data.sensors.bsec_air_quality = dummyInt ;
	// overwrite SENSOR_EVT_ENVIRONMENTAL_NOT_SUPPORTED; so the data gets sent
	sensor_module_event->type = SENSOR_EVT_ENVIRONMENTAL_DATA_READY;
// end change
#endif

asset_tracker_v2\src\cloud\nrf_cloud_integration.c line 41

	struct nrf_cloud_svc_info_ui ui_info = {
		.gps = true,
		.humidity = true,
		.temperature = true,
		.air_pressure = true,
		.air_quality = true,
		.rsrp = true,
		.button = true
	};

asset_tracker_v2\src\cloud\cloud_codec\cloud_codec.h line 123

struct cloud_data_sensors {
	/** Environmental sensors timestamp. UNIX milliseconds. */
	int64_t env_ts;
	/** Temperature in celcius */
	double temp;
	/** Humidity level in percentage */
	double hum;
// begin changes
    /** Atmospheric pressure in kilopascal. */
	double pressure;
	/** BSEC Air quality in Indoor-Air-Quality (IAQ) index.
	 *  If -1, the value is not provided.
	 */
	int bsec_air_quality;
// end changes
	/** Flag signifying that the data entry is to be encoded. */
	bool queued : 1;
};

asset_tracker_v2\src\cloud\cloud_codec\json_common.c line 275

int json_common_sensor_data_add(cJSON *parent,
				struct cloud_data_sensors *data,
				enum json_common_op_code op,
				const char *object_label,
				cJSON **parent_ref)
{
	int err;

	if (!data->queued) {
		return -ENODATA;
	}

	err = date_time_uptime_to_unix_time_ms(&data->env_ts);
	if (err) {
		LOG_ERR("date_time_uptime_to_unix_time_ms, error: %d", err);
		return err;
	}

	cJSON *sensor_obj = cJSON_CreateObject();
	cJSON *sensor_val_obj = cJSON_CreateObject();

	if (sensor_obj == NULL || sensor_val_obj == NULL) {
		err = -ENOMEM;
		goto exit;
	}

	err = json_add_number(sensor_val_obj, DATA_TEMPERATURE, data->temp);
	if (err) {
		LOG_ERR("Encoding error: %d returned at %s:%d", err, __FILE__, __LINE__);
		goto exit;
	}

	err = json_add_number(sensor_val_obj, DATA_HUMID, data->hum);
	if (err) {
		LOG_ERR("Encoding error: %d returned at %s:%d", err, __FILE__, __LINE__);
		goto exit;
	}
// begin changes
	err = json_add_number(sensor_val_obj, DATA_PRESSURE, data->pressure);
	if (err) {
		LOG_ERR("Encoding error: %d returned at %s:%d", err, __FILE__, __LINE__);
		goto exit;
	}
	/* If air quality is negative, the value is not provided. */
	if (data->bsec_air_quality >= 0) {
		err = json_add_number(sensor_val_obj, DATA_BSEC_IAQ, data->bsec_air_quality);
		if (err) {
			LOG_ERR("Encoding error: %d returned at %s:%d", err, __FILE__, __LINE__);
			goto exit;
		}
	}
// end changes
	json_add_obj(sensor_obj, DATA_VALUE, sensor_val_obj);

	err = json_add_number(sensor_obj, DATA_TIMESTAMP, data->env_ts);
	if (err) {
		LOG_ERR("Encoding error: %d returned at %s:%d", err, __FILE__, __LINE__);
		cJSON_Delete(sensor_obj);
		return err;
	}

	err = op_code_handle(parent, op, object_label, sensor_obj, parent_ref);
	if (err) {
		cJSON_Delete(sensor_obj);
		return err;
	}

	data->queued = false;

	return 0;

exit:
	cJSON_Delete(sensor_obj);
	cJSON_Delete(sensor_val_obj);
	return err;
}

asset_tracker_v2\src\cloud\cloud_codec\nrf_cloud\json_protocol_names_nrf_cloud.h line 20

#define DATA_MODEM_DYNAMIC  "networkInfo"
#define DATA_MODEM_STATIC   "deviceInfo"
#define DATA_BATTERY	    "batteryVoltage"
#define DATA_TEMPERATURE    "temp"
#define DATA_HUMID	    "hum"
#define DATA_PRESSURE       "atmp"          // added
#define DATA_BSEC_IAQ       "bsec_iaq"      // added
#define DATA_ENVIRONMENTALS "env"
#define DATA_BUTTON	    "btn"
#define DATA_CONFIG	    "config"
#define DATA_VERSION	    "version"

#define DATA_GROUP     "messageType"
#define DATA_ID	       "appId"
#define DATA_TYPE      "data"
#define DATA_TIMESTAMP "ts"
#define DATA_VALUE     "data"

#define MESSAGE_TYPE_DATA "DATA"

#define APP_ID_BUTTON	   "BUTTON"
#define APP_ID_GPS	   "GPS"
#define APP_ID_HUMIDITY	   "HUMID"
#define APP_ID_AIR_PRESS   "AIR_PRESS"      // added
#define APP_ID_AIR_QUAL    "AIR_QUAL"       // added
#define APP_ID_TEMPERATURE "TEMP"
#define APP_ID_RSRP	   "RSRP"
#define APP_ID_CELL_POS    "CELL_POS"

asset_tracker_v2\src\cloud\cloud_codec\nrf_cloud\nrf_cloud_codec.c line 147

		case ENVIRONMENTALS: {
			int err, len;
			char humidity[10];
			char temperature[10];
			char pressure[10]; // JDS
			char bsec_air_quality[4]; // JDS
			struct cloud_data_sensors *data = (struct cloud_data_sensors *)buf;

			len = snprintk(humidity, sizeof(humidity), "%.2f", data[i].hum);
			if ((len < 0) || (len >= sizeof(humidity))) {
				LOG_ERR("Cannot convert humidity to string, buffer to small");
				return -ENOMEM;
			}

			len = snprintk(temperature, sizeof(temperature), "%.2f", data[i].temp);
			if ((len < 0) || (len >= sizeof(temperature))) {
				LOG_ERR("Cannot convert temperature to string, buffer to small");
				return -ENOMEM;
			}
// begin change
			len = snprintk(pressure, sizeof(pressure), "%.2f",
				       data[i].pressure);
			if ((len < 0) || (len >= sizeof(pressure))) {
				LOG_ERR("Cannot convert pressure to string, buffer too small");
			}

			if (data[i].bsec_air_quality >= 0) {
				len = snprintk(bsec_air_quality, sizeof(bsec_air_quality), "%d",
					data[i].bsec_air_quality);
				if ((len < 0) || (len >= sizeof(bsec_air_quality))) {
					LOG_ERR("Cannot convert BSEC air quality to string, "
						"buffer too small");
				}

				err = add_data(array, APP_ID_AIR_QUAL, bsec_air_quality,
					       &data[i].env_ts, data[i].queued, NULL);
				if (err && err != -ENODATA) {
					return err;
				}
			}
// end change
			err = add_data(array, APP_ID_HUMIDITY, humidity,
				       &data[i].env_ts, data[i].queued, NULL);
			if (err && err != -ENODATA) {
				return err;
			}

			err =  add_data(array, APP_ID_TEMPERATURE, temperature,
					&data[i].env_ts, data[i].queued, NULL);
			if (err && err != -ENODATA) {
				return err;
			}
// begin change
			err =  add_data(array, APP_ID_AIR_PRESS, pressure,
					&data[i].env_ts, data[i].queued, NULL);
			if (err && err != -ENODATA) {
				return err;
			}
// end change		
			data[i].queued = false;
			break;
		}

asset_tracker_v2\src\events\sensor_module_event.h line 34

struct sensor_module_data {
	int64_t timestamp;
	double temperature;
	double humidity;
// begin change
	double pressure;
	int bsec_air_quality;
// end change
};

asset_tracker_v2\src\modules\data_module.c line 1210

	if (IS_EVENT(msg, sensor, SENSOR_EVT_ENVIRONMENTAL_DATA_READY)) {
		struct cloud_data_sensors new_sensor_data = {
			.temp = msg->module.sensor.data.sensors.temperature,
			.hum = msg->module.sensor.data.sensors.humidity,
			.pressure = msg->module.sensor.data.sensors.pressure,                   // added
			.bsec_air_quality = msg->module.sensor.data.sensors.bsec_air_quality,   // added
			.env_ts = msg->module.sensor.data.sensors.timestamp,
			.queued = true
		};

		cloud_codec_populate_sensor_buffer(sensors_buf,
						   &new_sensor_data,
						   &head_sensor_buf,
						   ARRAY_SIZE(sensors_buf));

		requested_data_status_set(APP_DATA_ENVIRONMENTAL);
	}

With all these changes, I still only get the original Temperature and Humidity sent to the Cloud, which leads me to believe I'm missing a step in how the data goes from sensor_module.c to actually being sent to the cloud. Any help is much appreciated! 

  • Hi,

    Unfortunately, I was never able to get any of the additional peripherals working in v2.x

    What additional peripherals are you having issues with? Instead of using an old version of the SDK, you should rather get the peripherals working.

    Natively it supports sending Temperature and Humidity, but Air Pressure and Air Quality don't seem to be 100% integrated into this version. I've made the following changes, but the additional environmental variables (Air Pressure and Air Quality) are not being sent up to the cloud. Is there a file/change that I'm missing?

    This was first added to Asset Tracker v2 in nRF Connect SDK v1.9.0, ref this release note here: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/releases/release-notes-1.9.0.html#nrf9160-asset-tracker-v2

  • Thank you for your reply Sigurd.

    I didn't remember exactly all the issues I had, and I wanted to be specific in my reply, so yesterday I reinstalled 2.2.0. I setup I2C referencing DevAcademy Lesson 6 inside of a fresh Asset Tracker v2 project aaaaand it just worked... I've got no idea what I did wrong the first time... I do remember kconfig appearing to not always save my changes, so maybe something was messed up with my SDK installation? Anyway, doesn't really matter at this point.

    I've also got the ADC working with the "unoffical example" after adding this to my overlay. 

    &adc {
    	label = "ADC_0";
    };

    Since yesterday, I did have my kconfig 'forget' my changes at least once. Not sure what I did wrong. Is a "Pristine Build" supposed to wipe the kconfig?

Related