ENTS-tock
Environmental NeTworked Sensor firmware on Tock OS
Loading...
Searching...
No Matches
config_server.cpp
Go to the documentation of this file.
1#include "config_server.hpp"
2
3#include <ArduinoLog.h>
4#include <LittleFS.h>
5#include <WebServer.h>
6#include <libents/proto/controller.pb.h>
8
9#include "configuration.hpp"
10#include "protobuf_utils.hpp"
11#include "validation.hpp"
12
14static WebServer server(80);
15
22
26void handleSave();
27
33void handleConfig();
34
40void handleIdentity();
41
47void printQuery();
48
57String validateInputs();
58
59void handleSave() {
60 printQuery();
61
62 Log.infoln("Slope: %s", server.arg("calibration_v_slope"));
63 Log.infoln("Slope: %D", server.arg("calibration_v_slope").toDouble());
64
65 // validate inputs and return error if any
66 String error = validateInputs();
67 if (error != "") {
68 error.replace("\"", "\\\"");
69 String errorJson = "{\"error\":\"" + error + "\"}";
70 server.send(400, "application/json", errorJson);
71 return;
72 }
73
74 UserConfiguration config = UserConfiguration_init_default;
75
76 // Parsing the webpage data into our config structure
77 config.logger_id = server.arg("logger_id").toInt();
78 config.cell_id = server.arg("cell_id").toInt();
79
80 // set upload method
81 String upload_method = server.arg("upload_method");
82 if (upload_method == "LoRa") {
83 config.Upload_method = Uploadmethod_LoRa;
84 } else if (upload_method == "WiFi") {
85 config.Upload_method = Uploadmethod_WiFi;
86 } else {
87 Log.errorln("Invalid upload method: %s.", upload_method.c_str());
88 Log.errorln("Defaulting to LoRa.");
89 config.Upload_method = Uploadmethod_LoRa;
90 }
91
92 // copy ssid
93 String wifi_ssid = server.arg("wifi_ssid");
94 wifi_ssid.trim();
95 strncpy(config.WiFi_SSID, wifi_ssid.c_str(), sizeof(config.WiFi_SSID));
96
97 // copy password
98 bool use_previous_password = server.hasArg("use_previous_password");
99 if (use_previous_password) {
100 const UserConfiguration& config_old = getConfig();
101 strncpy(config.WiFi_Password, config_old.WiFi_Password,
102 sizeof(config.WiFi_Password));
103 } else {
104 String wifi_password = server.arg("wifi_password");
105 wifi_password.trim();
106 strncpy(config.WiFi_Password, wifi_password.c_str(),
107 sizeof(config.WiFi_Password));
108 }
109
110 // copy url
111 String api_endpoint_url = server.arg("api_endpoint_url");
112 api_endpoint_url.trim();
113 strncpy(config.API_Endpoint_URL, api_endpoint_url.c_str(),
114 sizeof(config.API_Endpoint_URL));
115
116 config.Upload_interval = server.arg("upload_interval").toInt();
117
118 bool voltage_enabled = server.hasArg("voltage_enabled");
119 if (voltage_enabled) {
120 config.enabled_sensors[config.enabled_sensors_count++] =
121 EnabledSensor_Voltage;
122 }
123
124 bool current_enabled = server.hasArg("current_enabled");
125 if (current_enabled) {
126 config.enabled_sensors[config.enabled_sensors_count++] =
127 EnabledSensor_Current;
128 }
129
130 bool teros12_enabled = server.hasArg("teros12_enabled");
131 if (teros12_enabled) {
132 config.enabled_sensors[config.enabled_sensors_count++] =
133 EnabledSensor_Teros12;
134 }
135
136 bool teros21_enabled = server.hasArg("teros21_enabled");
137 if (teros21_enabled) {
138 config.enabled_sensors[config.enabled_sensors_count++] =
139 EnabledSensor_Teros21;
140 }
141
142 bool bme280_enabled = server.hasArg("bme280_enabled");
143 if (bme280_enabled) {
144 config.enabled_sensors[config.enabled_sensors_count++] =
145 EnabledSensor_BME280;
146 }
147
148 bool Phytos31_enabled = server.hasArg("Phytos31_enabled");
149 if (Phytos31_enabled) {
150 config.enabled_sensors[config.enabled_sensors_count++] =
151 EnabledSensor_Phytos31;
152 }
153
154 bool SEN0308_enabled = server.hasArg("SEN0308_enabled");
155 if (SEN0308_enabled) {
156 config.enabled_sensors[config.enabled_sensors_count++] =
157 EnabledSensor_SEN0308;
158 }
159
160 bool SEN0257_enabled = server.hasArg("SEN0257_enabled");
161 if (SEN0257_enabled) {
162 config.enabled_sensors[config.enabled_sensors_count++] =
163 EnabledSensor_SEN0257;
164 }
165
166 bool YFS210C_enabled = server.hasArg("YFS210C_enabled");
167 if (YFS210C_enabled) {
168 config.enabled_sensors[config.enabled_sensors_count++] =
169 EnabledSensor_YFS210C;
170 }
171
172 bool PCAP02_enabled = server.hasArg("PCAP02_enabled");
173 if (PCAP02_enabled) {
174 config.enabled_sensors[config.enabled_sensors_count++] =
175 EnabledSensor_PCAP02;
176 }
177
178 config.Voltage_Slope =
179 strtod(server.arg("calibration_v_slope").c_str(), NULL);
180 config.Voltage_Offset =
181 strtod(server.arg("calibration_v_offset").c_str(), NULL);
182 config.Current_Slope =
183 strtod(server.arg("calibration_i_slope").c_str(), NULL);
184 config.Current_Offset =
185 strtod(server.arg("calibration_i_offset").c_str(), NULL);
186
187 // POSTED config
188 // Log.noticeln("Received configuration:");
189 // Log.noticeln("-----------------------");
190 // printConfig(config);
191
192 setConfig(config);
194
195 // NOTE: Direclty setting
196 // Update the module's current configuration
197 // user_config.updateConfig(&decoded_config);
198
199 // Prepare success message
200 String successMessage = "Configuration saved successfully!\\n";
201 successMessage += "Please RESET the STM32 to update the configurations";
202 String successJson = "{\"success\":\"" + successMessage + "\"}";
203 server.send(200, "application/json", successJson);
204}
205
207 printQuery();
208
209 String json = getConfigJson();
210
211 server.send(200, "application/json", json);
212}
213
215 printQuery();
216
217 String json = "{";
218 json += "\"ESP32_STA_MAC\":\"" + String(WiFi.macAddress()) + "\",";
219 json += "\"ESP32_AP_MAC\":\"" + String(WiFi.softAPmacAddress()) + "\",";
220 json += "\"ESP32_AP_SSID\":\"" + String(WiFi.softAPSSID()) + "\",";
221
222 // The last 8 characters of the AP SSID represent the 4 byte STM32 device
223 // address in hex
224 String STM32_devAddr = WiFi.softAPSSID().substring(5, 7) + ":" +
225 WiFi.softAPSSID().substring(7, 9) + ":" +
226 WiFi.softAPSSID().substring(9, 11) + ":" +
227 WiFi.softAPSSID().substring(11, 13);
228
229 json += "\"STM32_AppKey\":\"" +
230 String("2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C") + "\",";
231 json += "\"STM32_NwkKey\":\"" +
232 String("2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C") + "\",";
233 json += "\"STM32_AppSKey\":\"" +
234 String("2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C") + "\",";
235 json += "\"STM32_NwkSKey\":\"" +
236 String("2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C") + "\",";
237 json +=
238 "\"STM32_DevEUI\":\"" + String("00:80:E1:15:") + STM32_devAddr + "\",";
239 json += "\"STM32_AppEUI\":\"" + String("01:01:01:01:01:01:01:01") + "\",";
240 json += "\"STM32_DevAddr\":\"" + String(STM32_devAddr) + "\"";
241 json += "}";
242
243 server.send(200, "application/json", json);
244}
245
247 // start server once
248 bool started = false;
249 if (!started) {
250 server.serveStatic("/", LittleFS, "/index.html");
251 server.on("/save", HTTP_POST, handleSave);
252 server.on("/config", HTTP_GET, handleConfig);
253 server.on("/identity", HTTP_GET, handleIdentity);
254 server.begin();
255
256 started = true;
257 }
258}
259
260void handleClient() { server.handleClient(); }
261
263 String error;
264
265 // Validate Upload Settings
266 if ((error = validateUInt(server.arg("logger_id"), "Logger ID")) != "")
267 return error;
268 if ((error = validateUInt(server.arg("cell_id"), "Cell ID")) != "")
269 return error;
270 if ((error = validateUInt(server.arg("upload_interval"),
271 "Upload Interval")) != "")
272 return error;
273
274 // Validate Measurement Settings
275 if ((error = validateFloat(server.arg("calibration_v_slope"),
276 "Calibration V Slope")) != "")
277 return error;
278 if ((error = validateFloat(server.arg("calibration_v_offset"),
279 "Calibration V Offset")) != "")
280 return error;
281 if ((error = validateFloat(server.arg("calibration_i_slope"),
282 "Calibration I Slope")) != "")
283 return error;
284 if ((error = validateFloat(server.arg("calibration_i_offset"),
285 "Calibration I Offset")) != "")
286 return error;
287
288 // Validate WiFi Settings if WiFi is selected
289 if (server.arg("upload_method") == "WiFi") {
290 if (server.arg("wifi_ssid").length() == 0)
291 return "WiFi SSID cannot be empty";
292 if ((error = validateURL(server.arg("api_endpoint_url"))) != "")
293 return error;
294 }
295
296 return ""; // Empty string when no error
297}
298
300 IPAddress ip = server.client().remoteIP();
301 String path = server.uri();
302
303 std::string method = "";
304 switch (server.method()) {
305 case HTTP_GET:
306 method = "GET";
307 break;
308 case HTTP_POST:
309 method = "POST";
310 break;
311 case HTTP_PUT:
312 method = "PUT";
313 break;
314 case HTTP_DELETE:
315 method = "DELETE";
316 break;
317 default:
318 method = "UNKNOWN";
319 break;
320 }
321
322 Log.noticeln("%s - %s %s", ip.toString().c_str(), method.c_str(),
323 path.c_str());
324}
void handleConfig()
Get the current configuration.
void setupServer()
Setup webserver.
void handleSave()
Handle save action.
void handleClient()
Call to handle requests to the web server.
String validateInputs()
Validate user inputs from the web form.
void printQuery()
Prints debug information for http queries.
void handleRoot()
Handle the root path of the web server.
void handleIdentity()
Get the ESP32 STA MAC, ESP32 AP MAC, and STM32 device address (DevEUI)
void printReceivedConfig()
Print the current user configuration to the log.
String getConfigJson()
Get the current configuration as a JSON string.
void setConfig(const UserConfiguration &new_config)
Set the user configuration.
const UserConfiguration & getConfig()
Get a copy of the current user configuration.
Library for encoding/decoding protobuf messages.
String validateFloat(const String &value, const String &name)
Validate a string as a floating-point number.
String validateUInt(const String &value, const String &name)
Validate a string as an unsigned integer.
Definition validation.cpp:3
String validateURL(const String &value)
Validate a string as a URL.