15 Commits

Author SHA1 Message Date
adrien balleyguier
78167ceb38 feat(nodes): adding nodes firmware v1.0
Refs: #3
2026-06-04 21:01:42 +02:00
adrien balleyguier
3cdfbef680 fix(nodes): changing window status sensor to have unequipped nodes return 'window is closed' status
Refs: #3
2026-06-04 21:01:42 +02:00
adrien balleyguier
94e0518fa6 fix(nodes): co2 level fetched as desibed in the documentation
The first samples (up to 3) sends co2 level 0xffffffff since the sensor is not ready yet
Refs: #3
2026-06-04 20:59:58 +02:00
adrien balleyguier
f4ac6e91b0 fix(nodes): properly fetching data from temp/hygro sensor
Refs: #3
2026-06-04 20:59:36 +02:00
adrien balleyguier
6fd9959329 fix(nodes): fixing switch device tree and wrong ordering of ble values 2026-06-04 20:59:20 +02:00
adrien balleyguier
35fbe7c488 feat(nodes): adding window status reading 2026-06-04 20:59:20 +02:00
adrien balleyguier
158767deec fix(nodes): adjusting broadcasted data to fit definition
Refs: #3
2026-06-04 20:59:20 +02:00
adrien balleyguier
bce2417ded feat(nodes): adding co2_level retrieval
Refs: #3
2026-06-04 20:59:10 +02:00
adrien balleyguier
53ccda306b feat(nodes): WIP adding first implementation for BLE advertising.
wip: Not tested for now

Refs: #3
2026-06-04 20:58:59 +02:00
adrien balleyguier
71ed4c4bf9 feat(nodes): adding thermometer and hygrometer
Changed sensor value retrieval to return error_code
2026-06-04 20:58:14 +02:00
adrien balleyguier
e1d274470b feat(nodes): WIP supervisor first implementation
wip: untested
2026-06-04 20:58:14 +02:00
adrien balleyguier
f0bc4ee373 feat(nodes) : setting folder construction 2026-06-04 20:47:48 +02:00
adrien balleyguier
f71db42f47 feat(nodes) : adding blinky as starting point for the node implementation 2026-06-04 20:47:48 +02:00
adrien balleyguier
8b9e215cc6 doc(nodes): adding battery to class diagram
linked #63
2026-06-04 15:06:21 +02:00
adrien balleyguier
caee92c595 fix(doc) : changing small mishaps following discussions 2026-06-04 15:06:21 +02:00
21 changed files with 4765 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ class "Window_status" as win{}
class "Hygrometer" as hygro{}
class "Thermometer" as thermo{}
class "CO2_level" as co2{}
class "Battery_level" as batt{}
sup o-d- ble
sup o-u- sens
@@ -22,5 +23,6 @@ sens <|-l- win
sens <|-u- hygro
sens <|-u- thermo
sens <|-r- co2
sens <|-- batt
@enduml

7
nodes/CMakeLists.txt Normal file
View File

@@ -0,0 +1,7 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(plein_de_eeeeeeeeeeee)
target_sources(app PRIVATE src/main.c src/window_status.c src/window_status.h src/thermometer.c src/thermometer.h src/hygrometer.c src/hygrometer.h src/co2_level.c src/co2_level.h src/supervisor.c src/supervisor.h src/ble_advertiser.c src/ble_advertiser.h)

97
nodes/README.rst Normal file
View File

