Das Weblight-Projekt besteht aus einem übers lokale Netzwerk kontrollierbaren Netzteil für LEDs. Die Features der von mir dazu entwickelten Firmware erlauben zudem eine Nutzung der Einheit als Lichtwecker. Die Firmware läuft auf einem ESP8266 und unterstützt unter anderem HTTPS.
Features
- Über Netzwerk kontrollierbares Netzteil mit Dimming-Funktion.
- Einfache Konfiguration via Webbrowser.
- Unterstützt An- sowie Ausschalten bei Erreichbarkeit einer bestimmten IP-Adresse.
- Frei wählbares Protokoll: HTTP oder HTTPS.
- Passwortgeschützte Steuerungsseite.
Firmware
/*****************************************************************************
Weblight Sketch
Copyright (c) 2020 Robin Lux <info[guesswhat]robinlux[ismissinghere]de>
Requires Pinger Library
https://github.com/bluemurder/esp8266-ping
*****************************************************************************/
#include <Pinger.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266WebServerSecure.h>
#include <EEPROM.h>
#include <ESP8266mDNS.h>
#include "myTypes.h"
//#define TESTSUITE
#define HTTPS
//#define TEMP_SENSORS
#ifdef TESTSUITE
#define OUT_PWM LED_BUILTIN
#define OUT_PIN D1
#else
#define OUT_PIN D1
#define OUT_PWM D2
#endif
static const char serverCert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
INSERT CERTIFICATE STRING HERE!
-----END CERTIFICATE-----
)EOF";
static const char serverKey[] PROGMEM = R"EOF(
-----BEGIN PRIVATE KEY-----
INSERT CERTIFICATE STRING HERE!
-----END PRIVATE KEY-----
)EOF";
const char* www_username = "user interface user";
const char* www_password = "user password";
const char* fallback_ssid = "weblight";
volatile bool last_reachable = false;
volatile bool enableOnPing = true;
volatile bool enableOffPing = true;
volatile unsigned long lastPingTime = 0;
volatile bool pinState = false;
bool pingSuccess[3] = {false, false, false};
int pingIntervall = 30;
int ledBrigthness = 500;
extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}
// Set global to avoid object removing after setup() routine
Pinger pinger;
IPAddress ip(192,168,1,31);
IPAddress mask(255,255,255,0);
IPAddress gate(192,168,1,1);
IPAddress device_ip(192,168,1,128);
#ifdef TESTSUITE
uint32_t freev;
uint16_t maxv;
uint8_t fragv;
#endif
#ifdef TEMP_SENSORS
#include <OneWire.h>
#include <DallasTemperature.h>
#define TEMPFETCHINTERVALL 1000*2
#define TEMP_SENSORS 10
#define ONE_WIRE_BUS D5
#define TEMPERATURE_PRECISION 9
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress TemperatureProbe;
unsigned long lastTempFetch = 0;
short temperatures[TEMP_SENSORS][144] = {0};
int temperatures_i[TEMP_SENSORS] = {0};
int found_sensors = 0;
#endif
#ifdef HTTPS
BearSSL::ESP8266WebServerSecure server(443);
#else
ESP8266WebServer server(80);
#endif
configData_t eeprom_cfg;
void setup()
{
// Begin serial connection at 9600 baud
Serial.begin(115200);
pinMode(OUT_PIN, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
Serial.print("Loading Config ... ");
//eraseConfig();eeprom_cfg.valid == 1
loadConfig();
if(eeprom_cfg.valid == 1){
pinState = (eeprom_cfg.defaultLED == 1);
enableOnPing = (eeprom_cfg.defaultOnPing == 1);
enableOffPing = (eeprom_cfg.defaultOffPing == 1);
updatePin();
ip.fromString(eeprom_cfg.ip);
gate.fromString(eeprom_cfg.gate);
mask.fromString(eeprom_cfg.mask);
WiFi.disconnect();
delay(500);
WiFi.begin(String(eeprom_cfg.SSID),String(eeprom_cfg.password));
delay(500);
WiFi.config(ip, gate, mask);
device_ip.fromString(eeprom_cfg.device_ip);
delay(500);
Serial.print("Address : ");
Serial.println(ip);
Serial.print("Mask : ");
Serial.println(mask);
Serial.print("Gate : ");
Serial.println(gate);
Serial.print("Ping Address : ");
Serial.println(device_ip);
Serial.print("SSID : ");
Serial.println(eeprom_cfg.SSID);
Serial.print("Password : ");
Serial.println(eeprom_cfg.password);
Serial.println("Ok!");
} else {
pinState = false;
updatePin();
enableOnPing = true;
eeprom_cfg.connectionTimeout = 60;
WiFi.disconnect();
delay(500);
WiFi.softAP(fallback_ssid);
delay(500);
WiFi.config(ip, gate, mask);
Serial.println("Failed! Used fallbacks");
}
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
Serial.print("Starting Webserver...");
#ifdef HTTPS
server.setRSACert(new BearSSL::X509List(serverCert), new BearSSL::PrivateKey(serverKey));
#endif
server.onNotFound(handleRoot);
server.on("/", handleRoot);
server.on("/settings", handleUpdatePage);
server.on("/update", HTTP_POST, updateSettings);
server.on("/updatedefaults", HTTP_POST, updateDefaultSettings);
server.on("/reset", HTTP_POST, resetController);
server.on("/resetsettings", HTTP_POST, resetSettings);
#ifdef TEMP_SENSORS
server.on("/temp", handleTempPage);
#endif
server.begin();
Serial.print("Ok\n");
if (MDNS.begin("weblight")) {
Serial.println("MDNS responder started");
}
// Wait connection completed
Serial.print("Connecting to AP...");
int ticks_since_connect = 0;
while((WiFi.status() != WL_CONNECTED) and (ticks_since_connect < eeprom_cfg.connectionTimeout))
{
delay(500);
Serial.print(".");
ticks_since_connect++;
}
if(ticks_since_connect == eeprom_cfg.connectionTimeout){
Serial.println("Can't connect to AP");
WiFi.disconnect();
WiFi.softAP("ESP8266", "82668266");
Serial.print("Config interface at: ");
Serial.println(WiFi.softAPIP());
}
Serial.println("Ok\n");
lastPingTime = millis();
#ifdef TEMP_SENSORS
lastTempFetch = millis();
sensors.begin();
#endif
pinger.OnReceive([](const PingerResponse& response)
{
if(response.ReceivedResponse){
pingSuccess[0] = true;
}
pingSuccess[0] = response.ReceivedResponse;
return false;
});
}
void updatePin(){
#ifdef TESTSUITE
digitalWrite(OUT_PIN, !pinState);
analogWrite(OUT_PWM, ledBrigthness);
#else
digitalWrite(OUT_PIN, pinState);
analogWrite(OUT_PWM, ledBrigthness);
#endif
}
#ifdef TEMP_SENSORS
void handleTempPage(){
char status_String[576] = {};
char partString[4] = {0};
int probe_id = 0;
if(server.hasArg("probeId")){
probe_id = server.arg("probeId").toInt();
}
if((probe_id > 9) || (probe_id < 0)){
server.send(400, "text/html", "Invalid Sensor ID!");
return;
}
int temp_index = temperatures_i[0];
Serial.printf("Sending Temperatures of probe %d ...", probe_id);
for(int status_i = 0; status_i < 144; ++status_i){
sprintf(partString, "%03d,", temperatures[0][temp_index]/2);
for(int i = 0; i < 4; i++){
status_String[i + status_i*4] = partString[i];
}
//memcpy((status_String + status_i*4), &partString, 4);
temp_index = (temp_index+1)%144;
}
Serial.println("done");
server.send(200, "text/html", status_String);
}
#endif
void handleRoot(){
// Simple Auth
if (!server.authenticate(www_username, www_password)) {
return server.requestAuthentication();
}
String status_string;
char timeString[50];
sprintf(timeString, "Time since last device Ping: %d", (long) ((millis() - lastPingTime) / 1000));
// Give the device some time to leave WiFi
status_string = "<title>LED Lamp</title><center><font size='20'>Manage LED Lamp</font><font size='5'>Copyright (c) 2020 Robin Lux</font><br><br>";
status_string += String(timeString);
status_string += "<br><br><form action='/update' method='POST'>LED :<input type='radio' name='led' value='1' ";
if(pinState){
status_string += "checked>ON <input type='radio' name='led' value='0'>OFF";
} else {
status_string += ">ON <input type='radio' name='led' value='0' checked>OFF";
}
status_string += "<br><br>Activation Ping Mode :<input type='radio' name='pingon' value='1' ";
if(enableOnPing){
status_string += "checked>ON <input type='radio' name='pingon' value='0'>OFF";
} else {
status_string += ">ON <input type='radio' name='pingon' value='0' checked>OFF";
}
status_string += "<br>Deactivation Ping Mode :<input type='radio' name='pingoff' value='1' ";
if(enableOffPing){
status_string += "checked>ON <input type='radio' name='pingoff' value='0'>OFF";
} else {
status_string += ">ON <input type='radio' name='pingoff' value='0' checked>OFF";
}
status_string += "<br><br>LED Brightness: <input type='text' value='" + String(ledBrigthness) + "' name='brigthness'>";
status_string += "<br><br><input type='submit' value='Send'></form><a href='/settings'>Settings</a></center>";
status_string += "<center>Link History: ";
for(int i = 0; i < 3; i++){
if(pingSuccess[i]){
status_string += "-";
} else {
status_string += "_";
}
}
status_string += "</center>";
server.send(200, "text/html", status_string);
}
void handleUpdatePage(){
// Simple Auth
if (!server.authenticate(www_username, www_password)) {
return server.requestAuthentication();
}
String status_string;
char timeString[50];
long millisecs = millis();
sprintf(timeString, "Uptime: %02d:%02d:%02d", int((millisecs / (1000 * 60 * 60 * 24)) % 365), int((millisecs / (1000 * 60 * 60)) % 24), int((millisecs / (1000 * 60)) % 60));
// Give the device some time to leave WiFi
status_string = "<title>Settings</title><center>" + String(timeString);
status_string += "<br><br><form action='/updatedefaults' method='POST'>Default LED :<input type='radio' name='led' value='1' ";
if(eeprom_cfg.defaultLED){
status_string += "checked>ON <input type='radio' name='led' value='0'>OFF";
} else {
status_string += ">ON <input type='radio' name='led' value='0' checked>OFF";
}
status_string += "<br><br>Default Activation Ping Mode :<input type='radio' name='pingon' value='1' ";
if(eeprom_cfg.defaultOnPing){
status_string += "checked>ON <input type='radio' name='pingon' value='0'>OFF<br>";
} else {
status_string += ">ON <input type='radio' name='pingon' value='0' checked>OFF";
}
status_string += "<br>Default Deactivation Ping Mode :<input type='radio' name='pingoff' value='1' ";
if(eeprom_cfg.defaultOffPing){
status_string += "checked>ON <input type='radio' name='pingoff' value='0'>OFF<br><br>";
} else {
status_string += ">ON <input type='radio' name='pingoff' value='0' checked>OFF<br><br>";
}
status_string += "Ping Intervall :<input type='text' name='defaultintervall' value='" + String(eeprom_cfg.pingIntervall) + "' ><br>";
status_string += "Device Address :<input type='text' name='defaultdaddr' value='" + String(eeprom_cfg.ip) + "' ><br>";
status_string += "Subnet Mask :<input type='text' name='defaultmask' value='" + String(eeprom_cfg.mask) + "' ><br>";
status_string += "Gate Address :<input type='text' name='defaultgate' value='" + String(eeprom_cfg.gate) + "' ><br>";
status_string += "Ping Address :<input type='text' name='defaultpaddr' value='" + String(eeprom_cfg.device_ip) + "' ><br><br>";
status_string += "SSID :<input type='text' name='wifiName' value='" + String(eeprom_cfg.SSID) + "' ><br>";
status_string += "Password :<input type='text' name='wifiPasswd' value='" + String(eeprom_cfg.password) + "' ><br>";
status_string += "AP Connection Timeout :<input type='text' name='connecttimeout' value='" + String(eeprom_cfg.connectionTimeout) + "' ><br>";
status_string += "<br><br><input type='submit' value='Save'></form><form action='/reset' method='POST'><input type='submit' value='Reset'></form><form action='/resetsettings' method='POST'><input type='submit' value='Reset Settings'></form><br><a href='/'>Main Page</a>Copyright (c) 2020 Robin Lux";
// Display build info
status_string += "<br><br><br> Build Time :";
status_string += __DATE__ " " __TIME__;
#ifdef TEMP_SENSORS
status_string += "<br>Build Option: Temperature Sensors";
#endif
#ifdef TESTSUITE
status_string += "<br>Build Option: Test Suite";
#endif
#ifdef HTTPS
status_string += "<br>Build Option: HTTPS Server";
#endif
status_string += "</center>";
server.send(200, "text/html", status_string);
}
void updateSettings(){
last_reachable = false;
if(server.hasArg("led")){
pinState = (server.arg("led") == "1");
}
if(server.hasArg("brigthness")){
ledBrigthness = server.arg("brigthness").toInt();
}
if(server.hasArg("pingon")){
enableOnPing = (server.arg("pingon") == "1");
}
if(server.hasArg("pingoff")){
enableOffPing = (server.arg("pingoff") == "1");
}
lastPingTime = millis();
server.sendHeader("Location","/"); // Add a header to respond with a new location for the browser to go to the home page again
server.send(303);
}
void updateDefaultSettings(){
eeprom_cfg.valid = 1;
server.arg("wifiName").toCharArray(eeprom_cfg.SSID, 31);
server.arg("wifiPasswd").toCharArray(eeprom_cfg.password, 31);
server.arg("defaultdaddr").toCharArray(eeprom_cfg.ip, 16);
server.arg("defaultmask").toCharArray(eeprom_cfg.mask, 16);
server.arg("defaultgate").toCharArray(eeprom_cfg.gate, 16);
server.arg("defaultpaddr").toCharArray(eeprom_cfg.device_ip, 16);
eeprom_cfg.pingIntervall = server.arg("defaultintervall").toInt();
eeprom_cfg.defaultLED = server.arg("led").toInt();
eeprom_cfg.defaultOnPing = server.arg("pingon").toInt();
eeprom_cfg.defaultOffPing = server.arg("pingoff").toInt();
eeprom_cfg.connectionTimeout = server.arg("connecttimeout").toInt();
server.sendHeader("Location","/settings"); // Add a header to respond with a new location for the browser to go to the home page again
server.send(303);
saveConfig();
}
void resetController(){
server.sendHeader("Location","/settings"); // Add a header to respond with a new location for the browser to go to the home page again
server.send(303);
delay(1000);
ESP.restart();
}
void resetSettings(){
eraseConfig();
resetController();
}
void eraseConfig() {
// Reset EEPROM bytes to '0' for the length of the data structure
EEPROM.begin(512);
for (int i = 0 ; i < sizeof(eeprom_cfg) ; i++) {
EEPROM.write(i, 0);
}
delay(200);
EEPROM.commit();
EEPROM.end();
}
void saveConfig() {
// Save configuration from RAM into EEPROM
EEPROM.begin(512);
EEPROM.put(0, eeprom_cfg);
delay(200);
EEPROM.commit(); // Only needed for ESP8266 to get data written
EEPROM.end(); // Free RAM copy of structure
}
void loadConfig() {
EEPROM.begin(512);
EEPROM.get(0, eeprom_cfg);
EEPROM.end(); // Free RAM copy of structure
}
void loop()
{
server.handleClient();
MDNS.update();
updatePin();
//analogWrite(OUT_PWM, (millis()/10)%1000);
if((millis() - lastPingTime) > 333*eeprom_cfg.pingIntervall){
lastPingTime = millis();
// Use buffer to determine if device is up or down and toggle light
if(enableOnPing and pingSuccess[0] and pingSuccess[1] and pingSuccess[2]){
pinState = true;
}
if(enableOffPing and not pingSuccess[0] and not pingSuccess[1] and not pingSuccess[2]){
pinState = false;
}
#ifdef TESTSUITE
ESP.getHeapStats(&freev, &maxv, &fragv);
Serial.printf("DEBUG: Free RAM: %d", freev);
Serial.printf("Ping state: %d %d\n", pingSuccess[0], pingSuccess[1]);
#endif
// update sample buffer
pingSuccess[2] = pingSuccess[1];
pingSuccess[1] = pingSuccess[0];
pingSuccess[0] = false;
pinger.Ping(device_ip);
pinger.Ping(device_ip);
pinger.Ping(device_ip);
pinger.Ping(device_ip);
lastPingTime = millis();
}
#ifdef TEMPSENSORS
if(millis() - lastTempFetch > TEMPFETCHINTERVALL){
sensors.requestTemperatures();
for(int i = 0; i < TEMP_SENSORS; ++i){
if(!sensors.getAddress(TemperatureProbe, i)){
if(i == 0){
found_sensors = 0;
Serial.println("No OneWire Temperature Sensors!");
}
break; // no more temperature sensors to read
}
found_sensors = (i+1);
sensors.setResolution(TemperatureProbe, TEMPERATURE_PRECISION);
temperatures[i][temperatures_i[i]] = (int) sensors.getTempC(TemperatureProbe)*2;
Serial.printf("Got Temp: %f for Sensor %d\n", sensors.getTempC(TemperatureProbe), i);
temperatures_i[i]++;
if(temperatures_i[i] > 143) temperatures_i[i] = 0;
}
lastTempFetch = millis();
}
#endif
}
Weblight Sketch
Copyright (c) 2020 Robin Lux <info[guesswhat]robinlux[ismissinghere]de>
Requires Pinger Library
https://github.com/bluemurder/esp8266-ping
*****************************************************************************/
#include <Pinger.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266WebServerSecure.h>
#include <EEPROM.h>
#include <ESP8266mDNS.h>
#include "myTypes.h"
//#define TESTSUITE
#define HTTPS
//#define TEMP_SENSORS
#ifdef TESTSUITE
#define OUT_PWM LED_BUILTIN
#define OUT_PIN D1
#else
#define OUT_PIN D1
#define OUT_PWM D2
#endif
static const char serverCert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
INSERT CERTIFICATE STRING HERE!
-----END CERTIFICATE-----
)EOF";
static const char serverKey[] PROGMEM = R"EOF(
-----BEGIN PRIVATE KEY-----
INSERT CERTIFICATE STRING HERE!
-----END PRIVATE KEY-----
)EOF";
const char* www_username = "user interface user";
const char* www_password = "user password";
const char* fallback_ssid = "weblight";
volatile bool last_reachable = false;
volatile bool enableOnPing = true;
volatile bool enableOffPing = true;
volatile unsigned long lastPingTime = 0;
volatile bool pinState = false;
bool pingSuccess[3] = {false, false, false};
int pingIntervall = 30;
int ledBrigthness = 500;
extern "C"
{
#include <lwip/icmp.h> // needed for icmp packet definitions
}
// Set global to avoid object removing after setup() routine
Pinger pinger;
IPAddress ip(192,168,1,31);
IPAddress mask(255,255,255,0);
IPAddress gate(192,168,1,1);
IPAddress device_ip(192,168,1,128);
#ifdef TESTSUITE
uint32_t freev;
uint16_t maxv;
uint8_t fragv;
#endif
#ifdef TEMP_SENSORS
#include <OneWire.h>
#include <DallasTemperature.h>
#define TEMPFETCHINTERVALL 1000*2
#define TEMP_SENSORS 10
#define ONE_WIRE_BUS D5
#define TEMPERATURE_PRECISION 9
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress TemperatureProbe;
unsigned long lastTempFetch = 0;
short temperatures[TEMP_SENSORS][144] = {0};
int temperatures_i[TEMP_SENSORS] = {0};
int found_sensors = 0;
#endif
#ifdef HTTPS
BearSSL::ESP8266WebServerSecure server(443);
#else
ESP8266WebServer server(80);
#endif
configData_t eeprom_cfg;
void setup()
{
// Begin serial connection at 9600 baud
Serial.begin(115200);
pinMode(OUT_PIN, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
Serial.print("Loading Config ... ");
//eraseConfig();eeprom_cfg.valid == 1
loadConfig();
if(eeprom_cfg.valid == 1){
pinState = (eeprom_cfg.defaultLED == 1);
enableOnPing = (eeprom_cfg.defaultOnPing == 1);
enableOffPing = (eeprom_cfg.defaultOffPing == 1);
updatePin();
ip.fromString(eeprom_cfg.ip);
gate.fromString(eeprom_cfg.gate);
mask.fromString(eeprom_cfg.mask);
WiFi.disconnect();
delay(500);
WiFi.begin(String(eeprom_cfg.SSID),String(eeprom_cfg.password));
delay(500);
WiFi.config(ip, gate, mask);
device_ip.fromString(eeprom_cfg.device_ip);
delay(500);
Serial.print("Address : ");
Serial.println(ip);
Serial.print("Mask : ");
Serial.println(mask);
Serial.print("Gate : ");
Serial.println(gate);
Serial.print("Ping Address : ");
Serial.println(device_ip);
Serial.print("SSID : ");
Serial.println(eeprom_cfg.SSID);
Serial.print("Password : ");
Serial.println(eeprom_cfg.password);
Serial.println("Ok!");
} else {
pinState = false;
updatePin();
enableOnPing = true;
eeprom_cfg.connectionTimeout = 60;
WiFi.disconnect();
delay(500);
WiFi.softAP(fallback_ssid);
delay(500);
WiFi.config(ip, gate, mask);
Serial.println("Failed! Used fallbacks");
}
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
Serial.print("Starting Webserver...");
#ifdef HTTPS
server.setRSACert(new BearSSL::X509List(serverCert), new BearSSL::PrivateKey(serverKey));
#endif
server.onNotFound(handleRoot);
server.on("/", handleRoot);
server.on("/settings", handleUpdatePage);
server.on("/update", HTTP_POST, updateSettings);
server.on("/updatedefaults", HTTP_POST, updateDefaultSettings);
server.on("/reset", HTTP_POST, resetController);
server.on("/resetsettings", HTTP_POST, resetSettings);
#ifdef TEMP_SENSORS
server.on("/temp", handleTempPage);
#endif
server.begin();
Serial.print("Ok\n");
if (MDNS.begin("weblight")) {
Serial.println("MDNS responder started");
}
// Wait connection completed
Serial.print("Connecting to AP...");
int ticks_since_connect = 0;
while((WiFi.status() != WL_CONNECTED) and (ticks_since_connect < eeprom_cfg.connectionTimeout))
{
delay(500);
Serial.print(".");
ticks_since_connect++;
}
if(ticks_since_connect == eeprom_cfg.connectionTimeout){
Serial.println("Can't connect to AP");
WiFi.disconnect();
WiFi.softAP("ESP8266", "82668266");
Serial.print("Config interface at: ");
Serial.println(WiFi.softAPIP());
}
Serial.println("Ok\n");
lastPingTime = millis();
#ifdef TEMP_SENSORS
lastTempFetch = millis();
sensors.begin();
#endif
pinger.OnReceive([](const PingerResponse& response)
{
if(response.ReceivedResponse){
pingSuccess[0] = true;
}
pingSuccess[0] = response.ReceivedResponse;
return false;
});
}
void updatePin(){
#ifdef TESTSUITE
digitalWrite(OUT_PIN, !pinState);
analogWrite(OUT_PWM, ledBrigthness);
#else
digitalWrite(OUT_PIN, pinState);
analogWrite(OUT_PWM, ledBrigthness);
#endif
}
#ifdef TEMP_SENSORS
void handleTempPage(){
char status_String[576] = {};
char partString[4] = {0};
int probe_id = 0;
if(server.hasArg("probeId")){
probe_id = server.arg("probeId").toInt();
}
if((probe_id > 9) || (probe_id < 0)){
server.send(400, "text/html", "Invalid Sensor ID!");
return;
}
int temp_index = temperatures_i[0];
Serial.printf("Sending Temperatures of probe %d ...", probe_id);
for(int status_i = 0; status_i < 144; ++status_i){
sprintf(partString, "%03d,", temperatures[0][temp_index]/2);
for(int i = 0; i < 4; i++){
status_String[i + status_i*4] = partString[i];
}
//memcpy((status_String + status_i*4), &partString, 4);
temp_index = (temp_index+1)%144;
}
Serial.println("done");
server.send(200, "text/html", status_String);
}
#endif
void handleRoot(){
// Simple Auth
if (!server.authenticate(www_username, www_password)) {
return server.requestAuthentication();
}
String status_string;
char timeString[50];
sprintf(timeString, "Time since last device Ping: %d", (long) ((millis() - lastPingTime) / 1000));
// Give the device some time to leave WiFi
status_string = "<title>LED Lamp</title><center><font size='20'>Manage LED Lamp</font><font size='5'>Copyright (c) 2020 Robin Lux</font><br><br>";
status_string += String(timeString);
status_string += "<br><br><form action='/update' method='POST'>LED :<input type='radio' name='led' value='1' ";
if(pinState){
status_string += "checked>ON <input type='radio' name='led' value='0'>OFF";
} else {
status_string += ">ON <input type='radio' name='led' value='0' checked>OFF";
}
status_string += "<br><br>Activation Ping Mode :<input type='radio' name='pingon' value='1' ";
if(enableOnPing){
status_string += "checked>ON <input type='radio' name='pingon' value='0'>OFF";
} else {
status_string += ">ON <input type='radio' name='pingon' value='0' checked>OFF";
}
status_string += "<br>Deactivation Ping Mode :<input type='radio' name='pingoff' value='1' ";
if(enableOffPing){
status_string += "checked>ON <input type='radio' name='pingoff' value='0'>OFF";
} else {
status_string += ">ON <input type='radio' name='pingoff' value='0' checked>OFF";
}
status_string += "<br><br>LED Brightness: <input type='text' value='" + String(ledBrigthness) + "' name='brigthness'>";
status_string += "<br><br><input type='submit' value='Send'></form><a href='/settings'>Settings</a></center>";
status_string += "<center>Link History: ";
for(int i = 0; i < 3; i++){
if(pingSuccess[i]){
status_string += "-";
} else {
status_string += "_";
}
}
status_string += "</center>";
server.send(200, "text/html", status_string);
}
void handleUpdatePage(){
// Simple Auth
if (!server.authenticate(www_username, www_password)) {
return server.requestAuthentication();
}
String status_string;
char timeString[50];
long millisecs = millis();
sprintf(timeString, "Uptime: %02d:%02d:%02d", int((millisecs / (1000 * 60 * 60 * 24)) % 365), int((millisecs / (1000 * 60 * 60)) % 24), int((millisecs / (1000 * 60)) % 60));
// Give the device some time to leave WiFi
status_string = "<title>Settings</title><center>" + String(timeString);
status_string += "<br><br><form action='/updatedefaults' method='POST'>Default LED :<input type='radio' name='led' value='1' ";
if(eeprom_cfg.defaultLED){
status_string += "checked>ON <input type='radio' name='led' value='0'>OFF";
} else {
status_string += ">ON <input type='radio' name='led' value='0' checked>OFF";
}
status_string += "<br><br>Default Activation Ping Mode :<input type='radio' name='pingon' value='1' ";
if(eeprom_cfg.defaultOnPing){
status_string += "checked>ON <input type='radio' name='pingon' value='0'>OFF<br>";
} else {
status_string += ">ON <input type='radio' name='pingon' value='0' checked>OFF";
}
status_string += "<br>Default Deactivation Ping Mode :<input type='radio' name='pingoff' value='1' ";
if(eeprom_cfg.defaultOffPing){
status_string += "checked>ON <input type='radio' name='pingoff' value='0'>OFF<br><br>";
} else {
status_string += ">ON <input type='radio' name='pingoff' value='0' checked>OFF<br><br>";
}
status_string += "Ping Intervall :<input type='text' name='defaultintervall' value='" + String(eeprom_cfg.pingIntervall) + "' ><br>";
status_string += "Device Address :<input type='text' name='defaultdaddr' value='" + String(eeprom_cfg.ip) + "' ><br>";
status_string += "Subnet Mask :<input type='text' name='defaultmask' value='" + String(eeprom_cfg.mask) + "' ><br>";
status_string += "Gate Address :<input type='text' name='defaultgate' value='" + String(eeprom_cfg.gate) + "' ><br>";
status_string += "Ping Address :<input type='text' name='defaultpaddr' value='" + String(eeprom_cfg.device_ip) + "' ><br><br>";
status_string += "SSID :<input type='text' name='wifiName' value='" + String(eeprom_cfg.SSID) + "' ><br>";
status_string += "Password :<input type='text' name='wifiPasswd' value='" + String(eeprom_cfg.password) + "' ><br>";
status_string += "AP Connection Timeout :<input type='text' name='connecttimeout' value='" + String(eeprom_cfg.connectionTimeout) + "' ><br>";
status_string += "<br><br><input type='submit' value='Save'></form><form action='/reset' method='POST'><input type='submit' value='Reset'></form><form action='/resetsettings' method='POST'><input type='submit' value='Reset Settings'></form><br><a href='/'>Main Page</a>Copyright (c) 2020 Robin Lux";
// Display build info
status_string += "<br><br><br> Build Time :";
status_string += __DATE__ " " __TIME__;
#ifdef TEMP_SENSORS
status_string += "<br>Build Option: Temperature Sensors";
#endif
#ifdef TESTSUITE
status_string += "<br>Build Option: Test Suite";
#endif
#ifdef HTTPS
status_string += "<br>Build Option: HTTPS Server";
#endif
status_string += "</center>";
server.send(200, "text/html", status_string);
}
void updateSettings(){
last_reachable = false;
if(server.hasArg("led")){
pinState = (server.arg("led") == "1");
}
if(server.hasArg("brigthness")){
ledBrigthness = server.arg("brigthness").toInt();
}
if(server.hasArg("pingon")){
enableOnPing = (server.arg("pingon") == "1");
}
if(server.hasArg("pingoff")){
enableOffPing = (server.arg("pingoff") == "1");
}
lastPingTime = millis();
server.sendHeader("Location","/"); // Add a header to respond with a new location for the browser to go to the home page again
server.send(303);
}
void updateDefaultSettings(){
eeprom_cfg.valid = 1;
server.arg("wifiName").toCharArray(eeprom_cfg.SSID, 31);
server.arg("wifiPasswd").toCharArray(eeprom_cfg.password, 31);
server.arg("defaultdaddr").toCharArray(eeprom_cfg.ip, 16);
server.arg("defaultmask").toCharArray(eeprom_cfg.mask, 16);
server.arg("defaultgate").toCharArray(eeprom_cfg.gate, 16);
server.arg("defaultpaddr").toCharArray(eeprom_cfg.device_ip, 16);
eeprom_cfg.pingIntervall = server.arg("defaultintervall").toInt();
eeprom_cfg.defaultLED = server.arg("led").toInt();
eeprom_cfg.defaultOnPing = server.arg("pingon").toInt();
eeprom_cfg.defaultOffPing = server.arg("pingoff").toInt();
eeprom_cfg.connectionTimeout = server.arg("connecttimeout").toInt();
server.sendHeader("Location","/settings"); // Add a header to respond with a new location for the browser to go to the home page again
server.send(303);
saveConfig();
}
void resetController(){
server.sendHeader("Location","/settings"); // Add a header to respond with a new location for the browser to go to the home page again
server.send(303);
delay(1000);
ESP.restart();
}
void resetSettings(){
eraseConfig();
resetController();
}
void eraseConfig() {
// Reset EEPROM bytes to '0' for the length of the data structure
EEPROM.begin(512);
for (int i = 0 ; i < sizeof(eeprom_cfg) ; i++) {
EEPROM.write(i, 0);
}
delay(200);
EEPROM.commit();
EEPROM.end();
}
void saveConfig() {
// Save configuration from RAM into EEPROM
EEPROM.begin(512);
EEPROM.put(0, eeprom_cfg);
delay(200);
EEPROM.commit(); // Only needed for ESP8266 to get data written
EEPROM.end(); // Free RAM copy of structure
}
void loadConfig() {
EEPROM.begin(512);
EEPROM.get(0, eeprom_cfg);
EEPROM.end(); // Free RAM copy of structure
}
void loop()
{
server.handleClient();
MDNS.update();
updatePin();
//analogWrite(OUT_PWM, (millis()/10)%1000);
if((millis() - lastPingTime) > 333*eeprom_cfg.pingIntervall){
lastPingTime = millis();
// Use buffer to determine if device is up or down and toggle light
if(enableOnPing and pingSuccess[0] and pingSuccess[1] and pingSuccess[2]){
pinState = true;
}
if(enableOffPing and not pingSuccess[0] and not pingSuccess[1] and not pingSuccess[2]){
pinState = false;
}
#ifdef TESTSUITE
ESP.getHeapStats(&freev, &maxv, &fragv);
Serial.printf("DEBUG: Free RAM: %d", freev);
Serial.printf("Ping state: %d %d\n", pingSuccess[0], pingSuccess[1]);
#endif
// update sample buffer
pingSuccess[2] = pingSuccess[1];
pingSuccess[1] = pingSuccess[0];
pingSuccess[0] = false;
pinger.Ping(device_ip);
pinger.Ping(device_ip);
pinger.Ping(device_ip);
pinger.Ping(device_ip);
lastPingTime = millis();
}
#ifdef TEMPSENSORS
if(millis() - lastTempFetch > TEMPFETCHINTERVALL){
sensors.requestTemperatures();
for(int i = 0; i < TEMP_SENSORS; ++i){
if(!sensors.getAddress(TemperatureProbe, i)){
if(i == 0){
found_sensors = 0;
Serial.println("No OneWire Temperature Sensors!");
}
break; // no more temperature sensors to read
}
found_sensors = (i+1);
sensors.setResolution(TemperatureProbe, TEMPERATURE_PRECISION);
temperatures[i][temperatures_i[i]] = (int) sensors.getTempC(TemperatureProbe)*2;
Serial.printf("Got Temp: %f for Sensor %d\n", sensors.getTempC(TemperatureProbe), i);
temperatures_i[i]++;
if(temperatures_i[i] > 143) temperatures_i[i] = 0;
}
lastTempFetch = millis();
}
#endif
}
#ifndef myTypes_h
#define myTypes_h
#include <WString.h>
// Types 'byte' und 'word' doesn't work!
typedef struct {
int valid; // 0=no configuration, 1=valid configuration
char SSID[31]; // SSID of WiFi
char password[31]; // Password of WiFi
char ip[16];
char mask[16];
char gate[16];
char device_ip[16];
int defaultLED;
int defaultOnPing;
int defaultOffPing;
int pingIntervall;
int connectionTimeout;
int fadeOnMax;
int fadeOnTime;
int fadeOffMin;
int fadeOffTime;
} configData_t;
#endif
#define myTypes_h
#include <WString.h>
// Types 'byte' und 'word' doesn't work!
typedef struct {
int valid; // 0=no configuration, 1=valid configuration
char SSID[31]; // SSID of WiFi
char password[31]; // Password of WiFi
char ip[16];
char mask[16];
char gate[16];
char device_ip[16];
int defaultLED;
int defaultOnPing;
int defaultOffPing;
int pingIntervall;
int connectionTimeout;
int fadeOnMax;
int fadeOnTime;
int fadeOffMin;
int fadeOffTime;
} configData_t;
#endif
Der Schaltplan des Netzteil ist noch in Arbeit.