web_config.cpp 9.52 KB
Newer Older
1
2
#include "web_config.h"

Eric Duminil's avatar
Eric Duminil committed
3
4
5
6
7
8
9
10
11
12
13
14
#if defined(ESP8266)
#  include <ESP8266WebServer.h>
#elif defined(ESP32)
#  include <WebServer.h>
#endif

#include "config.h"
#include "util.h"
#include "sensor_console.h"
#include <IotWebConf.h>
#include <IotWebConfOptionalGroup.h>

Eric Duminil's avatar
Notes    
Eric Duminil committed
15
16
//TODO: Is there any conflict with SPIFFS/LittleFS?
//TODO: Actually use those parameters
17
18
//TODO: Check memory consumption. Disable DEBUG info?
//TODO: Convert all strings to F-strings
Eric Duminil's avatar
Notes    
Eric Duminil committed
19

20
21
22
23
24
25
26
namespace web_config {
#if defined(ESP8266)
  ESP8266WebServer http(80); // Create a webserver object that listens for HTTP request on port 80
#elif defined(ESP32)
  WebServer http(80);
#endif

Eric Duminil's avatar
Eric Duminil committed
27
  DNSServer dnsServer; //TODO: Check if needed
28
29
30

  IotWebConf *iotWebConf;

Eric Duminil's avatar
Eric Duminil committed
31
  const char config_version[IOTWEBCONF_CONFIG_VERSION_LENGTH] = "a06"; // -- Configuration specific key. The value should be modified if config structure was changed.
32
  using namespace iotwebconf;
33

Eric Duminil's avatar
Eric Duminil committed
34
  /**
Eric Duminil's avatar
Eric Duminil committed
35
   * WiFi params
Eric Duminil's avatar
Eric Duminil committed
36
   */
Eric Duminil's avatar
Eric Duminil committed
37
  CheckboxTParameter ampelWifiParam = Builder<CheckboxTParameter>("WiFi").label("WiFi").defaultValue(true).build();
Eric Duminil's avatar
Eric Duminil committed
38
39
40
  IntTParameter<uint16_t> wifiTimeoutParam =
      Builder<IntTParameter<uint16_t>>("wifi_timeout").label("WiFi timeout").defaultValue(WIFI_TIMEOUT).min(0).placeholder(
          "[s]").build();
Eric Duminil's avatar
Eric Duminil committed
41

Eric Duminil's avatar
Eric Duminil committed
42
43
44
45
  //TODO: Distribute to corresponding classes, possibly with callbacks?
  /**
   * CO2 sensor
   */
Eric Duminil's avatar
Eric Duminil committed
46
  ParameterGroup co2Params = ParameterGroup("co2", "CO2 Sensor"); //TODO: Conflict with labels?
Eric Duminil's avatar
Eric Duminil committed
47
48

  //TODO: UIntTParameter?
Eric Duminil's avatar
Eric Duminil committed
49
50
  IntTParameter<uint16_t> timestepParam =
      Builder<IntTParameter<uint16_t>>("timestep").label("Measurement timestep").defaultValue(MEASUREMENT_TIMESTEP).min(
Eric Duminil's avatar
Eric Duminil committed
51
          2).max(1800).placeholder("[s]").build();
Eric Duminil's avatar
Eric Duminil committed
52

Eric Duminil's avatar
Eric Duminil committed
53
  FloatTParameter temperatureOffsetParam =
Eric Duminil's avatar
Eric Duminil committed
54
      Builder<FloatTParameter>("temp_offset").label("Temperature offset").defaultValue(TEMPERATURE_OFFSET).placeholder(
Eric Duminil's avatar
Eric Duminil committed
55
          "[K]").step(0.1).build();
Eric Duminil's avatar
Eric Duminil committed
56

Eric Duminil's avatar
Eric Duminil committed
57
  IntTParameter<uint16_t> altitudeParam = Builder<IntTParameter<uint16_t>>("altitude").label("Altitude").defaultValue(
Eric Duminil's avatar
Eric Duminil committed
58
  ALTITUDE_ABOVE_SEA_LEVEL).min(0).step(1).placeholder("[m]").build();
Eric Duminil's avatar
Eric Duminil committed
59

Eric Duminil's avatar
Eric Duminil committed
60
61
  IntTParameter<uint16_t> atmosphericCO2Param = Builder<IntTParameter<uint16_t>>("atmospheric_co2").label(
      "Atmospheric CO2 concentration").defaultValue(
Eric Duminil's avatar
Eric Duminil committed
62
  ATMOSPHERIC_CO2_CONCENTRATION).min(400).max(2000).step(1).placeholder("ppm").build();
Eric Duminil's avatar
Eric Duminil committed
63

Eric Duminil's avatar
Eric Duminil committed
64
  CheckboxTParameter autoCalibrateParam = Builder<CheckboxTParameter>("asc").label("Auto-calibration").defaultValue(
Eric Duminil's avatar
Eric Duminil committed
65
  AUTO_CALIBRATE_SENSOR).build();
Eric Duminil's avatar
Eric Duminil committed
66

Eric Duminil's avatar
Eric Duminil committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  /**
   * LED
   */
  ParameterGroup ledParams = ParameterGroup("LED", "LED");

  IntTParameter<uint8_t> maxBrightnessParam =
      Builder<IntTParameter<uint8_t>>("max_brightness").label("Max Brightness").defaultValue(MAX_BRIGHTNESS).min(0).max(
          255).build();
  IntTParameter<uint8_t> minBrightnessParam =
      Builder<IntTParameter<uint8_t>>("min_brightness").label("Min Brightness").defaultValue(MIN_BRIGHTNESS).min(0).max(
          255).build();
  IntTParameter<uint8_t> ledCountParam = Builder<IntTParameter<uint8_t>>("led_count").label("LED ring").defaultValue(
  LED_COUNT).min(12).max(16).step(4).build();

//  #  define HTTP_USER "co2ampel"
//  #  define HTTP_PASSWORD "my_password"

// WARNING: If AMPEL_LORAWAN is enabled, you need to modify the 3 following constants!
// This EUI must be in little-endian format, so least-significant-byte first.
// When copying an EUI from ttnctl output, this means to reverse the bytes.

Eric Duminil's avatar
Eric Duminil committed
88
89
90
  /**
   * CSV
   */
Eric Duminil's avatar
Eric Duminil committed
91
  OptionalParameterGroup csvParams = OptionalParameterGroup("CSV", "CSV", true);
Eric Duminil's avatar
Eric Duminil committed
92

Eric Duminil's avatar
Eric Duminil committed
93
  IntTParameter<uint16_t> csvTimestepParam =
Eric Duminil's avatar
Eric Duminil committed
94
95
      Builder<IntTParameter<uint16_t>>("csv_timestep").label("CSV timestep").defaultValue(CSV_INTERVAL).min(0).step(1).placeholder(
          "[s]").build();
Eric Duminil's avatar
Eric Duminil committed
96
97
98
99