@@ -0,0 +1,97 @@
.. zephyr:code-sample:: blinky
:name: Blinky
:relevant-api: gpio_interface
Blink an LED forever using the GPIO API.
Overview
********
The Blinky sample blinks an LED forever using the :ref:`GPIO API <gpio_api>`.
The source code shows how to:
#. Get a pin specification from the :ref:`devicetree <dt-guide>` as a
:c:struct:`gpio_dt_spec`
#. Configure the GPIO pin as an output
#. Toggle the pin forever
See :zephyr:code-sample:`pwm-blinky` for a similar sample that uses the PWM API instead.
.. _blinky-sample-requirements:
Requirements
************
Your board must:
#. Have an LED connected via a GPIO pin (these are called "User LEDs" on many of
Zephyr's :ref:`boards`).
#. Have the LED configured using the ``led0`` devicetree alias.
Building and Running
********************
Build and flash Blinky as follows, changing ``reel_board`` for your board:
.. zephyr-app-commands::
:zephyr-app: samples/basic/blinky
:board: reel_board
:goals: build flash
:compact:
After flashing, the LED starts to blink and messages with the current LED state
are printed on the console. If a runtime error occurs, the sample exits without
printing to the console.
Build errors
************
You will see a build error at the source code line defining the ``struct
gpio_dt_spec led`` variable if you try to build Blinky for an unsupported
board.
On GCC-based toolchains, the error looks like this:
.. code-block:: none
error: '__device_dts_ord_DT_N_ALIAS_led_P_gpios_IDX_0_PH_ORD' undeclared here (not in a function)
Adding board support
********************
To add support for your board, add something like this to your devicetree:
.. code-block:: DTS
/ {
aliases {
led0 = &myled0;
};
leds {
compatible = "gpio-leds";
myled0: led_0 {
gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
};
};
};
The above sets your board's ``led0`` alias to use pin 13 on GPIO controller
``gpio0``. The pin flags :c:macro:`GPIO_ACTIVE_LOW` mean the LED is on when
the pin is set to its low state, and off when the pin is in its high state.
Tips:
- See :dtcompatible:`gpio-leds` for more information on defining GPIO-based LEDs
in devicetree.
- If you're not sure what to do, check the devicetrees for supported boards which
use the same SoC as your target. See :ref:`get-devicetree-outputs` for details.
- See :zephyr_file:`include/zephyr/dt-bindings/gpio/gpio.h` for the flags you can use
in devicetree.
- If the LED is built in to your board hardware, the alias should be defined in
your :ref:`BOARD.dts file <devicetree-in-out-files>`. Otherwise, you can
define one in a :ref:`devicetree overlay <set-devicetree-overlays>`.

11
nodes/app.overlay Normal file
View File

@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: Apache-2.0 */
/ {
buttons{
compatible = "gpio-keys";
window_switch: window_switch {
gpios = <&sx1509b 0 GPIO_ACTIVE_LOW>;
label = "Window Switch";
};
};
};

3
nodes/prj.conf Normal file
View File

@@ -0,0 +1,3 @@
CONFIG_I2C=y
CONFIG_SENSOR=y
CONFIG_BT=y

4281
nodes/release/nodes_v1.0.hex Normal file

File diff suppressed because it is too large Load Diff

12
nodes/sample.yaml Normal file
View File

@@ -0,0 +1,12 @@
sample:
name: Blinky Sample
tests:
sample.basic.blinky:
tags:
- LED
- gpio
filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds")
depends_on: gpio
harness: led
integration_platforms:
- frdm_k64f

View File

@@ -0,0 +1,67 @@
#include "ble_advertiser.h"
static const int BT_MS_ADV_UP = 500; // [ms] time during which the advertising is active
static const char BT_KEY_WINDOW = 0x01;
static const char BT_KEY_HUMIDITY = 0x02;
static const char BT_KEY_TEMP = 0x03;
static const char BT_KEY_CO2_LVL = 0x04;
// value size [B]
static const char BT_PREAMBLE_SIZE = 2;
static const char BT_VALUE_SIZE_WINDOW = 1;
static const char BT_VALUE_SIZE_HUMIDITY = 1;
static const char BT_VALUE_SIZE_TEMP = 2;
static const char BT_VALUE_SIZE_CO2_LVL = 4;
static const int BT_AD_DATA_INDEX_WINDOW = BT_PREAMBLE_SIZE + 1;
static const int BT_AD_DATA_INDEX_HUMIDITY = BT_AD_DATA_INDEX_WINDOW + 2;
static const int BT_AD_DATA_INDEX_TEMP = BT_AD_DATA_INDEX_HUMIDITY + 2;
static const int BT_AD_DATA_INDEX_CO2_LVL = BT_AD_DATA_INDEX_TEMP + 3;
// sum of all value size + size for all keys
static const char BT_AD_TOTAL_SIZE =
BT_VALUE_SIZE_WINDOW + BT_VALUE_SIZE_HUMIDITY + BT_VALUE_SIZE_TEMP + BT_VALUE_SIZE_CO2_LVL + 4 + 2;
static uint8_t ad_data[] = {
0xff, 0xff,
BT_KEY_WINDOW, 0x00,
BT_KEY_HUMIDITY, 0x00,
BT_KEY_TEMP, 0x00, 0x00,
BT_KEY_CO2_LVL, 0x00, 0x00, 0x00, 0x00
};
static const struct bt_data ad[] = {
BT_DATA(BT_DATA_MANUFACTURER_DATA, ad_data, BT_AD_TOTAL_SIZE),
};
enum error_code ble_init(){
return ((0 == bt_enable(NULL)) ? success : init_failed);
}
enum error_code ble_advertise(
enum window_status window_value,
int hygro_value,
int thermo_value,
int co2_lvl_value
){
enum error_code ret = write_failed;
int shift = 0;
// set values here
ad_data[BT_AD_DATA_INDEX_WINDOW] = (uint8_t)(window_value == open ? 0x1 : 0x0);
ad_data[BT_AD_DATA_INDEX_HUMIDITY] = (uint8_t)(hygro_value & 0xff);
for(int i=0;i<BT_VALUE_SIZE_TEMP;i++){
shift = 8 * (BT_VALUE_SIZE_TEMP - i - 1);
ad_data[BT_AD_DATA_INDEX_TEMP + i] = (uint8_t)((thermo_value>>(shift)) & 0xff);
}
for(int i=0;i<BT_VALUE_SIZE_CO2_LVL;i++){
shift = 8 * (BT_VALUE_SIZE_CO2_LVL - i - 1);
ad_data[BT_AD_DATA_INDEX_CO2_LVL + i] = (uint8_t)((co2_lvl_value>>(shift)) & 0xff);
}
if(0 == bt_le_adv_start(BT_LE_ADV_NCONN, ad, ARRAY_SIZE(ad), NULL, 0)){
k_msleep(BT_MS_ADV_UP);
if(0 == bt_le_adv_stop()){
ret = success;
}else{}
}else{}
return ret;
}

