Skip to content

Commit 0b30107

Browse files
committed
modules: sensor: add sensor module with ZBUS communication
- Create dedicated sensor module with SMF state machine - Implement ZBUS-based communication for sensor requests - Add configurable timeouts, retries, and thresholds via Kconfig - Introduce sensor health tracking and recovery mechanisms Refs: #11 Signed-off-by: Natalia Pluta <pluta.natalia.m@gmail.com>
1 parent 13a7e6d commit 0b30107

7 files changed

Lines changed: 1014 additions & 261 deletions

File tree

app/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,10 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
99

1010
project(app LANGUAGES C)
1111

12-
target_sources(app PRIVATE src/main.c)
12+
target_sources(app PRIVATE
13+
src/main.c
14+
src/modules/sensor/sensor_module.c
15+
)
16+
17+
# Add include directories for modules
18+
target_include_directories(app PRIVATE src)

app/Kconfig

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,8 @@ endmenu
1212

1313
menu "Application Configuration"
1414

15-
config CCS811_ENV_COMPENSATION
16-
bool "Enable environmental compensation for CCS811"
17-
default y
18-
depends on CCS811 && BME280
19-
help
20-
Enable updating CCS811 environmental data register with
21-
temperature and humidity values from BME280 sensor.
22-
This improves accuracy of CO2 and VOC measurements by
23-
compensating for environmental conditions.
24-
25-
config CCS811_DEFAULT_TEMPERATURE
26-
int "Fallback temperature for CCS811, Celsius"
27-
default 22
28-
depends on CCS811_ENV_COMPENSATION
29-
help
30-
Default temperature value to use for CCS811 environmental
31-
compensation when BME280 sensor is not available or fails.
32-
33-
config CCS811_DEFAULT_HUMIDITY
34-
int "Fallback humidity for CCS811, %RH"
35-
default 50
36-
depends on CCS811_ENV_COMPENSATION
37-
help
38-
Default humidity value to use for CCS811 environmental
39-
compensation when BME280 sensor is not available or fails.
15+
# Include sensor module configuration
16+
rsource "src/modules/sensor/Kconfig.sensor"
4017

4118
endmenu
4219

app/prj.conf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,12 @@ CONFIG_BME280=y
1313
CONFIG_CCS811=y
1414
CONFIG_CCS811_ENV_COMPENSATION=y
1515
CONFIG_HM330X=y
16+
17+
# Enable ZBUS for inter-module communication
18+
CONFIG_ZBUS=y
19+
20+
# Enable SMF (State Machine Framework)
21+
CONFIG_SMF=y
22+
23+
# Enable sensor module
24+
CONFIG_SENSOR_MODULE=y

app/src/main.c

Lines changed: 44 additions & 235 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
*/
55

66
#include <zephyr/kernel.h>
7-
#include <zephyr/drivers/sensor.h>
8-
#include <zephyr/drivers/i2c.h>
97
#include <zephyr/logging/log.h>
10-
#include <zephyr/drivers/sensor/ccs811.h>
8+
#include <zephyr/zbus/zbus.h>
119

1210
#include <app/drivers/blink.h>
13-
1411
#include <app_version.h>
1512

13+
#include <modules/sensor/sensor_module.h>
14+
1615
LOG_MODULE_REGISTER(main, CONFIG_APP_LOG_LEVEL);
1716

1817
#define BLINK_PERIOD_MS_STEP 100U
@@ -21,54 +20,16 @@ LOG_MODULE_REGISTER(main, CONFIG_APP_LOG_LEVEL);
2120
#define SENSORS_WARMUP_DELAY_MS 5000U
2221
#define SENSOR_READ_INTERVAL_MS 1000U
2322

24-
/* CCS811 environmental compensation configuration */
25-
#define SENSOR_VALUE_TO_MICRO(val) ((val)->val1 * 1000000UL + (val)->val2)
26-
#define CCS811_TEMP_THRESHOLD_MICRO 500000 /* 0.5°C in microseconds */
27-
#define CCS811_HUM_THRESHOLD_MICRO 500000 /* 0.5% RH in microseconds */
23+
/* ZBUS observer for sensor messages */
24+
static void sensor_response_callback(const struct zbus_channel *chan);
25+
ZBUS_LISTENER_DEFINE(sensor_response_listener, sensor_response_callback);
2826

