Skip to content

Commit ca05255

Browse files
committed
Add home assistant service and app
1 parent 6572b50 commit ca05255

File tree

14 files changed

+433
-1
lines changed

14 files changed

+433
-1
lines changed

src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ list(APPEND SOURCE_FILES
398398
displayapp/screens/Alarm.cpp
399399
displayapp/screens/Styles.cpp
400400
displayapp/screens/WeatherSymbols.cpp
401+
displayapp/screens/Home.cpp
401402
displayapp/Colors.cpp
402403
displayapp/widgets/Counter.cpp
403404
displayapp/widgets/PageIndicator.cpp
@@ -466,6 +467,7 @@ list(APPEND SOURCE_FILES
466467
components/ble/ServiceDiscovery.cpp
467468
components/ble/HeartRateService.cpp
468469
components/ble/MotionService.cpp
470+
components/ble/HomeService.cpp
469471
components/firmwarevalidator/FirmwareValidator.cpp
470472
components/motor/MotorController.cpp
471473
components/settings/Settings.cpp
@@ -658,6 +660,7 @@ set(INCLUDE_FILES
658660
components/ble/HeartRateService.h
659661
components/ble/MotionService.h
660662
components/ble/SimpleWeatherService.h
663+
components/ble/HomeService.h
661664
components/settings/Settings.h
662665
components/timer/Timer.h
663666
components/stopwatch/StopWatchController.h

src/components/ble/HomeService.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#include "HomeService.h"
2+
3+
#include <libraries/log/nrf_log.h>
4+
#include "components/ble/NimbleController.h"
5+
6+
namespace {
7+
// 0006yyxx-78fc-48fe-8e23-433b3a1942d0
8+
constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) {
9+
return ble_uuid128_t {.u = {.type = BLE_UUID_TYPE_128},
10+
.value = {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, x, y, 0x06, 0x00}};
11+
}
12+
13+
// 00060000-78fc-48fe-8e23-433b3a1942d0
14+
constexpr ble_uuid128_t BaseUuid() {
15+
return CharUuid(0x00, 0x00);
16+
}
17+
18+
constexpr ble_uuid128_t homeUuid {BaseUuid()};
19+
20+
constexpr ble_uuid128_t homeOpenUuid {CharUuid(0x01, 0x00)};
21+
constexpr ble_uuid128_t homeLayoutUuid {CharUuid(0x02, 0x00)};
22+
constexpr ble_uuid128_t homePressUuid {CharUuid(0x03, 0x00)};
23+
24+
int HomeCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) {
25+
return static_cast<Pinetime::Controllers::HomeService*>(arg)->OnCommand(ctxt);
26+
}
27+
} // namespace
28+
29+
Pinetime::Controllers::HomeService::HomeService(NimbleController& nimble) : nimble(nimble) {
30+
characteristicDefinition[0] = {.uuid = &homeLayoutUuid.u, .access_cb = HomeCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE};
31+
characteristicDefinition[1] = {.uuid = &homeOpenUuid.u,
32+
.access_cb = HomeCallback,
33+
.arg = this,
34+
.flags = BLE_GATT_CHR_F_NOTIFY,
35+
.val_handle = &eventOpenedHandle};
36+
characteristicDefinition[2] = {.uuid = &homePressUuid.u,
37+
.access_cb = HomeCallback,
38+
.arg = this,
39+
.flags = BLE_GATT_CHR_F_NOTIFY,
40+
.val_handle = &eventPressedHandle};
41+
characteristicDefinition[3] = {0};
42+
43+
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &homeUuid.u, .characteristics = characteristicDefinition};
44+
serviceDefinition[1] = {0};
45+
}
46+
47+
void Pinetime::Controllers::HomeService::Init() {
48+
uint8_t res = 0;
49+
res = ble_gatts_count_cfg(serviceDefinition);
50+
ASSERT(res == 0);
51+
52+
res = ble_gatts_add_svcs(serviceDefinition);
53+
ASSERT(res == 0);
54+
}
55+
56+
int Pinetime::Controllers::HomeService::OnCommand(ble_gatt_access_ctxt* ctxt) {
57+
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
58+
size_t bufferSize = OS_MBUF_PKTLEN(ctxt->om);
59+
60+
uint8_t data[bufferSize];
61+
os_mbuf_copydata(ctxt->om, 0, bufferSize, data);
62+
63+
if (ble_uuid_cmp(ctxt->chr->uuid, &homeLayoutUuid.u) == 0) {
64+
auto screen = std::make_unique<Screen>();
65+
uint8_t* ptr = &data[0];
66+
67+
numScreens = *ptr++;
68+
screen->index = *ptr++;
69+
70+
screen->cols = *ptr >> 4;
71+
screen->rows = *ptr & 0x0F;
72+
ptr++;
73+
uint8_t num_comps = *(ptr++);
74+
75+
for (size_t j = 0; j < num_comps; j++) {
76+
Component comp;
77+
comp.type = (ComponentType) (*(ptr++));
78+
79+
comp.x = *ptr >> 4;
80+
comp.y = *ptr & 0x0F;
81+
ptr++;
82+
comp.w = *ptr >> 4;
83+
comp.h = *ptr & 0x0F;
84+
ptr++;
85+
86+
uint8_t label_len = *(ptr++);
87+
auto label = std::make_unique<char[]>(label_len + 1);
88+
memcpy(label.get(), ptr, label_len);
89+
label.get()[label_len] = 0;
90+
ptr += label_len;
91+
92+
comp.label = std::move(label);
93+
94+
screen->components.emplace_back(std::move(comp));
95+
}
96+
97+
currentScreen = std::move(screen);
98+
dataUpdateTime = xTaskGetTickCount();
99+
}
100+
}
101+
102+
return 0;
103+
}
104+
105+
bool Pinetime::Controllers::HomeService::NotifyOpened(int8_t screenIndex) {
106+
uint16_t connectionHandle = nimble.connHandle();
107+
108+
if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
109+
return false;
110+
}
111+
112+
auto* om = ble_hs_mbuf_from_flat(&screenIndex, sizeof(screenIndex));
113+
ble_gattc_notify_custom(connectionHandle, eventOpenedHandle, om);
114+
115+
return true;
116+
}
117+
118+
bool Pinetime::Controllers::HomeService::OnOpened() {
119+
return NotifyOpened(0);
120+
}
121+
122+
void Pinetime::Controllers::HomeService::OnViewScreen(uint8_t n) {
123+
NotifyOpened(n);
124+
}
125+
126+
void Pinetime::Controllers::HomeService::OnClosed() {
127+
dataUpdateTime = 0;
128+
numScreens = 0;
129+
currentScreen.reset();
130+
131+
NotifyOpened(-1);
132+
}
133+
134+
void Pinetime::Controllers::HomeService::OnPressed(uint8_t screen, uint8_t componentId) {
135+
uint16_t connectionHandle = nimble.connHandle();
136+
137+
if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
138+
return;
139+
}
140+
141+
uint8_t v[] = {screen, componentId};
142+
auto* om = ble_hs_mbuf_from_flat(v, sizeof(v));
143+
ble_gattc_notify_custom(connectionHandle, eventPressedHandle, om);
144+
}

src/components/ble/HomeService.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#pragma once
2+
#define min // workaround: nimble's min/max macros conflict with libstdc++
3+
#define max
4+
#include <host/ble_gap.h>
5+
#undef max
6+
#undef min
7+
#include <atomic>
8+
#include <memory>
9+
#include <vector>
10+
11+
namespace Pinetime {
12+
namespace Controllers {
13+
class NimbleController;
14+
15+
class HomeService {
16+
public:
17+
enum ComponentType : uint8_t {
18+
Button,
19+
Label,
20+
};
21+
22+
struct Component {
23+
ComponentType type;
24+
uint8_t x, y, w, h;
25+
std::unique_ptr<char[]> label;
26+
};
27+
28+
struct Screen {
29+
uint8_t index, rows, cols;
30+
std::vector<Component> components {};
31+
};
32+
33+
HomeService(NimbleController& nimble);
34+
void Init();
35+
36+
int OnCommand(struct ble_gatt_access_ctxt* ctxt);
37+
38+
bool OnOpened();
39+
void OnViewScreen(uint8_t n);
40+
void OnClosed();
41+
void OnPressed(uint8_t screen, uint8_t componentId);
42+
43+
TickType_t DataUpdateTime() {
44+
return dataUpdateTime;
45+
}
46+
47+
const Screen& CurrentScreen() {
48+
return *currentScreen.get();
49+
}
50+
51+
uint8_t NumScreens() {
52+
return numScreens;
53+
}
54+
55+
private:
56+
NimbleController& nimble;
57+
58+
uint16_t eventOpenedHandle {}, eventPressedHandle;
59+
60+
std::unique_ptr<Screen> currentScreen;
61+
TickType_t dataUpdateTime = 0;
62+
uint8_t numScreens;
63+
64+
struct ble_gatt_chr_def characteristicDefinition[4];
65+
struct ble_gatt_svc_def serviceDefinition[2];
66+
67+
bool NotifyOpened(int8_t screenIndex);
68+
};
69+
}
70+
}

src/components/ble/NimbleController.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
4949
heartRateService {*this, heartRateController},
5050
motionService {*this, motionController},
5151
fsService {systemTask, fs},
52-
serviceDiscovery({&currentTimeClient, &alertNotificationClient}) {
52+
serviceDiscovery({&currentTimeClient, &alertNotificationClient}),
53+
homeService {*this} {
5354
}
5455

5556
void nimble_on_reset(int reason) {
@@ -98,6 +99,7 @@ void NimbleController::Init() {
9899
heartRateService.Init();
99100
motionService.Init();
100101
fsService.Init();
102+
homeService.Init();
101103

102104
int rc;
103105
rc = ble_hs_util_ensure_addr(0);

src/components/ble/NimbleController.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "components/ble/ServiceDiscovery.h"
2323
#include "components/ble/MotionService.h"
2424
#include "components/ble/SimpleWeatherService.h"
25+
#include "components/ble/HomeService.h"
2526
#include "components/fs/FS.h"
2627

2728
namespace Pinetime {
@@ -71,6 +72,10 @@ namespace Pinetime {
7172
return weatherService;
7273
};
7374

75+
Pinetime::Controllers::HomeService& home() {
76+
return homeService;
77+
};
78+
7479
uint16_t connHandle();
7580
void NotifyBatteryLevel(uint8_t level);
7681

@@ -107,6 +112,7 @@ namespace Pinetime {
107112
MotionService motionService;
108113
FSService fsService;
109114
ServiceDiscovery serviceDiscovery;
115+
HomeService homeService;
110116

111117
uint8_t addrType;
112118
uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE;

src/displayapp/Controllers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace Pinetime {
2626
class Timer;
2727
class MusicService;
2828
class NavigationService;
29+
class HomeService;
2930
}
3031

3132
namespace System {
@@ -53,6 +54,7 @@ namespace Pinetime {
5354
Pinetime::Components::LittleVgl& lvgl;
5455
Pinetime::Controllers::MusicService* musicService;
5556
Pinetime::Controllers::NavigationService* navigationService;
57+
Pinetime::Controllers::HomeService* homeService;
5658
};
5759
}
5860
}

src/displayapp/DisplayApp.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,10 @@ void DisplayApp::Register(Pinetime::Controllers::NavigationService* NavigationSe
732732
this->controllers.navigationService = NavigationService;
733733
}
734734

735+
void DisplayApp::Register(Pinetime::Controllers::HomeService* homeService) {
736+
this->controllers.homeService = homeService;
737+
}
738+
735739
void DisplayApp::ApplyBrightness() {
736740
auto brightness = settingsController.GetBrightness();
737741
if (brightness != Controllers::BrightnessController::Levels::Low && brightness != Controllers::BrightnessController::Levels::Medium &&

src/displayapp/DisplayApp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ namespace Pinetime {
8181
void Register(Pinetime::Controllers::SimpleWeatherService* weatherService);
8282
void Register(Pinetime::Controllers::MusicService* musicService);
8383
void Register(Pinetime::Controllers::NavigationService* NavigationService);
84+
void Register(Pinetime::Controllers::HomeService* homeService);
8485

8586
private:
8687
Pinetime::Drivers::St7789& lcd;

src/displayapp/UserApps.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "displayapp/screens/Timer.h"
88
#include "displayapp/screens/Twos.h"
99
#include "displayapp/screens/Tile.h"
10+
#include "displayapp/screens/Home.h"
1011
#include "displayapp/screens/ApplicationList.h"
1112
#include "displayapp/screens/WatchFaceDigital.h"
1213
#include "displayapp/screens/WatchFaceAnalog.h"

src/displayapp/apps/Apps.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace Pinetime {
3131
Dice,
3232
Weather,
3333
PassKey,
34+
Home,
3435
QuickSettings,
3536
Settings,
3637
SettingWatchFace,

0 commit comments

Comments
 (0)