  /**
   * MQTT
   */
Eric Duminil's avatar
Eric Duminil committed
100
  OptionalParameterGroup mqttParams = OptionalParameterGroup("MQTT", "MQTT", true);
Eric Duminil's avatar
Eric Duminil committed
101

Eric Duminil's avatar
Eric Duminil committed
102
103
  IntTParameter<uint16_t> mqttTimestepParam =
      Builder<IntTParameter<uint16_t>>("mqtt_timestep").label("MQTT timestep").defaultValue(
Eric Duminil's avatar
Eric Duminil committed
104
      MQTT_SENDING_INTERVAL).min(0).step(1).defaultValue(300).placeholder("[s]").build();
Eric Duminil's avatar
Eric Duminil committed
105

Eric Duminil's avatar
Eric Duminil committed
106
107
  CheckboxTParameter mqttCommandsParam =
      Builder<CheckboxTParameter>("mqtt_commands").label("MQTT commands").defaultValue(false).build();
Eric Duminil's avatar
Eric Duminil committed
108

Eric Duminil's avatar
Eric Duminil committed
109
110
  TextTParameter<STRING_LEN> mqttServerParam =
      Builder<TextTParameter<STRING_LEN>>("mqtt_server").label("MQTT Server").defaultValue(MQTT_SERVER).build();
Eric Duminil's avatar
Eric Duminil committed
111

Eric Duminil's avatar
Eric Duminil committed
112
113
  IntTParameter<uint16_t> mqttPortParam = Builder<IntTParameter<uint16_t>>("mqtt_port").label("MQTT Port").defaultValue(
  MQTT_PORT).build();
Eric Duminil's avatar
Eric Duminil committed
114

Eric Duminil's avatar
Eric Duminil committed
115
116
  TextTParameter<STRING_LEN> mqttUserParam =
      Builder<TextTParameter<STRING_LEN>>("mqtt_user").label("MQTT User").defaultValue(MQTT_USER).build();
Eric Duminil's avatar
Eric Duminil committed
117

Eric Duminil's avatar
TODO    
Eric Duminil committed
118
  //TODO: Show the number of * for password?
Eric Duminil's avatar
Eric Duminil committed
119
120
  PasswordTParameter<STRING_LEN> mqttPasswordParam = Builder<PasswordTParameter< STRING_LEN>>("mqtt_password").label(
      "MQTT password").defaultValue(MQTT_PASSWORD).build();
Eric Duminil's avatar
Eric Duminil committed
121

Eric Duminil's avatar
Eric Duminil committed
122
123
124
  /**
   * NTP Time
   */
Eric Duminil's avatar
Eric Duminil committed
125

Eric Duminil's avatar
Eric Duminil committed
126
127
128
129
  ParameterGroup timeParams = ParameterGroup("NTP", "Time server");
  TextTParameter<STRING_LEN> ntpParam =
      Builder<TextTParameter< STRING_LEN>>("ntp_server").label("NTP Server").defaultValue(NTP_SERVER).build();
  IntTParameter<int16_t> timeOffsetParam = Builder<IntTParameter<int16_t>>("timezone").label("Timezone").defaultValue(
Eric Duminil's avatar
Eric Duminil committed
130
      (UTC_OFFSET_IN_SECONDS) / 3600).min(-23).max(23).step(1).placeholder("[h]").build();
Eric Duminil's avatar
Eric Duminil committed
131
132
  CheckboxTParameter dstParam =
      Builder<CheckboxTParameter>("dst").label("Daylight Saving Time").defaultValue(false).build();
133

Eric Duminil's avatar
Eric Duminil committed
134
135
136
  /**
   * LED
   */
Eric Duminil's avatar
Eric Duminil committed
137

Eric Duminil's avatar
Eric Duminil committed
138
139
140
  /**
   * LoRa & Stuff
   */
Eric Duminil's avatar
Eric Duminil committed
141
142
143
  OptionalParameterGroup loraParams = OptionalParameterGroup("LoRaWan", "LoRaWan", false);
  IntTParameter<uint16_t> loraTimestepParam =
      Builder<IntTParameter<uint16_t>>("lora_timestep").label("LoRa timestep").defaultValue(
Eric Duminil's avatar
Eric Duminil committed
144
145
146
147
148
149
150
151
      LORAWAN_SENDING_INTERVAL).min(0).step(1).defaultValue(300).placeholder("[s]").build();

  TextTParameter<17> deviceEUIParam = Builder<TextTParameter<17>>("device_eui").label("Device EUI").defaultValue(
      "70B3D5...").build();
  TextTParameter<17> appEUIParam =
      Builder<TextTParameter<17>>("app_eui").label("App EUI").defaultValue("00EA07...").build();
  TextTParameter<32> appKeyParam =
      Builder<TextTParameter<32>>("app_key").label("App key").defaultValue("81CCFE...").build();
152

Eric Duminil's avatar
Eric Duminil committed
153
  OptionalGroupHtmlFormatProvider optionalGroupHtmlFormatProvider;
154
155
156
157
158

  void update() {
    iotWebConf->doLoop(); // Listen for HTTP requests from clients
  }

Eric Duminil's avatar
Eric Duminil committed
159
160
161
162
163
  void setWifiConnectionCallback(void (*function)()) {
    iotWebConf->setWifiConnectionCallback(function);
  }

