Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BTHome: New feature #20996

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion drivers/isl29020/isl29020_saul.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static int read(const void *dev, phydat_t *res)
res->val[0] = (int16_t)isl29020_read((const isl29020_t *)dev);
res->val[1] = 0;
res->val[2] = 0;
res->unit = UNIT_CD;
res->unit = UNIT_LUX; /* https://www.renesas.com/en/document/dst/isl29020-datasheet */
res->scale = 0;
return 1;
}
Expand Down
33 changes: 33 additions & 0 deletions examples/skald_bthome/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# name of your application
APPLICATION = skald_bthome

# If no BOARD is found in the environment, use this default:
BOARD ?= nrf52dk

# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..

# include Skald using SAUL
USEMODULE += saul_default
USEMODULE += skald_bthome_saul

DEVELHELP ?= 1

BTHOME_NAME = "RIOT"
BTHOME_ADV_INTERVAL ?= 60000
ENCRYPTION_KEY ?=

ifneq ($(ENCRYPTION_KEY),)
USEMODULE += skald_bthome_encrypt
CFLAGS += -DENCRYPTION_KEY="\"$(ENCRYPTION_KEY)\""
endif

CFLAGS += -DISR_STACKSIZE=1024

CFLAGS += -DBTHOME_NAME="\"$(BTHOME_NAME)\""
CFLAGS += -DBTHOME_ADV_INTERVAL=$(BTHOME_ADV_INTERVAL)

# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1

include $(RIOTBASE)/Makefile.include
7 changes: 7 additions & 0 deletions examples/skald_bthome/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Skald BTHome Example

This example demonstrates the usage of `Skald` for creating a BTHome
setup, advertising sensors in the SAUL registry.

Simply compile and flash, and verify your newly created beacon with any type of
BLE scanner / BTHome receiver (e.g. Home Assistant).
149 changes: 149 additions & 0 deletions examples/skald_bthome/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (C) 2024 Martine S. Lenders
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup examples
* @{
*
* @file
* @brief BLE BTHome example using Skald
*
* @author Martine S. Lenders <[email protected]>
*
* @}
*/

#include <errno.h>
#include <stdio.h>

#include "saul_reg.h"
#include "ztimer.h"

#include "net/skald/bthome.h"

#ifndef CONFIG_BTHOME_SAUL_REG_DEVS
#define CONFIG_BTHOME_SAUL_REG_DEVS (16U)
#endif

#ifndef BTHOME_ADV_INTERVAL
#define BTHOME_ADV_INTERVAL (60000U)
#endif

static skald_bthome_ctx_t _ctx;
static skald_bthome_saul_t _saul_devs[CONFIG_BTHOME_SAUL_REG_DEVS];

#ifdef ENCRYPTION_KEY
int _get_encryption_key(void)
{
static const char enc_str[] = ENCRYPTION_KEY;
static uint8_t encryption_key[SKALD_BTHOME_KEY_LEN] = { 0 };
size_t enc_str_len = strlen(enc_str);
uint8_t key_len = 0;

uint8_t shift = 4;
for (unsigned i = 0; i < enc_str_len; i++) {
char c = enc_str[i];
unsigned char offset;

if (c >= '0' && c <= '9') {
offset = '0';
}
else if (c >= 'a' && c <= 'f') {
offset = 'a' - 10;
}
else {
continue;
}
encryption_key[i / 2] |= (c - offset) << shift;
shift = (shift) ? 0 : 4;
key_len = (i / 2) + 1;
if (key_len > SKALD_BTHOME_KEY_LEN) {
printf("Key was too long: %u bytes\n", key_len);
return -ENOBUFS;
}
}

if (key_len < SKALD_BTHOME_KEY_LEN) {
printf("Key was too short: %u bytes\n", key_len);
return -EINVAL;
}
memcpy(_ctx.key, encryption_key, key_len);
_ctx.encrypt = 1;
return key_len;
}
#endif

static int _add_text(skald_bthome_ctx_t *ctx, uint8_t obj_id, phydat_t *data, uint8_t idx)
{
static const char info[] = "RIOT";

(void)data;
(void)idx;
return skald_bthome_add_measurement(ctx, obj_id, info, strlen(info));
}

