mirror of
https://github.com/esphome/esphome.git
synced 2025-09-02 19:32:19 +01:00
beacon demo
This commit is contained in:
22
esphome/components/beacon/__init__.py
Normal file
22
esphome/components/beacon/__init__.py
Normal 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)
|
76
esphome/components/beacon/beacon.cpp
Normal file
76
esphome/components/beacon/beacon.cpp
Normal 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
|
11
esphome/components/beacon/beacon.h
Normal file
11
esphome/components/beacon/beacon.h
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
83
esphome/components/nrf52/__init__.py
Normal file
83
esphome/components/nrf52/__init__.py
Normal 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")
|
39
esphome/components/nrf52/core.cpp
Normal file
39
esphome/components/nrf52/core.cpp
Normal 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
|
3
esphome/components/nrf52/core.h
Normal file
3
esphome/components/nrf52/core.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void nrf52GetMacAddr(uint8_t *mac);
|
46
esphome/components/nrf52/preferences.cpp
Normal file
46
esphome/components/nrf52/preferences.cpp
Normal 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
|
15
esphome/components/nrf52/preferences.h
Normal file
15
esphome/components/nrf52/preferences.h
Normal 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
|
@@ -47,6 +47,11 @@
|
|||||||
#include <WiFi.h> // for macAddress()
|
#include <WiFi.h> // for macAddress()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_NRF52
|
||||||
|
#include "Adafruit_nRFCrypto.h"
|
||||||
|
#include "esphome/components/nrf52/core.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
||||||
static const char *const TAG = "helpers";
|
static const char *const TAG = "helpers";
|
||||||
@@ -201,6 +206,8 @@ uint32_t random_uint32() {
|
|||||||
std::mt19937 rng(dev());
|
std::mt19937 rng(dev());
|
||||||
std::uniform_int_distribution<uint32_t> dist(0, std::numeric_limits<uint32_t>::max());
|
std::uniform_int_distribution<uint32_t> dist(0, std::numeric_limits<uint32_t>::max());
|
||||||
return dist(rng);
|
return dist(rng);
|
||||||
|
#elif defined(USE_NRF52)
|
||||||
|
return rand();
|
||||||
#else
|
#else
|
||||||
#error "No random source available for this configuration."
|
#error "No random source available for this configuration."
|
||||||
#endif
|
#endif
|
||||||
@@ -238,6 +245,8 @@ bool random_bytes(uint8_t *data, size_t len) {
|
|||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return true;
|
return true;
|
||||||
|
#elif defined(USE_NRF52)
|
||||||
|
return nRFCrypto.Random.generate(data, len);
|
||||||
#else
|
#else
|
||||||
#error "No random source available for this configuration."
|
#error "No random source available for this configuration."
|
||||||
#endif
|
#endif
|
||||||
@@ -515,7 +524,7 @@ Mutex::Mutex() {}
|
|||||||
void Mutex::lock() {}
|
void Mutex::lock() {}
|
||||||
bool Mutex::try_lock() { return true; }
|
bool Mutex::try_lock() { return true; }
|
||||||
void Mutex::unlock() {}
|
void Mutex::unlock() {}
|
||||||
#elif defined(USE_ESP32) || defined(USE_LIBRETINY)
|
#elif defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_NRF52)
|
||||||
Mutex::Mutex() { handle_ = xSemaphoreCreateMutex(); }
|
Mutex::Mutex() { handle_ = xSemaphoreCreateMutex(); }
|
||||||
void Mutex::lock() { xSemaphoreTake(this->handle_, portMAX_DELAY); }
|
void Mutex::lock() { xSemaphoreTake(this->handle_, portMAX_DELAY); }
|
||||||
bool Mutex::try_lock() { return xSemaphoreTake(this->handle_, 0) == pdTRUE; }
|
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);
|
WiFi.macAddress(mac);
|
||||||
#elif defined(USE_LIBRETINY)
|
#elif defined(USE_LIBRETINY)
|
||||||
WiFi.macAddress(mac);
|
WiFi.macAddress(mac);
|
||||||
|
#elif defined(USE_NRF52)
|
||||||
|
nrf52GetMacAddr(mac);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
std::string get_mac_address() {
|
std::string get_mac_address() {
|
||||||
|
@@ -36,3 +36,5 @@ sensor:
|
|||||||
update_interval: 3s
|
update_interval: 3s
|
||||||
|
|
||||||
dfu:
|
dfu:
|
||||||
|
|
||||||
|
beacon:
|
||||||
|
Reference in New Issue
Block a user