#include "web_config.h" namespace config { using namespace iotwebconf; TextTParameter stringParam = Builder>("stringParam").label("String param").build(); } //TODO: Is there any conflict with SPIFFS/LittleFS? //TODO: Actually use those parameters //TODO: Check memory consumption. Disable DEBUG info? //TODO: Convert all strings to F-strings 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 DNSServer dnsServer; //TODO: Check if needed IotWebConf *iotWebConf; const char config_version[IOTWEBCONF_CONFIG_VERSION_LENGTH] = "a05"; // -- Configuration specific key. The value should be modified if config structure was changed. using namespace iotwebconf; /** * WiFi params */ CheckboxTParameter ampelWifiParam = Builder("WiFi").label("WiFi").defaultValue(true).build(); IntTParameter wifiTimeoutParam = Builder>("wifi_timeout").label("WiFi timeout").defaultValue(WIFI_TIMEOUT).min(0).placeholder( "[s]").build(); //TODO: Distribute to corresponding classes, possibly with callbacks? /** * CO2 sensor */ ParameterGroup co2Params = ParameterGroup("co2", "CO2 Sensor"); //TODO: Conflict with labels? //TODO: UIntTParameter? IntTParameter timestepParam = Builder>("timestep").label("Measurement timestep").defaultValue(MEASUREMENT_TIMESTEP).min( 2).max(1800).placeholder("[s]").build(); FloatTParameter temperatureOffsetParam = Builder("temp_offset").label("Temperature offset").defaultValue(TEMPERATURE_OFFSET).placeholder( "[K]").step(0.1).build(); IntTParameter altitudeParam = Builder>("altitude").label("Altitude").defaultValue( ALTITUDE_ABOVE_SEA_LEVEL).min(0).step(1).placeholder("[m]").build(); IntTParameter atmosphericCO2Param = Builder>("atmospheric_co2").label( "Atmospheric CO2 concentration").defaultValue( ATMOSPHERIC_CO2_CONCENTRATION).min(400).max(2000).step(1).placeholder("ppm").build(); CheckboxTParameter autoCalibrateParam = Builder("asc").label("Auto-calibration").defaultValue( AUTO_CALIBRATE_SENSOR).build(); /** * LED */ ParameterGroup ledParams = ParameterGroup("LED", "LED"); IntTParameter maxBrightnessParam = Builder>("max_brightness").label("Max Brightness").defaultValue(MAX_BRIGHTNESS).min(0).max( 255).build(); IntTParameter minBrightnessParam = Builder>("min_brightness").label("Min Brightness").defaultValue(MIN_BRIGHTNESS).min(0).max( 255).build(); IntTParameter ledCountParam = Builder>("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. /** * CSV */ OptionalParameterGroup csvParams = OptionalParameterGroup("CSV", "CSV", true); IntTParameter csvTimestepParam = Builder>("csv_timestep").label("CSV timestep").defaultValue(CSV_INTERVAL).min(0).step(1).placeholder( "[s]").build(); /** * MQTT */ OptionalParameterGroup mqttParams = OptionalParameterGroup("MQTT", "MQTT", true); IntTParameter mqttTimestepParam = Builder>("mqtt_timestep").label("MQTT timestep").defaultValue( MQTT_SENDING_INTERVAL).min(0).step(1).defaultValue(300).placeholder("[s]").build(); CheckboxTParameter mqttCommandsParam = Builder("mqtt_commands").label("MQTT commands").defaultValue(false).build(); TextTParameter mqttServerParam = Builder>("mqtt_server").label("MQTT Server").defaultValue(MQTT_SERVER).build(); IntTParameter mqttPortParam = Builder>("mqtt_port").label("MQTT Port").defaultValue( MQTT_PORT).build(); TextTParameter mqttUserParam = Builder>("mqtt_user").label("MQTT User").defaultValue(MQTT_USER).build(); //TODO: Show the number of * for password? PasswordTParameter mqttPasswordParam = Builder>("mqtt_password").label( "MQTT password").defaultValue(MQTT_PASSWORD).build(); /** * NTP Time */ ParameterGroup timeParams = ParameterGroup("NTP", "Time server"); TextTParameter ntpParam = Builder>("ntp_server").label("NTP Server").defaultValue(NTP_SERVER).build(); IntTParameter timeOffsetParam = Builder>("timezone").label("Timezone").defaultValue( (UTC_OFFSET_IN_SECONDS) / 3600).min(-23).max(23).step(1).placeholder("[h]").build(); CheckboxTParameter dstParam = Builder("dst").label("Daylight Saving Time").defaultValue(false).build(); /** * LED */ /** * LoRa & Stuff */ OptionalParameterGroup loraParams = OptionalParameterGroup("LoRaWan", "LoRaWan", false); IntTParameter loraTimestepParam = Builder>("lora_timestep").label("LoRa timestep").defaultValue( LORAWAN_SENDING_INTERVAL).min(0).step(1).defaultValue(300).placeholder("[s]").build(); TextTParameter<17> deviceEUIParam = Builder>("device_eui").label("Device EUI").defaultValue( "70B3D5...").build(); TextTParameter<17> appEUIParam = Builder>("app_eui").label("App EUI").defaultValue("00EA07...").build(); TextTParameter<32> appKeyParam = Builder>("app_key").label("App key").defaultValue("81CCFE...").build(); OptionalGroupHtmlFormatProvider optionalGroupHtmlFormatProvider; void update() { iotWebConf->doLoop(); // Listen for HTTP requests from clients } void setWifiConnectionCallback(void (*function)()) { iotWebConf->setWifiConnectionCallback(function); } void setWifiConnectionFailedCallback(void (*function)()) { iotWebConf->setWifiConnectionFailedHandler([&function]() -> WifiAuthInfo* { function(); return NULL; }); } void initialize() { iotWebConf = new IotWebConf(ampel.sensorId, &dnsServer, &http, HTTP_PASSWORD, config_version); iotWebConf->setHtmlFormatProvider(&optionalGroupHtmlFormatProvider); iotWebConf->addSystemParameter(&elWifiParam); iotWebConf->addSystemParameter(&wifiTimeoutParam); co2Params.addItem(×tepParam); co2Params.addItem(&temperatureOffsetParam); co2Params.addItem(&altitudeParam); co2Params.addItem(&atmosphericCO2Param); co2Params.addItem(&autoCalibrateParam); ledParams.addItem(&maxBrightnessParam); ledParams.addItem(&minBrightnessParam); ledParams.addItem(&ledCountParam); timeParams.addItem(&ntpParam); timeParams.addItem(&timeOffsetParam); timeParams.addItem(&dstParam); csvParams.addItem(&csvTimestepParam); mqttParams.addItem(&mqttTimestepParam); mqttParams.addItem(&mqttCommandsParam); mqttParams.addItem(&mqttServerParam); mqttParams.addItem(&mqttPortParam); mqttParams.addItem(&mqttUserParam); mqttParams.addItem(&mqttPasswordParam); //TODO: Only for ESP32 loraParams.addItem(&loraTimestepParam); loraParams.addItem(&deviceEUIParam); loraParams.addItem(&appEUIParam); loraParams.addItem(&appKeyParam); iotWebConf->addParameterGroup(&co2Params); iotWebConf->addParameterGroup(&ledParams); iotWebConf->addParameterGroup(&timeParams); iotWebConf->addParameterGroup(&csvParams); iotWebConf->addParameterGroup(&mqttParams); iotWebConf->addParameterGroup(&loraParams); sensor_console::defineCommand("reset_config", []() { Serial.println(F("Resetting config...")); //TODO: Reset every group iotWebConf->getSystemParameterGroup()->applyDefaultValue(); iotWebConf->saveConfig(); Serial.println(F("Done!")); }, F("(resets the complete IotWeb config)")); 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)")); #if !defined(AMPEL_WIFI) iotWebConf->loadConfig(); return; #endif 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) WiFi.hostname(ampel.sensorId); #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(); //TODO: Authenticate only if required? //TODO: / captive fast return? http.on("/config", [] { iotWebConf->handleConfig(); }); http.onNotFound([]() { iotWebConf->handleNotFound(); }); } }