1
0
mirror of https://github.com/esphome/esphome.git synced 2025-04-11 21:30:29 +01:00

beacon demo

This commit is contained in:
Tomasz Duda 2024-01-10 21:49:04 +01:00
parent 469aaecec9
commit ecfbca8522
10 changed files with 309 additions and 1 deletions

View File

@ -0,0 +1,22 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import (
CONF_ID,
)
dfu_ns = cg.esphome_ns.namespace("ble")
Beacon = dfu_ns.class_("Beacon", cg.Component)
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(Beacon),
}
).extend(cv.COMPONENT_SCHEMA),
cv.only_on_nrf52,
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)

View File

@ -0,0 +1,76 @@
#include "beacon.h"
#include <bluefruit.h>
// Beacon uses the Manufacturer Specific Data field in the advertising packet,
// which means you must provide a valid Manufacturer ID. Update
// the field below to an appropriate value. For a list of valid IDs see:
// https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
// - 0x004C is Apple
// - 0x0822 is Adafruit
// - 0x0059 is Nordic
// For testing with this sketch, you can use nRF Beacon app
// - on Android you may need change the MANUFACTURER_ID to Nordic
// - on iOS you may need to change the MANUFACTURER_ID to Apple.
// You will also need to "Add Other Beacon, then enter Major, Minor that you set in the sketch
#define MANUFACTURER_ID 0x0059
// "nRF Connect" app can be used to detect beacon
uint8_t beaconUuid[16] = {
0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0
};
// A valid Beacon packet consists of the following information:
// UUID, Major, Minor, RSSI @ 1M
BLEBeacon beacon(beaconUuid, 1, 2, -54);
void startAdv(void)
{
// Advertising packet
// Set the beacon payload using the BLEBeacon class populated
// earlier in this example
Bluefruit.Advertising.setBeacon(beacon);
// Secondary Scan Response packet (optional)
// Since there is no room for 'Name' in Advertising packet
Bluefruit.ScanResponse.addName();
/* Start Advertising
* - Enable auto advertising if disconnected
* - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
*
* Apple Beacon specs
* - Type: Non-connectable, scannable, undirected
* - Fixed interval: 100 ms -> fast = slow = 100 ms
*/
Bluefruit.Advertising.setType(BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED);
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(160, 160); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
namespace esphome {
namespace ble {
void Beacon::loop() {
}
void Beacon::setup(){
Bluefruit.begin();
// off Blue LED for lowest power consumption
Bluefruit.autoConnLed(false);
Bluefruit.setTxPower(0); // Check bluefruit.h for supported values
Bluefruit.setName("ESPHome");
// Manufacturer ID is required for Manufacturer Specific Data
beacon.setManufacturer(MANUFACTURER_ID);
// Setup the advertising packet
startAdv();
}
} // namespace dfu
} // namespace esphome

View File

@ -0,0 +1,11 @@
#pragma once
#include "esphome/core/component.h"
namespace esphome {
namespace ble {
class Beacon : public Component {
void loop() override;
void setup() override;
};
}
}

View File

@ -0,0 +1,83 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import (
CONF_BOARD,
CONF_FRAMEWORK,
KEY_CORE,
KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM,
PLATFORM_NRF52,
)
from esphome.core import CORE, coroutine_with_priority
# force import gpio to register pin schema
from .gpio import nrf52_pin_to_code # noqa
def set_core_data(config):
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_NRF52
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino"
return config
# https://github.com/platformio/platform-nordicnrf52/releases
ARDUINO_PLATFORM_VERSION = cv.Version(10, 3, 0)
def _arduino_check_versions(value):
value = value.copy()
value[CONF_PLATFORM_VERSION] = value.get(
CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION))
)
return value
def _parse_platform_version(value):
try:
# if platform version is a valid version constraint, prefix the default package
cv.platformio_version_constraint(value)
return f"platformio/nordicnrf52@{value}"
except cv.Invalid:
return value
CONF_PLATFORM_VERSION = "platform_version"
ARDUINO_FRAMEWORK_SCHEMA = cv.All(
cv.Schema(
{
cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version,
}
),
_arduino_check_versions,
)
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.Required(CONF_BOARD): cv.string_strict,
cv.Optional(CONF_FRAMEWORK, default={}): ARDUINO_FRAMEWORK_SCHEMA,
}
),
set_core_data,
)
nrf52_ns = cg.esphome_ns.namespace("nrf52")
@coroutine_with_priority(1000)
async def to_code(config):
cg.add(nrf52_ns.setup_preferences())
if config[CONF_BOARD] == "nrf52840":
# it has most generic GPIO mapping
config[CONF_BOARD] = "nrf52840_dk_adafruit"
cg.add_platformio_option("board", config[CONF_BOARD])
cg.add_build_flag("-DUSE_NRF52")
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
cg.add_define("ESPHOME_VARIANT", "nrf52840")
conf = config[CONF_FRAMEWORK]
cg.add_platformio_option("framework", "arduino")
cg.add_build_flag("-DUSE_ARDUINO")
cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION])
# make sure that firmware.zip is created
cg.add_platformio_option("board_upload.protocol", "nrfutil")

