2023-04-24 20:26:49 +02:00
|
|
|
#include <ESP8266WiFi.h>
|
|
|
|
#include <ESP8266mDNS.h>
|
|
|
|
#include <ESP8266HTTPUpdateServer.h>
|
|
|
|
#include <ESP8266WebServer.h>
|
|
|
|
#include <WiFiManager.h>
|
|
|
|
#include <ArduinoJson.h>
|
|
|
|
#include <EEPROM.h>
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
//********* Config block *********//
|
2023-04-29 12:05:13 +02:00
|
|
|
// ch1, ch2, ch3, ch4
|
|
|
|
uint8_t pins[LIGHTS_COUNT] = { 14, 12, 15, 13 };
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
IPAddress strip_ip(192, 168, 0, 26); // choose an unique IP Adress
|
|
|
|
IPAddress gateway_ip(192, 168, 0, 1); // Router IP
|
|
|
|
IPAddress subnet_mask(255, 255, 255, 0);
|
|
|
|
IPAddress dns(192, 168, 0, 1);
|
2023-04-24 20:26:49 +02:00
|
|
|
|
|
|
|
//********************************//
|
|
|
|
|
|
|
|
#define LIGHT_VERSION 2.1
|
|
|
|
|
|
|
|
#define LAST_STATE_STARTUP_LIGHT_LAST_STATE 0
|
2023-04-29 12:05:13 +02:00
|
|
|
#define LAST_STATE_STARTUP_LIGHT_ON_STATE 1
|
|
|
|
#define LAST_STATE_STARTUP_LIGHT_OFF_STATE 2
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
#define LIGHT_STATE_ON 1
|
2023-04-24 20:26:49 +02:00
|
|
|
#define LIGHT_STATE_OFF 0
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
#define TIMING_CONTROL_ENABLED 1
|
2023-04-24 20:26:49 +02:00
|
|
|
#define TIMING_CONTROL_DISABLED 0
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
#define SCENE_RELEAX 0
|
|
|
|
#define SCENE_BRIGHT 1
|
2023-04-24 20:26:49 +02:00
|
|
|
#define SCENE_NIGHTLY 2
|
|
|
|
|
|
|
|
// 10 bit PWM
|
2023-04-27 16:40:27 +02:00
|
|
|
#define PWM_OFF 0 // 0V
|
2023-04-29 12:05:13 +02:00
|
|
|
#define PWM_MIN 0 // 0V - minimum light amount (~1%)
|
2023-04-27 16:40:27 +02:00
|
|
|
#define PWM_MAX 1023 // 24V - maximum light amount (100%)
|
2023-04-29 12:05:13 +02:00
|
|
|
#define BRI_TO_PWM_FACTOR 4.012 // 24V-15V = 24V range
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
//********************************//
|
|
|
|
|
2023-04-24 20:26:49 +02:00
|
|
|
uint8_t scene;
|
|
|
|
uint8_t tc_enabled;
|
|
|
|
|
|
|
|
bool light_state[LIGHTS_COUNT];
|
|
|
|
bool in_transition;
|
|
|
|
|
2023-04-29 12:40:14 +02:00
|
|
|
int default_transitiontime = 4; // 4 seconds
|
|
|
|
|
2023-04-24 20:26:49 +02:00
|
|
|
int transitiontime[LIGHTS_COUNT];
|
|
|
|
int bri[LIGHTS_COUNT];
|
2023-04-28 12:01:50 +02:00
|
|
|
uint16_t current_pwm[LIGHTS_COUNT];
|
2023-04-24 20:26:49 +02:00
|
|
|
|
|
|
|
float step_level[LIGHTS_COUNT];
|
|
|
|
float current_bri[LIGHTS_COUNT];
|
|
|
|
byte mac[6];
|
|
|
|
|
|
|
|
ESP8266WebServer server(80);
|
|
|
|
ESP8266HTTPUpdateServer httpUpdateServer;
|
|
|
|
|
2023-04-25 20:06:04 +02:00
|
|
|
uint32_t last_lightengine_activity = 0;
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
//********************************//
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
void apply_scene(uint8_t new_scene, uint8_t light) {
|
|
|
|
if (new_scene == SCENE_RELEAX) {
|
2023-04-24 20:26:49 +02:00
|
|
|
bri[light] = 144;
|
2023-04-27 16:40:27 +02:00
|
|
|
} else if (new_scene == SCENE_BRIGHT) {
|
2023-04-24 20:26:49 +02:00
|
|
|
bri[light] = 254;
|
2023-04-27 16:40:27 +02:00
|
|
|
} else if (new_scene == SCENE_NIGHTLY) {
|
2023-04-24 20:26:49 +02:00
|
|
|
bri[0] = 25;
|
2023-04-27 16:40:27 +02:00
|
|
|
bri[1] = 0;
|
|
|
|
bri[2] = 0;
|
|
|
|
bri[3] = 0;
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
//********************************//
|
|
|
|
|
2023-04-29 12:40:14 +02:00
|
|
|
void process_lightdata(uint8_t light, float tt)
|
|
|
|
{
|
|
|
|
if (light_state[light])
|
|
|
|
{
|
2023-04-27 11:26:21 +02:00
|
|
|
step_level[light] = (bri[light] - current_bri[light]) / tt;
|
|
|
|
|
2023-04-24 20:26:49 +02:00
|
|
|
} else {
|
2023-04-27 11:26:21 +02:00
|
|
|
step_level[light] = current_bri[light] / tt;
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
//********************************//
|
|
|
|
|
2023-04-29 12:40:14 +02:00
|
|
|
void lightEngine()
|
|
|
|
{
|
2023-04-25 20:06:04 +02:00
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
if (millis() < (last_lightengine_activity + TIME_LIGHTENGINE_INTERVAL_MS)) {
|
2023-04-25 20:06:04 +02:00
|
|
|
// abort processing, the transition setting is a delay of seconds
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_lightengine_activity = millis();
|
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
for (int i = 0; i < LIGHTS_COUNT; i++)
|
|
|
|
{
|
2023-04-27 11:26:21 +02:00
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
if (light_state[i])
|
|
|
|
{
|
|
|
|
if (bri[i] != current_bri[i])
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
in_transition = true;
|
2023-04-27 11:26:21 +02:00
|
|
|
current_bri[i] += step_level[i] / BRI_MOD_STEPS_PER_SEC;
|
2023-04-29 12:40:14 +02:00
|
|
|
if ((step_level[i] > 0.0 && current_bri[i] > bri[i]) || (step_level[i] < 0.0 && current_bri[i] < bri[i]))
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
current_bri[i] = bri[i];
|
2023-04-27 11:26:21 +02:00
|
|
|
//Serial.println("Reached target bri[" + (String)i + "] = " + (String)bri[i]);
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
2023-04-25 16:40:28 +02:00
|
|
|
|
2023-04-25 20:06:04 +02:00
|
|
|
uint16_t tmp_pwm = calcPWM(current_bri[i]);
|
2023-04-28 12:01:50 +02:00
|
|
|
current_pwm[i] = tmp_pwm;
|
2023-04-27 11:26:21 +02:00
|
|
|
//Serial.println("lon: pin" + (String)i + " = PWM(" + (String)tmp_pwm + ")");
|
2023-04-25 20:06:04 +02:00
|
|
|
analogWrite(pins[i], tmp_pwm);
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
if (current_bri[i] != 0)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
in_transition = true;
|
2023-04-27 11:26:21 +02:00
|
|
|
current_bri[i] -= step_level[i] / BRI_MOD_STEPS_PER_SEC;
|
2023-04-28 12:01:50 +02:00
|
|
|
if (current_bri[i] < 0)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
current_bri[i] = 0;
|
2023-04-27 11:26:21 +02:00
|
|
|
//Serial.println("Reached target bri[" + (String)i + "] = " + (String)bri[i]);
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
2023-04-25 16:40:28 +02:00
|
|
|
|
2023-04-25 20:06:04 +02:00
|
|
|
uint16_t tmp_pwm = calcPWM(current_bri[i]);
|
2023-04-28 12:01:50 +02:00
|
|
|
current_pwm[i] = tmp_pwm;
|
2023-04-27 11:26:21 +02:00
|
|
|
//Serial.println("loff: pin" + (String)i + " = PWM(" + (String)tmp_pwm + ")");
|
2023-04-25 20:06:04 +02:00
|
|
|
analogWrite(pins[i], tmp_pwm);
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
}
|
2023-04-27 11:26:21 +02:00
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
} // for loop end
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
if (in_transition)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
delay(6);
|
|
|
|
in_transition = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
//********************************//
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
uint16_t calcPWM(float tbri)
|
|
|
|
{
|
2023-04-25 16:40:28 +02:00
|
|
|
uint16_t tmp_pwm = PWM_OFF;
|
2023-04-28 12:01:50 +02:00
|
|
|
if (tbri > 0.0)
|
|
|
|
{
|
2023-04-25 16:40:28 +02:00
|
|
|
tmp_pwm = PWM_MIN + (int)(tbri * BRI_TO_PWM_FACTOR);
|
|
|
|
}
|
2023-04-27 16:40:27 +02:00
|
|
|
if (tmp_pwm > PWM_MAX) {
|
2023-04-25 16:40:28 +02:00
|
|
|
tmp_pwm = PWM_MAX;
|
|
|
|
}
|
2023-04-28 12:01:50 +02:00
|
|
|
|
2023-04-25 16:40:28 +02:00
|
|
|
return tmp_pwm;
|
|
|
|
}
|
|
|
|
|
|
|
|
//********************************//
|
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
void read_eeprom_config()
|
|
|
|
{
|
|
|
|
for (uint8_t light = 0; light < LIGHTS_COUNT; light++)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
apply_scene(EEPROM.read(EEPROM_SCENE_ADDRESS), light);
|
|
|
|
step_level[light] = bri[light] / 150.0;
|
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == LAST_STATE_STARTUP_LIGHT_LAST_STATE ||
|
|
|
|
(EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == LAST_STATE_STARTUP_LIGHT_ON_STATE &&
|
|
|
|
EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == LIGHT_STATE_ON))
|
|
|
|
{
|
2023-04-27 16:40:27 +02:00
|
|
|
light_state[light] = true; // set the light state to on
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
2023-04-29 12:05:13 +02:00
|
|
|
Serial.println("light[" + (String)light + "] = " + (String)light_state[light]);
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
uint8_t tmp = EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS);
|
2023-04-28 12:01:50 +02:00
|
|
|
if (tmp == TIMING_CONTROL_DISABLED)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
tc_enabled = TIMING_CONTROL_DISABLED;
|
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
} else if (tmp == TIMING_CONTROL_ENABLED)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
tc_enabled = TIMING_CONTROL_ENABLED;
|
2023-04-27 16:40:27 +02:00
|
|
|
|
2023-04-24 20:26:49 +02:00
|
|
|
} else {
|
2023-04-27 16:40:27 +02:00
|
|
|
|
2023-04-24 20:26:49 +02:00
|
|
|
EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_DISABLED);
|
|
|
|
EEPROM.commit();
|
|
|
|
tc_enabled = TIMING_CONTROL_DISABLED;
|
|
|
|
}
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
Serial.println("tc_enabled = " + (String)tc_enabled);
|
|
|
|
|
|
|
|
if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == 255)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
// set the default value on uninitialized EEPROM
|
|
|
|
EEPROM.write(EEPROM_LAST_STATE_STARTUP_ADDRESS, 0);
|
|
|
|
EEPROM.commit();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_STATIC_IP
|
2023-04-29 12:05:13 +02:00
|
|
|
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 255)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, 0);
|
|
|
|
EEPROM.commit();
|
|
|
|
}
|
|
|
|
#else
|
2023-04-29 12:05:13 +02:00
|
|
|
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 255)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, 1);
|
|
|
|
EEPROM.commit();
|
|
|
|
}
|
|
|
|
#endif
|
2023-04-29 12:05:13 +02:00
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//********************************//
|
|
|
|
|
2023-04-28 10:56:26 +02:00
|
|
|
void setup()
|
|
|
|
{
|
2023-04-25 15:35:04 +02:00
|
|
|
EEPROM.begin(256);
|
2023-04-25 08:18:36 +02:00
|
|
|
|
|
|
|
Serial.begin(SERIAL_BAUD_RATE);
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 0)
|
|
|
|
{
|
2023-04-25 15:35:04 +02:00
|
|
|
WiFi.config(strip_ip, gateway_ip, subnet_mask, dns);
|
2023-04-25 08:18:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
read_eeprom_config();
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
for (int j = 0; j < 200; j++)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
lightEngine();
|
|
|
|
}
|
|
|
|
|
|
|
|
WiFi.mode(WIFI_STA);
|
|
|
|
WiFiManager wifiManager;
|
|
|
|
wifiManager.setConfigPortalTimeout(120);
|
|
|
|
wifiManager.autoConnect(light_name);
|
|
|
|
|
|
|
|
IPAddress myIP = WiFi.localIP();
|
|
|
|
Serial.print("IP: ");
|
|
|
|
Serial.println(myIP);
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
if (!light_state[0])
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
// Show that we are connected
|
|
|
|
analogWrite(pins[0], 100);
|
|
|
|
delay(500);
|
|
|
|
analogWrite(pins[0], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
WiFi.macAddress(mac);
|
|
|
|
|
|
|
|
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
|
|
|
|
digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
httpUpdateServer.setup(&server); // start http server
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
init_webserver();
|
|
|
|
|
|
|
|
tc_init();
|
|
|
|
|
|
|
|
server.begin();
|
2023-04-27 16:40:27 +02:00
|
|
|
} // end of setup
|
2023-04-25 08:18:36 +02:00
|
|
|
|
2023-04-25 14:32:42 +02:00
|
|
|
//********************************//
|
|
|
|
|
2023-04-28 10:56:26 +02:00
|
|
|
void loop()
|
|
|
|
{
|
2023-04-25 08:18:36 +02:00
|
|
|
server.handleClient();
|
|
|
|
lightEngine();
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
if (tc_enabled == TIMING_CONTROL_ENABLED)
|
|
|
|
{
|
|
|
|
//Serial.println("tc_enabled = " + (String)tc_enabled);
|
2023-04-27 11:26:21 +02:00
|
|
|
tc_update_loop();
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
2023-04-25 08:18:36 +02:00
|
|
|
}
|
|
|
|
|
2023-04-25 14:32:42 +02:00
|
|
|
//********************************//
|
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
void handleNotFound()
|
|
|
|
{
|
2023-04-25 08:18:36 +02:00
|
|
|
String message = "File Not Found\n\n";
|
|
|
|
message += "URI: ";
|
|
|
|
message += server.uri();
|
|
|
|
message += "\nMethod: ";
|
|
|
|
message += (server.method() == HTTP_GET) ? "GET" : "POST";
|
|
|
|
message += "\nArguments: ";
|
|
|
|
message += server.args();
|
|
|
|
message += "\n";
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
for (uint8_t i = 0; i < server.args(); i++)
|
|
|
|
{
|
2023-04-25 08:18:36 +02:00
|
|
|
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
|
|
|
|
}
|
|
|
|
server.send(404, "text/plain", message);
|
|
|
|
}
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-25 14:32:42 +02:00
|
|
|
//********************************//
|
|
|
|
|
2023-04-28 12:01:50 +02:00
|
|
|
void init_webserver()
|
|
|
|
{
|
2023-04-25 14:32:42 +02:00
|
|
|
|
|
|
|
#ifndef DISABLE_WEB_CONTROL
|
2023-04-29 12:05:13 +02:00
|
|
|
server.on("/state", HTTP_PUT, []()
|
|
|
|
{ // HTTP PUT request used to set a new light state
|
2023-04-24 20:26:49 +02:00
|
|
|
DynamicJsonDocument root(1024);
|
|
|
|
DeserializationError error = deserializeJson(root, server.arg("plain"));
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
if (error) {
|
2023-04-24 20:26:49 +02:00
|
|
|
server.send(404, "text/plain", "FAIL. " + server.arg("plain"));
|
|
|
|
} else {
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
for (JsonPair state : root.as<JsonObject>())
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
const char* key = state.key().c_str();
|
|
|
|
int light = atoi(key) - 1;
|
|
|
|
JsonObject values = state.value();
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
uint8_t tmp = EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS);
|
2023-04-29 12:05:13 +02:00
|
|
|
if (values.containsKey("on"))
|
|
|
|
{
|
|
|
|
if (values["on"])
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
light_state[light] = true;
|
2023-04-29 12:05:13 +02:00
|
|
|
if (tmp == LAST_STATE_STARTUP_LIGHT_LAST_STATE && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == LIGHT_STATE_OFF)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_ON);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
light_state[light] = false;
|
2023-04-29 12:05:13 +02:00
|
|
|
if (tmp == LAST_STATE_STARTUP_LIGHT_LAST_STATE && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == LIGHT_STATE_ON)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_OFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
if (values.containsKey("bri"))
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
bri[light] = values["bri"];
|
|
|
|
}
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
if (values.containsKey("bri_inc"))
|
|
|
|
{
|
2023-04-27 16:40:27 +02:00
|
|
|
bri[light] += (int)values["bri_inc"];
|
2023-04-24 20:26:49 +02:00
|
|
|
if (bri[light] > 255) bri[light] = 255;
|
|
|
|
else if (bri[light] < 1) bri[light] = 1;
|
|
|
|
}
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
if (values.containsKey("transitiontime"))
|
|
|
|
{
|
2023-04-29 12:40:14 +02:00
|
|
|
default_transitiontime = values["transitiontime"];
|
|
|
|
if (tc_enabled == TIMING_CONTROL_DISABLED)
|
|
|
|
{
|
|
|
|
for (uint8_t i = 0 ; i < LIGHTS_COUNT; i++)
|
|
|
|
{
|
|
|
|
// set the default transition time for all lights
|
|
|
|
process_lightdata(i, default_transitiontime);
|
|
|
|
}
|
|
|
|
}
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
2023-04-29 12:40:14 +02:00
|
|
|
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
String output;
|
|
|
|
serializeJson(root, output);
|
|
|
|
server.send(200, "text/plain", output);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
server.on("/state", HTTP_GET, []()
|
|
|
|
{ // HTTP GET request used to fetch current light state
|
2023-04-24 20:26:49 +02:00
|
|
|
uint8_t light = server.arg("light").toInt() - 1;
|
|
|
|
DynamicJsonDocument root(1024);
|
|
|
|
root["on"] = light_state[light];
|
|
|
|
root["bri"] = bri[light];
|
2023-04-28 10:56:26 +02:00
|
|
|
root["curbri"] = (int)current_bri[light];
|
2023-04-28 12:01:50 +02:00
|
|
|
root["curpwm"] = current_pwm[light];
|
2023-04-24 20:26:49 +02:00
|
|
|
String output;
|
|
|
|
serializeJson(root, output);
|
|
|
|
server.send(200, "text/plain", output);
|
|
|
|
});
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
server.on("/detect", []()
|
|
|
|
{ // HTTP GET request used to discover the light type
|
2023-04-27 16:40:27 +02:00
|
|
|
char macString[32] = { 0 };
|
2023-04-24 20:26:49 +02:00
|
|
|
sprintf(macString, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
|
|
DynamicJsonDocument root(1024);
|
|
|
|
root["name"] = light_name;
|
|
|
|
root["lights"] = LIGHTS_COUNT;
|
|
|
|
root["protocol"] = "native_multi";
|
|
|
|
root["modelid"] = "LWB010";
|
|
|
|
root["type"] = "dimmable_light";
|
|
|
|
root["mac"] = String(macString);
|
|
|
|
root["version"] = LIGHT_VERSION;
|
|
|
|
String output;
|
|
|
|
serializeJson(root, output);
|
|
|
|
server.send(200, "text/plain", output);
|
|
|
|
});
|
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
server.on("/tc_data_blocks", []()
|
|
|
|
{
|
2023-04-27 13:39:07 +02:00
|
|
|
String output = tc_getJsonData();
|
|
|
|
|
|
|
|
server.send(200, "application/json", output);
|
|
|
|
});
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
#endif // DISABLE_WEB_CONTROL
|
2023-04-25 14:32:42 +02:00
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
server.on("/", []()
|
|
|
|
{
|
2023-04-25 14:32:42 +02:00
|
|
|
|
|
|
|
#ifndef DISABLE_WEB_CONTROL
|
2023-04-25 08:18:36 +02:00
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
if (server.hasArg("transition"))
|
|
|
|
{
|
2023-04-29 12:40:14 +02:00
|
|
|
default_transitiontime = server.arg("transition").toFloat();
|
|
|
|
if (tc_enabled == TIMING_CONTROL_DISABLED)
|
|
|
|
{
|
|
|
|
for (uint8_t i = 0 ; i < LIGHTS_COUNT; i++)
|
|
|
|
{
|
|
|
|
// set the default transition time for all lights
|
|
|
|
process_lightdata(i, default_transitiontime);
|
|
|
|
}
|
|
|
|
}
|
2023-04-25 08:18:36 +02:00
|
|
|
}
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
// startup behavior switch handling
|
2023-04-29 12:05:13 +02:00
|
|
|
if (server.hasArg("startup"))
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
int startup = server.arg("startup").toInt();
|
2023-04-29 12:05:13 +02:00
|
|
|
if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) != startup)
|
|
|
|
{
|
2023-04-25 08:18:36 +02:00
|
|
|
EEPROM.write(EEPROM_LAST_STATE_STARTUP_ADDRESS, startup);
|
2023-04-25 14:32:42 +02:00
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
for (uint8_t i = 0; i < LIGHTS_COUNT; i++) {
|
2023-04-25 14:32:42 +02:00
|
|
|
uint8_t tmp = (light_state[i] == true ? LIGHT_STATE_ON : LIGHT_STATE_OFF);
|
2023-04-29 12:05:13 +02:00
|
|
|
if (EEPROM.read(EEPROM_LAST_STATE_ADDRESS + i) != tmp)
|
|
|
|
{
|
2023-04-25 14:32:42 +02:00
|
|
|
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + i, tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
EEPROM.commit();
|
2023-04-27 16:40:27 +02:00
|
|
|
Serial.print("Startup behavior set to ");
|
|
|
|
Serial.println(EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS));
|
2023-04-25 08:18:36 +02:00
|
|
|
}
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
2023-04-27 16:40:27 +02:00
|
|
|
#endif // DISABLE_WEB_CONTROL
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
// timing controller switch handling
|
2023-04-29 12:05:13 +02:00
|
|
|
if (server.hasArg("tc"))
|
|
|
|
{
|
|
|
|
if (server.arg("tc") == "true")
|
|
|
|
{
|
|
|
|
if (tc_enabled == TIMING_CONTROL_DISABLED)
|
|
|
|
{
|
|
|
|
if (EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS) != TIMING_CONTROL_ENABLED)
|
|
|
|
{
|
2023-04-25 08:18:36 +02:00
|
|
|
tc_enabled = TIMING_CONTROL_ENABLED;
|
|
|
|
EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_ENABLED);
|
|
|
|
EEPROM.commit();
|
2023-04-27 16:40:27 +02:00
|
|
|
Serial.print("Timing control = ");
|
|
|
|
Serial.println(EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS));
|
2023-04-29 12:40:14 +02:00
|
|
|
tc_update_main(); // call the main update function to read data and set the light states
|
2023-04-25 08:18:36 +02:00
|
|
|
}
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
} else { // tc is set to false or something else
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
if (tc_enabled == TIMING_CONTROL_ENABLED)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
tc_enabled = TIMING_CONTROL_DISABLED;
|
2023-04-29 12:05:13 +02:00
|
|
|
if (EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS) != TIMING_CONTROL_DISABLED)
|
|
|
|
{
|
2023-04-25 08:18:36 +02:00
|
|
|
EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_DISABLED);
|
|
|
|
EEPROM.commit();
|
2023-04-27 16:40:27 +02:00
|
|
|
Serial.print("Timing control = ");
|
|
|
|
Serial.println(EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS));
|
2023-04-29 12:40:14 +02:00
|
|
|
|
|
|
|
for (uint8_t i = 0 ; i < LIGHTS_COUNT; i++)
|
|
|
|
{
|
|
|
|
// set the default transition time for all lights
|
|
|
|
process_lightdata(i, default_transitiontime);
|
|
|
|
}
|
2023-04-25 08:18:36 +02:00
|
|
|
}
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-25 14:32:42 +02:00
|
|
|
#ifndef DISABLE_WEB_CONTROL
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
// scene switch handling
|
2023-04-27 16:40:27 +02:00
|
|
|
if (server.hasArg("scene")) {
|
2023-04-24 20:26:49 +02:00
|
|
|
scene = server.arg("scene").toInt();
|
2023-04-27 16:40:27 +02:00
|
|
|
if (EEPROM.read(EEPROM_SCENE_ADDRESS) != scene) {
|
2023-04-25 08:18:36 +02:00
|
|
|
EEPROM.write(EEPROM_SCENE_ADDRESS, scene);
|
|
|
|
EEPROM.commit();
|
2023-04-27 16:40:27 +02:00
|
|
|
Serial.print("Scene set to ");
|
|
|
|
Serial.println(EEPROM.read(EEPROM_SCENE_ADDRESS));
|
2023-04-25 08:18:36 +02:00
|
|
|
}
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
if (server.hasArg("dip")) {
|
2023-04-25 14:32:42 +02:00
|
|
|
uint8_t tmp = EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS);
|
|
|
|
uint8_t tmp2 = (server.arg("dip") == "true" ? 1 : 0);
|
2023-04-27 16:40:27 +02:00
|
|
|
if (tmp != tmp2) {
|
2023-04-25 14:32:42 +02:00
|
|
|
EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, tmp2);
|
|
|
|
EEPROM.commit();
|
2023-04-27 16:40:27 +02:00
|
|
|
Serial.print("Set dynamic IP to ");
|
|
|
|
Serial.println(EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS));
|
2023-04-25 14:32:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
// process the received data for every light
|
2023-04-29 12:40:14 +02:00
|
|
|
for (int light = 0; light < LIGHTS_COUNT; light++)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
if (server.hasArg("bri" + (String)light))
|
|
|
|
{
|
2023-04-27 16:40:27 +02:00
|
|
|
bri[light] = (int)server.arg("bri" + (String)light).toInt();
|
2023-04-27 19:26:06 +02:00
|
|
|
Serial.print("Brightness ");
|
|
|
|
Serial.print(light);
|
|
|
|
Serial.print(" set to ");
|
2023-04-27 16:40:27 +02:00
|
|
|
Serial.println(bri[light]);
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
2023-04-27 16:40:27 +02:00
|
|
|
|
2023-04-29 12:40:14 +02:00
|
|
|
if (server.hasArg("on" + (String)light))
|
|
|
|
{
|
2023-04-25 08:18:36 +02:00
|
|
|
uint8_t tmp = EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS);
|
2023-04-29 12:40:14 +02:00
|
|
|
if (server.arg("on" + (String)light) == "true" && light_state[light] == false)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
light_state[light] = true;
|
2023-04-29 12:40:14 +02:00
|
|
|
if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 0)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_ON);
|
|
|
|
}
|
2023-04-27 16:40:27 +02:00
|
|
|
Serial.print("Light ");
|
|
|
|
Serial.print(light);
|
|
|
|
Serial.print(" state set to ");
|
|
|
|
Serial.println(light_state[light]);
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-29 12:40:14 +02:00
|
|
|
} else if (server.arg("on" + (String)light) == "false" && light_state[light] == true)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
light_state[light] = false;
|
2023-04-29 12:40:14 +02:00
|
|
|
if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 1)
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_OFF);
|
|
|
|
}
|
2023-04-27 16:40:27 +02:00
|
|
|
Serial.print("Light ");
|
|
|
|
Serial.print(light);
|
|
|
|
Serial.print(" state set to ");
|
|
|
|
Serial.println(light_state[light]);
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
EEPROM.commit();
|
2023-04-29 12:40:14 +02:00
|
|
|
} else {
|
|
|
|
// light is off
|
|
|
|
if (tc_enabled == TIMING_CONTROL_DISABLED)
|
|
|
|
{
|
|
|
|
process_lightdata(light, default_transitiontime);
|
|
|
|
}
|
2023-04-24 20:26:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
// start alerting for every light
|
2023-04-29 12:40:14 +02:00
|
|
|
if (server.hasArg("alert"))
|
|
|
|
{
|
|
|
|
if (light_state[light])
|
|
|
|
{
|
2023-04-24 20:26:49 +02:00
|
|
|
current_bri[light] = 0;
|
|
|
|
} else {
|
|
|
|
current_bri[light] = 255;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
} // process all lights
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
#endif // DISABLE_WEB_CONTROL
|
2023-04-25 14:32:42 +02:00
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
if (server.hasArg("resettc")) { // reqrite the tc config and reboot
|
2023-04-24 20:26:49 +02:00
|
|
|
tc_write_default();
|
|
|
|
ESP.reset();
|
|
|
|
}
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
if (server.hasArg("reset")) {
|
2023-04-24 20:26:49 +02:00
|
|
|
ESP.reset();
|
|
|
|
}
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
// Generate HTML page
|
2023-04-24 20:26:49 +02:00
|
|
|
String http_content = "<!doctype html>";
|
|
|
|
http_content += "<html>";
|
|
|
|
http_content += "<head>";
|
2023-04-27 19:26:06 +02:00
|
|
|
http_content += "<style></style>";
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<meta charset=\"utf-8\">";
|
|
|
|
http_content += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">";
|
2023-04-27 16:40:27 +02:00
|
|
|
//http_content += "<meta http-equiv=\"refresh\" content=\"15\">"; // Reload the page every 15 seconds automatically
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<title>Light Setup</title>";
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "<script src=\"https://code.jquery.com/jquery-3.6.0.min.js\"></script>";
|
|
|
|
http_content += "<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>";
|
2023-04-28 12:01:50 +02:00
|
|
|
http_content += "<script src=\"https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js\"></script>";
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<link rel=\"stylesheet\" href=\"https://unpkg.com/purecss@0.6.2/build/pure-min.css\">";
|
|
|
|
http_content += "</head>";
|
|
|
|
http_content += "<body>";
|
|
|
|
http_content += "<fieldset>";
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "<h3>" + (String)light_name + "</h3>";
|
|
|
|
|
|
|
|
http_content += "<div class=\"pure-controls\">";
|
|
|
|
http_content += "<span class=\"pure-form-message\"><a href=\"/?alert=1\">alert</a> <a href=\"/?reset=1\">reset</a> <a href=\"/?resettc\">reset timing control data</a> <a href=\"/update\">update</a></span>";
|
|
|
|
http_content += "<label for=\"cb\" class=\"pure-checkbox\">";
|
|
|
|
http_content += "</label>";
|
|
|
|
http_content += "</div>";
|
2023-04-24 20:26:49 +02:00
|
|
|
|
|
|
|
http_content += "<form class=\"pure-form pure-form-aligned\" action=\"/\" method=\"post\">";
|
2023-04-27 19:26:06 +02:00
|
|
|
http_content += "<script>"
|
2023-04-28 10:56:26 +02:00
|
|
|
"let timeoutId;" // slider value change submit to server
|
2023-04-27 19:26:06 +02:00
|
|
|
"function sendSliderValue(x) {"
|
|
|
|
"x = x - 1;"
|
|
|
|
"clearTimeout(timeoutId);"
|
|
|
|
"timeoutId = setTimeout(() => {"
|
|
|
|
"var value = document.getElementById(`bri${x}`).value;"
|
|
|
|
"var url = `http://192.168.0.26/?bri${x}=${value}`;"
|
|
|
|
"fetch(url).then(response => {"
|
|
|
|
"if (!response.ok) {"
|
|
|
|
"throw new Error(`HTTP error! status: ${response.status}`);"
|
|
|
|
"}"
|
|
|
|
"console.log(`Sent slider value ${value} to ${url}`);"
|
|
|
|
"}).catch(error => {"
|
|
|
|
"console.error(`Error sending slider value to ${url}: ${error}`);"
|
|
|
|
"});"
|
|
|
|
"}, 500);"
|
|
|
|
"}</script>";
|
2023-04-24 20:26:49 +02:00
|
|
|
|
2023-04-25 14:32:42 +02:00
|
|
|
#ifndef DISABLE_WEB_CONTROL
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "<br><table border=0><tr><td>";
|
2023-04-25 14:32:42 +02:00
|
|
|
// Light control
|
2023-04-27 19:26:06 +02:00
|
|
|
for (uint8 light_num = 0; light_num < LIGHTS_COUNT; light_num++)
|
|
|
|
{
|
|
|
|
// on/off buttons
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "<h4>Light " + (String)(light_num + 1) + "</h4>";
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
|
|
|
http_content += "<label for=\"power\"><strong>Power</strong></label>";
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "<a id=\"on" + (String)light_num + "_on\" class=\"pure-button";
|
|
|
|
http_content += "\" href=\"/?on" + (String)light_num + "=true\">ON</a>";
|
|
|
|
http_content += "<a id=\"on" + (String)light_num + "_off\" class=\"pure-button";
|
|
|
|
http_content += "\" href=\"/?on" + (String)light_num + "=false\">OFF</a>";
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "</div>";
|
|
|
|
|
2023-04-27 19:26:06 +02:00
|
|
|
// slider for brightness
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
|
|
|
http_content += "<label for=\"bri\"" + (String)light_num + ">Bri</label>";
|
2023-04-27 19:26:06 +02:00
|
|
|
http_content += "<input id=\"bri" + (String)light_num + "\" onchange=\"sendSliderValue(" + (String)(light_num+1) + ")\" name=\"bri" + (String)light_num + "\" type=\"range\" min=\"0\" max=\"255\" value=\"" + (String)bri[light_num] + "\">";
|
2023-04-28 14:26:02 +02:00
|
|
|
http_content += " <span id=\"bri" + (String)light_num + "_val\" name=\"bri" + (String)light_num + "\">" + (String)(int)(bri[light_num] * 100.0 / 255.0) + "</span>%";
|
2023-04-28 19:49:52 +02:00
|
|
|
http_content += "<br><label for=\"light" + (String)light_num + "_pwm\">PWM-Wert</label>";
|
|
|
|
http_content += "<input type=\"range\" min=\"0\" max=\"100\" value=\"0\" id=\"light" + (String)light_num + "_pwm\" disabled>";
|
|
|
|
http_content += " <span id=\"light" + (String)light_num + "_pwm_txt\"></span>%";
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "<script>";
|
|
|
|
http_content += "var slider" + (String)light_num + " = document.getElementById(\"bri" + (String)light_num + "\");";
|
|
|
|
http_content += "var output" + (String)light_num + " = document.getElementById(\"bri" + (String)light_num + "\_val\");";
|
2023-04-25 20:06:04 +02:00
|
|
|
http_content += "output" + (String)light_num + ".innerHTML = (Math.round((slider" + (String)light_num + ".value * 100.0 / 255.0) * 100) / 100).toFixed(2);";
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "slider" + (String)light_num + ".oninput = function() {";
|
2023-04-25 20:06:04 +02:00
|
|
|
http_content += "output" + (String)light_num + ".innerHTML = (Math.round((this.value * 100.0 / 255.0) * 100) / 100).toFixed(2);";
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "}";
|
|
|
|
http_content += "</script>";
|
2023-04-28 14:26:02 +02:00
|
|
|
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "</div>";
|
2023-04-27 19:26:06 +02:00
|
|
|
|
2023-04-25 14:32:42 +02:00
|
|
|
}
|
|
|
|
|
2023-04-27 19:26:06 +02:00
|
|
|
// startup state and scene for all of the lights
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "</td><td>";
|
|
|
|
http_content += "<div id=\"plot_chart\"></div>";
|
|
|
|
http_content += "</td></tr></table><br>";
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "<h3>Config</h3>";
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "<label for=\"startup\"><strong>Startup</strong></label>";
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<select onchange=\"this.form.submit()\" id=\"startup\" name=\"startup\">";
|
|
|
|
int ls_val = EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS);
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "<option ";
|
|
|
|
if (ls_val == LAST_STATE_STARTUP_LIGHT_LAST_STATE) http_content += "selected=\"selected\"";
|
|
|
|
http_content += " value=\"0\">Last state</option>";
|
|
|
|
http_content += "<option ";
|
|
|
|
if (ls_val == LAST_STATE_STARTUP_LIGHT_ON_STATE) http_content += "selected=\"selected\"";
|
|
|
|
http_content += " value=\"1\">On</option>";
|
|
|
|
http_content += "<option ";
|
|
|
|
if (ls_val == LAST_STATE_STARTUP_LIGHT_OFF_STATE) http_content += "selected=\"selected\"";
|
|
|
|
http_content += " value=\"2\">Off</option>";
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "</select>";
|
|
|
|
http_content += "</div>";
|
|
|
|
|
2023-04-27 19:26:06 +02:00
|
|
|
// scene
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
2023-04-25 14:32:42 +02:00
|
|
|
http_content += "<label for=\"scene\"><strong>Scene</strong></label>";
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<select onchange = \"this.form.submit()\" id=\"scene\" name=\"scene\">";
|
|
|
|
int sc_val = EEPROM.read(EEPROM_SCENE_ADDRESS);
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "<option ";
|
|
|
|
if (sc_val == SCENE_RELEAX) http_content += "selected=\"selected\"";
|
|
|
|
http_content += " value=\"0\">Relax</option>";
|
|
|
|
http_content += "<option ";
|
|
|
|
if (sc_val == SCENE_BRIGHT) http_content += "selected=\"selected\"";
|
|
|
|
http_content += " value=\"1\">Bright</option>";
|
|
|
|
http_content += "<option ";
|
|
|
|
if (sc_val == SCENE_NIGHTLY) http_content += "selected=\"selected\"";
|
|
|
|
http_content += " value=\"2\">Night</option>";
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "</select>";
|
|
|
|
http_content += "</div>";
|
|
|
|
|
2023-04-27 19:26:06 +02:00
|
|
|
// timing control button
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
2023-04-27 19:26:06 +02:00
|
|
|
http_content += "<label for=\"tc\"><strong>Timing control</strong></label>";
|
2023-04-24 20:26:49 +02:00
|
|
|
int tc_val = EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS);
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "<a class=\"pure-button";
|
|
|
|
if (tc_val == TIMING_CONTROL_ENABLED) http_content += " pure-button-primary";
|
|
|
|
http_content += "\" href=\"/?tc=true\">ON</a>";
|
|
|
|
http_content += "<a class=\"pure-button";
|
|
|
|
if (tc_val == TIMING_CONTROL_DISABLED) http_content += " pure-button-primary";
|
|
|
|
http_content += "\" href=\"/?tc=false\">OFF</a>";
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "</div>";
|
|
|
|
http_content += "<br>";
|
|
|
|
|
2023-04-25 08:18:36 +02:00
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
|
|
|
http_content += "<label for=\"transition\">Transition time (s)</label>";
|
2023-04-29 12:40:14 +02:00
|
|
|
http_content += "<input id=\"transition\" name=\"transition\" type=\"text\" placeholder=\"10\" value=\"" + (String)default_transitiontime + "\">";
|
2023-04-25 08:18:36 +02:00
|
|
|
http_content += "</div>";
|
2023-04-24 20:26:49 +02:00
|
|
|
|
|
|
|
// Wifi settings
|
|
|
|
http_content += "<br>";
|
|
|
|
http_content += "<h3>Wifi</h3>";
|
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
|
|
|
http_content += "<label for=\"ip\">SSID</label>";
|
|
|
|
http_content += "<input id=\"ssid\" name=\"ssid\" type=\"text\" value=\"" + WiFi.SSID() + "\">";
|
|
|
|
http_content += "</div>";
|
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
|
|
|
http_content += "<label for=\"wpw\">Passphrase</label>";
|
|
|
|
http_content += "<input id=\"wpw\" name=\"wpw\" type=\"text\" placeholder=\"1234password\">";
|
|
|
|
http_content += "</div>";
|
|
|
|
|
|
|
|
// Network settings
|
|
|
|
uint8_t dip = EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS);
|
|
|
|
http_content += "<br>";
|
|
|
|
http_content += "<h3>Network</h3>";
|
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
|
|
|
http_content += "<label for=\"dip\"><strong>Dynamic-IP</strong></label>";
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "<a class=\"pure-button";
|
|
|
|
if (dip) http_content += " pure-button-primary";
|
|
|
|
http_content += "\" href=\"/?dip=true\">ON</a>";
|
|
|
|
http_content += "<a class=\"pure-button";
|
|
|
|
if (!dip) http_content += " pure-button-primary";
|
|
|
|
http_content += "\" href=\"/?dip=false\">OFF</a>";
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "</div>";
|
|
|
|
|
2023-04-28 10:56:26 +02:00
|
|
|
// ip config
|
2023-04-27 16:40:27 +02:00
|
|
|
if (dip == 0) {
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
|
|
|
http_content += "<label for=\"ip\">IP</label>";
|
|
|
|
http_content += "<input id=\"ip\" name=\"ip\" type=\"text\" value=\"" + WiFi.localIP().toString() + "\">";
|
|
|
|
http_content += "</div>";
|
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
|
|
|
http_content += "<label for=\"gwip\">Gateway IP</label>";
|
|
|
|
http_content += "<input id=\"gwip\" name=\"gwip\" type=\"text\" value=\"" + WiFi.gatewayIP().toString() + "\">";
|
|
|
|
http_content += "</div>";
|
|
|
|
http_content += "<div class=\"pure-control-group\">";
|
|
|
|
http_content += "<label for=\"ip\">Netmask</label>";
|
|
|
|
http_content += "<input id=\"netmask\" name=\"netmas\" type=\"text\" value=\"" + WiFi.subnetMask().toString() + "\">";
|
|
|
|
http_content += "</div>";
|
|
|
|
}
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
// The save button
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "<div class=\"pure-controls\">";
|
|
|
|
http_content += "<button type=\"submit\" class=\"pure-button pure-button-primary\">Save</button>";
|
|
|
|
http_content += "</div>";
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
http_content += "<script>"
|
2023-04-28 10:56:26 +02:00
|
|
|
"function loadData() {" // load tc data and generate graph
|
2023-04-29 12:05:13 +02:00
|
|
|
"console.log('----> generate graph <----');"
|
2023-04-27 16:40:27 +02:00
|
|
|
"$.getJSON('/tc_data_blocks', function(data) {"
|
2023-04-28 10:56:26 +02:00
|
|
|
"var currenttime = [];"
|
2023-04-27 16:40:27 +02:00
|
|
|
"var time = [];"
|
|
|
|
"var channel1 = [];"
|
|
|
|
"var channel2 = [];"
|
|
|
|
"var channel3 = [];"
|
|
|
|
"var channel4 = [];"
|
|
|
|
"for (var i = 0; i < data['tcdata'].length; i++) {"
|
|
|
|
"time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']);"
|
|
|
|
"channel1.push(data['tcdata'][i]['ch1']);"
|
|
|
|
"channel2.push(data['tcdata'][i]['ch2']);"
|
|
|
|
"channel3.push(data['tcdata'][i]['ch3']);"
|
|
|
|
"channel4.push(data['tcdata'][i]['ch4']);"
|
|
|
|
"}"
|
2023-04-28 10:56:26 +02:00
|
|
|
"currenttime.push(data['currenttime']['hour']);"
|
|
|
|
"currenttime.push(data['currenttime']['min']);"
|
2023-04-28 12:01:50 +02:00
|
|
|
"console.log(currenttime);"
|
2023-04-28 10:56:26 +02:00
|
|
|
|
|
|
|
// index suche für die vertikale linie
|
|
|
|
"var currentTimeStr = currenttime[0] + ':' + (currenttime[1] < 10 ? '0' : '') + currenttime[1];"
|
|
|
|
"var index = time.indexOf(currentTimeStr);"
|
|
|
|
"if (index === -1) {"
|
|
|
|
"var lowerIndex = -1;"
|
|
|
|
"var upperIndex = -1;"
|
|
|
|
"for (var i = 0; i < time.length - 1; i++) {"
|
2023-04-28 12:01:50 +02:00
|
|
|
"console.log(time[i] + ' <= ' + currentTimeStr + ' >= ' + time[i+1]);"
|
|
|
|
|
|
|
|
"const currentDate = new Date();"
|
|
|
|
"const year = currentDate.getFullYear();"
|
|
|
|
"const month = (currentDate.getMonth() + 1).toString().padStart(2, '0');"
|
|
|
|
"const day = currentDate.getDate().toString().padStart(2, '0');"
|
|
|
|
"const dateString = `${year}-${month}-${day}`;"
|
|
|
|
//"console.log(dateString);" // 2023-04-28
|
|
|
|
|
|
|
|
"const start = moment(dateString+' '+time[i], 'YYYY-MM-DD HH:mm');"
|
|
|
|
"const curr = moment(dateString+' '+currentTimeStr, 'YYYY-MM-DD HH:mm');"
|
|
|
|
"const end = moment(dateString+' '+time[i+1], 'YYYY-MM-DD HH:mm');"
|
|
|
|
"console.log(start.format('YYYY-MM-DD HH:mm') + ' <= ' + curr.format('YYYY-MM-DD HH:mm') + ' >= ' + end.format('YYYY-MM-DD HH:mm'));"
|
|
|
|
|
|
|
|
"console.log(curr.isBetween(start, end));"
|
|
|
|
"if (curr.isBetween(start, end)) {"
|
2023-04-28 10:56:26 +02:00
|
|
|
"lowerIndex = i;"
|
|
|
|
"upperIndex = i + 1;"
|
|
|
|
"break;"
|
|
|
|
"}"
|
|
|
|
"}"
|
2023-04-28 12:01:50 +02:00
|
|
|
|
|
|
|
"console.log('lowerIndex='+lowerIndex);"
|
|
|
|
"console.log('upperIndex='+upperIndex);"
|
2023-04-28 10:56:26 +02:00
|
|
|
"if (lowerIndex === -1 || upperIndex === -1) {"
|
|
|
|
"console.log(\"Error: Current time not found in time array and not between two elements in time array.\");"
|
2023-04-28 22:38:59 +02:00
|
|
|
"lowerIndex = 0;"
|
|
|
|
"upperIndex = 1;"
|
|
|
|
"var tmp1 = time[0].split(':');"
|
|
|
|
"console.log('tmp1 = ' + tmp1);"
|
|
|
|
"currenttime[0] = tmp1[0];"
|
|
|
|
"currenttime[1] = tmp1[1];"
|
2023-04-28 10:56:26 +02:00
|
|
|
"}"
|
|
|
|
"var lowerTime = time[lowerIndex].split(\":\");"
|
|
|
|
"var upperTime = time[upperIndex].split(\":\");"
|
|
|
|
"var timeDiff = (currenttime[0] - lowerTime[0]) + ((currenttime[1] - lowerTime[1]) / 60);"
|
|
|
|
"var indexFloat = lowerIndex + timeDiff / ((upperTime[0] - lowerTime[0]) + ((upperTime[1] - lowerTime[1]) / 60));"
|
2023-04-28 12:01:50 +02:00
|
|
|
"console.log(\"Index (float): \" + indexFloat);"
|
2023-04-28 10:56:26 +02:00
|
|
|
"} else {"
|
2023-04-28 12:01:50 +02:00
|
|
|
"console.log(\"Index (integer): \" + index);"
|
|
|
|
"console.log(\"Index (float): \" + index);"
|
2023-04-28 10:56:26 +02:00
|
|
|
"}"
|
|
|
|
"if (indexFloat > index) {"
|
|
|
|
"index = indexFloat;"
|
|
|
|
"}"
|
2023-04-29 12:05:13 +02:00
|
|
|
"console.log(\"index in graph >>>\" + index);"
|
2023-04-28 10:56:26 +02:00
|
|
|
|
2023-04-29 12:05:13 +02:00
|
|
|
// TODO in array dynamisch erzeugt umschreiben
|
2023-04-27 16:40:27 +02:00
|
|
|
"var trace1 = {"
|
|
|
|
"x: time,"
|
|
|
|
"y: channel1,"
|
|
|
|
"name: 'Channel 1',"
|
|
|
|
"type: 'scatter',"
|
|
|
|
"mode: 'lines+markers',"
|
|
|
|
"};"
|
|
|
|
"var trace2 = {"
|
|
|
|
"x: time,"
|
|
|
|
"y: channel2,"
|
|
|
|
"name: 'Channel 2',"
|
|
|
|
"type: 'scatter',"
|
|
|
|
"mode: 'lines+markers',"
|
|
|
|
"};"
|
|
|
|
"var trace3 = {"
|
|
|
|
"x: time,"
|
|
|
|
"y: channel3,"
|
|
|
|
"name: 'Channel 3',"
|
|
|
|
"type: 'scatter',"
|
|
|
|
"mode: 'lines+markers',"
|
|
|
|
"};"
|
|
|
|
"var trace4 = {"
|
|
|
|
"x: time,"
|
|
|
|
"y: channel4,"
|
|
|
|
"name: 'Channel 4',"
|
|
|
|
"type: 'scatter',"
|
|
|
|
"mode: 'lines+markers',"
|
|
|
|
"};"
|
2023-04-29 12:05:13 +02:00
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
"var layout = {"
|
|
|
|
"title: 'Timing Control Data Blocks',"
|
|
|
|
"xaxis: {"
|
|
|
|
"title: 'Time',"
|
|
|
|
"tickangle: -45,"
|
|
|
|
"},"
|
|
|
|
"yaxis: {"
|
|
|
|
"title: 'Brightness',"
|
|
|
|
"range: [0, 255],"
|
|
|
|
"},"
|
|
|
|
"shapes: [{"
|
|
|
|
"type: 'line',"
|
2023-04-28 10:56:26 +02:00
|
|
|
"x0: index,"
|
2023-04-27 16:40:27 +02:00
|
|
|
"y0: 0,"
|
2023-04-28 10:56:26 +02:00
|
|
|
"x1: index,"
|
2023-04-27 16:40:27 +02:00
|
|
|
"y1: 255,"
|
|
|
|
"line: {"
|
|
|
|
"color: 'lightgrey',"
|
|
|
|
"width: 3,"
|
|
|
|
"dash: 'dot'"
|
|
|
|
"}"
|
|
|
|
"}]"
|
|
|
|
"};"
|
2023-04-29 12:05:13 +02:00
|
|
|
"Plotly.newPlot('plot_chart', [trace1, trace2, trace3, trace4], layout);" // TODO array der traces dynamisch erzeugen
|
2023-04-27 16:40:27 +02:00
|
|
|
"});"
|
|
|
|
"}"
|
|
|
|
"setInterval(loadData, 10000);"
|
|
|
|
"loadData();"
|
2023-04-29 12:05:13 +02:00
|
|
|
|
2023-04-28 10:56:26 +02:00
|
|
|
"function updateLightState() {" // load the light data from server and set on state and brightness
|
2023-04-29 12:05:13 +02:00
|
|
|
"console.log('----> setting bri and power switch <----');"
|
2023-04-27 16:40:27 +02:00
|
|
|
"for (let i = 1; i <= 4; i++) {"
|
|
|
|
"const lightURL = `http://192.168.0.26/state?light=${i}`;"
|
|
|
|
"fetch(lightURL)"
|
|
|
|
".then(response => response.json())"
|
|
|
|
".then(data => {"
|
|
|
|
"const briSlider = document.getElementById(`bri${i - 1}`);"
|
|
|
|
"const briSliderVal = document.getElementById(`bri${i - 1}_val`);"
|
|
|
|
"const onLinkOn = document.getElementById(`on${i - 1}_on`);"
|
|
|
|
"const onLinkOff = document.getElementById(`on${i - 1}_off`);"
|
|
|
|
"briSlider.value = data.bri;"
|
|
|
|
"briSliderVal.innerHTML = (Math.round((data.bri * 100.0 / 255.0) * 100) / 100).toFixed(2);"
|
2023-04-29 12:05:13 +02:00
|
|
|
"console.log('data.on ' + i + ' = ' + data.on);"
|
|
|
|
"if (data.on == true) {"
|
|
|
|
//"console.log('true');"
|
2023-04-27 16:40:27 +02:00
|
|
|
"onLinkOn.classList.add('pure-button-primary');"
|
|
|
|
"onLinkOff.classList.remove('pure-button-primary');"
|
2023-04-29 12:05:13 +02:00
|
|
|
"} else {"
|
|
|
|
//"console.log('false');"
|
|
|
|
"onLinkOn.classList.remove('pure-button-primary');"
|
|
|
|
"onLinkOff.classList.add('pure-button-primary');"
|
2023-04-27 16:40:27 +02:00
|
|
|
"}"
|
|
|
|
"})"
|
|
|
|
".catch(error => console.error(error));"
|
|
|
|
"}"
|
|
|
|
"}"
|
|
|
|
"setInterval(updateLightState, 10000);"
|
|
|
|
"updateLightState();"
|
2023-04-28 14:26:02 +02:00
|
|
|
|
|
|
|
// show pwm values in webinterface
|
|
|
|
"function updatePWMValues() {"
|
2023-04-29 12:05:13 +02:00
|
|
|
"console.log('----> setting pwm data <----');"
|
2023-04-28 14:26:02 +02:00
|
|
|
"for (let i = 0; i < " + (String)LIGHTS_COUNT + "; i++) {"
|
|
|
|
"const lightID = i + 1;"
|
|
|
|
"const pwmElement = document.getElementById(`light${i}_pwm`);"
|
|
|
|
"const pwmElementTxt = document.getElementById(`light${i}_pwm_txt`);"
|
|
|
|
"if (pwmElement) {"
|
|
|
|
"const url = `http://192.168.0.26/state?light=${lightID}`;"
|
|
|
|
"fetch(url)"
|
|
|
|
".then(response => response.json())"
|
|
|
|
".then(data => {"
|
2023-04-29 12:05:13 +02:00
|
|
|
"const pwmValue = ((Math.round((data.curpwm - ((data.curpwm >= " + (String)PWM_MIN+ ") ? " + (String)PWM_MIN + " : 0)) / " + (String)PWM_MAX + " * 100.0) * 100.0) / 100.0).toFixed(2);" // pwm as % PWM_MIN to PWM_MAX
|
2023-04-28 19:49:52 +02:00
|
|
|
"console.log('curpwm[' + i + '] = ' + data.curpwm + ' = ' + pwmValue);"
|
2023-04-28 14:26:02 +02:00
|
|
|
"pwmElement.innerText = pwmValue.toString();"
|
|
|
|
"pwmElement.value = pwmValue;"
|
|
|
|
"pwmElementTxt.innerText = pwmValue.toString();"
|
|
|
|
"})"
|
|
|
|
".catch(error => console.error(error));"
|
|
|
|
"}"
|
|
|
|
"}"
|
|
|
|
"}"
|
|
|
|
"updatePWMValues();"
|
|
|
|
"setInterval(updatePWMValues, 5000);"
|
2023-04-27 16:40:27 +02:00
|
|
|
"</script>";
|
|
|
|
|
|
|
|
#endif // DISABLE_WEB_CONTROL
|
2023-04-25 14:32:42 +02:00
|
|
|
|
2023-04-24 20:26:49 +02:00
|
|
|
http_content += "</fieldset>";
|
|
|
|
http_content += "</form>";
|
|
|
|
http_content += "</body>";
|
|
|
|
http_content += "</html>";
|
|
|
|
|
|
|
|
server.send(200, "text/html", http_content);
|
|
|
|
});
|
|
|
|
|
2023-04-27 16:40:27 +02:00
|
|
|
server.on("/reset", []() { // trigger manual reset
|
2023-04-24 20:26:49 +02:00
|
|
|
server.send(200, "text/html", "reset");
|
|
|
|
delay(1000);
|
|
|
|
ESP.restart();
|
|
|
|
});
|
|
|
|
|
|
|
|
server.onNotFound(handleNotFound);
|
|
|
|
}
|