View File

@@ -0,0 +1,19 @@
#ifndef BLE_ADVERTISER_H
#define BLE_ADVERTISER_H
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/assigned_numbers.h>
#include <zephyr/bluetooth/bluetooth.h>
#include "error_code.h"
#include "window_status.h"
enum error_code ble_init();
enum error_code ble_advertise(
enum window_status window_value,
int hygro_value,
int thermo_value,
int co2_lvl_value
);
#endif //BLE_ADVERTISER_H

36
nodes/src/co2_level.c Normal file
View File

@@ -0,0 +1,36 @@
#include "co2_level.h"
static const struct device* dev = DEVICE_DT_GET_ONE(ams_ccs811);
const int CO2_LEVEL_EMPTY_ROOM = 400; // [ppm]
enum error_code co2_lvl_init(){
enum error_code ret = init_failed;
if(device_is_ready(dev)){
ret = success;
}else{}
return ret;
}
enum error_code co2_lvl_get_value(int* holder){
struct sensor_value temp, humidity, co2;
enum error_code ret = read_failed;
int temp_value, humidity_value;
if( (success == thermo_get_value(&temp_value)) && (success == hygro_get_value(&humidity_value)) ){
// temperature conversion from deci, no function in the API
temp.val1 = temp_value/10;
temp.val2 = temp_value%10;
// humidity conversion is straight away
humidity.val1 = humidity_value;
if(
(0 == ccs811_envdata_update(dev, &temp, &humidity)) &&
(0 == sensor_sample_fetch(dev)) &&
(0 == sensor_channel_get(dev, SENSOR_CHAN_CO2, &co2))
){
*holder = co2.val1; // taking only the integer part
ret = success;
}else{}
}else{}
return success;
}

16
nodes/src/co2_level.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef CO2_LEVEL_H
#define CO2_LEVEL_H
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/sensor/ccs811.h>
#include "error_code.h"
#include "hygrometer.h"
#include "thermometer.h"
extern const int CO2_LEVEL_EMPTY_ROOM; // [ppm]
enum error_code co2_lvl_init();
enum error_code co2_lvl_get_value(int* holder);
#endif //CO2_LEVEL_H

15
nodes/src/error_code.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef ERROR_CODE_H
#define ERROR_CODE_H
#include <limits.h>
enum error_code{
success = 0,
init_failed,
read_failed,
write_failed,
error_unknown,
error_code_last, // iteration purpose
};
#endif //ERROR_CODE_H

23
nodes/src/hygrometer.c Normal file
View File

@@ -0,0 +1,23 @@
#include "hygrometer.h"
static const struct device* dev = DEVICE_DT_GET_ONE(st_hts221);
enum error_code hygro_init(){
enum error_code ret = init_failed;
if(device_is_ready(dev)){
ret = success;
}else{}
return ret;
}
enum error_code hygro_get_value(int* holder){
enum error_code ret = read_failed;
struct sensor_value humidity;
if( (sensor_sample_fetch(dev) >= 0) &&
(sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &humidity) >= 0)
){
*holder = humidity.val1; //taking only the integer part
ret = success;
}else{}
return ret;
}

13
nodes/src/hygrometer.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef HYGROMETER_H
#define HYGROMETER_H
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include "error_code.h"
enum error_code hygro_init();
enum error_code hygro_get_value(int* holder);
#endif //HYGROMETER_H

18
nodes/src/main.c Normal file
View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include "supervisor.h"
int main(void){
supervisor_init();
supervisor_run();
// should never come here
return 0;
}

53
nodes/src/supervisor.c Normal file
View File

@@ -0,0 +1,53 @@
#include "supervisor.h"
const int SLEEP_GRANULARITY = 2; // [min]
const int SLEEP_MIN_DURATION = SLEEP_GRANULARITY; // [min]
const int SLEEP_MAX_DURATION = 30; // [min]
enum error_code supervisor_init(){
enum error_code ret = init_failed;
ret = ble_init();
if(success == ret){
ret = co2_lvl_init();
if(success == ret){
ret = hygro_init();
if(success == ret){
ret = thermo_init();
if(success == ret){
ret = window_init();
}else{}
}else{}
}else{}
}else{}
return ret;
}
enum error_code supervisor_run(){
int co2_lvl_value = -1;
int hygro_value = -1;
int thermo_value = -1;
enum window_status window_value = unknown;
enum error_code co2_lvl_status, hygro_status, thermo_status, window_status;
int current_sleep_time = SLEEP_MIN_DURATION;
while(1){
co2_lvl_status = co2_lvl_get_value(&co2_lvl_value);
hygro_status = hygro_get_value(&hygro_value);
thermo_status = thermo_get_value(&thermo_value);
window_status = window_get_value(&window_value);
// maybe change arguments order
// todo : manage special values
ble_advertise(window_value, hygro_value, thermo_value, co2_lvl_value);
if((co2_lvl_value > CO2_LEVEL_EMPTY_ROOM) || (window_value == open)){
// there are people in the room, or someone forgot to close the window
current_sleep_time = SLEEP_MIN_DURATION;
}else{
// no one is in the room, we can wait a liitle bit longer before getting the next data point
current_sleep_time += SLEEP_GRANULARITY;
if(current_sleep_time > SLEEP_MAX_DURATION){
current_sleep_time = SLEEP_MAX_DURATION;
}else{}
}
k_sleep(K_MINUTES(current_sleep_time));
}
return error_unknown; // should never return
}

21
nodes/src/supervisor.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef SUPERVISOR_H
#define SUPERVISOR_H
#include <zephyr/kernel.h>
#include "error_code.h"
#include "ble_advertiser.h"
#include "window_status.h"
#include "thermometer.h"
#include "hygrometer.h"
#include "co2_level.h"
extern const int SLEEP_GRANULARITY; // [min]
extern const int SLEEP_MIN_DURATION; // [min]
extern const int SLEEP_MAX_DURATION; // [min]
enum error_code supervisor_init();
enum error_code supervisor_run();
#endif //SUPERVISOR_H

23
nodes/src/thermometer.c Normal file
View File

@@ -0,0 +1,23 @@
#include "thermometer.h"
static const struct device* dev = DEVICE_DT_GET_ONE(st_hts221);
enum error_code thermo_init(){
enum error_code ret = init_failed;
if(device_is_ready(dev)){
ret = success;
}else{}
return ret;
}
enum error_code thermo_get_value(int* holder){
enum error_code ret = read_failed;
struct sensor_value temp;
if( (sensor_sample_fetch(dev) >= 0) &&
(sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp) >= 0)
){
*holder = sensor_value_to_deci(&temp);
ret = success;
}else{}
return ret;
}

13
nodes/src/thermometer.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef THERMOMETER_H
#define THERMOMETER_H
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include "error_code.h"
enum error_code thermo_init();
enum error_code thermo_get_value(int* holder);
#endif //THERMOMETER_H

17
nodes/src/window_status.c Normal file
View File

@@ -0,0 +1,17 @@
#include "window_status.h"
static const struct gpio_dt_spec window_switch = GPIO_DT_SPEC_GET(DT_NODELABEL(window_switch), gpios);
enum error_code window_init(){
enum error_code ret = init_failed;
if(gpio_is_ready_dt(&window_switch) && gpio_pin_configure_dt(&window_switch, GPIO_INPUT)){
ret = success;
}else{}
return ret;
}
enum error_code window_get_value(enum window_status* holder){
// active high
*holder = (gpio_pin_get_dt(&window_switch) ? closed : open);
return success;
}

18
nodes/src/window_status.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef WINDOW_STATUS_H
#define WINDOW_STATUS_H
#include <zephyr/drivers/gpio.h>
#include "error_code.h"
enum window_status{
closed = 0,
open,
unknown,
windows_status_last, // iteration purpose
};
enum error_code window_init();
enum error_code window_get_value(enum window_status* holder);
#endif //WINDOW_STATUS_