View File

@ -0,0 +1,39 @@
#ifdef USE_NRF52
#include <Arduino.h>
#include "Adafruit_nRFCrypto.h"
namespace esphome {
void yield() { ::yield(); }
uint32_t millis() { return ::millis(); }
void delay(uint32_t ms) { ::delay(ms); }
uint32_t micros() { return ::micros(); }
void arch_init() {
nRFCrypto.begin();
// Init random seed
union seedParts {
uint32_t seed32;
uint8_t seed8[4];
} seed;
nRFCrypto.Random.generate(seed.seed8, sizeof(seed.seed8));
randomSeed(seed.seed32);
}
void arch_feed_wdt() { /* TODO */ }
void nrf52GetMacAddr(uint8_t *mac)
{
const uint8_t *src = (const uint8_t *)NRF_FICR->DEVICEADDR;
mac[5] = src[0];
mac[4] = src[1];
mac[3] = src[2];
mac[2] = src[3];
mac[1] = src[4];
mac[0] = src[5] | 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack
}
} // namespace esphome
#endif // USE_RP2040

View File

@ -0,0 +1,3 @@
#pragma once
void nrf52GetMacAddr(uint8_t *mac);

View File

@ -0,0 +1,46 @@
#ifdef USE_NRF52
#include "esphome/core/preferences.h"
namespace esphome {
namespace nrf52 {
class NRF52Preferences : public ESPPreferences {
public:
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override {
return make_preference(length, type);
}
ESPPreferenceObject make_preference(size_t length, uint32_t type) override {
//TODO
return {};
}
bool sync() override {
//TODO
return true;
}
bool reset() override {
// TODO
return true;
}
// protected:
// uint8_t *eeprom_sector_;
};
void setup_preferences() {
auto *prefs = new NRF52Preferences(); // NOLINT(cppcoreguidelines-owning-memory)
global_preferences = prefs;
}
//TODO
// void preferences_prevent_write(bool prevent) { s_prevent_write = prevent; }
} // namespace nrf52
ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace esphome
#endif // USE_RP2040

View File

@ -0,0 +1,15 @@
#pragma once
#ifdef USE_NRF52
namespace esphome {
namespace nrf52 {
void setup_preferences();
//TODO
// void preferences_prevent_write(bool prevent);
} // namespace nrf52
} // namespace esphome
#endif // USE_RP2040

View File

@ -47,6 +47,11 @@
#include <WiFi.h> // for macAddress()
#endif
#ifdef USE_NRF52
#include "Adafruit_nRFCrypto.h"
#include "esphome/components/nrf52/core.h"
#endif
namespace esphome {
static const char *const TAG = "helpers";
@ -201,6 +206,8 @@ uint32_t random_uint32() {
std::mt19937 rng(dev());
std::uniform_int_distribution<uint32_t> dist(0, std::numeric_limits<uint32_t>::max());
return dist(rng);
#elif defined(USE_NRF52)
return rand();
#else
#error "No random source available for this configuration."
#endif
@ -238,6 +245,8 @@ bool random_bytes(uint8_t *data, size_t len) {
}
fclose(fp);
return true;
#elif defined(USE_NRF52)
return nRFCrypto.Random.generate(data, len);
#else
#error "No random source available for this configuration."
#endif
@ -515,7 +524,7 @@ Mutex::Mutex() {}
void Mutex::lock() {}
bool Mutex::try_lock() { return true; }
void Mutex::unlock() {}
#elif defined(USE_ESP32) || defined(USE_LIBRETINY)
#elif defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_NRF52)
Mutex::Mutex() { handle_ = xSemaphoreCreateMutex(); }
void Mutex::lock() { xSemaphoreTake(this->handle_, portMAX_DELAY); }
bool Mutex::try_lock() { return xSemaphoreTake(this->handle_, 0) == pdTRUE; }
@ -569,6 +578,8 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame
WiFi.macAddress(mac);
#elif defined(USE_LIBRETINY)
WiFi.macAddress(mac);
#elif defined(USE_NRF52)
nrf52GetMacAddr(mac);
#endif
}
std::string get_mac_address() {

View File

@ -36,3 +36,5 @@ sensor:
update_interval: 3s
dfu:
beacon: