EmlaLockSafe
ConfigurationServer.h
Go to the documentation of this file.
1
5#pragma once
6
7#include "../UsedInterrupts.h"
8#include "../views/ViewStore.h"
10
11#include <Arduino.h>
12#include <ESPAsyncWebServer.h>
13#include <LiquidCrystal_PCF8574.h>
14#include <RotaryEncoder.h>
15#include <SPIFFS.h>
16#include <WiFi.h>
17#include <list>
18#include <mutex>
19#include <stdlib.h>
20
21namespace configuration {
26#pragma region Singelton
27protected:
31 inline static ConfigurationServer** getInstance() {
32 static ConfigurationServer* instance = nullptr;
33 return &instance;
34 }
35
36public:
41 return **getInstance();
42 }
43
44public:
51 inline static ConfigurationServer& begin(LiquidCrystal_PCF8574& display, RotaryEncoder& encoder) {
52 if (!*getInstance()) {
54 }
55 return **getInstance();
56 }
57#pragma endregion
58
59protected:
63 AsyncWebSocket remoteControlWebSocket;
64
65protected:
69 LiquidCrystal_PCF8574& display;
70
71protected:
75 RotaryEncoder& encoder;
76
77private:
84 ConfigurationServer(LiquidCrystal_PCF8574& display, RotaryEncoder& encoder)
88 , encoder(encoder) {
89 // Add files to webserver which are loaded from the file system
90 server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
93 request->send(SPIFFS, "/indexConfig.html", "text/html");
94 }
95 else {
96 request->send(SPIFFS, "/indexRemote.html", "text/html");
97 }
98 });
99 });
100 addSpiffsFileToServer("/zones.json", "text/json");
101 addSpiffsFileToServer("/moment.js", "text/javascript");
102 addSpiffsFileToServer("/dotmatrix.js", "text/javascript");
103 addSpiffsFileToServer("/remoteLcd.js", "text/javascript");
104 addSpiffsFileToServer("/rotate.svg", "image/svg+xml");
105
106 // Add file to webserver returning the current settings
107 server.on("/lastValues", HTTP_GET, [this](AsyncWebServerRequest* request) {
108 onGetLastValues(request);
109 });
110
111 // Handler to save the configuration
112 server.on("/saveData", HTTP_GET, [this](AsyncWebServerRequest* request) {
113 onSaveData(request);
114 });
115
116 // Handler to generate a new emergency key
117 server.on("/generateNewKey", HTTP_GET, [this](AsyncWebServerRequest* request) {
118 onGenerateNewKey(request);
119 });
120
121 // Handler of the websocket for the remote control of the safe
123 [this](AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
124 onRemoteControlWebSocketEvent(client, type, arg, data, len);
125 });
126 server.addHandler(&remoteControlWebSocket);
127
128 // Start Webserver
129 server.begin();
130 }
131
132protected:
136 static String getParam(AsyncWebServerRequest* request, const String& paramName) {
137 auto param = request->getParam(paramName);
138 if (param == nullptr) {
139 Serial.println("Error getting parameter: " + paramName);
140 return "";
141 }
142 else {
143 Serial.println("Getting parameter: " + paramName + " = \"" + param->value() + "\"");
144 return param->value();
145 }
146 }
147
148protected:
152 static inline bool isConfigurationAllowed() {
153 return views::ViewStore::getView(views::ViewStore::ConfigurationServerView) == lcd::ViewBase::getCurrentView();
154 }
155
156protected:
162 void onGetLastValues(AsyncWebServerRequest* request) {
164 String response = "";
165
167 response += "\r\n";
169 response += "\r\n";
171 response += "\r\n";
172 response += Configuration::getSingleton().getDisableFailedSession() ? "true" : "false";
173 response += "\r\n";
175 response += "\r\n";
177 response += "\r\n";
178 response += Configuration::getSingleton().getAutoLockHygieneOpeningTimeout() ? "true" : "false";
179 response += "\r\n";
181 response += "\r\n";
183 response += "\r\n";
185 response += "\r\n";
187 response += "\r\n";
189 response += "\r\n";
191 response += "\r\n";
192
193 request->send(200, "text/plain", response);
194 }
195 else {
196 request->send(404, "text/plain", "Not Found!");
197 }
198 }
199
200protected:
206 void onSaveData(AsyncWebServerRequest* request) {
209 restrictions.startTime = strtoul(getParam(request, "timeRestrictionsStartTime").c_str(), NULL, 0);
210 restrictions.endTime = strtoul(getParam(request, "timeRestrictionsEndTime").c_str(), NULL, 0);
211 restrictions.restrictUnlockTimes = getParam(request, "timeRestrictionsRestrictUnlockTimes") == "true";
212 restrictions.restrictHygieneOpeningTimes = getParam(request, "timeRestrictionsRestrictHygieneOpeningTimes") == "true";
213 restrictions.restrictEmergencyKeyTimes = getParam(request, "timeRestrictionsRestrictEmergencyKeyTimes") == "true";
214 restrictions.restrictConfigurationServer = getParam(request, "timeRestrictionsRestrictConfigurationServer") == "true";
215
217 getParam(request, "apiKey"),
218 getParam(request, "disableFailedSession") == "true",
219 getParam(request, "timezoneName"),
220 getParam(request, "timezone"),
221 strtoul(getParam(request, "backlightTimeOut").c_str(), NULL, 0),
222 getParam(request, "autoLockHygieneOpeningTimeout") == "true",
223 restrictions);
224 request->send(200, "text/plain", "Configuration updated");
225 }
226 else {
227 request->send(404, "text/plain", "Not Found!");
228 }
229 }
230
231protected:
237 void onGenerateNewKey(AsyncWebServerRequest* request) {
239 request->send(200, "text/plain", Configuration::getSingleton().generateNewEmergencyKey());
240 }
241 else {
242 request->send(404, "text/plain", "Not Found!");
243 }
244 }
245
246protected:
257 void onRemoteControlWebSocketEvent(AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
258 if (type == WS_EVT_CONNECT) {
259 Serial.println("Websocket client connection received");
260 }
261 else if (type == WS_EVT_DATA) {
262 AwsFrameInfo* info = (AwsFrameInfo*)arg;
263 if ((info->opcode == WS_TEXT) && (len == 1)) {
264 if (data[0] == 'L') {
265 String response = display.getCompleteContent();
266 response += isConfigurationAllowed() ? "true\n" : "false\n";
267 response += lcd::ViewBase::isBacklightOn() ? "true\n" : "false\n";
268 client->text(response);
269 }
270 else if (data[0] == 'A') {
271 encoder.injectClockwiseRotation();
272 }
273 else if (data[0] == 'B') {
274 encoder.injectClick();
275 }
276 else if (data[0] == 'C') {
277 encoder.injectCounterClockwiseRotation();
278 }
279 }
280 }
281 else if (type == WS_EVT_DISCONNECT) {
282 Serial.println("Client disconnected");
283 }
284 else {
285 Serial.println("else");
286 }
287 }
288};
289} // namespace configuration
static void executeWithoutInterrupts(std::function< void(void)> f)
Execute the passed function without interrupts.
Definition: UsedInterrupts.h:58
Container to restrict the time when the safe can be opened.
Definition: Configuration.h:27
bool restrictUnlockTimes
If set, the safe can only be opened during the specified time using the normal unlock function.
Definition: Configuration.h:46
bool restrictEmergencyKeyTimes
If set, the time when the emergency key is accepted is restricted.
Definition: Configuration.h:58
bool restrictHygieneOpeningTimes
If set, the time for hygiene openings is restricted.
Definition: Configuration.h:52
uint32_t startTime
The number of seconds after midnight after which the safe can be opened.
Definition: Configuration.h:34
bool restrictConfigurationServer
If set, the time when the configuration server can be started is restricted.
Definition: Configuration.h:64
uint32_t endTime
The number of seconds after midnight until which the safe can be opened.
Definition: Configuration.h:40
const bool & getAutoLockHygieneOpeningTimeout() const
return if the safe should automatically lock after the time for hygiene opening is over....
Definition: Configuration.h:346
void setConfigurationSettings(const String &userId, const String &apiKey, const bool &disableFailedSession, const String &timezoneName, const String &timezone, const long &backlightTimeOut, const bool &autoLockHygieneOpeningTimeout, const TimeRestrictions &timeRestrictions)
Set the Configuration Settings.
Definition: Configuration.h:389
const bool & getDisableFailedSession() const
get disable support of failed session. Note: If selected, the safe will be locked until the last know...
Definition: Configuration.h:309
const unsigned long & getBacklightTimeOut() const
get the timeout of display backlight in seconds
Definition: Configuration.h:337
const String & getUserId() const
get the User ID extracted from the webpage settings > API
Definition: Configuration.h:283
const TimeRestrictions & getTimeRestrictions() const
get the timeout of display backlight in seconds
Definition: Configuration.h:354
const String & getTimezoneName() const
get the name to the timezone-string (e.g. "Europe/Berlin")
Definition: Configuration.h:329
static Configuration & getSingleton()
Get the Singleton object.
Definition: Configuration.h:162
const String & getEmergencyKey() const
get the emergency key of the safe
Definition: Configuration.h:299
const String & getApiKey() const
get the API Key extracted from the webpage settings > API
Definition: Configuration.h:291
Base class for configuring the controller over WiFi.
Definition: ConfigurationServerBase.h:16
void addSpiffsFileToServer(const char *path, String contentType, const char *filename=nullptr)
Adds the file from the SPIFFS with the filename to the webserver under the given path.
Definition: ConfigurationServerBase.h:43
AsyncWebServer server
The used asynchronous webserver.
Definition: ConfigurationServerBase.h:21
Class implementing all functions to configure the Controller.
Definition: ConfigurationServer.h:25
void onRemoteControlWebSocketEvent(AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
Event handler for the WebSocket connection which is used to remote control the safe.
Definition: ConfigurationServer.h:257
static ConfigurationServer & getSingleton()
Get the Singleton object.
Definition: ConfigurationServer.h:40
AsyncWebSocket remoteControlWebSocket
Websocket to remote control the display.
Definition: ConfigurationServer.h:63
void onGetLastValues(AsyncWebServerRequest *request)
Event handler called if the current configuration should be sent to the browser.
Definition: ConfigurationServer.h:162
static bool isConfigurationAllowed()
Quick check if the ConfigurationServerView is active --> changing the configuration is allowed.
Definition: ConfigurationServer.h:152
LiquidCrystal_PCF8574 & display
Reference to the display.
Definition: ConfigurationServer.h:69
RotaryEncoder & encoder
Refernce to the encoder.
Definition: ConfigurationServer.h:75
static String getParam(AsyncWebServerRequest *request, const String &paramName)
Extract a passed parameter value from a HTTP GET request.
Definition: ConfigurationServer.h:136
static ConfigurationServer ** getInstance()
Function providing the instance for the singleton.
Definition: ConfigurationServer.h:31
void onGenerateNewKey(AsyncWebServerRequest *request)
Event handler called if a new emergency key should be generated.
Definition: ConfigurationServer.h:237
void onSaveData(AsyncWebServerRequest *request)
Event handler called if new configuration data should be saved.
Definition: ConfigurationServer.h:206
ConfigurationServer(LiquidCrystal_PCF8574 &display, RotaryEncoder &encoder)
Construct a new Configuration Server object.
Definition: ConfigurationServer.h:84
static ConfigurationServer & begin(LiquidCrystal_PCF8574 &display, RotaryEncoder &encoder)
Create a new Configuration server.
Definition: ConfigurationServer.h:51
static lcd::ViewBase * getView(const ViewId &id)
Returns the pointer to the view registered by the given id.
Definition: ViewStore.h:71
@ ConfigurationServerView
Definition: ViewStore.h:24
Definition: Configuration.h:16