Give Bluetooth settings a bit of a refresh

It's now a bit more responsive to stuff happening, gives you more information, and remembers your previously paired devices for faster switching between them.
custom
jacqueline 9 months ago
parent a3eb2dd9dc
commit f78de39a75
  1. 46
      lua/settings.lua
  2. 9
      lua/widgets.lua
  3. 24
      src/drivers/bluetooth.cpp
  4. 2
      src/drivers/include/drivers/nvs.hpp
  5. 2
      src/drivers/nvs.cpp
  6. 51
      src/tangara/lua/property.cpp

@ -46,6 +46,7 @@ local BluetoothPairing = SettingsScreen:new {
for _, dev in pairs(devs) do
devices:add_btn(nil, dev.name):onClicked(function()
bluetooth.paired_device:set(dev)
backstack.pop()
end)
end
end)
@ -101,16 +102,15 @@ local BluetoothSettings = SettingsScreen:new {
theme.set_style(paired_label, "settings_title")
self.bindings = self.bindings + {
bluetooth.connected:bind(function(conn)
if conn then
paired_label:set { text = "Connected to:" }
else
paired_label:set { text = "Paired with:" }
end
end),
bluetooth.connecting:bind(function(conn)
if conn then
paired_label:set { text = "Connecting to:" }
else
if bluetooth.connected:get() then
paired_label:set { text = "Connected to:" }
else
paired_label:set { text = "Paired with:" }
end
end
end),
}
@ -159,22 +159,42 @@ local BluetoothSettings = SettingsScreen:new {
h = lvgl.SIZE_CONTENT,
}
-- 'Pair new device' button that goes to the discovery screen.
local button_container = self.content:Object {
w = lvgl.PCT(100),
h = lvgl.SIZE_CONTENT,
flex = {
flex_direction = "row",
justify_content = "center",
align_items = "space-evenly",
align_content = "center",
},
pad_top = 4,
pad_column = 4,
}
button_container:add_style(styles.list_item)
local pair_new = button_container:Button {}
pair_new:Label { text = "Pair new device" }
pair_new:onClicked(function()
backstack.push(BluetoothPairing:new())
end)
self.bindings = self.bindings + {
bluetooth.known_devices:bind(function(devs)
local group = lvgl.group.get_default()
group.remove_obj(pair_new)
devices:clean()
for _, dev in pairs(devs) do
devices:add_btn(nil, dev.name):onClicked(function()
bluetooth.paired_device:set(dev)
end)
end
group:add_obj(pair_new)
end)
}
local pair_new = self.content:Button {}
pair_new:Label { text = "Pair new device" }
pair_new:onClicked(function()
backstack.push(BluetoothPairing:new())
end)
end
}

@ -79,11 +79,10 @@ function widgets.Row(parent, left, right)
}
end
local bindings_meta = {
__add = function(a, b)
return table.move(a, 1, #a, #b + 1, b)
end
}
local bindings_meta = {}
bindings_meta["__add"] = function(a, b)
return setmetatable(table.move(a, 1, #a, #b + 1, b), bindings_meta)
end
function widgets.StatusBar(parent, opts)
local root = parent.root:Object {

@ -603,16 +603,21 @@ void Disabled::react(const events::Enable&) {
void Idle::entry() {
ESP_LOGI(kTag, "bt is idle");
std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged);
}
void Idle::exit() {}
void Idle::exit() {
std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged);
}
void Idle::react(const events::Disable& ev) {
transit<Disabled>();
}
void Idle::react(const events::PairedDeviceChanged& ev) {
connect(*sPairedWith_);
if (sPairedWith_) {
connect(*sPairedWith_);
}
}
void Idle::react(events::internal::Gap ev) {
@ -633,18 +638,10 @@ void Connecting::entry() {
sTimeoutTimer = xTimerCreate("bt_timeout", pdMS_TO_TICKS(15000), false, NULL,
timeoutCallback);
xTimerStart(sTimeoutTimer, portMAX_DELAY);
if (sEventHandler_) {
std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged);
}
}
void Connecting::exit() {
xTimerDelete(sTimeoutTimer, portMAX_DELAY);
if (sEventHandler_) {
std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged);
}
}
void Connecting::react(const events::ConnectTimedOut& ev) {
@ -751,12 +748,16 @@ void Connected::entry() {
sStorage_->PreferredBluetoothDevice(sPairedWith_);
}
std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged);
// TODO: if we already have a source, immediately start playing
}
void Connected::exit() {
ESP_LOGI(kTag, "exiting connected state");
esp_a2d_source_disconnect(connected_to_.data());
std::invoke(sEventHandler_, SimpleEvent::kConnectionStateChanged);
}
void Connected::react(const events::Disable& ev) {
@ -765,6 +766,9 @@ void Connected::react(const events::Disable& ev) {
void Connected::react(const events::PairedDeviceChanged& ev) {
transit<Idle>();
if (sPairedWith_) {
connect(*sPairedWith_);
}
}
void Connected::react(const events::SourceChanged& ev) {

@ -34,7 +34,7 @@ class Setting {
dirty_ = true;
}
}
auto get() -> std::optional<T>& { return val_; }
auto get() -> std::optional<T> { return val_; }
/* Reads the stored value from NVS and parses it into the correct type. */
auto load(nvs_handle_t) -> std::optional<T>;

@ -391,7 +391,7 @@ auto NvsStorage::BluetoothNames() -> std::vector<bluetooth::MacAndName> {
auto NvsStorage::BluetoothName(const bluetooth::mac_addr_t& mac,
std::optional<std::string> name) -> void {
std::lock_guard<std::mutex> lock{mutex_};
auto& val = bt_names_.get();
auto val = bt_names_.get();
if (!val) {
val.emplace();
}

@ -371,33 +371,34 @@ auto popRichType(lua_State* L) -> LuaValue {
}
auto Property::popValue(lua_State& s) -> bool {
LuaValue new_val;
switch (lua_type(&s, 2)) {
case LUA_TNIL:
new_val = std::monostate{};
break;
case LUA_TNUMBER:
if (lua_isinteger(&s, 2)) {
new_val = lua_tointeger(&s, 2);
} else {
new_val = static_cast<lua_Integer>(std::round(lua_tonumber(&s, 2)));
}
break;
case LUA_TBOOLEAN:
new_val = static_cast<bool>(lua_toboolean(&s, 2));
break;
case LUA_TSTRING:
new_val = lua_tostring(&s, 2);
break;
default:
if (lua_istable(&s, 2)) {
new_val = popRichType(&s);
if (std::holds_alternative<std::monostate>(new_val)) {
LuaValue new_val{std::monostate{}};
if (lua_gettop(&s) >= 2) {
switch (lua_type(&s, 2)) {
case LUA_TNIL:
break;
case LUA_TNUMBER:
if (lua_isinteger(&s, 2)) {
new_val = lua_tointeger(&s, 2);
} else {
new_val = static_cast<lua_Integer>(std::round(lua_tonumber(&s, 2)));
}
break;
case LUA_TBOOLEAN:
new_val = static_cast<bool>(lua_toboolean(&s, 2));
break;
case LUA_TSTRING:
new_val = lua_tostring(&s, 2);
break;
default:
if (lua_istable(&s, 2)) {
new_val = popRichType(&s);
if (std::holds_alternative<std::monostate>(new_val)) {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
}
return set(new_val);

Loading…
Cancel
Save