  void setWifiConnectionFailedCallback(void (*function)()) {
Eric Duminil's avatar
Eric Duminil committed
164
    iotWebConf->setWifiConnectionFailedHandler([&function]() -> WifiAuthInfo* {
Eric Duminil's avatar
Eric Duminil committed
165
166
167
168
169
      function();
      return NULL;
    });
  }

170
171
172
  void initialize() {
    iotWebConf = new IotWebConf(ampel.sensorId, &dnsServer, &http, HTTP_PASSWORD, config_version);

173
174
175
    iotWebConf->setHtmlFormatProvider(&optionalGroupHtmlFormatProvider);

    iotWebConf->addSystemParameter(&ampelWifiParam);
Eric Duminil's avatar
Eric Duminil committed
176
    iotWebConf->addSystemParameter(&wifiTimeoutParam);
Eric Duminil's avatar
Eric Duminil committed
177
178
179

    co2Params.addItem(&timestepParam);
    co2Params.addItem(&temperatureOffsetParam);
Eric Duminil's avatar
Eric Duminil committed
180
181
182
    co2Params.addItem(&altitudeParam);
    co2Params.addItem(&atmosphericCO2Param);
    co2Params.addItem(&autoCalibrateParam);
Eric Duminil's avatar
Eric Duminil committed
183

Eric Duminil's avatar
Eric Duminil committed
184
185
186
187
    ledParams.addItem(&maxBrightnessParam);
    ledParams.addItem(&minBrightnessParam);
    ledParams.addItem(&ledCountParam);

188
189
190
191
    timeParams.addItem(&ntpParam);
    timeParams.addItem(&timeOffsetParam);
    timeParams.addItem(&dstParam);

Eric Duminil's avatar
Eric Duminil committed
192
193
194
195
196
197
198
199
200
    csvParams.addItem(&csvTimestepParam);

    mqttParams.addItem(&mqttTimestepParam);
    mqttParams.addItem(&mqttCommandsParam);
    mqttParams.addItem(&mqttServerParam);
    mqttParams.addItem(&mqttPortParam);
    mqttParams.addItem(&mqttUserParam);
    mqttParams.addItem(&mqttPasswordParam);

Eric Duminil's avatar
Eric Duminil committed
201
    //TODO: Only for ESP32
202
    loraParams.addItem(&loraTimestepParam);
Eric Duminil's avatar
Eric Duminil committed
203
204
205
    loraParams.addItem(&deviceEUIParam);
    loraParams.addItem(&appEUIParam);
    loraParams.addItem(&appKeyParam);
206

Eric Duminil's avatar
Eric Duminil committed
207
    iotWebConf->addParameterGroup(&co2Params);
Eric Duminil's avatar
Eric Duminil committed
208
    iotWebConf->addParameterGroup(&ledParams);
209
    iotWebConf->addParameterGroup(&timeParams);
Eric Duminil's avatar
Eric Duminil committed
210
211
    iotWebConf->addParameterGroup(&csvParams);
    iotWebConf->addParameterGroup(&mqttParams);
212
    iotWebConf->addParameterGroup(&loraParams);
Eric Duminil's avatar
Eric Duminil committed
213
214
215
216
217
218
219
220
221
222
223
224
225

    sensor_console::defineCommand("reset_config", []() {
      Serial.println(F("Resetting config..."));
      iotWebConf->getSystemParameterGroup()->applyDefaultValue();
      iotWebConf->saveConfig();
      Serial.println(F("Done!"));
    }, F("(resets the complete IotWeb config)"));

#if !defined(AMPEL_WIFI)
    iotWebConf->loadConfig();
    return;
#endif

226
227
228
229
230
231
232
233
234
    const int ONBOARD_LED_PIN = 2;
# ifdef ESP8266
    iotWebConf->setStatusPin(ONBOARD_LED_PIN, LOW);
# else
    iotWebConf->setStatusPin(ONBOARD_LED_PIN, HIGH);
# endif
    iotWebConf->setWifiConnectionTimeoutMs(1000UL * WIFI_TIMEOUT);

#if defined(ESP8266)
Eric Duminil's avatar
Eric Duminil committed
235
  WiFi.hostname(ampel.sensorId);
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#elif defined(ESP32)
    WiFi.setHostname(ampel.sensorId);
#endif

    iotWebConf->skipApStartup();
    //TODO: Add callbacks
    //TODO: Add LED effects
    //TODO: Allow offline config loading
    //TODO: Add default values for SSID/password
    //TODO: Add other params
    //TODO: Use HTTP_USER / HTTP_PASSWORD for config
    //TODO: Move to own class
    //TODO: Remove AP Password config?
    //TODO: Save LoRaWAN key if possible?
    //FIXME: Why does MQTT fail? (on ESP32)

    iotWebConf->init();

Eric Duminil's avatar
Eric Duminil committed
254
255
    //TODO: Authenticate only if required?
    //TODO: / captive fast return?
256
257
258
259

    http.on("/config", [] {
      iotWebConf->handleConfig();
    });
Eric Duminil's avatar
Eric Duminil committed
260

261
262
263
264
265
    http.onNotFound([]() {
      iotWebConf->handleNotFound();
    });
  }
}
Eric Duminil's avatar
Eric Duminil committed
266
267
268
269

namespace config {
  uint16_t *csv_interval = &web_config::csvTimestepParam.value();
}