The Weblight-project consist of an power supply for LEDs which can be controlled over the local network. The firmware also has the option to turn the unit into a alarm clock which wakes you up using light.
Features
- Network-controllable, dimmable LED power supply.
- Easy configuration using a webbrowser.
- Supports Switching on/off the light when certain IP address is reachable (this is the alarm clock feature).
- Supports both HTTP and HTTPS.
- Safe, password-protected control.
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
The circuit diagram is still work-in-progress.