int main(void)
{
saul_reg_t *dev = saul_reg;
unsigned i = 0;
int res;

ztimer_sleep(ZTIMER_MSEC, 2000);
printf("Skald and the tale of Harald's home\n");

#ifdef ENCRYPTION_KEY
int key_len;

key_len = _get_encryption_key();

if (key_len != SKALD_BTHOME_KEY_LEN) {
printf(
"Key should be of length 16 (32 chars), "
"was \"%s\" (%u chars)\n",
ENCRYPTION_KEY,
strlen(ENCRYPTION_KEY)
);
return 1;
}
#endif
_ctx.skald.update_pkt = NULL;
_ctx.devs = NULL;
if (skald_bthome_init(&_ctx, NULL, BTHOME_NAME, 0) < 0) {
return 1;
}
if (!saul_reg) {
puts("Hark! The board does not know SAUL. :-(");
return 1;
}
while (dev && (i < CONFIG_BTHOME_SAUL_REG_DEVS)) {
printf("Adding %s to BTHome.\n", dev->name);
_saul_devs[i].saul = *dev; /* copy registry entry */
_saul_devs[i].saul.next = NULL;
if ((res = skald_bthome_saul_add(&_ctx, &_saul_devs[i])) < 0) {
errno = -res;
perror("Unable to add sensor to BTHome");
};
dev = dev->next;
i++;
}
assert(!saul_reg || _ctx.devs);
if (i < CONFIG_BTHOME_SAUL_REG_DEVS) {
memset(&_saul_devs[i].saul, 0, sizeof(_saul_devs[i].saul));
_saul_devs[i].obj_id = BTHOME_ID_TEXT;
_saul_devs[i].flags = SKALD_BTHOME_SAUL_FLAGS_CUSTOM;
_saul_devs[i].add_measurement = _add_text;
if ((res = skald_bthome_saul_add(&_ctx, &_saul_devs[i])) < 0) {
errno = -res;
perror("Unable to add text info to BTHome");
};
i++;
}
skald_bthome_advertise(&_ctx, BTHOME_ADV_INTERVAL);
printf("First advertisement should show up in %u ms\n", BTHOME_ADV_INTERVAL);
return 0;
}
4 changes: 4 additions & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -590,8 +590,12 @@ NO_PSEUDOMODULES += periph_common
PSEUDOMODULES += pio_autostart_%

# Submodules provided by Skald
PSEUDOMODULES += skald_update_pkt_cb
PSEUDOMODULES += skald_ibeacon
PSEUDOMODULES += skald_eddystone
PSEUDOMODULES += skald_bthome
PSEUDOMODULES += skald_bthome_encrypt
PSEUDOMODULES += skald_bthome_saul

PSEUDOMODULES += crypto_aes_128
PSEUDOMODULES += crypto_aes_192
Expand Down
11 changes: 11 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,17 @@ ifneq (,$(filter skald,$(USEMODULE)))
USEMODULE += ztimer_msec
endif

ifneq (,$(filter skald_bthome_encrypt,$(USEMODULE)))
USEMODULE += cipher_modes
USEMODULE += skald_bthome
endif

ifneq (,$(filter skald_bthome_saul,$(USEMODULE)))
USEMODULE += skald_bthome
USEMODULE += skald_update_pkt_cb
USEMODULE += saul_reg
endif

ifneq (,$(filter bluetil_addr,$(USEMODULE)))
USEMODULE += fmt
endif
Expand Down
29 changes: 22 additions & 7 deletions sys/include/net/skald.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@

#include <stdint.h>

#include "kernel_defines.h"
#include "ztimer.h"
#include "net/ble.h"
#include "net/netdev/ble.h"
Expand All @@ -68,16 +69,30 @@
uint8_t u8[16]; /**< UUID with byte-wise access */
} skald_uuid_t;


Check warning on line 72 in sys/include/net/skald.h

View workflow job for this annotation

GitHub Actions / static-tests

too many consecutive empty lines
/**
* @brief Forward declaration
*/
typedef struct skald_ctx skald_ctx_t;

/**
* @brief Advertising context holding the advertising data and state
*/
typedef struct {
netdev_ble_pkt_t pkt; /**< packet holding the advertisement (GAP) data */
ztimer_t timer; /**< timer for scheduling advertising events */
ztimer_now_t last; /**< last timer trigger (for offset compensation) */
uint8_t cur_chan; /**< keep track of advertising channels */
uint32_t adv_itvl_ms; /**< advertising interval [ms] */
} skald_ctx_t;
struct skald_ctx {
netdev_ble_pkt_t pkt; /**< packet holding the advertisement (GAP) data */
#if IS_USED(MODULE_SKALD_UPDATE_PKT_CB) || defined(DOXYGEN)
/**
* @brief callback to update packet on periodic advertisements
*
* Requires module `skald_pkt_update_cb`
*/
void (*update_pkt)(skald_ctx_t *);
#endif
ztimer_t timer; /**< timer for scheduling advertising events */
ztimer_now_t last; /**< last timer trigger (for offset compensation) */
uint8_t cur_chan; /**< keep track of advertising channels */
uint32_t adv_itvl_ms; /**< advertising interval [ms] */
};

/**
* @brief Initialize Skald and the underlying radio
Expand Down
Loading
Loading