Merge pull request #53 from rbaron/bthome
Adds support for the BTHome BLE protocol
This commit is contained in:
commit
5c1ea4a164
5 changed files with 135 additions and 50 deletions
|
|
@ -27,9 +27,15 @@
|
|||
// BLE.
|
||||
// Prints out BLE debug info, such as the final encoded advertisement packet.
|
||||
#define PRST_BLE_DEBUG 0
|
||||
// The BLE protocol version defines how the sensors' data is encoded inside the
|
||||
// BLE advertisement packet. Possible values are 1 and 2.
|
||||
#define PRST_BLE_PROTOCOL_VERSION 1
|
||||
|
||||
// Supported BLE protocols.
|
||||
// Default, custom BLE protocol.
|
||||
#define PRST_BLE_PROTOCOL_BPARASITE_V2 0x01
|
||||
// BTHome BLE protocol - https://bthome.io.
|
||||
#define PRST_BLE_PROTOCOL_BTHOME 0x02
|
||||
|
||||
// Chosen BLE protocol.
|
||||
#define PRST_BLE_PROTOCOL PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
|
||||
// There are two options for configuring the MAC address of b-parasites:
|
||||
// 1. Comment out the PRST_BLE_MAC_ADDR to use a random static MAC address that
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "nrf_pwr_mgmt.h"
|
||||
#include "prst/adc.h"
|
||||
#include "prst/ble.h"
|
||||
#include "prst/data.h"
|
||||
#include "prst/pwm.h"
|
||||
#include "prst/rtc.h"
|
||||
#include "prst/shtc3.h"
|
||||
|
|
@ -86,9 +87,16 @@ static void rtc_callback() {
|
|||
nrf_gpio_pin_clear(PRST_PHOTO_V_PIN);
|
||||
#endif
|
||||
|
||||
prst_ble_update_adv_data(batt_read.millivolts, temp_humi.temp_celsius,
|
||||
temp_humi.humidity, soil_read.relative, lux,
|
||||
run_counter);
|
||||
prst_sensor_data_t sensors = {
|
||||
.batt_mv = batt_read.millivolts,
|
||||
.temp_c = temp_humi.temp_celsius,
|
||||
.humi = temp_humi.humidity,
|
||||
.soil_moisture = soil_read.relative,
|
||||
.lux = lux,
|
||||
.run_counter = run_counter,
|
||||
};
|
||||
|
||||
prst_ble_update_adv_data(&sensors);
|
||||
|
||||
state = ADVERTISING;
|
||||
prst_adv_start();
|
||||
|
|
|
|||
|
|
@ -3,16 +3,13 @@
|
|||
#include <ble_advdata.h>
|
||||
#include <ble_gap.h>
|
||||
#include <nordic_common.h>
|
||||
#include <nrf_delay.h>
|
||||
#include <nrf_log.h>
|
||||
#include <nrf_sdh.h>
|
||||
#include <nrf_sdh_ble.h>
|
||||
|
||||
#include "prst_config.h"
|
||||
|
||||
// We need to pick a service UUID for broadcasting our sensor data.
|
||||
// 0x181a is defined as "environmental sensing", which seems appopriate.
|
||||
#define SERVICE_UUID 0x181a
|
||||
|
||||
// The connection to configure. We only have the one.
|
||||
#define PRST_CONN_CFG_TAG 1
|
||||
|
||||
|
|
@ -46,7 +43,16 @@ whether or not they have added the LDR by setting the PRST_HAS_LDR to 1 in
|
|||
prst_config.h.
|
||||
*/
|
||||
|
||||
#if PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
#define SERVICE_UUID 0x181a
|
||||
#define SERVICE_DATA_LEN 18
|
||||
#elif PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BTHOME
|
||||
#define SERVICE_UUID 0x181c
|
||||
#define SERVICE_DATA_LEN 16
|
||||
#else
|
||||
#error "PRST_BLE_PROTOCOL is not properly configured"
|
||||
#endif
|
||||
|
||||
static uint8_t service_data[SERVICE_DATA_LEN];
|
||||
|
||||
// Stores the encoded advertisement data. As per BLE spec, 31 bytes max.
|
||||
|
|
@ -112,26 +118,12 @@ static void init_advertisement_data() {
|
|||
|
||||
ble_gap_conn_sec_mode_t sec_mode;
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
|
||||
sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)PRST_BLE_ADV_NAME,
|
||||
sd_ble_gap_device_name_set(&sec_mode, (const uint8_t*)PRST_BLE_ADV_NAME,
|
||||
strlen(PRST_BLE_ADV_NAME));
|
||||
|
||||
uint32_t err_code =
|
||||
sd_ble_gap_adv_set_configure(&adv_handle_, &gap_adv_data_, &adv_params_);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Four bits for the protocol version.
|
||||
service_data[0] |= (PRST_BLE_PROTOCOL_VERSION << 4) & 0xf0;
|
||||
|
||||
// Bit 0 of byte 0 specifies whether or not ambient light data exists in the
|
||||
// payload.
|
||||
#if PRST_HAS_LDR || PRST_HAS_PHOTOTRANSISTOR
|
||||
service_data[0] |= 1;
|
||||
#endif
|
||||
|
||||
// Bytes 10-15 (inclusive) contain the whole MAC address in big-endian.
|
||||
for (int i = 0; i < 6; i++) {
|
||||
service_data[10 + i] = gap_addr_.addr[5 - i];
|
||||
}
|
||||
}
|
||||
|
||||
void prst_ble_init() {
|
||||
|
|
@ -169,37 +161,100 @@ void prst_ble_init() {
|
|||
init_advertisement_data();
|
||||
}
|
||||
|
||||
void prst_ble_update_adv_data(uint16_t batt_millivolts, float temp_celsius,
|
||||
uint16_t humidity, uint16_t soil_moisture,
|
||||
uint16_t brightness, uint8_t run_counter) {
|
||||
#if PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
static void set_service_data_bparasite_protocol(
|
||||
const prst_sensor_data_t* sensors) {
|
||||
// Four bits for the protocol version.
|
||||
service_data[0] |= (2 << 4) & 0xf0;
|
||||
|
||||
// Bit 0 of byte 0 specifies whether or not ambient light data exists in the
|
||||
// payload.
|
||||
#if PRST_HAS_LDR || PRST_HAS_PHOTOTRANSISTOR
|
||||
service_data[0] |= 1;
|
||||
#endif
|
||||
|
||||
// 4 bits for a small wrap-around counter for deduplicating messages on the
|
||||
// receiver.
|
||||
service_data[1] = run_counter & 0x0f;
|
||||
service_data[1] = sensors->run_counter & 0x0f;
|
||||
|
||||
service_data[2] = batt_millivolts >> 8;
|
||||
service_data[3] = batt_millivolts & 0xff;
|
||||
service_data[2] = sensors->batt_mv >> 8;
|
||||
service_data[3] = sensors->batt_mv & 0xff;
|
||||
|
||||
#if PRST_BLE_PROTOCOL_VERSION == 1
|
||||
uint16_t temp_millicelsius = temp_celsius * 1000;
|
||||
service_data[4] = temp_millicelsius >> 8;
|
||||
service_data[5] = temp_millicelsius & 0xff;
|
||||
#elif PRST_BLE_PROTOCOL_VERSION == 2
|
||||
int16_t temp_centicelsius = temp_celsius * 100;
|
||||
int16_t temp_centicelsius = 100 * sensors->temp_c;
|
||||
service_data[4] = temp_centicelsius >> 8;
|
||||
service_data[5] = temp_centicelsius & 0xff;
|
||||
#else
|
||||
#error "[ble] Unsupported BLE protocol version"
|
||||
#endif // PRST_BLE_PROTOCOL_VERSION
|
||||
|
||||
service_data[6] = humidity >> 8;
|
||||
service_data[7] = humidity & 0xff;
|
||||
service_data[6] = sensors->humi >> 8;
|
||||
service_data[7] = sensors->humi & 0xff;
|
||||
|
||||
service_data[8] = soil_moisture >> 8;
|
||||
service_data[9] = soil_moisture & 0xff;
|
||||
service_data[8] = sensors->soil_moisture >> 8;
|
||||
service_data[9] = sensors->soil_moisture & 0xff;
|
||||
|
||||
// Bytes 10-15 (inclusive) contain the whole MAC address in big-endian.
|
||||
for (int i = 0; i < 6; i++) {
|
||||
service_data[10 + i] = gap_addr_.addr[5 - i];
|
||||
}
|
||||
|
||||
#if PRST_HAS_LDR || PRST_HAS_PHOTOTRANSISTOR
|
||||
service_data[16] = brightness >> 8;
|
||||
service_data[17] = brightness & 0xff;
|
||||
service_data[16] = sensors->lux >> 8;
|
||||
service_data[17] = sensors->lux & 0xff;
|
||||
#endif
|
||||
}
|
||||
#endif // PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
|
||||
#if PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BTHOME
|
||||
static void set_service_data_bthome_protocol(
|
||||
const prst_sensor_data_t* sensors) {
|
||||
// See values in https://bthome.io/.
|
||||
|
||||
// 1. Soil moisture.
|
||||
// uint16_t.
|
||||
service_data[0] = (0b000 << 5) | 2;
|
||||
// Type of measurement - Moisture.
|
||||
service_data[1] = 0x14;
|
||||
// Value. Factor of 0.01, so we need to multiply our the value in 100% by
|
||||
// 1/0.01 = 100.
|
||||
uint16_t soil_val = (10000 * sensors->soil_moisture) / UINT16_MAX;
|
||||
service_data[2] = soil_val & 0xff;
|
||||
service_data[3] = soil_val >> 8;
|
||||
|
||||
// 2. Temp.
|
||||
// int16_t.
|
||||
service_data[4] = (0b001 << 5) | 2;
|
||||
// Type of measurement - temperature.
|
||||
service_data[5] = 0x02;
|
||||
// Value. Factor 0.01.
|
||||
int16_t temp_val = 100 * sensors->temp_c;
|
||||
service_data[6] = temp_val & 0xff;
|
||||
service_data[7] = temp_val >> 8;
|
||||
|
||||
// 3. Humidity
|
||||
// uint16_t.
|
||||
service_data[8] = (0b000 << 5) | 2;
|
||||
// Type - humidity.
|
||||
service_data[9] = 0x03;
|
||||
// Value. Factor 0.01, over 100%.
|
||||
uint16_t humi_val = (10000 * sensors->humi) / UINT16_MAX;
|
||||
service_data[10] = humi_val & 0xff;
|
||||
service_data[11] = humi_val >> 8;
|
||||
|
||||
// 4. Battery voltage.
|
||||
// uint16_t.
|
||||
service_data[12] = (0b000 << 5) | 2;
|
||||
// Type - voltage.
|
||||
service_data[13] = 0x0c;
|
||||
// Value. Factor of 0.001.
|
||||
uint16_t batt_val = sensors->batt_mv;
|
||||
service_data[14] = batt_val & 0xff;
|
||||
service_data[15] = batt_val >> 8;
|
||||
}
|
||||
#endif // PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BTHOME
|
||||
|
||||
void prst_ble_update_adv_data(const prst_sensor_data_t* sensors) {
|
||||
#if PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
set_service_data_bparasite_protocol(sensors);
|
||||
#elif PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BTHOME
|
||||
set_service_data_bthome_protocol(sensors);
|
||||
#endif
|
||||
|
||||
// Encodes adv_data_ into .gap_adv_data_.
|
||||
|
|
@ -210,7 +265,8 @@ void prst_ble_update_adv_data(uint16_t batt_millivolts, float temp_celsius,
|
|||
#if PRST_BLE_DEBUG
|
||||
NRF_LOG_INFO("[ble] Encoded BLE adv packet:");
|
||||
for (int i = 0; i < sizeof(encoded_adv_data_); i++) {
|
||||
NRF_LOG_INFO("[ble] 0x%02x", encoded_adv_data_[i]);
|
||||
NRF_LOG_INFO("[ble] byte %02d: 0x%02x", i, encoded_adv_data_[i]);
|
||||
nrf_delay_ms(50);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#include <app_error.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "prst/data.h"
|
||||
|
||||
// Initializes SoftDevice.
|
||||
void prst_ble_init();
|
||||
|
||||
|
|
@ -11,8 +13,6 @@ void prst_adv_start();
|
|||
|
||||
void prst_adv_stop();
|
||||
|
||||
void prst_ble_update_adv_data(uint16_t batt_millivolts, float temp_celsius,
|
||||
uint16_t humidity, uint16_t soil_moisture,
|
||||
uint16_t brightness, uint8_t run_counter);
|
||||
void prst_ble_update_adv_data(const prst_sensor_data_t* sensors);
|
||||
|
||||
#endif // _PRST_BLE_H_
|
||||
15
code/b-parasite/src/prst/data.h
Normal file
15
code/b-parasite/src/prst/data.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef _PRST_DATA_H_
|
||||
#define _PRST_DATA_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t batt_mv;
|
||||
float temp_c;
|
||||
uint16_t humi;
|
||||
uint16_t soil_moisture;
|
||||
uint16_t lux;
|
||||
uint8_t run_counter;
|
||||
} prst_sensor_data_t;
|
||||
|
||||
#endif // _PRST_DATA_H_
|
||||
Loading…
Add table
Reference in a new issue