Merge pull request #81 from rbaron/zigbee-sample
Introduce an experimental/educactional/exploratory Zigbee firmware sample
This commit is contained in:
commit
54792ce35f
32 changed files with 808 additions and 24 deletions
7
.github/actions/build/build.sh
vendored
7
.github/actions/build/build.sh
vendored
|
|
@ -7,8 +7,15 @@ REVISION=$3
|
|||
CMAKE_EXTRA=$4
|
||||
OUTPUT_BIN=$5
|
||||
|
||||
TODAY=$(date +'%Y-%m-%d')
|
||||
|
||||
# Replaces occurrences of "__TODAY__" with $TODAY in $CMAKE_EXTRA.
|
||||
CMAKE_EXTRA="${CMAKE_EXTRA/__TODAY__/"$TODAY"}"
|
||||
|
||||
cd "${GITHUB_WORKSPACE}/${SAMPLE_DIR}"
|
||||
|
||||
echo $CMAKE_EXTRA
|
||||
|
||||
west build --build-dir ./build --pristine --board "${BOARD}@${REVISION}" -- $CMAKE_EXTRA
|
||||
|
||||
mv build/zephyr/zephyr.hex build/zephyr/"${OUTPUT_BIN}"
|
||||
10
.github/workflows/b-parasite.yml
vendored
10
.github/workflows/b-parasite.yml
vendored
|
|
@ -17,6 +17,7 @@ jobs:
|
|||
uses: jidicula/clang-format-action@v4.9.0
|
||||
with:
|
||||
check-path: 'code/nrf-connect'
|
||||
exclude-regex: '\/build\/'
|
||||
- name: Build blinky
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
|
|
@ -71,4 +72,11 @@ jobs:
|
|||
with:
|
||||
sample-dir: code/nrf-connect/samples/ble
|
||||
board: bparasite_nrf52833
|
||||
output-bin: ble_nrf52833_default.hex
|
||||
output-bin: ble_nrf52833_default.hex
|
||||
- name: Build zigbee_nrf528340_default.hex
|
||||
uses: ./.github/actions/build_and_upload
|
||||
with:
|
||||
sample-dir: code/nrf-connect/samples/zigbee
|
||||
board: bparasite_nrf52840
|
||||
output-bin: zigbee_nrf52840_default.hex
|
||||
cmake-extra: -DPRST_ZB_BUILD_DATE=__TODAY__
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ This repository also hosts a few different firmware samples for b-parasite.
|
|||
|Sample|Description|Extra Documentation|
|
||||
|---|---|---|
|
||||
|[samples/ble](./code/nrf-connect/samples/ble)|This is the most battle-tested and useful firmware. It periodically reads all sensors and broadcast them via Bluetooth Low Energy (BLE). It works with [Home Assistant](https://www.home-assistant.io/) out of the box. |[Docs](./code/nrf-connect/samples/ble/README.md)|
|
||||
|[samples/zigbee](./code/nrf-connect/samples/zigbee)| An experimental/educational/exploratory basic Zigbee sample built on [nRF Connect + ZBOSS](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/ug_zigbee.html). It integrates with [Home Assistant](https://www.home-assistant.io/) via [ZHA](https://www.home-assistant.io/integrations/zha) or [Zigbee2MQTT](https://www.zigbee2mqtt.io/). |[Docs](./code/nrf-connect/samples/zigbee/README.md)|
|
||||
|[samples/blinky](./code/nrf-connect/samples/blinky)| The classic "Hello, world" |-|
|
||||
|[samples/soil_read_loop](./code/nrf-connect/samples/soil_read_loop)| Read the soil moisture sensor on a loop. Useful for experimenting and calibrating the sensor. |-|
|
||||
|
||||
|
|
|
|||
3
code/nrf-connect/prstlib/Kconfig
Normal file
3
code/nrf-connect/prstlib/Kconfig
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module = PRSTLIB
|
||||
module-str = prstlib
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
|
@ -6,4 +6,4 @@ config BOARD_ENABLE_DCDC
|
|||
select SOC_DCDC_NRF52X
|
||||
default y
|
||||
|
||||
endif # BOARD_BPARASITE_NRF52833
|
||||
endif # BOARD_BPARASITE_NRF52833
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ config BOARD_ENABLE_DCDC_HV
|
|||
select SOC_DCDC_NRF52X_HV
|
||||
default y
|
||||
|
||||
endif # BOARD_BPARASITE_NRF52840
|
||||
endif # BOARD_BPARASITE_NRF52840
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ typedef struct {
|
|||
float voltage;
|
||||
} prst_adc_read_t;
|
||||
|
||||
typedef struct {
|
||||
prst_adc_read_t adc_read;
|
||||
float percentage;
|
||||
} prst_batt_t;
|
||||
|
||||
typedef struct {
|
||||
prst_adc_read_t adc_read;
|
||||
// A value from 0 (completely dry) to 2^10 (completely wet).
|
||||
|
|
@ -25,7 +30,7 @@ typedef struct prst_adc_photo_sensor {
|
|||
|
||||
int prst_adc_init();
|
||||
|
||||
int prst_adc_batt_read(prst_adc_read_t* out);
|
||||
int prst_adc_batt_read(prst_batt_t* out);
|
||||
|
||||
int prst_adc_soil_read(float battery_voltage, prst_adc_soil_moisture_t* out);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
typedef struct {
|
||||
prst_adc_soil_moisture_t soil;
|
||||
prst_adc_photo_sensor_t photo;
|
||||
prst_adc_read_t batt;
|
||||
prst_batt_t batt;
|
||||
prst_shtc3_read_t shtc3;
|
||||
} prst_sensors_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "prstlib/macros.h"
|
||||
|
||||
LOG_MODULE_REGISTER(adc, LOG_LEVEL_WRN);
|
||||
LOG_MODULE_REGISTER(adc, CONFIG_PRSTLIB_LOG_LEVEL);
|
||||
|
||||
// PWM spec for square wave. Input to the soil sensing circuit.
|
||||
static const struct pwm_dt_spec soil_pwm_dt =
|
||||
|
|
@ -48,6 +48,37 @@ struct gpio_dt_spec ldr_enable_dt =
|
|||
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// High (h) and low (p) voltage (v) and % (p) points.
|
||||
float vh, vl, ph, pl;
|
||||
} batt_disch_linear_section_t;
|
||||
|
||||
static void set_battery_percent(const prst_adc_read_t* read, prst_batt_t* out) {
|
||||
// Must be sorted by .vh.
|
||||
static const batt_disch_linear_section_t sections[] = {
|
||||
{.vh = 3.00f, .vl = 2.90f, .ph = 1.00f, .pl = 0.42f},
|
||||
{.vh = 2.90f, .vl = 2.74f, .ph = 0.42f, .pl = 0.18f},
|
||||
{.vh = 2.74f, .vl = 2.44f, .ph = 0.18f, .pl = 0.06f},
|
||||
{.vh = 2.44f, .vl = 2.01f, .ph = 0.06f, .pl = 0.00f},
|
||||
};
|
||||
|
||||
const float v = read->voltage;
|
||||
|
||||
if (v > sections[0].vh) {
|
||||
out->percentage = 1.0f;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < ARRAY_SIZE(sections); i++) {
|
||||
const batt_disch_linear_section_t* s = §ions[i];
|
||||
if (v > s->vl) {
|
||||
out->percentage = s->pl + (v - s->vl) * ((s->ph - s->pl) / (s->vh - s->vl));
|
||||
return;
|
||||
}
|
||||
}
|
||||
out->percentage = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
static inline float get_soil_moisture_percent(float battery_voltage,
|
||||
int16_t raw_adc_output) {
|
||||
const double x = battery_voltage;
|
||||
|
|
@ -93,8 +124,9 @@ int prst_adc_init() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int prst_adc_batt_read(prst_adc_read_t* out) {
|
||||
RET_IF_ERR(read_adc_spec(&adc_batt_spec, out));
|
||||
int prst_adc_batt_read(prst_batt_t* out) {
|
||||
RET_IF_ERR(read_adc_spec(&adc_batt_spec, &out->adc_read));
|
||||
set_battery_percent(&out->adc_read, out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#include "prstlib/led.h"
|
||||
#include "prstlib/macros.h"
|
||||
|
||||
LOG_MODULE_REGISTER(button, LOG_LEVEL_WRN);
|
||||
LOG_MODULE_REGISTER(button, CONFIG_PRSTLIB_LOG_LEVEL);
|
||||
|
||||
static struct gpio_dt_spec button =
|
||||
GPIO_DT_SPEC_GET(DT_NODELABEL(button0), gpios);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "prstlib/macros.h"
|
||||
|
||||
LOG_MODULE_REGISTER(led, LOG_LEVEL_WRN);
|
||||
LOG_MODULE_REGISTER(led, CONFIG_PRSTLIB_LOG_LEVEL);
|
||||
|
||||
struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_NODELABEL(led0), gpios);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,21 +6,22 @@
|
|||
#include "prstlib/led.h"
|
||||
#include "prstlib/macros.h"
|
||||
|
||||
LOG_MODULE_REGISTER(sensors, LOG_LEVEL_WRN);
|
||||
LOG_MODULE_REGISTER(sensors, CONFIG_PRSTLIB_LOG_LEVEL);
|
||||
|
||||
int prst_sensors_read_all(prst_sensors_t *sensors) {
|
||||
RET_IF_ERR(prst_adc_batt_read(&sensors->batt));
|
||||
RET_IF_ERR(prst_adc_soil_read(sensors->batt.voltage, &sensors->soil));
|
||||
RET_IF_ERR(prst_adc_photo_read(sensors->batt.voltage, &sensors->photo));
|
||||
RET_IF_ERR(prst_adc_soil_read(sensors->batt.adc_read.voltage, &sensors->soil));
|
||||
RET_IF_ERR(prst_adc_photo_read(sensors->batt.adc_read.voltage, &sensors->photo));
|
||||
RET_IF_ERR(prst_shtc3_read(&sensors->shtc3))
|
||||
|
||||
LOG_DBG("Batt: %d mV", sensors->batt.millivolts);
|
||||
LOG_DBG("Soil: %.0f %% (%.3f mV)", 100 * sensors->soil.percentage,
|
||||
sensors->soil.adc_read.voltage);
|
||||
LOG_DBG("Photo: %u lx (%.3f mV)", sensors->photo.brightness,
|
||||
sensors->soil.adc_read.voltage);
|
||||
LOG_DBG("Batt: %d mV (%.2f%%)", sensors->batt.adc_read.millivolts,
|
||||
100 * sensors->batt.percentage);
|
||||
LOG_DBG("Soil: %.0f %% (%d mV)", 100 * sensors->soil.percentage,
|
||||
sensors->soil.adc_read.millivolts);
|
||||
LOG_DBG("Photo: %u lx (%d mV)", sensors->photo.brightness,
|
||||
sensors->soil.adc_read.millivolts);
|
||||
LOG_DBG("Temp: %f oC", sensors->shtc3.temp_c);
|
||||
LOG_DBG("Humi: %.0f %%", 100.0 * sensors->shtc3.rel_humi);
|
||||
LOG_DBG("Humi: %.0f %%", 100 * sensors->shtc3.rel_humi);
|
||||
LOG_DBG("--------------------------------------------------");
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "prstlib/macros.h"
|
||||
|
||||
LOG_MODULE_REGISTER(shtc3, LOG_LEVEL_WRN);
|
||||
LOG_MODULE_REGISTER(shtc3, CONFIG_PRSTLIB_LOG_LEVEL);
|
||||
|
||||
static const struct i2c_dt_spec shtc3 = I2C_DT_SPEC_GET(DT_NODELABEL(shtc3));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
source "Kconfig.zephyr"
|
||||
rsource "../../prstlib/Kconfig"
|
||||
|
||||
config PRST_SLEEP_DURATION_SEC
|
||||
int "Sleep duration in seconds"
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ int prst_ble_encode_service_data(const prst_sensors_t* sensors,
|
|||
// 4 bits for a small wrap-around counter for deduplicating messages on the
|
||||
// receiver.
|
||||
// out[3] = sensors->run_counter & 0x0f;
|
||||
out[4] = sensors->batt.millivolts >> 8;
|
||||
out[5] = sensors->batt.millivolts & 0xff;
|
||||
out[4] = sensors->batt.adc_read.millivolts >> 8;
|
||||
out[5] = sensors->batt.adc_read.millivolts & 0xff;
|
||||
int16_t temp_centicelsius = 100 * sensors->shtc3.temp_c;
|
||||
out[6] = temp_centicelsius >> 8;
|
||||
out[7] = temp_centicelsius & 0xff;
|
||||
|
|
@ -82,7 +82,7 @@ int prst_ble_encode_service_data(const prst_sensors_t* sensors,
|
|||
// Type - voltage.
|
||||
out[15] = 0x0c;
|
||||
// Value. Factor of 0.001.
|
||||
uint16_t batt_val = sensors->batt.millivolts;
|
||||
uint16_t batt_val = sensors->batt.adc_read.millivolts;
|
||||
out[16] = batt_val & 0xff;
|
||||
out[17] = batt_val >> 8;
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ int prst_ble_encode_service_data(const prst_sensors_t* sensors,
|
|||
// Battery voltage.
|
||||
out[13] = 0x0c;
|
||||
// Value. Factor of 0.001.
|
||||
uint16_t batt_val = sensors->batt.millivolts;
|
||||
uint16_t batt_val = sensors->batt.adc_read.millivolts;
|
||||
out[14] = batt_val & 0xff;
|
||||
out[15] = batt_val >> 8;
|
||||
// Soil moisture.
|
||||
|
|
|
|||
2
code/nrf-connect/samples/soil_read_loop/Kconfig
Normal file
2
code/nrf-connect/samples/soil_read_loop/Kconfig
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
source "Kconfig.zephyr"
|
||||
rsource "../../prstlib/Kconfig"
|
||||
2
code/nrf-connect/samples/zigbee/.gitignore
vendored
Normal file
2
code/nrf-connect/samples/zigbee/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
build
|
||||
build_*
|
||||
21
code/nrf-connect/samples/zigbee/CMakeLists.txt
Normal file
21
code/nrf-connect/samples/zigbee/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
# Pull in the dts/ and boards/ from prstlib.
|
||||
set(DTS_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../prstlib)
|
||||
set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../prstlib)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
|
||||
project("b-parasite Zigbee sample")
|
||||
|
||||
include_directories(src)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
src/prst_zb_attrs.c
|
||||
src/prst_zb_soil_moisture_defs.c
|
||||
)
|
||||
|
||||
add_subdirectory(../../prstlib prstlib)
|
||||
target_include_directories(app PRIVATE ../../prstlib/include)
|
||||
target_link_libraries(app PUBLIC prstlib)
|
||||
22
code/nrf-connect/samples/zigbee/Kconfig
Normal file
22
code/nrf-connect/samples/zigbee/Kconfig
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
source "Kconfig.zephyr"
|
||||
rsource "../../prstlib/Kconfig"
|
||||
|
||||
config PRST_ZB_SLEEP_DURATION_SEC
|
||||
int "Sleep duration between waking up and reading sensors in seconds."
|
||||
default 600
|
||||
|
||||
config PRST_ZB_PARENT_POLL_INTERVAL_SEC
|
||||
int "Interval for when b-parasite polls its parent for data in seconds."
|
||||
default 60
|
||||
|
||||
config PRST_ZB_BUILD_DATE
|
||||
string "Zigbee basic cluster build date attribute. Max 16 bytes."
|
||||
default ""
|
||||
|
||||
config PRST_ZB_MODEL_ID
|
||||
string "Zigbee basic cluster model id attribute. Max 32 bytes."
|
||||
default "b-parasite"
|
||||
|
||||
config PRST_ZB_HARDWARE_VERSION
|
||||
int "Zigbee basic cluster hardware version attribute. 1 byte."
|
||||
default 2
|
||||
46
code/nrf-connect/samples/zigbee/README.md
Normal file
46
code/nrf-connect/samples/zigbee/README.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Zigbee firmware sample
|
||||
This sample is adapted from the [zigbee_template](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/samples/zigbee/template/README.html) from the nRF Connect SDK. It's a basic experimental/educational/exploratory firmware sample for b-parasite.
|
||||
|
||||
## Clusters
|
||||
These [clusters](https://en.wikipedia.org/wiki/Zigbee#Cluster_library) are defined in the sample:
|
||||
|
||||
|Cluster ID|Name|
|
||||
|--------|---|
|
||||
|0x0001|Power Configuration|
|
||||
|0x0400|Illuminance Measurement|
|
||||
|0x0402|Temperature Measurement|
|
||||
|0x0405|Relative Humidity Measurement|
|
||||
|0x0408|Soil Moisture Measurement|
|
||||
|
||||
## Pairing Mode
|
||||
The sample will first boot and start looking for a Zigbee coordinator - in pairing mode. The onboard LED will be flashing once a second while in this mode. Once a suitable network is found, the LED will briefly flash 3 times and remain off.
|
||||
|
||||
### Factory Reset
|
||||
Most Zigbee devices provide a physical button to "factory reset" it - causing it to forget its joined network and look for a new one.
|
||||
|
||||
b-parasite has no physical buttons, and the implemented work around is to distinguish between two *reset modes*:
|
||||
#### Power up mode
|
||||
The device enters this mode when it is powered. For example, swapping an old battery or connecting to eternal power. This is the "usual" reset mode, and joined networks will be remembered.
|
||||
|
||||
#### Reset pin mode
|
||||
If the device's RESET pin is briefly grounded, the device will effectively be **factory reset**. The device will leave its previous network and start looking for a new one.
|
||||
|
||||
## Configs
|
||||
Available options in `Kconfig`. Notable options:
|
||||
* `CONFIG_PRST_ZB_SLEEP_DURATION_SEC`: amount of time (in seconds) the device sleeps between reading all sensors and updating its clusters
|
||||
* `CONFIG_PRST_ZB_PARENT_POLL_INTERVAL_SEC`: amount of time (in seconds) the device waits between polling its parent for data
|
||||
|
||||
## Home Assistant Integration
|
||||
This firmware sample has only been tested with Home Assistant, using one of the following integrations.
|
||||
|
||||
### Zigbee Home Automation (ZHA)
|
||||
With the [ZHA](https://www.home-assistant.io/integrations/zha) Home Assistant integration, b-parasite should work out of the box.
|
||||
|
||||
### Zigbee2MQTT & Home Assistant
|
||||
With [Zigbee2MQTT](https://zigbee2mqtt.io/), a custom converter is required. The [b-parasite.js](b-parasite.js) file contains such a converter. See [Support new devices](https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html) for instructions.
|
||||
|
||||
## Battery Life
|
||||
While sleeping, the device consumes around 2 uA:
|
||||

|
||||
In the active cycle, it averages around 125 uA for 1 second:
|
||||

|
||||
47
code/nrf-connect/samples/zigbee/b-parasite.js
Normal file
47
code/nrf-connect/samples/zigbee/b-parasite.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// This is a zigbee2mqtt zigbee2mqtt.io converter for this sample.
|
||||
// See https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html
|
||||
// on how to use it.
|
||||
|
||||
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
|
||||
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
|
||||
const exposes = require('zigbee-herdsman-converters/lib/exposes');
|
||||
const reporting = require('zigbee-herdsman-converters/lib/reporting');
|
||||
const extend = require('zigbee-herdsman-converters/lib/extend');
|
||||
const e = exposes.presets;
|
||||
const ea = exposes.access;
|
||||
|
||||
const definition = {
|
||||
zigbeeModel: ['b-parasite'],
|
||||
model: 'b-parasite',
|
||||
vendor: 'b-parasite',
|
||||
description: 'IoT development board - Zigbee sample',
|
||||
fromZigbee: [fz.temperature, fz.humidity, fz.battery, fz.soil_moisture, fz.illuminance],
|
||||
toZigbee: [],
|
||||
exposes: [
|
||||
e.temperature(),
|
||||
e.humidity(),
|
||||
e.battery(),
|
||||
e.soil_moisture(),
|
||||
e.illuminance_lux()],
|
||||
configure: async (device, coordinatorEndpoint, logger) => {
|
||||
const endpoint = device.getEndpoint(10);
|
||||
await reporting.bind(
|
||||
endpoint,
|
||||
coordinatorEndpoint, [
|
||||
'genPowerCfg',
|
||||
'msTemperatureMeasurement',
|
||||
'msRelativeHumidity',
|
||||
'msSoilMoisture',
|
||||
'msIlluminanceMeasurement',
|
||||
]);
|
||||
await reporting.batteryPercentageRemaining(endpoint);
|
||||
// Not reportable :(
|
||||
// await reporting.batteryVoltage(endpoint);
|
||||
await reporting.temperature(endpoint);
|
||||
await reporting.humidity(endpoint);
|
||||
await reporting.soil_moisture(endpoint);
|
||||
await reporting.illuminance(endpoint);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = definition;
|
||||
BIN
code/nrf-connect/samples/zigbee/media/power-profile/active.png
Normal file
BIN
code/nrf-connect/samples/zigbee/media/power-profile/active.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
BIN
code/nrf-connect/samples/zigbee/media/power-profile/sleeping.png
Normal file
BIN
code/nrf-connect/samples/zigbee/media/power-profile/sleeping.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
43
code/nrf-connect/samples/zigbee/prj.conf
Normal file
43
code/nrf-connect/samples/zigbee/prj.conf
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_ADC=y
|
||||
CONFIG_GPIO=y
|
||||
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_DEVICE=y
|
||||
|
||||
CONFIG_NEWLIB_LIBC=y
|
||||
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
|
||||
|
||||
CONFIG_SERIAL=n
|
||||
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=2048
|
||||
CONFIG_MAIN_THREAD_PRIORITY=7
|
||||
|
||||
CONFIG_ZIGBEE=y
|
||||
CONFIG_ZIGBEE_APP_UTILS=y
|
||||
CONFIG_ZIGBEE_ROLE_END_DEVICE=y
|
||||
|
||||
# This example requires more workqueue stack
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
|
||||
|
||||
# Enable nRF ECB driver
|
||||
CONFIG_CRYPTO=y
|
||||
CONFIG_CRYPTO_NRF_ECB=y
|
||||
CONFIG_CRYPTO_INIT_PRIORITY=80
|
||||
|
||||
# Networking
|
||||
CONFIG_NET_IPV6_MLD=n
|
||||
CONFIG_NET_IPV6_NBR_CACHE=n
|
||||
CONFIG_NET_IPV6_RA_RDNSS=n
|
||||
CONFIG_NET_IP_ADDR_CHECK=n
|
||||
CONFIG_NET_UDP=n
|
||||
|
||||
# Get Zigbee to scan every channel.
|
||||
CONFIG_ZIGBEE_CHANNEL_SELECTION_MODE_MULTI=y
|
||||
|
||||
# Enable API for powering down unused RAM parts.
|
||||
# https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.7.1/nrf/ug_zigbee_configuring.html#power-saving-during-sleep
|
||||
CONFIG_RAM_POWER_DOWN_LIBRARY=y
|
||||
49
code/nrf-connect/samples/zigbee/prj_debug.conf
Normal file
49
code/nrf-connect/samples/zigbee/prj_debug.conf
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_ADC=y
|
||||
CONFIG_GPIO=y
|
||||
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_DEVICE=y
|
||||
|
||||
CONFIG_NEWLIB_LIBC=y
|
||||
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
|
||||
|
||||
CONFIG_SERIAL=n
|
||||
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=2048
|
||||
CONFIG_MAIN_THREAD_PRIORITY=7
|
||||
|
||||
CONFIG_ZIGBEE=y
|
||||
CONFIG_ZIGBEE_APP_UTILS=y
|
||||
CONFIG_ZIGBEE_ROLE_END_DEVICE=y
|
||||
|
||||
# This example requires more workqueue stack
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
|
||||
|
||||
# Enable nRF ECB driver
|
||||
CONFIG_CRYPTO=y
|
||||
CONFIG_CRYPTO_NRF_ECB=y
|
||||
CONFIG_CRYPTO_INIT_PRIORITY=80
|
||||
|
||||
# Networking
|
||||
CONFIG_NET_IPV6_MLD=n
|
||||
CONFIG_NET_IPV6_NBR_CACHE=n
|
||||
CONFIG_NET_IPV6_RA_RDNSS=n
|
||||
CONFIG_NET_IP_ADDR_CHECK=n
|
||||
CONFIG_NET_UDP=n
|
||||
|
||||
# Get Zigbee to scan every channel.
|
||||
CONFIG_ZIGBEE_CHANNEL_SELECTION_MODE_MULTI=y
|
||||
|
||||
# Enable API for powering down unused RAM parts.
|
||||
# https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.7.1/nrf/ug_zigbee_configuring.html#power-saving-during-sleep
|
||||
CONFIG_RAM_POWER_DOWN_LIBRARY=y
|
||||
|
||||
# Config options in Kconfig.
|
||||
CONFIG_PRST_ZB_SLEEP_DURATION_SEC=10
|
||||
|
||||
CONFIG_LOG_DEFAULT_LEVEL=4
|
||||
CONFIG_PRSTLIB_LOG_LEVEL_DBG=y
|
||||
232
code/nrf-connect/samples/zigbee/src/main.c
Normal file
232
code/nrf-connect/samples/zigbee/src/main.c
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
#include <dk_buttons_and_leds.h>
|
||||
#include <hal/nrf_power.h>
|
||||
#include <math.h>
|
||||
#include <prstlib/adc.h>
|
||||
#include <prstlib/button.h>
|
||||
#include <prstlib/led.h>
|
||||
#include <prstlib/macros.h>
|
||||
#include <prstlib/sensors.h>
|
||||
#include <prstlib/shtc3.h>
|
||||
#include <ram_pwrdn.h>
|
||||
#include <zb_nrf_platform.h>
|
||||
#include <zboss_api.h>
|
||||
#include <zboss_api_addons.h>
|
||||
#include <zcl/zb_zcl_power_config.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zigbee/zigbee_app_utils.h>
|
||||
#include <zigbee/zigbee_error_handler.h>
|
||||
|
||||
#include "prst_zb_attrs.h"
|
||||
#include "prst_zb_endpoint_defs.h"
|
||||
#include "prst_zb_soil_moisture_defs.h"
|
||||
|
||||
#define FACTORY_RESET_BUTTON DK_BTN4_MSK
|
||||
|
||||
LOG_MODULE_REGISTER(app, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
static struct zb_device_ctx dev_ctx;
|
||||
|
||||
static prst_sensors_t sensors;
|
||||
|
||||
static void maybe_erase_pairing_info(struct k_timer *timer) {
|
||||
uint32_t reset_reason = nrf_power_resetreas_get(NRF_POWER);
|
||||
// If we're resetting via the RESET pin (e.g.: reset pin shorting, firmware flashing).
|
||||
if (reset_reason & 0x1) {
|
||||
LOG_WRN("Manual reset / re-flashing detected - erasing pairing info");
|
||||
// TODO: consider zb_bdb_reset_via_local_action(/*param=*/0);
|
||||
zigbee_erase_persistent_storage(/*erase=*/true);
|
||||
} else { // It's a power-on cycle (e.g.: swapping battery, first boot).
|
||||
LOG_INF("Power-on cycle - keeping pairing info");
|
||||
}
|
||||
}
|
||||
|
||||
static void led_flashing_cb(struct k_timer *timer) {
|
||||
prst_led_toggle();
|
||||
}
|
||||
|
||||
K_TIMER_DEFINE(led_flashing_timer, led_flashing_cb, /*stop_fn=*/NULL);
|
||||
|
||||
ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(
|
||||
identify_attr_list,
|
||||
&dev_ctx.identify_attr.identify_time);
|
||||
|
||||
ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(
|
||||
basic_attr_list,
|
||||
&dev_ctx.basic_attr.zcl_version,
|
||||
&dev_ctx.basic_attr.app_version,
|
||||
&dev_ctx.basic_attr.stack_version,
|
||||
&dev_ctx.basic_attr.hw_version,
|
||||
&dev_ctx.basic_attr.mf_name,
|
||||
&dev_ctx.basic_attr.model_id,
|
||||
&dev_ctx.basic_attr.date_code,
|
||||
&dev_ctx.basic_attr.power_source,
|
||||
&dev_ctx.basic_attr.location_id,
|
||||
&dev_ctx.basic_attr.ph_env,
|
||||
&dev_ctx.basic_attr.sw_ver);
|
||||
|
||||
ZB_ZCL_DECLARE_TEMP_MEASUREMENT_ATTRIB_LIST(temp_measurement_attr_list,
|
||||
&dev_ctx.temp_measure_attrs.measure_value,
|
||||
&dev_ctx.temp_measure_attrs.min_measure_value,
|
||||
&dev_ctx.temp_measure_attrs.max_measure_value,
|
||||
&dev_ctx.temp_measure_attrs.tolerance);
|
||||
|
||||
ZB_ZCL_DECLARE_REL_HUMIDITY_MEASUREMENT_ATTRIB_LIST(
|
||||
rel_humi_attr_list,
|
||||
&dev_ctx.rel_humidity_attrs.rel_humidity,
|
||||
&dev_ctx.rel_humidity_attrs.min_val,
|
||||
&dev_ctx.rel_humidity_attrs.max_val);
|
||||
|
||||
// https://devzone.nordicsemi.com/f/nordic-q-a/85315/zboss-declare-power-config-attribute-list-for-battery-bat_num
|
||||
#define bat_num
|
||||
ZB_ZCL_DECLARE_POWER_CONFIG_BATTERY_ATTRIB_LIST_EXT(
|
||||
batt_attr_list,
|
||||
&dev_ctx.batt_attrs.voltage,
|
||||
/*battery_size=*/ZB_ZCL_POWER_CONFIG_BATTERY_SIZE_OTHER,
|
||||
/*battery_quantity=*/1,
|
||||
/*battery_rated_voltage=*/NULL,
|
||||
/*battery_alarm_mask=*/NULL,
|
||||
/*battery_voltage_min_threshold=*/NULL,
|
||||
/*battery_percentage_remaining=*/&dev_ctx.batt_attrs.percentage,
|
||||
/*battery_voltage_threshold1=*/NULL,
|
||||
/*battery_voltage_threshold2=*/NULL,
|
||||
/*battery_voltage_threshold3=*/NULL,
|
||||
/*battery_percentage_min_threshold=*/NULL,
|
||||
/*battery_percentage_threshold1=*/NULL,
|
||||
/*battery_percentage_threshold2=*/NULL,
|
||||
/*battery_percentage_threshold3=*/NULL,
|
||||
/*battery_alarm_state=*/NULL);
|
||||
|
||||
PRST_ZB_ZCL_DECLARE_SOIL_MOISTURE_ATTRIB_LIST(
|
||||
soil_moisture_attr_list,
|
||||
&dev_ctx.soil_moisture_attrs.percentage);
|
||||
|
||||
ZB_ZCL_DECLARE_ILLUMINANCE_MEASUREMENT_ATTRIB_LIST(
|
||||
illuminance_attr_list,
|
||||
/*value=*/&dev_ctx.illuminance_attrs.log_lux,
|
||||
/*min_value=*/NULL,
|
||||
/*max_value*/ NULL);
|
||||
|
||||
PRST_ZB_DECLARE_CLUSTER_LIST(
|
||||
app_template_clusters,
|
||||
basic_attr_list,
|
||||
identify_attr_list,
|
||||
temp_measurement_attr_list,
|
||||
rel_humi_attr_list,
|
||||
batt_attr_list,
|
||||
soil_moisture_attr_list,
|
||||
illuminance_attr_list);
|
||||
|
||||
PRST_ZB_DECLARE_ENDPOINT(
|
||||
app_template_ep,
|
||||
PRST_ZIGBEE_ENDPOINT,
|
||||
app_template_clusters);
|
||||
|
||||
ZBOSS_DECLARE_DEVICE_CTX_1_EP(
|
||||
app_template_ctx,
|
||||
app_template_ep);
|
||||
|
||||
void zboss_signal_handler(zb_bufid_t bufid) {
|
||||
// See zigbee_default_signal_handler() for all available signals.
|
||||
zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, /*sg_p=*/NULL);
|
||||
zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);
|
||||
switch (sig) {
|
||||
case ZB_BDB_SIGNAL_STEERING: // New network.
|
||||
case ZB_BDB_SIGNAL_DEVICE_REBOOT: { // Previously joined network.
|
||||
LOG_DBG("Steering complete. Status: %d", status);
|
||||
prst_led_flash(/*times=*/3);
|
||||
if (status == RET_OK) {
|
||||
k_timer_stop(&led_flashing_timer);
|
||||
prst_led_off();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ZB_ZDO_SIGNAL_SKIP_STARTUP:
|
||||
case ZB_ZDO_SIGNAL_LEAVE: {
|
||||
LOG_DBG("Will restart flashing");
|
||||
k_timer_start(&led_flashing_timer, K_NO_WAIT, K_SECONDS(1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
|
||||
if (bufid) {
|
||||
zb_buf_free(bufid);
|
||||
}
|
||||
}
|
||||
|
||||
void update_sensors_cb(zb_uint8_t arg) {
|
||||
LOG_INF("Updating sensors");
|
||||
|
||||
if (prst_sensors_read_all(&sensors)) {
|
||||
LOG_ERR("Unable to read sensors");
|
||||
return;
|
||||
}
|
||||
|
||||
// Battery voltage in units of 100 mV.
|
||||
uint8_t batt_voltage = sensors.batt.adc_read.millivolts / 100;
|
||||
prst_zb_set_attr_value(ZB_ZCL_CLUSTER_ID_POWER_CONFIG,
|
||||
ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID,
|
||||
&batt_voltage);
|
||||
|
||||
// Battery percentage in units of 0.5%.
|
||||
zb_uint8_t batt_percentage = 2 * 100 * sensors.batt.percentage;
|
||||
prst_zb_set_attr_value(ZB_ZCL_CLUSTER_ID_POWER_CONFIG,
|
||||
ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID,
|
||||
&batt_percentage);
|
||||
|
||||
// Temperature in units of 0.01 degrees Celcius.
|
||||
zb_int16_t temperature_value = 100 * sensors.shtc3.temp_c;
|
||||
prst_zb_set_attr_value(ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT,
|
||||
ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID,
|
||||
&temperature_value);
|
||||
|
||||
// Relative humidity in units of 0.01%.
|
||||
zb_int16_t rel_humi = 100 * 100 * sensors.shtc3.rel_humi;
|
||||
prst_zb_set_attr_value(ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT,
|
||||
ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID,
|
||||
&rel_humi);
|
||||
|
||||
// Soil moisture in units of 0.01%.
|
||||
zb_int16_t soil_moisture = 100 * 100 * sensors.soil.percentage;
|
||||
prst_zb_set_attr_value(PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_CLUSTER_ID,
|
||||
PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_VALUE_ID,
|
||||
&soil_moisture);
|
||||
|
||||
// Illuminance in 10000 * log_10(lux) + 1.
|
||||
zb_int16_t log_lux = 10000 * log10((float)sensors.photo.brightness) + 1;
|
||||
prst_zb_set_attr_value(ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT,
|
||||
ZB_ZCL_ATTR_ILLUMINANCE_MEASUREMENT_MEASURED_VALUE_ID,
|
||||
&log_lux);
|
||||
|
||||
ZB_SCHEDULE_APP_ALARM(update_sensors_cb,
|
||||
/*param=*/0,
|
||||
ZB_TIME_ONE_SECOND * CONFIG_PRST_ZB_SLEEP_DURATION_SEC);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
RET_IF_ERR(prst_adc_init());
|
||||
RET_IF_ERR(prst_led_init());
|
||||
RET_IF_ERR(prst_button_init());
|
||||
|
||||
maybe_erase_pairing_info(NULL);
|
||||
|
||||
register_factory_reset_button(FACTORY_RESET_BUTTON);
|
||||
|
||||
prst_zb_attrs_init(&dev_ctx);
|
||||
|
||||
ZB_AF_REGISTER_DEVICE_CTX(&app_template_ctx);
|
||||
|
||||
update_sensors_cb(/*arg=*/0);
|
||||
|
||||
zb_zdo_pim_set_long_poll_interval(
|
||||
ZB_TIME_ONE_SECOND * CONFIG_PRST_ZB_PARENT_POLL_INTERVAL_SEC);
|
||||
power_down_unused_ram();
|
||||
|
||||
RET_IF_ERR(prst_led_flash(2));
|
||||
|
||||
zigbee_enable();
|
||||
zigbee_configure_sleepy_behavior(/*enable=*/true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
38
code/nrf-connect/samples/zigbee/src/prst_zb_attrs.c
Normal file
38
code/nrf-connect/samples/zigbee/src/prst_zb_attrs.c
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#include "prst_zb_attrs.h"
|
||||
|
||||
#include <zboss_api_addons.h>
|
||||
|
||||
#include "prst_zb_endpoint_defs.h"
|
||||
|
||||
void prst_zb_attrs_init(struct zb_device_ctx *dev_ctx) {
|
||||
dev_ctx->basic_attr.zcl_version = ZB_ZCL_VERSION;
|
||||
dev_ctx->basic_attr.power_source = ZB_ZCL_BASIC_POWER_SOURCE_BATTERY;
|
||||
ZB_ZCL_SET_STRING_VAL(
|
||||
dev_ctx->basic_attr.mf_name,
|
||||
PRST_BASIC_MANUF_NAME,
|
||||
ZB_ZCL_STRING_CONST_SIZE(PRST_BASIC_MANUF_NAME));
|
||||
|
||||
ZB_ZCL_SET_STRING_VAL(
|
||||
dev_ctx->basic_attr.model_id,
|
||||
CONFIG_PRST_ZB_MODEL_ID,
|
||||
ZB_ZCL_STRING_CONST_SIZE(CONFIG_PRST_ZB_MODEL_ID));
|
||||
|
||||
ZB_ZCL_SET_STRING_VAL(
|
||||
dev_ctx->basic_attr.date_code,
|
||||
CONFIG_PRST_ZB_BUILD_DATE,
|
||||
ZB_ZCL_STRING_CONST_SIZE(CONFIG_PRST_ZB_BUILD_DATE));
|
||||
|
||||
dev_ctx->basic_attr.hw_version = CONFIG_PRST_ZB_HARDWARE_VERSION;
|
||||
|
||||
dev_ctx->identify_attr.identify_time =
|
||||
ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;
|
||||
}
|
||||
|
||||
zb_zcl_status_t prst_zb_set_attr_value(zb_uint16_t cluster_id, zb_uint16_t attr_id, void *data) {
|
||||
return zb_zcl_set_attr_val(PRST_ZIGBEE_ENDPOINT,
|
||||
cluster_id,
|
||||
ZB_ZCL_CLUSTER_SERVER_ROLE,
|
||||
attr_id,
|
||||
(zb_uint8_t *)data,
|
||||
ZB_FALSE);
|
||||
}
|
||||
50
code/nrf-connect/samples/zigbee/src/prst_zb_attrs.h
Normal file
50
code/nrf-connect/samples/zigbee/src/prst_zb_attrs.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef _PRST_ZB_ATTRS_H_
|
||||
#define _PRST_ZB_ATTRS_H_
|
||||
|
||||
#include <zboss_api_addons.h>
|
||||
|
||||
// Relative humimdity cluster - section 4.7.2.2.1.
|
||||
typedef struct {
|
||||
// 100x relative humidity (mandatory).
|
||||
zb_uint16_t rel_humidity;
|
||||
// 0x0000 – 0x270f (mandatory).
|
||||
zb_uint16_t min_val;
|
||||
// 0x0001 – 0x2710 (mandatory).
|
||||
zb_uint16_t max_val;
|
||||
} prst_rel_humidity_attrs_t;
|
||||
|
||||
// Power configuration cluster - section 3.3.2.2.3.
|
||||
typedef struct {
|
||||
// Units of 100 mV. 0x00 - 0xff (optional, not reportable :()).
|
||||
zb_uint8_t voltage;
|
||||
// Units of 0.5%. 0x00 (0%) - 0xc8 (100%) (optional, reportable).
|
||||
zb_uint8_t percentage;
|
||||
} prst_batt_attrs_t;
|
||||
|
||||
// Soil moisture cluster.
|
||||
typedef struct {
|
||||
// 0-100, units of 0.01?
|
||||
zb_uint16_t percentage;
|
||||
} prst_soil_moisture_attrs_t;
|
||||
|
||||
// Illuminance cluster - section 4.2.2.2.
|
||||
typedef struct {
|
||||
// 10000 * log_10(lux) + 1.
|
||||
zb_uint16_t log_lux;
|
||||
} prst_illuminancce_attrs_t;
|
||||
|
||||
struct zb_device_ctx {
|
||||
zb_zcl_basic_attrs_ext_t basic_attr;
|
||||
zb_zcl_identify_attrs_t identify_attr;
|
||||
zb_zcl_temp_measurement_attrs_t temp_measure_attrs;
|
||||
prst_rel_humidity_attrs_t rel_humidity_attrs;
|
||||
prst_batt_attrs_t batt_attrs;
|
||||
prst_soil_moisture_attrs_t soil_moisture_attrs;
|
||||
prst_illuminancce_attrs_t illuminance_attrs;
|
||||
};
|
||||
|
||||
void prst_zb_attrs_init(struct zb_device_ctx *dev_ctx);
|
||||
|
||||
zb_zcl_status_t prst_zb_set_attr_value(zb_uint16_t cluster_id, zb_uint16_t attr_id, void *data);
|
||||
|
||||
#endif // _PRST_ZB_ATTRS_H_
|
||||
103
code/nrf-connect/samples/zigbee/src/prst_zb_endpoint_defs.h
Normal file
103
code/nrf-connect/samples/zigbee/src/prst_zb_endpoint_defs.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#ifndef _PRST_ZB_H_
|
||||
#define _PRST_ZB_H_
|
||||
|
||||
#include "prst_zb_soil_moisture_defs.h"
|
||||
|
||||
#define PRST_ZIGBEE_ENDPOINT 10
|
||||
#define PRST_BASIC_MANUF_NAME "b-parasite"
|
||||
|
||||
#define PRST_ZB_DEVICE_ID 0x0008
|
||||
#define PRST_ZB_DEVICE_VERSION 0
|
||||
#define PRST_ZB_IN_CLUSTER_NUM 7
|
||||
#define PRST_ZB_OUT_CLUSTER_NUM 0
|
||||
#define PRST_ZB_CLUSTER_NUM (PRST_ZB_IN_CLUSTER_NUM + PRST_ZB_OUT_CLUSTER_NUM)
|
||||
#define PRST_ZB_ATTR_REPORTING_COUNT 5
|
||||
|
||||
#define PRST_ZB_DECLARE_CLUSTER_LIST( \
|
||||
cluster_list_name, \
|
||||
basic_attr_list, \
|
||||
identify_attr_list, \
|
||||
temp_measurement_attr_list, \
|
||||
rel_humidity_attr_list, \
|
||||
batt_att_list, \
|
||||
soil_moisture_attr_list, \
|
||||
illuminance_attr_list) \
|
||||
zb_zcl_cluster_desc_t cluster_list_name[] = \
|
||||
{ \
|
||||
ZB_ZCL_CLUSTER_DESC( \
|
||||
ZB_ZCL_CLUSTER_ID_IDENTIFY, \
|
||||
ZB_ZCL_ARRAY_SIZE(identify_attr_list, zb_zcl_attr_t), \
|
||||
(identify_attr_list), \
|
||||
ZB_ZCL_CLUSTER_SERVER_ROLE, \
|
||||
ZB_ZCL_MANUF_CODE_INVALID), \
|
||||
ZB_ZCL_CLUSTER_DESC( \
|
||||
ZB_ZCL_CLUSTER_ID_BASIC, \
|
||||
ZB_ZCL_ARRAY_SIZE(basic_attr_list, zb_zcl_attr_t), \
|
||||
(basic_attr_list), \
|
||||
ZB_ZCL_CLUSTER_SERVER_ROLE, \
|
||||
ZB_ZCL_MANUF_CODE_INVALID), \
|
||||
ZB_ZCL_CLUSTER_DESC( \
|
||||
ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, \
|
||||
ZB_ZCL_ARRAY_SIZE(temp_measurement_attr_list, zb_zcl_attr_t), \
|
||||
(temp_measurement_attr_list), \
|
||||
ZB_ZCL_CLUSTER_SERVER_ROLE, \
|
||||
ZB_ZCL_MANUF_CODE_INVALID), \
|
||||
ZB_ZCL_CLUSTER_DESC( \
|
||||
ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT, \
|
||||
ZB_ZCL_ARRAY_SIZE(rel_humidity_attr_list, zb_zcl_attr_t), \
|
||||
(rel_humi_attr_list), \
|
||||
ZB_ZCL_CLUSTER_SERVER_ROLE, \
|
||||
ZB_ZCL_MANUF_CODE_INVALID), \
|
||||
ZB_ZCL_CLUSTER_DESC( \
|
||||
PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_CLUSTER_ID, \
|
||||
ZB_ZCL_ARRAY_SIZE(soil_moisture_attr_list, zb_zcl_attr_t), \
|
||||
(soil_moisture_attr_list), \
|
||||
ZB_ZCL_CLUSTER_SERVER_ROLE, \
|
||||
ZB_ZCL_MANUF_CODE_INVALID), \
|
||||
ZB_ZCL_CLUSTER_DESC( \
|
||||
ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT, \
|
||||
ZB_ZCL_ARRAY_SIZE(illuminance_attr_list, zb_zcl_attr_t), \
|
||||
(illuminance_attr_list), \
|
||||
ZB_ZCL_CLUSTER_SERVER_ROLE, \
|
||||
ZB_ZCL_MANUF_CODE_INVALID), \
|
||||
ZB_ZCL_CLUSTER_DESC( \
|
||||
ZB_ZCL_CLUSTER_ID_POWER_CONFIG, \
|
||||
ZB_ZCL_ARRAY_SIZE(batt_attr_list, zb_zcl_attr_t), \
|
||||
(batt_attr_list), \
|
||||
ZB_ZCL_CLUSTER_SERVER_ROLE, \
|
||||
ZB_ZCL_MANUF_CODE_INVALID)}
|
||||
|
||||
#define PRST_ZB_DECLARE_SIMPLE_DESC(ep_name, ep_id, in_clust_num, out_clust_num) \
|
||||
ZB_DECLARE_SIMPLE_DESC(in_clust_num, out_clust_num); \
|
||||
ZB_AF_SIMPLE_DESC_TYPE(in_clust_num, out_clust_num) \
|
||||
simple_desc_##ep_name = \
|
||||
{ \
|
||||
ep_id, \
|
||||
ZB_AF_HA_PROFILE_ID, \
|
||||
PRST_ZB_DEVICE_ID, \
|
||||
PRST_ZB_DEVICE_VERSION, \
|
||||
0, \
|
||||
in_clust_num, \
|
||||
out_clust_num, \
|
||||
{ \
|
||||
ZB_ZCL_CLUSTER_ID_BASIC, \
|
||||
ZB_ZCL_CLUSTER_ID_IDENTIFY, \
|
||||
ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, \
|
||||
ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT, \
|
||||
PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_CLUSTER_ID, \
|
||||
ZB_ZCL_CLUSTER_ID_ILLUMINANCE_MEASUREMENT, \
|
||||
ZB_ZCL_CLUSTER_ID_POWER_CONFIG, \
|
||||
}}
|
||||
|
||||
#define PRST_ZB_DECLARE_ENDPOINT(ep_name, ep_id, cluster_list) \
|
||||
ZBOSS_DEVICE_DECLARE_REPORTING_CTX(reporting_ctx_##ep_name, PRST_ZB_ATTR_REPORTING_COUNT); \
|
||||
PRST_ZB_DECLARE_SIMPLE_DESC(ep_name, ep_id, \
|
||||
PRST_ZB_IN_CLUSTER_NUM, PRST_ZB_OUT_CLUSTER_NUM); \
|
||||
ZB_AF_DECLARE_ENDPOINT_DESC(ep_name, ep_id, ZB_AF_HA_PROFILE_ID, \
|
||||
/*reserved_length=*/0, /*reserved_ptr=*/NULL, \
|
||||
ZB_ZCL_ARRAY_SIZE(cluster_list, zb_zcl_cluster_desc_t), cluster_list, \
|
||||
(zb_af_simple_desc_1_1_t *)&simple_desc_##ep_name, \
|
||||
PRST_ZB_ATTR_REPORTING_COUNT, reporting_ctx_##ep_name, \
|
||||
/*lev_ctrl_count=*/0, /*lev_ctrl_ctx=*/NULL)
|
||||
|
||||
#endif // _PRST_ZB_H_
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#include "prst_zb_soil_moisture_defs.h"
|
||||
|
||||
#include <zboss_api.h>
|
||||
|
||||
void prst_zcl_soil_moisture_init_server(void) {
|
||||
zb_zcl_add_cluster_handlers(PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_CLUSTER_ID,
|
||||
ZB_ZCL_CLUSTER_SERVER_ROLE,
|
||||
/*cluster_check_value=*/NULL,
|
||||
/*cluster_write_attr_hook=*/NULL,
|
||||
/*cluster_handler=*/NULL);
|
||||
}
|
||||
|
||||
void prst_zcl_soil_moisture_init_client(void) {
|
||||
// Nothing.
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef _PRST_ZB_SOIL_MOISTURE_DEFS_
|
||||
#define _PRST_ZB_SOIL_MOISTURE_DEFS_
|
||||
|
||||
#include <zboss_api.h>
|
||||
#include <zcl/zb_zcl_common.h>
|
||||
|
||||
// Most defines in this file are updated from the ZB_ZCL_DECLARE_TEMP_MEASUREMENT_ATTRIB_LIST,
|
||||
// adapting attributes and IDs to match the mSoilMoisture cluster spec.
|
||||
// Values from https://github.com/Koenkk/zigbee-herdsman/blob/master/src/zcl/definition/cluster.ts#L2570
|
||||
// (msSoilMoisture).
|
||||
// Cluster attributes definitions in https://www.st.com/resource/en/user_manual/um2977-stm32wb-series-zigbee-cluster-library-api-stmicroelectronics.pdf.
|
||||
|
||||
#define PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_CLUSTER_ID 1032
|
||||
|
||||
// Soil moisture value represented as an uint16.
|
||||
#define PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_VALUE_ID 0x00
|
||||
|
||||
// Required callbacks. ZBOSS will call these.
|
||||
void prst_zcl_soil_moisture_init_server(void);
|
||||
void prst_zcl_soil_moisture_init_client(void);
|
||||
|
||||
#define PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_CLUSTER_ID_SERVER_ROLE_INIT prst_zcl_soil_moisture_init_server
|
||||
#define PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_CLUSTER_ID_CLIENT_ROLE_INIT prst_zcl_soil_moisture_init_client
|
||||
|
||||
#define PRST_ZB_ZCL_SOIL_MOISTURE_CLUSTER_REVISION_DEFAULT ((zb_uint16_t)0x42)
|
||||
|
||||
#define ZB_SET_ATTR_DESCR_WITH_PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_VALUE_ID(data_ptr) \
|
||||
{ \
|
||||
PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_VALUE_ID, \
|
||||
ZB_ZCL_ATTR_TYPE_U16, \
|
||||
ZB_ZCL_ATTR_ACCESS_READ_ONLY | ZB_ZCL_ATTR_ACCESS_REPORTING, \
|
||||
(void*)data_ptr \
|
||||
}
|
||||
|
||||
#define PRST_ZB_ZCL_DECLARE_SOIL_MOISTURE_ATTRIB_LIST(attr_list, value) \
|
||||
ZB_ZCL_START_DECLARE_ATTRIB_LIST_CLUSTER_REVISION(attr_list, PRST_ZB_ZCL_SOIL_MOISTURE) \
|
||||
ZB_ZCL_SET_ATTR_DESC(PRST_ZB_ZCL_ATTR_SOIL_MOISTURE_VALUE_ID, (value)) \
|
||||
ZB_ZCL_FINISH_DECLARE_ATTRIB_LIST
|
||||
|
||||
#endif // _PRST_ZB_SOIL_MOISTURE_DEFS_
|
||||
16
code/nrf-connect/samples/zigbee/zigbee.code-workspace
Normal file
16
code/nrf-connect/samples/zigbee/zigbee.code-workspace
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "../../prstlib"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"C_Cpp.autoAddFileAssociations": false,
|
||||
"nrf-connect.applications": [
|
||||
"${workspaceFolder}"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue