-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.cpp
More file actions
177 lines (151 loc) · 5.97 KB
/
Copy pathmain.cpp
File metadata and controls
177 lines (151 loc) · 5.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include <Arduino.h>
#include <Button2.h>
#include <Wire.h>
// Controller and services
#include "Controller.h"
#include "LightService.h"
#include "DistanceService.h"
#include <WiFi.h>
#include "NetworkService.h"
#include "CommunicationService.h"
#include "ConfigService.h"
#include "PreferencesConfigStore.h"
#include "CaptivePortalService.h"
#include "OtaService.h"
#include "HomeAssistantService.h"
#include "IntegrationConsole.h"
#include "ModeRegistration.h"
// Config
#include "GlowConfig.h"
// Shown as the device firmware version in Home Assistant.
#ifndef GLOW_FIRMWARE_VERSION
#define GLOW_FIRMWARE_VERSION "dev"
#endif
// Services
Button2 button;
LightService lightService;
NetworkService networkService;
CommunicationService communicationService;
DistanceService distanceService;
PreferencesConfigStore configStore;
CaptivePortalService captivePortalService;
OtaService otaService;
HomeAssistantService homeAssistantService;
// Controller
Controller controller(&distanceService, &communicationService);
/*
* This is the main setup function; it is called only once during startup.
*/
void setup() {
#ifdef GLOW_INTEGRATION_TEST
// A single injected ESP-NOW frame is a 507 character console line, which does
// not fit the default receive buffer.
Serial.setRxBufferSize(2048);
#endif
Serial.begin(115200);
// Setup I2C for the distance sensor
Wire.begin(DISTANCE_SENSOR_SDA, DISTANCE_SENSOR_SCL);
Serial.println("[INFO] Starting Glow");
DeviceConfig deviceConfig = DeviceConfig::compileTimeDefaults();
if (configStore.load(&deviceConfig)) {
Serial.println("[INFO] Loaded persistent device configuration");
} else {
Serial.println("[INFO] Using compile-time device configuration");
}
String configError;
if (!deviceConfig.validate(&configError)) {
Serial.printf("[ERROR] Device configuration rejected: %s\n",
configError.c_str());
deviceConfig = DeviceConfig::safeDefaults();
}
// Every lamp is flashed from the same configuration, so a default hostname
// would be identical everywhere. Deriving it once here makes the mDNS name and
// the Home Assistant device name unique, because both follow this value.
uint8_t localMac[6] = {};
WiFi.macAddress(localMac);
deviceConfig.hostname = DeviceConfig::uniqueHostname(deviceConfig.hostname, localMac);
NetworkConfig networkConfig;
networkConfig.enabled = deviceConfig.wifiEnabled;
networkConfig.ssid = deviceConfig.wifiSsid;
networkConfig.password = deviceConfig.wifiPassword;
networkConfig.hostname = deviceConfig.hostname;
networkConfig.fallbackChannel = deviceConfig.fallbackChannel;
pinMode(BUTTON_PIN, INPUT_PULLUP);
bool portalRequested = GLOW_PORTAL_ENABLED && digitalRead(BUTTON_PIN) == LOW;
String portalSsid = deviceConfig.hostname.substring(0, 26) + "-setup";
// NetworkService owns the shared radio and must configure station mode before
// ESP-NOW starts. Joining an access point continues asynchronously.
lightService.setup();
distanceService.setup();
bool portalStarted = portalRequested &&
networkService.setupProvisioning(networkConfig, portalSsid,
GLOW_PORTAL_PASSWORD);
if (!portalStarted) networkService.setup(networkConfig);
CommunicationConfig communicationConfig;
communicationConfig.enabled = deviceConfig.communicationEnabled;
communicationConfig.groupKeyHex = deviceConfig.groupKeyHex;
communicationService.setup(communicationConfig);
networkService.onChannelChanged([](uint8_t channel) {
communicationService.radioChannelChanged(channel);
controller.requestResync();
});
button.begin(BUTTON_PIN);
// Set debounce time (this is the time the button needs to be stable before a press is registered)
button.setLongClickTime(500);
registerModes(controller, lightService, distanceService, communicationService);
// Setup controller
controller.configureSyncDefaults(deviceConfig.syncFollow,
deviceConfig.syncPublish);
controller.configureRuntimeFeatures(GLOW_PORTAL_ENABLED,
deviceConfig.otaEnabled);
controller.setup();
if (portalStarted) {
captivePortalService.setup(configStore, networkService, deviceConfig);
} else {
OtaConfig otaConfig;
otaConfig.enabled = deviceConfig.otaEnabled;
otaConfig.password = deviceConfig.otaPassword;
otaService.setup(networkService, otaConfig);
// Home Assistant shares the infrastructure connection with OTA and is only
// meaningful once the lamp is on the network, so it stays off in the portal.
HomeAssistantConfig homeAssistantConfig;
homeAssistantConfig.enabled = deviceConfig.mqttEnabled;
homeAssistantConfig.host = deviceConfig.mqttHost;
homeAssistantConfig.port = deviceConfig.mqttPort;
homeAssistantConfig.user = deviceConfig.mqttUser;
homeAssistantConfig.password = deviceConfig.mqttPassword;
homeAssistantConfig.discoveryPrefix = deviceConfig.mqttDiscoveryPrefix;
char deviceId[24];
snprintf(deviceId, sizeof(deviceId), "glow-%u", communicationService.getNodeId());
homeAssistantService.setup(networkService, controller, homeAssistantConfig,
deviceId, GLOW_FIRMWARE_VERSION);
}
// Configure button handlers
button.setLongClickHandler([](Button2 &btn) {
controller.nextMode();
});
button.setClickHandler([](Button2 &btn) {
controller.nextOption();
});
// This click can be used for custom actions in the current mode
button.setDoubleClickHandler([](Button2 &btn) {
controller.customClick();
});
Serial.println("[INFO] GlowLight started");
}
/*
* This is the main loop function; it is called repeatedly by the system.
*/
void loop() {
// The services and controller need to be looped
integrationConsoleLoop(controller, communicationService);
button.loop();
distanceService.loop();
controller.loop();
lightService.loop();
networkService.loop();
captivePortalService.loop();
otaService.loop();
homeAssistantService.loop();
communicationService.loop();
}