Add BT1035 pairing and station presets (fw 0.7.0).

Expose discoverable mode and A2DP control over REST, add persisted
DAB/FM preset list with web UI, and document gaps in docs/TODO.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 17:42:11 +02:00
co-authored by Cursor
parent a08a9c19ee
commit 82c9f401da
46 changed files with 2819 additions and 33 deletions
@@ -0,0 +1,8 @@
idf_component_register(
SRCS
"src/BluetoothService.cpp"
INCLUDE_DIRS "include"
REQUIRES core bt1035
)
target_compile_features(${COMPONENT_LIB} PUBLIC cxx_std_23)
@@ -0,0 +1,102 @@
/**
* @file BluetoothService.hpp
* @brief Intent-level Bluetooth API for HTTP and UI.
*
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
*
* Copyright 2026 Michele Bigi
* SPDX-License-Identifier: Apache-2.0
*
* @author Michele Bigi
* @date 2026-07-06
*/
#pragma once
#include "bt1035/Bt1035Driver.hpp"
#include "bt1035/Bt1035Error.hpp"
#include "core/BluetoothJson.hpp"
#include <expected>
namespace bluetooth {
/**
* @brief BluetoothService — pairing and A2DP status for the web API.
*
* @dname BluetoothService
* @return n/a (type)
* @pubstate Borrows bt1035::Bt1035Driver for the process lifetime. Tracks
* whether discoverable mode was requested via startPairing().
*
* @author Michele Bigi
* @date 2026-07-06
*/
class BluetoothService {
public:
/**
* @brief BluetoothService — bind to the BT1035 driver.
*
* @dname BluetoothService
* @param driver Booted BT1035 driver (must outlive this service).
* @pubstate stores driver reference; pairing inactive initially.
*
* @author Michele Bigi
* @date 2026-07-06
*/
explicit BluetoothService(bt1035::Bt1035Driver& driver);
/**
* @brief refreshStatus — read module boot, pairing, and A2DP state.
*
* @dname refreshStatus
* @return BluetoothStatus on success, or Bt1035Error from the driver.
* @pubstate queries driver for A2DP state when booted.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<core::BluetoothStatus, bt1035::Bt1035Error>
refreshStatus();
/**
* @brief startPairing — enter discoverable mode (AT+PAIR=1).
*
* @dname startPairing
* @return Ok on success, or Bt1035Error.
* @pubstate sets pairingActive_ on success.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, bt1035::Bt1035Error> startPairing();
/**
* @brief stopPairing — leave discoverable mode (AT+PAIR=0).
*
* @dname stopPairing
* @return Ok on success, or Bt1035Error.
* @pubstate clears pairingActive_ on success.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, bt1035::Bt1035Error> stopPairing();
/**
* @brief disconnect — release the active A2DP link (AT+A2DPDISC).
*
* @dname disconnect
* @return Ok on success, or Bt1035Error.
* @pubstate delegates to driver.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, bt1035::Bt1035Error> disconnect();
private:
bt1035::Bt1035Driver& driver_;
bool pairingActive_;
};
} // namespace bluetooth
@@ -0,0 +1,68 @@
/**
* @file BluetoothService.cpp
* @brief BluetoothService implementation.
*
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
*
* Copyright 2026 Michele Bigi
* SPDX-License-Identifier: Apache-2.0
*
* @author Michele Bigi
* @date 2026-07-06
*/
#include "bluetooth/BluetoothService.hpp"
namespace bluetooth {
BluetoothService::BluetoothService(bt1035::Bt1035Driver& driver)
: driver_(driver)
, pairingActive_(false)
{
}
std::expected<core::BluetoothStatus, bt1035::Bt1035Error>
BluetoothService::refreshStatus()
{
core::BluetoothStatus status{
.booted = driver_.isBooted(),
.pairing = pairingActive_,
.a2dpState = core::Bt1035A2dpState::Standby,
};
if (!status.booted) {
return status;
}
auto a2dp = driver_.queryA2dpState();
if (!a2dp) {
return std::unexpected(a2dp.error());
}
status.a2dpState = *a2dp;
return status;
}
std::expected<void, bt1035::Bt1035Error> BluetoothService::startPairing()
{
if (auto result = driver_.enterPairingMode(); !result) {
return result;
}
pairingActive_ = true;
return {};
}
std::expected<void, bt1035::Bt1035Error> BluetoothService::stopPairing()
{
if (auto result = driver_.leavePairingMode(); !result) {
return result;
}
pairingActive_ = false;
return {};
}
std::expected<void, bt1035::Bt1035Error> BluetoothService::disconnect()
{
return driver_.disconnectA2dp();
}
} // namespace bluetooth