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

Eric Duminil's avatar
Eric Duminil committed
3
namespace config {
Eric Duminil's avatar
Eric Duminil committed
4
5
6
  using namespace iotwebconf;
  TextTParameter<STRING_LEN> stringParam =
      Builder<TextTParameter<STRING_LEN>>("stringParam").label("String param").build();
Eric Duminil's avatar
Eric Duminil committed
7
8
}

Eric Duminil's avatar
Notes    
Eric Duminil committed
9
10
//TODO: Is there any conflict with SPIFFS/LittleFS?
//TODO: Actually use those parameters
11
12
//TODO: Check memory consumption. Disable DEBUG info?
//TODO: Convert all strings to F-strings
Eric Duminil's avatar
Notes    
Eric Duminil committed
13

14
15
16
17
18
19
20
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
21
  DNSServer dnsServer; //TODO: Check if needed
22
23
24

  IotWebConf *iotWebConf;

Eric Duminil's avatar
Eric Duminil committed
25
26
  // -- Configuration specific key. The value should be modified if config structure was changed.

Eric Duminil's avatar
Eric Duminil committed
27
  const char config_version[IOTWEBCONF_CONFIG_VERSION_LENGTH] = "a04";
28
  using namespace iotwebconf;
29

Eric Duminil's avatar
Eric Duminil committed
30
31
32
  /**
   * Services
   */
Eric Duminil's avatar
Eric Duminil committed
33
  CheckboxTParameter ampelWifiParam = Builder<CheckboxTParameter>("WiFi").label("WiFi").defaultValue(true).build();
Eric Duminil's avatar
Eric Duminil committed
34

Eric Duminil's avatar
Eric Duminil committed
35
36
37
38
  //TODO: Distribute to corresponding classes, possibly with callbacks?
  /**
   * CO2 sensor
   */
Eric Duminil's avatar
Eric Duminil committed
39
  ParameterGroup co2Params = ParameterGroup("co2", "CO2 Sensor"); //TODO: Conflict with labels?
Eric Duminil's avatar
Eric Duminil committed
40
41

  //TODO: UIntTParameter?
Eric Duminil's avatar
Eric Duminil committed
42
43
44
  IntTParameter<uint16_t> timestepParam =
      Builder<IntTParameter<uint16_t>>("timestep").label("Measurement timestep").defaultValue(MEASUREMENT_TIMESTEP).min(
          2).max(1800).step(1).placeholder("2..1800").build();
Eric Duminil's avatar
Eric Duminil committed
45

Eric Duminil's avatar
Eric Duminil committed
46
47
48
  FloatTParameter temperatureOffsetParam =
      Builder<FloatTParameter>("temp_offset").label("Temperature offset").defaultValue( TEMPERATURE_OFFSET).placeholder(
          "-3").step(0.1).build();
Eric Duminil's avatar
Eric Duminil committed
49

Eric Duminil's avatar
Eric Duminil committed
50
51
  IntTParameter<uint16_t> altitudeParam = Builder<IntTParameter<uint16_t>>("altitude").label("Altitude").defaultValue(
  ALTITUDE_ABOVE_SEA_LEVEL).min(0).step(1).build();
Eric Duminil's avatar
Eric Duminil committed
52

Eric Duminil's avatar
Eric Duminil committed
53
54
  IntTParameter<uint16_t> atmosphericCO2Param = Builder<IntTParameter<uint16_t>>("atmospheric_co2").label(
      "Atmospheric CO2 concentration").defaultValue(
Eric Duminil's avatar
Eric Duminil committed
55
56
  ATMOSPHERIC_CO2_CONCENTRATION).min(400).max(2000).step(1).placeholder("400..2000").build();

Eric Duminil's avatar
Eric Duminil committed
57
58
  CheckboxTParameter autoCalibrateParam = Builder<CheckboxTParameter>("asc").label("Auto-calibration").defaultValue(
      true).build();
Eric Duminil's avatar
Eric Duminil committed
59
60
61
62

  /**
   * CSV
   */
Eric Duminil's avatar
Eric Duminil committed
63
  OptionalParameterGroup csvParams = OptionalParameterGroup("CSV", "CSV", true);
Eric Duminil's avatar
Eric Duminil committed
64

Eric Duminil's avatar
Eric Duminil committed
65
66
  IntTParameter<uint16_t> csvTimestepParam =
      Builder<IntTParameter<uint16_t>>("csv_timestep").label("CSV timestep").defaultValue(CSV_INTERVAL).min(0).step(1).build();
Eric Duminil's avatar
Eric Duminil committed
67
68
69
70

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

Eric Duminil's avatar
Eric Duminil committed
73
74
75
  IntTParameter<uint16_t> mqttTimestepParam =
      Builder<IntTParameter<uint16_t>>("mqtt_timestep").label("MQTT timestep").defaultValue(
      MQTT_SENDING_INTERVAL).min(0).step(1).defaultValue(300).build();
Eric Duminil's avatar
Eric Duminil committed
76

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

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

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

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

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

Eric Duminil's avatar
Eric Duminil committed
93
94
95
  /**
   * NTP Time
   */
Eric Duminil's avatar
Eric Duminil committed
96

Eric Duminil's avatar
Eric Duminil committed
97
98
99
100
101
102
103
  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(
      (UTC_OFFSET_IN_SECONDS) / 3600).min(-23).max(23).step(1).build();
  CheckboxTParameter dstParam =
      Builder<CheckboxTParameter>("dst").label("Daylight Saving Time").defaultValue(false).build();
104

Eric Duminil's avatar
Eric Duminil committed
105
106
107
  /**
   * LED
   */
Eric Duminil's avatar
Eric Duminil committed
108

Eric Duminil's avatar
Eric Duminil committed
109
110
111
  /**
   * LoRa & Stuff
   */
Eric Duminil's avatar
Eric Duminil committed
112
113
114
115
  OptionalParameterGroup loraParams = OptionalParameterGroup("LoRaWan", "LoRaWan", false);
  IntTParameter<uint16_t> loraTimestepParam =
      Builder<IntTParameter<uint16_t>>("lora_timestep").label("LoRa timestep").defaultValue(
      LORAWAN_SENDING_INTERVAL).min(0).step(1).defaultValue(300).build();
116

Eric Duminil's avatar
Eric Duminil committed
117
  OptionalGroupHtmlFormatProvider optionalGroupHtmlFormatProvider;
118
119
120
121
122

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

Eric Duminil's avatar
Eric Duminil committed
123
124
125
126
127
  void setWifiConnectionCallback(void (*function)()) {
    iotWebConf->setWifiConnectionCallback(function);
  }

  void setWifiConnectionFailedCallback(void (*function)()) {
Eric Duminil's avatar
Eric Duminil committed
128
    iotWebConf->setWifiConnectionFailedHandler([&function]() -> WifiAuthInfo* {
Eric Duminil's avatar
Eric Duminil committed
129
130
131
132
133
      function();
      return NULL;
    });
  }

134
135
136
  void initialize() {
    iotWebConf = new IotWebConf(ampel.sensorId, &dnsServer, &http, HTTP_PASSWORD, config_version);

137
138
139
    iotWebConf->setHtmlFormatProvider(&optionalGroupHtmlFormatProvider);

    iotWebConf->addSystemParameter(&ampelWifiParam);
Eric Duminil's avatar
Eric Duminil committed
140
141
142

    co2Params.addItem(&timestepParam);
    co2Params.addItem(&temperatureOffsetParam);
Eric Duminil's avatar
Eric Duminil committed
143
144
145
    co2Params.addItem(&altitudeParam);
    co2Params.addItem(&atmosphericCO2Param);
    co2Params.addItem(&autoCalibrateParam);
Eric Duminil's avatar
Eric Duminil committed
146

147
148
149
150
    timeParams.addItem(&ntpParam);
    timeParams.addItem(&timeOffsetParam);
    timeParams.addItem(&dstParam);

Eric Duminil's avatar
Eric Duminil committed
151
152
153
154
155
156
157
158
159
    csvParams.addItem(&csvTimestepParam);

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

160
161
    loraParams.addItem(&loraTimestepParam);

Eric Duminil's avatar
Eric Duminil committed
162
    iotWebConf->addParameterGroup(&co2Params);
163
    iotWebConf->addParameterGroup(&timeParams);
Eric Duminil's avatar
Eric Duminil committed
164
165
    iotWebConf->addParameterGroup(&csvParams);
    iotWebConf->addParameterGroup(&mqttParams);
166
    iotWebConf->addParameterGroup(&loraParams);
Eric Duminil's avatar
Eric Duminil committed
167
168
169

    sensor_console::defineCommand("reset_config", []() {
      Serial.println(F("Resetting config..."));
Eric Duminil's avatar
Notes    
Eric Duminil committed
170
      //TODO: Reset every group
Eric Duminil's avatar
Eric Duminil committed
171
172
173
174
175
      iotWebConf->getSystemParameterGroup()->applyDefaultValue();
      iotWebConf->saveConfig();
      Serial.println(F("Done!"));
    }, F("(resets the complete IotWeb config)"));

Eric Duminil's avatar
Eric Duminil committed
176
177
178
179
180
181
182
183
    sensor_console::defineStringCommand("conf", [](char *new_value) {
      Serial.print(F("Setting stringParam to "));
      Serial.println(new_value);
      strncpy(config::stringParam.value(), new_value, STRING_LEN);
      Serial.println(F("Done"));
      iotWebConf->saveConfig();
    }, F("some_text (config setter)"));

Eric Duminil's avatar
Eric Duminil committed
184
185
186
187
188
#if !defined(AMPEL_WIFI)
    iotWebConf->loadConfig();
    return;
#endif

189
190
191
192
193
194
195
196
197
    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
198
  WiFi.hostname(ampel.sensorId);
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#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
217
218
    //TODO: Authenticate only if required?
    //TODO: / captive fast return?
219
220
221
222

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

224
225
226
227
228
    http.onNotFound([]() {
      iotWebConf->handleNotFound();
    });
  }
}