2927
/* Function prototypes */
30-
static int init_sensors(const struct device **bme280, const struct device **ccs811,
31-
const struct device **hm3301, const struct device **blink);
32-
static int read_bme280_data(const struct device *sensor, struct sensor_value *temp,
33-
struct sensor_value *press, struct sensor_value *hum);
34-
static int read_ccs811_data(const struct device *sensor, struct sensor_value *co2,
35-
struct sensor_value *voc);
36-
static int read_hm3301_data(const struct device *sensor, struct sensor_value *pm1,
37-
struct sensor_value *pm25, struct sensor_value *pm10);
38-
39-
#ifdef CONFIG_CCS811_ENV_COMPENSATION
40-
static int update_ccs811_env_data(const struct device *ccs811_sensor,
41-
const struct sensor_value *temp, const struct sensor_value *hum);
42-
static void handle_ccs811_env_compensation(const struct device *ccs811_sensor,
43-
const struct sensor_value *temp,
44-
const struct sensor_value *hum);
45-
static void handle_ccs811_fallback_compensation(const struct device *ccs811_sensor);
46-
#endif
28+
static int init_blink_led(const struct device **blink);
29+
static void log_sensor_data(const struct sensor_msg *msg);
4730

48-
static int init_sensors(const struct device **bme280, const struct device **ccs811,
49-
const struct device **hm3301, const struct device **blink)
31+
static int init_blink_led(const struct device **blink)
5032
{
51-
/* Initialize BME280 sensor */
52-
*bme280 = DEVICE_DT_GET(DT_NODELABEL(bme280));
53-
if (!device_is_ready(*bme280)) {
54-
LOG_ERR("BME280 sensor not ready");
55-
return -ENODEV;
56-
}
57-
58-
/* Initialize CCS811 sensor */
59-
*ccs811 = DEVICE_DT_GET(DT_NODELABEL(ccs811));
60-
if (!device_is_ready(*ccs811)) {
61-
LOG_ERR("CCS811 sensor not ready");
62-
return -ENODEV;
63-
}
64-
65-
/* Initialize HM3301 sensor */
66-
*hm3301 = DEVICE_DT_GET(DT_NODELABEL(hm3301));
67-
if (!device_is_ready(*hm3301)) {
68-
LOG_ERR("HM3301 sensor not ready");
69-
return -ENODEV;
70-
}
71-
7233
*blink = DEVICE_DT_GET(DT_NODELABEL(blink_led));
7334
if (!device_is_ready(*blink)) {
7435
LOG_ERR("Blink LED not ready");
@@ -81,222 +42,70 @@ static int init_sensors(const struct device **bme280, const struct device **ccs8
8142
return ret;
8243
}
8344

84-
LOG_INF("All sensors initialized successfully");
45+
LOG_INF("Blink LED initialized successfully");
8546
return 0;
8647
}
8748

88-
static int read_bme280_data(const struct device *sensor, struct sensor_value *temp,
89-
struct sensor_value *press, struct sensor_value *hum)
49+
static void log_sensor_data(const struct sensor_msg *msg)
9050
{
91-
int ret = sensor_sample_fetch(sensor);
92-
if (ret < 0) {
93-
LOG_ERR("Could not fetch BME280 sample (%d)", ret);
94-
return ret;
95-
}
51+
/* Log BME280 data */
52+
LOG_INF("BME280: Temp: %d.%06d C, Press: %d.%06d kPa, Hum: %d.%06d %%",
53+
msg->temperature.val1, msg->temperature.val2, msg->pressure.val1,
54+
msg->pressure.val2, msg->humidity.val1, msg->humidity.val2);
9655

97-
ret = sensor_channel_get(sensor, SENSOR_CHAN_AMBIENT_TEMP, temp);
98-
if (ret < 0) {
99-
LOG_ERR("Could not get temperature (%d)", ret);
100-
return ret;
101-
}
56+
/* Log CCS811 data */
57+
LOG_INF("CCS811: CO2: %d ppm, VOC: %d ppb", msg->co2.val1, msg->voc.val1);
10258

103-
ret = sensor_channel_get(sensor, SENSOR_CHAN_PRESS, press);
104-
if (ret < 0) {
105-
LOG_ERR("Could not get pressure (%d)", ret);
106-
return ret;
107-
}
59+
/* Log HM3301 data */
60+
LOG_INF("HM3301: PM1.0: %d ug/m3, PM2.5: %d ug/m3, PM10: %d ug/m3", msg->pm1_0.val1,
61+
msg->pm2_5.val1, msg->pm10.val1);
10862

109-
ret = sensor_channel_get(sensor, SENSOR_CHAN_HUMIDITY, hum);
110-
if (ret < 0) {
111-
LOG_ERR("Could not get humidity (%d)", ret);
112-
return ret;
113-
}
114-
115-
return 0;
63+
LOG_INF("Sensor data timestamp: %lld ms", msg->timestamp);
11664
}
11765

118-
static int read_ccs811_data(const struct device *sensor, struct sensor_value *co2,
119-
struct sensor_value *voc)
66+
static void sensor_response_callback(const struct zbus_channel *chan)
12067
{
121-
int ret = sensor_sample_fetch(sensor);
122-
if (ret < 0) {
123-
LOG_ERR("Could not fetch CCS811 sample (%d)", ret);
124-
return ret;
125-
}
126-
127-
ret = sensor_channel_get(sensor, SENSOR_CHAN_CO2, co2);
128-
if (ret < 0) {
129-
LOG_ERR("Could not get CO2 (%d)", ret);
130-
return ret;
131-
}
68+
const struct sensor_msg *msg;
13269

133-
ret = sensor_channel_get(sensor, SENSOR_CHAN_VOC, voc);
134-
if (ret < 0) {
135-
LOG_ERR("Could not get VOC (%d)", ret);
136-
return ret;
137-
}
138-
139-
return 0;
140-
}
141-
142-
static int read_hm3301_data(const struct device *sensor, struct sensor_value *pm1,
143-
struct sensor_value *pm25, struct sensor_value *pm10)
144-
{
145-
int ret = sensor_sample_fetch(sensor);
146-
if (ret < 0) {
147-
LOG_ERR("Could not fetch HM3301 sample (%d)", ret);
148-
return ret;
149-
}
150-
151-
ret = sensor_channel_get(sensor, SENSOR_CHAN_PM_1_0, pm1);
152-
if (ret < 0) {
153-
LOG_ERR("Could not get PM1.0 (%d)", ret);
154-
return ret;
155-
}
156-
157-
ret = sensor_channel_get(sensor, SENSOR_CHAN_PM_2_5, pm25);
158-
if (ret < 0) {
159-
LOG_ERR("Could not get PM2.5 (%d)", ret);
160-
return ret;
161-
}
162-
163-
ret = sensor_channel_get(sensor, SENSOR_CHAN_PM_10, pm10);
164-
if (ret < 0) {
165-
LOG_ERR("Could not get PM10 (%d)", ret);
166-
return ret;
167-
}
168-
169-
return 0;
170-
}
171-
172-
#ifdef CONFIG_CCS811_ENV_COMPENSATION
173-
static int update_ccs811_env_data(const struct device *ccs811_sensor,
174-
const struct sensor_value *temp, const struct sensor_value *hum)
175-
{
176-
/* Previous environmental values for smart updates */
177-
static struct sensor_value prev_temp = {0, 0};
178-
static struct sensor_value prev_hum = {0, 0};
179-
static bool env_data_initialized = false;
180-
181-
bool should_update = false;
182-
183-
/* Check if this is the first update */
184-
if (!env_data_initialized) {
185-
should_update = true;
186-
env_data_initialized = true;
187-
LOG_INF("Initializing CCS811 environmental data");
188-
} else {
189-
/* Check for significant changes (0.5°C or 0.5% RH threshold) */
190-
int32_t temp_diff =
191-
abs(SENSOR_VALUE_TO_MICRO(temp) - SENSOR_VALUE_TO_MICRO(&prev_temp));
192-
int32_t hum_diff =
193-
abs(SENSOR_VALUE_TO_MICRO(hum) - SENSOR_VALUE_TO_MICRO(&prev_hum));
194-
195-
/* Update if temperature or humidity changed beyond thresholds */
196-
if (temp_diff >= CCS811_TEMP_THRESHOLD_MICRO ||
197-
hum_diff >= CCS811_HUM_THRESHOLD_MICRO) {
198-
should_update = true;
199-
LOG_DBG("Environmental change detected - updating CCS811");
70+
if (chan == &sensor_chan) {
71+
msg = &MSG_TO_SENSOR_MSG(zbus_chan_const_msg(chan));
72+
if (msg != NULL && msg->type == SENSOR_SAMPLE_RESPONSE) {
73+
LOG_DBG("Received sensor response");
74+
log_sensor_data(msg);
20075
}
20176
}
202-
203-
if (should_update) {
204-
int ret = ccs811_envdata_update(ccs811_sensor, temp, hum);
205-
if (ret < 0) {
206-
LOG_ERR("Could not update CCS811 environmental data (%d)", ret);
207-
return ret;
208-
}
209-
210-
LOG_INF("CCS811 env data updated: T=%d.%06d°C, H=%d.%06d%%", temp->val1, temp->val2,
211-
hum->val1, hum->val2);
212-
213-
/* Store current values for next comparison */
214-
prev_temp = *temp;
215-
prev_hum = *hum;
216-
}
217-
218-
return 0;
219-
}
220-
221-
static void handle_ccs811_env_compensation(const struct device *ccs811_sensor,
222-
const struct sensor_value *temp,
223-
const struct sensor_value *hum)
224-
{
225-
int env_ret = update_ccs811_env_data(ccs811_sensor, temp, hum);
226-
if (env_ret < 0) {
227-
LOG_ERR("Failed to update CCS811 environmental data");
228-
}
229-
}
230-
231-
static void handle_ccs811_fallback_compensation(const struct device *ccs811_sensor)
232-
{
233-
/* Use default environmental data when BME280 fails */
234-
struct sensor_value default_temp = {.val1 = CONFIG_CCS811_DEFAULT_TEMPERATURE, .val2 = 0};
235-
struct sensor_value default_hum = {.val1 = CONFIG_CCS811_DEFAULT_HUMIDITY, .val2 = 0};
236-
237-
LOG_WRN("Using default environmental data: T=%d°C, H=%d%%RH",
238-
CONFIG_CCS811_DEFAULT_TEMPERATURE, CONFIG_CCS811_DEFAULT_HUMIDITY);
239-
240-
int env_ret = update_ccs811_env_data(ccs811_sensor, &default_temp, &default_hum);
241-
if (env_ret < 0) {
242-
LOG_ERR("Failed to update CCS811 environmental data with defaults");
243-
}
24477
}
245-
#endif /* CONFIG_CCS811_ENV_COMPENSATION */
24678

24779
int main(void)
24880
{
24981
int ret;
250-
const struct device *bme280_sensor, *ccs811_sensor, *hm3301_sensor, *blink;
251-
struct sensor_value temp, press, hum, co2, voc, pm1, pm25, pm10;
82+
const struct device *blink;
25283

25384
LOG_INF("Zephyr Fire Detection System %s", APP_VERSION_STRING);
25485

25586
/* Wait for sensors to stabilize */
25687
k_sleep(K_MSEC(SENSORS_WARMUP_DELAY_MS));
25788

258-
/* Initialize all sensors */
259-
ret = init_sensors(&bme280_sensor, &ccs811_sensor, &hm3301_sensor, &blink);
89+
/* Initialize blink LED */
90+
ret = init_blink_led(&blink);
26091
if (ret < 0) {
261-
LOG_ERR("Sensor initialization failed");
92+
LOG_ERR("Blink LED initialization failed");
26293
return 0;
26394
}
26495

265-
while (1) {
266-
/* Read BME280 data (temperature, pressure, humidity) */
267-
ret = read_bme280_data(bme280_sensor, &temp, &press, &hum);
268-
if (ret == 0) {
269-
LOG_INF("BME280: Temp: %d.%06d C, Press: %d.%06d kPa, Hum: %d.%06d %%",
270-
temp.val1, temp.val2, press.val1, press.val2, hum.val1, hum.val2);
271-
272-
#ifdef CONFIG_CCS811_ENV_COMPENSATION
273-
/* Use BME280 data if reading was successful */
274-
handle_ccs811_env_compensation(ccs811_sensor, &temp, &hum);
275-
#endif /* CONFIG_CCS811_ENV_COMPENSATION */
276-
} else {
277-
LOG_ERR("Failed to read BME280 data");
278-
279-
#ifdef CONFIG_CCS811_ENV_COMPENSATION
280-
/* Use fallback environmental data when BME280 fails */
281-
handle_ccs811_fallback_compensation(ccs811_sensor);
282-
#endif /* CONFIG_CCS811_ENV_COMPENSATION */
283-
}
284-
285-
/* Read CCS811 data (CO2 and VOC) */
286-
ret = read_ccs811_data(ccs811_sensor, &co2, &voc);
287-
if (ret == 0) {
288-
LOG_INF("CCS811: CO2: %d ppm, VOC: %d ppb", co2.val1, voc.val1);
289-
} else {
290-
LOG_ERR("Failed to read CCS811 data");
291-
}
96+
/* Initialize sensor module */
97+
ret = sensor_module_init();
98+
if (ret < 0) {
99+
LOG_ERR("Sensor module initialization failed");
100+
return 0;
101+
}
292102

293-
/* Read HM3301 data (PM1.0, PM2.5, PM10) */
294-
ret = read_hm3301_data(hm3301_sensor, &pm1, &pm25, &pm10);
295-
if (ret == 0) {
296-
LOG_INF("HM3301: PM1.0: %d ug/m3, PM2.5: %d ug/m3, PM10: %d ug/m3",
297-
pm1.val1, pm25.val1, pm10.val1);
298-
} else {
299-
LOG_ERR("Failed to read HM3301 data");
103+
while (1) {
104+
/* Request sensor data */
105+
LOG_DBG("Requesting sensor data");
106+
ret = sensor_module_request_data();
107+
if (ret < 0) {
108+
LOG_ERR("Failed to request sensor data (%d)", ret);
300109
}
301110

302111
k_sleep(K_MSEC(SENSOR_READ_INTERVAL_MS));

0 commit comments

Comments
 (0)