diff --git a/data/index.htm b/data/index.htm index 0839547ab5755a20a83513c2ce6e24f40bb7aaff..860ff5d2ce1623c1d0505452d6dcf6539b6b1dd2 100644 --- a/data/index.htm +++ b/data/index.htm @@ -30,17 +30,14 @@ <a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank"><img src="images/atom196.png" style="width: 24px; height: 24px;" /></a> <a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank">Evil Genius Labs</a> <div class="navbar-brand">&</div> - <a class="navbar-brand" href="https://www.thingiverse.com/Surrbradl08/designs" target="_blank"><img src="images/surr.png" style="width: 24px; height: 24px;" /></a> + <a class="navbar-brand" href="https://www.thingiverse.com/Surrbradl08/designs" target="_blank"><img src="images/surr.png" style="width: 24px; height: 24px;" /></a> <a class="navbar-brand" href="https://www.thingiverse.com/Surrbradl08/designs" target="_blank">Surrbradl08</a> </div> <div class="collapse navbar-collapse" id="navbar-collapse-1"> <ul class="nav navbar-nav"> - <li class="active bg-light"><a href="/" class="bg-light">Home <span class="sr-only bg-light">(current)</span></a></li> - <li><a href="/ota" target="_blank" title="OTA">OTA Update</a></li> - <li><a href="/alexa" target="_blank" title="Alexa">Alexa Pairing</a></li> - <li><a href="/reboot" target="_blank" title="Reboot">Reboot</a></li> - <!--<li><a href="/simple" target="_blank" title="Simple Page">Simple</a></li> - <li><a href="/wifi" target="_blank" title="WiFi - Config">WiFi</a></li>--> + <li class="active bg-light"><a href="/" class="bg-light" title="Home">Home <span class="sr-only bg-light">(current)</span></a></li> + <li><a href="/simple.htm" title="Simple Page">Simple</a></li> + <li><a href="/settings.htm" title="Settings">Settings</a></li> <li> <a> <div class="custom-control custom-switch"> diff --git a/data/js/app.js b/data/js/app.js index 005dc3492c439803621115725689577532970792..187590bb32a01c67144a666bb9c519bbd21c5dc3 100644 --- a/data/js/app.js +++ b/data/js/app.js @@ -41,6 +41,8 @@ $(document).ready(function() { addColorFieldPicker(field); } else if (field.type == "Section") { addSectionField(field); + } else if (field.type == "Setting") { + handleSetting(field); } }); @@ -391,7 +393,41 @@ function updateFieldValue(name, value) { var input = group.find(".form-control"); input.val("rgb(" + value + ")"); } -}; +} + +function handleSetting(field) { + console.log(field); + + if (field.name == "hostname") { + $("#inputHostname").val(field.value); + } + + if (field.name.includes("Support") && field.value == false) { + $("#" + field.name + "Entry").addClass("hidden"); + } + if (field.name == "mqttSettings") { + $("#btnOnmqtt").attr("class", field.enabled ? "btn btn-primary" : "btn btn-default"); + $("#btnOffmqtt").attr("class", !field.enabled ? "btn btn-primary" : "btn btn-default"); + $("#inputMqttEnabled").val(field.enabled ? "1" : "0"); + + $("#btnOnmqtt").click(function() { + $("#btnOnmqtt").attr("class", "btn btn-primary"); + $("#btnOffmqtt").attr("class", "btn btn-default"); + $("#inputMqttEnabled").val("1"); + }); + $("#btnOffmqtt").click(function() { + $("#btnOnmqtt").attr("class", "btn btn-default"); + $("#btnOffmqtt").attr("class", "btn btn-primary"); + $("#inputMqttEnabled").val("0"); + }); + + $("#inputMqttHostname").val(field.hostname); + $("#inputMqttPort").val(field.port); + $("#inputMqttUser").val(field.username); + $("#inputMqttTopic").val(field.topic); + $("#inputMqttDeviceName").val(field.devicename); + } +} function setBooleanFieldValue(field, btnOn, btnOff, value) { field.value = value; diff --git a/data/settings.htm b/data/settings.htm new file mode 100644 index 0000000000000000000000000000000000000000..f80b1baa179c0c0e9d5ffadbbe2da211ca6041fc --- /dev/null +++ b/data/settings.htm @@ -0,0 +1,185 @@ +<!DOCTYPE html> +<html> + + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>WiFi Settings</title> + + <!-- request CSS from the ESP8266 web server --> + <link rel="stylesheet" href="css/bootstrap.min.css"> + <link rel="stylesheet" href="css/minicolors.min.css"> + + <link rel="stylesheet" href="css/styles.css"> + <link rel="stylesheet" href="css/dark-mode.css"> + <link rel="icon" href="images/atom196.png"> + </head> + + <body> + +<body> + + <nav class="navbar navbar-default navbar-static-top bg-light" id="top" role="banner"> + <div class="container"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse-1" aria-expanded="false"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank"><img src="images/atom196.png" style="width: 24px; height: 24px;" /></a> + <a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank">Evil Genius Labs</a> + <div class="navbar-brand">&</div> + <a class="navbar-brand" href="https://www.thingiverse.com/Surrbradl08/designs" target="_blank"><img src="images/surr.png" style="width: 24px; height: 24px;" /></a> + <a class="navbar-brand" href="https://www.thingiverse.com/Surrbradl08/designs" target="_blank">Surrbradl08</a> + </div> + <div class="collapse navbar-collapse" id="navbar-collapse-1"> + <ul class="nav navbar-nav"> + <li><a href="/" title="Home">Home</a></li> + <li><a href="/simple.htm" title="Simple Page">Simple</a></li> + <li class="active bg-light"><a href="/settings.htm" class="bg-light" title="Settings">Settings <span class="sr-only bg-light">(current)</span></a></li> + <li> + <a> + <div class="custom-control custom-switch"> + <input type="checkbox" class="custom-control-input" id="darkSwitch" /> + <label class="custom-control-label" for="darkSwitch">Dark Mode</label> + </div> + <script src="js/dark-mode-switch.min.js"></script> + </a> + </li> + </ul> + <ul class="nav navbar-nav navbar-right"> + <li> + <a href="https://github.com/NimmLor/esp8266-fastled-iot-webserver"> + <img style="height: 16px;" src="images/github.ico" /> + </a> + </li> + </ul> + </div> + </div> + </nav> + + <div id="container" class="container"> + + <form class="form-horizontal" id="form" action="/settings" method="post"> + + <div class="form-group"> + <label for="inputSSID" class="col-sm-2 control-label">SSID</label> + <div class="col-sm-10"> + <input type="text" autocorrect="off" autocapitalize="none" + class="form-control" id="inputSSID" name="ssid" placeholder="SSID (Wi-Fi network name)"> + </div> + </div> + + <div class="form-group"> + <label for="inputPassword" class="col-sm-2 control-label">Password</label> + <div class="col-sm-10"> + <input type="password" class="form-control" id="inputPassword" name="password" placeholder="Password"> + </div> + </div> + + <div id="mdnsSupportEntry" class="form-group"> + <div class="col-sm-offset-2 col-sm-10"> + <hr style="margin-bottom: 20px;margin-top: 5px;" /> + </div> + <label for="inputHostname" class="col-sm-2 control-label">Hostname</label> + <div class="col-sm-10"> + <input type="text" autocorrect="off" autocapitalize="none" + class="form-control" id="inputHostname" name="hostname" placeholder="Hostname"> + </div> + </div> + + <div id="mqttSupportEntry"> + <div class="form-group"> + <div class="col-sm-offset-2 col-sm-10"> + <hr style="margin-bottom: 5px;margin-top: 5px;" /> + </div> + </div> + <div id="form-group-mqtt" class="form-group" data-field-type="Boolen"> + <label for="btn-group-mqtt" class="col-sm-2 control-label">MQTT Support</label> + <div class="col-sm-10"> + <div class="btn-group" role="group" id="btn-group-mqtt"> + <button type="button" class="btn btn-default" id="btnOnmqtt">On</button> + <button type="button" class="btn btn-default" id="btnOffmqtt">Off</button> + </div> + <input type="hidden" id="inputMqttEnabled" name="mqtt-enabled"> + </div> + </div> + <div class="form-group"> + <label for="inputMqttHostname" class="col-sm-2 control-label">MQTT Hostname</label> + <div class="col-sm-10"> + <input type="text" autocorrect="off" autocapitalize="none" + class="form-control" id="inputMqttHostname" name="mqtt-hostname" placeholder="MQTT host name"> + </div> + </div> + <div class="form-group"> + <label for="inputMqttPort" class="col-sm-2 control-label">MQTT Port</label> + <div class="col-sm-10"> + <input type="text" autocorrect="off" autocapitalize="none" + class="form-control" id="inputMqttPort" name="mqtt-port" placeholder="MQTT host port"> + </div> + </div> + <div class="form-group"> + <label for="inputMqttUser" class="col-sm-2 control-label">MQTT Username</label> + <div class="col-sm-10"> + <input type="text" autocorrect="off" autocapitalize="none" + class="form-control" id="inputMqttUser" name="mqtt-user" placeholder="MQTT username"> + </div> + </div> + <div class="form-group"> + <label for="mqttPassword" class="col-sm-2 control-label">MQTT Password</label> + <div class="col-sm-10"> + <input type="password" class="form-control" id="mqttPassword" + name="mqtt-password" placeholder="MQTT password"> + </div> + </div> + <div class="form-group"> + <label for="inputMqttTopic" class="col-sm-2 control-label">MQTT Topic</label> + <div class="col-sm-10"> + <input type="text" autocorrect="off" autocapitalize="none" + class="form-control" id="inputMqttTopic" name="mqtt-topic" placeholder="MQTT topic"> + </div> + </div> + <div class="form-group"> + <label for="inputMqttDeviceName" class="col-sm-2 control-label">MQTT Device Name</label> + <div class="col-sm-10"> + <input type="text" autocorrect="off" autocapitalize="none" + class="form-control" id="inputMqttDeviceName" name="mqtt-device-name" placeholder="MQTT device name"> + </div> + </div> + </div> + + <div class="form-group"> + <div class="col-sm-offset-2 col-sm-10"> + <hr style="margin-bottom: 5px;margin-top: 5px;" /> + </div> + </div> + + <div class="form-group"> + <div class="col-sm-offset-2 col-sm-10"> + <button type="submit" class="btn btn-default">Update</button> + <a role="button" href='/reset' class="pull-right btn btn-danger" style="margin-left: 10px;" title="Reset">RESET</a> + <a role="button" href='/reboot' class="pull-right btn btn-info" style="margin-left: 10px;" title="Reboot">Reboot</a> + <a id="alexaSupportEntry" role="button" href='/alexa' target="_blank" class="pull-right btn btn-success" style="margin-left: 10px;" title="Alexa">Alexa Pairing</a> + <a id="otaSupportEntry" role="button" href="/ota" target="_blank" class="pull-right btn btn-success" title="OTA">OTA Update</a> + + </div> + </div> + + </form> + + </div> + + <!-- request js from the ESP8266 web server --> + <script src="js/jquery-3.1.1.min.js"></script> + <script src="js/bootstrap.min.js"></script> + <script src="js/minicolors.min.js"></script> + <script src="js/r-websocket.min.js"></script> + + <script src="js/app.js"></script> + +</body> + +</html> diff --git a/data/simple.htm b/data/simple.htm index 5fc862278f51e232b823054811e220aed3bf9219..cf2a0534a01fe0f55a9cb176351b679fccfcdc86 100644 --- a/data/simple.htm +++ b/data/simple.htm @@ -1,25 +1,64 @@ <!DOCTYPE html> <html> -<head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>ESP8266 + FastLED by Evil Genius Labs</title> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>LED-Lighting (Simple)</title> - <!-- request CSS from internet CDN --> - <!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> --> + <!-- request CSS from the ESP8266 web server --> + <link rel="stylesheet" href="css/bootstrap.min.css"> + <link rel="stylesheet" href="css/minicolors.min.css"> - <!-- request CSS from the ESP8266 web server --> - <link rel="stylesheet" href="css/bootstrap.min.css"> - - <link rel="stylesheet" href="css/simple.css"> - - <link rel="icon" href="images/atom196.png"> -</head> + <link rel="stylesheet" href="css/styles.css"> + <link rel="stylesheet" href="css/dark-mode.css"> + <link rel="icon" href="images/atom196.png"> + </head> <body> + <nav class="navbar navbar-default navbar-static-top bg-light" id="top" role="banner"> + <div class="container"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse-1" aria-expanded="false"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank"><img src="images/atom196.png" style="width: 24px; height: 24px;" /></a> + <a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank">Evil Genius Labs</a> + <div class="navbar-brand">&</div> + <a class="navbar-brand" href="https://www.thingiverse.com/Surrbradl08/designs" target="_blank"><img src="images/surr.png" style="width: 24px; height: 24px;" /></a> + <a class="navbar-brand" href="https://www.thingiverse.com/Surrbradl08/designs" target="_blank">Surrbradl08</a> + </div> + <div class="collapse navbar-collapse" id="navbar-collapse-1"> + <ul class="nav navbar-nav"> + <li><a href="/" title="Home">Home</a></li> + <li class="active bg-light"><a href="/simple.htm" title="Simple Page" class="bg-light">Simple <span class="sr-only bg-light">(current)</span></a></li> + <li><a href="/settings.htm" title="Settings">Settings</a></li> + <li> + <a> + <div class="custom-control custom-switch"> + <input type="checkbox" class="custom-control-input" id="darkSwitch" /> + <label class="custom-control-label" for="darkSwitch">Dark Mode</label> + </div> + <script src="js/dark-mode-switch.min.js"></script> + </a> + </li> + </ul> + <ul class="nav navbar-nav navbar-right"> + <li> + <a href="https://github.com/NimmLor/esp8266-fastled-iot-webserver"> + <img style="height: 16px;" src="images/github.ico" /> + </a> + </li> + </ul> + </div> + </div> + </nav> + <div id="container" class="container"> <div style="margin: 5px;"> @@ -41,12 +80,6 @@ </div> - <!-- request js from internet CDN --> - <!-- <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script> --> - <!-- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> --> - <!-- <script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js"></script> --> - <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js" integrity="sha256-A4JwlcDvqO4JXpvEtvWY1RH8JAEMu5W21wP8GUXLUNs=" crossorigin="anonymous"></script> --> - <!-- request js from the ESP8266 web server --> <script src="js/jquery-3.1.1.min.js"></script> <script src="js/bootstrap.min.js"></script> diff --git a/data/wifi.htm b/data/wifi.htm deleted file mode 100644 index 6c9a8c648f4c1c60517a5ba46742e43b29723d16..0000000000000000000000000000000000000000 --- a/data/wifi.htm +++ /dev/null @@ -1,85 +0,0 @@ -<!DOCTYPE html> -<html> - -<head> - <meta charset="utf-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>ESP8266 + FastLED by Evil Genius Labs</title> - - <!-- request CSS from internet CDN --> - <!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> --> - - <!-- request CSS from the ESP8266 web server --> - <link rel="stylesheet" href="css/bootstrap.min.css"> - - <link rel="stylesheet" href="css/styles.css"> - - <link rel="icon" href="images/atom196.png"> -</head> - -<body> - - <nav class="navbar navbar-default navbar-static-top" id="top" role="banner"> - <div class="container"> - <div class="navbar-header"> - <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse-1" aria-expanded="false"> - <span class="sr-only">Toggle navigation</span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - </button> - <a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank"><img src="/images/atom196.png" style="width: 24px; height: 24px;" /></a> - <a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank">Evil Genius Labs</a> - </div> - <div class="collapse navbar-collapse" id="navbar-collapse-1"> - <ul class="nav navbar-nav"> - <li><a href="/">Home<span class="sr-only">(current)</span></a></li> - <li class="active"><a href="/wifi.htm" target="_blank" title="Wi-Fi Settings">Wi-Fi</a></li> - </ul> - </div> - </div> - </nav> - - <div id="container" class="container"> - - <form class="form-horizontal" id="form" action="/wifi" method="post"> - - <div class="form-group"> - <label for="inputSSID" class="col-sm-2 control-label">SSID</label> - <div class="col-sm-10"> - <input type="text" autocorrect="off" autocapitalize="none" - class="form-control" id="inputSSID" name="ssid" placeholder="SSID (Wi-Fi network name)"> - </div> - </div> - - <div class="form-group"> - <label for="inputPassword" class="col-sm-2 control-label">Password</label> - <div class="col-sm-10"> - <input type="password" class="form-control" id="inputPassword" name="password" placeholder="Password"> - </div> - </div> - - <div class="form-group"> - <div class="col-sm-offset-2 col-sm-10"> - <button type="submit" class="btn btn-default">Connect</button> - </div> - </div> - - </form> - - </div> - - <!-- request js from internet CDN --> - <!-- <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script> --> - <!-- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> --> - <!-- <script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js"></script> --> - <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js" integrity="sha256-A4JwlcDvqO4JXpvEtvWY1RH8JAEMu5W21wP8GUXLUNs=" crossorigin="anonymous"></script> --> - - <!-- request js from the ESP8266 web server --> - <script src="js/jquery-3.1.1.min.js"></script> - <script src="js/bootstrap.min.js"></script> - -</body> - -</html> diff --git a/esp8266-fastled-iot-webserver.ino b/esp8266-fastled-iot-webserver.ino index b656534661116614e16c050288fd4fc18579a371..11b9ff1edd11237b8d6d3c877d49ff3cc4244038 100644 --- a/esp8266-fastled-iot-webserver.ino +++ b/esp8266-fastled-iot-webserver.ino @@ -64,7 +64,7 @@ extern "C" { //#define REMOVE_VISUALIZATION // remove the comment to completly disable all udp-based visualization patterns -#define HOSTNAME "LEDs" // Name that appears in your network, don't use whitespaces, use "-" instead +#define DEFAULT_HOSTNAME "LEDs" // Name that appears in your network, don't use whitespaces, use "-" instead #define DEVICE_TYPE 0 // The following types are available /* @@ -186,13 +186,13 @@ extern "C" { * */ #ifdef ENABLE_ALEXA_SUPPORT - #define ALEXA_DEVICE_NAME HOSTNAME - //#define AddAutoplayDevice ((String)HOSTNAME + (String)" Autoplay") - //#define AddStrobeDevice ((String)HOSTNAME + (String)" Strobe") - //#define AddSpecificPatternDeviceA ((String)HOSTNAME + (String)" Party") - //#define AddSpecificPatternDeviceB ((String)HOSTNAME + (String)" Chill") - //#define AddSpecificPatternDeviceC ((String)HOSTNAME + (String)" Rainbow") - //#define AddAudioDevice ((String)HOSTNAME + (String)" Audio") + //#define ALEXA_DEVICE_NAME DEFAULT_HOSTNAME + //#define AddAutoplayDevice ((String)DEFAULT_HOSTNAME + (String)" Autoplay") + //#define AddStrobeDevice ((String)DEFAULT_HOSTNAME + (String)" Strobe") + //#define AddSpecificPatternDeviceA ((String)DEFAULT_HOSTNAME + (String)" Party") + //#define AddSpecificPatternDeviceB ((String)DEFAULT_HOSTNAME + (String)" Chill") + //#define AddSpecificPatternDeviceC ((String)DEFAULT_HOSTNAME + (String)" Rainbow") + //#define AddAudioDevice ((String)DEFAULT_HOSTNAME + (String)" Audio") //#define SpecificPatternA 37 // Parameter defines what pattern gets executed //#define SpecificPatternB 12 // Parameter defines what pattern gets executed //#define SpecificPatternC 0 // Parameter defines what pattern gets executed @@ -258,8 +258,12 @@ if you have connected the ring first it should look like this: const int twpOffs /*######################## MQTT Configuration ########################*/ #ifdef ENABLE_MQTT_SUPPORT - const char* mqttServer = "homeassistant.local"; - const int mqttPort = 1883; + // these are deafault settings which can be changed in the web interface "settings" page + #define MQTT_ENABLED 0 + #define MQTT_HOSTNAME "homeassistant.local" + #define MQTT_PORT 1883 + #define MQTT_USER "MyUserName" + #define MQTT_PASS "" #if DEVICE_TYPE == 0 #define MQTT_TOPIC "homeassistant/light/ledstrip" // MQTT Topic to Publish to for state and config (Home Assistant) #define MQTT_TOPIC_SET "/set" // MQTT Topic to subscribe to for changes(Home Assistant) @@ -288,9 +292,6 @@ if you have connected the ring first it should look like this: const int twpOffs #define MQTT_UNIQUE_IDENTIFIER WiFi.macAddress() // A Unique Identifier for the device in Homeassistant (MAC Address used by default) #define MQTT_MAX_PACKET_SIZE 512 #define MQTT_MAX_TRANSFER_SIZE 512 - // For the user / password check the Secrets.h file and modify your settings in there. - // const char* mqttUser = "YourMqttUser"; - // const char* mqttPassword = "YourMqttUserPassword"; #include <PubSubClient.h> // Include the MQTT Library, must be installed via the library manager #include <ArduinoJson.h> @@ -371,6 +372,35 @@ if you have connected the ring first it should look like this: const int twpOffs uint8_t incomingPacket[PACKET_LENGTH + 1]; #endif +// define EEPROM settings +// https://www.kriwanek.de/index.php/de/homeautomation/esp8266/364-eeprom-für-parameter-verwenden + +typedef struct { + uint8_t brightness; + uint8_t currentPatternIndex; + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t power; + uint8_t autoplay; + uint8_t autoplayDuration; + uint8_t currentPaletteIndex; + uint8_t speed; + char hostname[33]; + uint8_t MQTTEnabled; + char MQTTHost[65]; + uint16_t MQTTPort; + char MQTTUser[33]; + char MQTTPass[65]; + char MQTTTopic[65]; + char MQTTDeviceName[33]; +} configData_t; + +configData_t cfg; + +// set to true if config has changedneeds to be w +bool save_config = false; + ESP8266WebServer webServer(80); #include "FSBrowser.h" @@ -378,20 +408,6 @@ ESP8266WebServer webServer(80); #define FRAMES_PER_SECOND 120 // here you can control the speed. With the Access Point / Web Server the animations run a bit slower. #define SOUND_REACTIVE_FPS FRAMES_PER_SECOND - -#include "Secrets.h" // this file is intentionally not included in the sketch, so nobody accidentally commits their secret information. -// create a Secrets.h file with the following: -// AP mode password -// const char WiFiAPPSK[] = "your-password"; - -// Wi-Fi network to connect to (if not in AP mode) -// char* ssid = "your-ssid"; -// char* password = "your-password"; - -// MQTT user and password for your broker (if MQTT is enabled) -// const char* mqttUser = "your-mqtt-user"; -// const char* mqttPassword = "your-mqtt-password"; - #ifdef ENABLE_OTA_SUPPORT #include <ArduinoOTA.h> #endif @@ -643,10 +659,10 @@ void setSolidColor(uint8_t r, uint8_t g, uint8_t b, bool updatePattern) { solidColor = CRGB(r, g, b); - EEPROM.write(2, r); - EEPROM.write(3, g); - EEPROM.write(4, b); - EEPROM.commit(); + cfg.red = r; + cfg.green = g; + cfg.blue = b; + save_config = true; if (updatePattern && currentPatternIndex != patternCount - 2)setPattern(patternCount - 1); @@ -715,8 +731,7 @@ void setup() { fill_solid(leds, NUM_LEDS, CRGB::Black); FastLED.show(); - EEPROM.begin(4095); - loadSettings(); + loadConfig(); FastLED.setBrightness(brightness); @@ -759,25 +774,32 @@ void setup() { String(mac[WL_MAC_ADDR_LENGTH - 1], HEX); macID.toUpperCase(); - String nameString = ((String)HOSTNAME + ' - ' + macID); + String nameString = String(cfg.hostname) + String(" - ") + macID; char nameChar[nameString.length() + 1]; - memset(nameChar, 0, nameString.length() + 1); - - for (int i = 0; i < nameString.length(); i++) - nameChar[i] = nameString.charAt(i); - - Serial.printf("Name: %s\n", nameChar); + nameString.toCharArray(nameChar, sizeof(nameChar)); //reset settings - wipe credentials for testing // wifiManager.resetSettings(); wifiManager.setConfigPortalBlocking(false); + wifiManager.setHostname(cfg.hostname); //automatically connect using saved credentials if they exist //If connection fails it starts an access point with the specified name if (wifiManager.autoConnect(nameChar)) { Serial.println("Wi-Fi connected"); + Serial.print("Open http://"); + Serial.print(WiFi.localIP()); + Serial.println(" in your browser"); +#ifdef ENABLE_MULTICAST_DNS + if (!MDNS.begin(cfg.hostname)) { + Serial.println("\nError while setting up MDNS responder! \n"); + } else { + Serial.println("mDNS responder started"); + MDNS.addService("http", "tcp", 80); + } +#endif } else { Serial.println("Wi-Fi manager portal running"); @@ -807,7 +829,7 @@ void setup() { //delay(500); //webServer.close(); //delay(500); - ArduinoOTA.setHostname(HOSTNAME); + ArduinoOTA.setHostname(cfg.hostname); #ifdef OTA_PASSWORD ArduinoOTA.setPassword(OTA_PASSWORD); #endif @@ -866,7 +888,7 @@ void setup() { #ifdef ALEXA_DEVICE_NAME alexa_main = new EspalexaDevice(ALEXA_DEVICE_NAME, mainAlexaEvent, EspalexaDeviceType::color); #else - alexa_main = new EspalexaDevice(HOSTNAME, mainAlexaEvent, EspalexaDeviceType::color); + alexa_main = new EspalexaDevice(cfg.hostname, mainAlexaEvent, EspalexaDeviceType::color); #endif espalexa.addDevice(alexa_main); #ifdef AddAutoplayDevice @@ -936,6 +958,8 @@ void setup() { delay(1); } }); +#else + addRebootPage(0); #endif webServer.on("/all", HTTP_GET, []() { @@ -943,13 +967,143 @@ void setup() { json += ",{\"name\":\"lines\",\"label\":\"Amount of Lines for the Visualizer\",\"type\":\"String\",\"value\":"; json += PACKET_LENGTH; json += "}"; - json += ",{\"name\":\"hostname\",\"label\":\"Name of the device\",\"type\":\"String\",\"value\":\""; - json += HOSTNAME; + json += ",{\"name\":\"hostname\",\"label\":\"Name of the device\",\"type\":\"Setting\",\"value\":\""; + json += cfg.hostname; json += "\"}"; + json += ",{\"name\":\"otaSupport\",\"label\":\"Device supports OTA\",\"type\":\"Setting\",\"value\":"; +#ifdef ENABLE_OTA_SUPPORT + json += "true"; +#else + json += "false"; +#endif + json += "}"; + json += ",{\"name\":\"alexaSupport\",\"label\":\"Device supports Alexa\",\"type\":\"Setting\",\"value\":"; +#ifdef ENABLE_ALEXA_SUPPORT + json += "true"; +#else + json += "false"; +#endif + json += "}"; + json += ",{\"name\":\"mqttSupport\",\"label\":\"Device supports MQTT\",\"type\":\"Setting\",\"value\":"; +#ifdef ENABLE_MQTT_SUPPORT + json += "true"; +#else + json += "false"; +#endif + json += "}"; +#ifdef ENABLE_MQTT_SUPPORT + json += ",{\"name\":\"mqttSettings\",\"label\":\"MQTT Settings\",\"type\":\"Setting\",\"enabled\":"; + json += cfg.MQTTEnabled; + json += ",\"hostname\":\""; + json += cfg.MQTTHost; + json += "\",\"port\":"; + json += cfg.MQTTPort; + json += ",\"username\":\""; + json += cfg.MQTTUser; + json += "\",\"topic\":\""; + json += cfg.MQTTTopic; + json += "\",\"devicename\":\""; + json += cfg.MQTTDeviceName; + json += "\"}"; +#endif json += "]"; webServer.send(200, "text/json", json); }); + webServer.on("/settings", HTTP_POST, []() { + + bool force_restart = false; + + String ssid = webServer.arg("ssid"); + String password = webServer.arg("password"); + + if (ssid.length() != 0 && password.length() != 0) { +#ifdef ESP8266 + struct station_config conf; + + wifi_station_get_config(&conf); + + memset(conf.ssid, 0, sizeof(conf.ssid)); + for (int i = 0; i < ssid.length() && i < sizeof(conf.ssid); i++) + conf.ssid[i] = ssid.charAt(i); + + memset(conf.password, 0, sizeof(conf.password)); + for (int i = 0; i < password.length() && i < sizeof(conf.password); i++) + conf.password[i] = password.charAt(i); + + wifi_station_set_config(&conf); + +// untested due to lack of ESP32 +#elif defined(ESP32) + if(WiFiGenericClass::getMode() != WIFI_MODE_NULL){ + + wifi_config_t conf; + esp_wifi_get_config(WIFI_IF_STA, &conf); + + memset(conf.sta.ssid, 0, sizeof(conf.sta.ssid)); + ssid.toCharArray(conf.sta.ssid, sizeof(conf.sta.ssid)); + memset(conf.sta.password, 0, sizeof(conf.sta.password)); + password.toCharArray(conf.sta.password, sizeof(conf.sta.password)); + + esp_wifi_set_config(WIFI_IF_STA, &conf); + } +#endif + force_restart = true; + } + + String new_hostname = webServer.arg("hostname"); + + if (new_hostname.length() != 0 && String(cfg.hostname) != new_hostname) { + setHostname(new_hostname); + force_restart = true; + } + +#ifdef ENABLE_MQTT_SUPPORT + uint8_t mqtt_enabled = uint8_t(webServer.arg("mqtt-enabled").toInt()); + String mqtt_hostname = webServer.arg("mqtt-hostname"); + uint16_t mqtt_port = uint16_t(webServer.arg("mqtt-port").toInt()); + String mqtt_username = webServer.arg("mqtt-user"); + String mqtt_password = webServer.arg("mqtt-password"); + String mqtt_topic = webServer.arg("mqtt-topic"); + String mqtt_device_name = webServer.arg("mqtt-device-name"); + + if (cfg.MQTTEnabled != mqtt_enabled) { + cfg.MQTTEnabled = mqtt_enabled; + save_config = true; + } + if (cfg.MQTTPort != mqtt_port) { + cfg.MQTTPort = mqtt_port; + force_restart = true; + } + if (mqtt_hostname.length() > 0 && String(cfg.MQTTHost) != mqtt_hostname) { + mqtt_hostname.toCharArray(cfg.MQTTHost, sizeof(cfg.MQTTHost)); + force_restart = true; + } + if (mqtt_username.length() > 0 && String(cfg.MQTTUser) != mqtt_username) { + mqtt_username.toCharArray(cfg.MQTTUser, sizeof(cfg.MQTTUser)); + force_restart = true; + } + if (mqtt_password.length() > 0 && String(cfg.MQTTPass) != mqtt_password) { + mqtt_password.toCharArray(cfg.MQTTPass, sizeof(cfg.MQTTPass)); + force_restart = true; + } + if (mqtt_topic.length() > 0 && String(cfg.MQTTTopic) != mqtt_topic) { + mqtt_topic.toCharArray(cfg.MQTTTopic, sizeof(cfg.MQTTTopic)); + force_restart = true; + } + if (mqtt_device_name.length() > 0 && String(cfg.MQTTDeviceName) != mqtt_device_name) { + mqtt_device_name.toCharArray(cfg.MQTTDeviceName, sizeof(cfg.MQTTDeviceName)); + force_restart = true; + } +#endif + if (force_restart) { + saveConfig(true); + handleReboot(); + } else { + webServer.send(200, "text/html", "<html><head><meta http-equiv=\"refresh\" content=\"0; url=/settings.htm\"/></head><body></body>"); + } + }); + webServer.on("/fieldValue", HTTP_GET, []() { String name = webServer.arg("name"); String value = getFieldValue(name, fields, fieldCount); @@ -1123,7 +1277,8 @@ void broadcastInt(String name, uint8_t value) String json = "{\"name\":\"" + name + "\",\"value\":" + String(value) + "}"; // webSocketsServer.broadcastTXT(json); #ifdef ENABLE_MQTT_SUPPORT - sendStatus(); + if (cfg.MQTTEnabled == 1) + sendStatus(); #endif } @@ -1132,7 +1287,8 @@ void broadcastString(String name, String value) String json = "{\"name\":\"" + name + "\",\"value\":\"" + String(value) + "\"}"; // webSocketsServer.broadcastTXT(json); #ifdef ENABLE_MQTT_SUPPORT - sendStatus(); + if (cfg.MQTTEnabled == 1) + sendStatus(); #endif } @@ -1152,46 +1308,23 @@ void loop() { MDNS.update(); #endif // ENABLE_MULTICAST_DNS #ifdef ENABLE_MQTT_SUPPORT - mqttClient.loop(); -#endif - - // handleIrInput(); + static bool mqttConnected = false; - static bool hasConnected = false; - EVERY_N_SECONDS(1) { - if (WiFi.status() != WL_CONNECTED) { - // Serial.printf("Connecting to %s\n", ssid); - hasConnected = false; - } - else if (!hasConnected) { - hasConnected = true; - Serial.print("Connected! Open http://"); - Serial.print(WiFi.localIP()); - Serial.println(" in your browser"); -#ifdef ENABLE_MULTICAST_DNS - if (!MDNS.begin(HOSTNAME)) { - Serial.println("\nError setting up MDNS responder! \n"); - } - else { - Serial.println("\nmDNS responder started \n"); - MDNS.addService("http", "tcp", 80); - } -#endif - } - } + if (cfg.MQTTEnabled == 1) + mqttClient.loop(); + else + mqttConnected = false; -#ifdef ENABLE_MQTT_SUPPORT - static bool mqttConnected = false; EVERY_N_SECONDS(10) { - if (!mqttClient.connected()) { - mqttClient.setServer(mqttServer, mqttPort); + if (!mqttClient.connected() && cfg.MQTTEnabled != 0) { + mqttClient.setServer(cfg.MQTTHost, cfg.MQTTPort); mqttClient.setCallback(mqttCallback); mqttConnected = false; } - if (!mqttConnected) { + if (!mqttConnected && cfg.MQTTEnabled != 0) { mqttConnected = true; Serial.println("Connecting to MQTT..."); - if (mqttClient.connect(HOSTNAME, mqttUser, mqttPassword)) { + if (mqttClient.connect(cfg.hostname, cfg.MQTTUser, cfg.MQTTPass)) { mqttClient.setKeepAlive(10); Serial.println("connected \n"); @@ -1199,12 +1332,12 @@ void loop() { mqttClient.subscribe(MQTT_TOPIC MQTT_TOPIC_SET); DynamicJsonDocument JSONencoder(2048); - JSONencoder["~"] = MQTT_TOPIC, - JSONencoder["name"] = MQTT_DEVICE_NAME, + JSONencoder["~"] = cfg.MQTTTopic, + JSONencoder["name"] = cfg.MQTTDeviceName, JSONencoder["dev"]["ids"] = MQTT_UNIQUE_IDENTIFIER, JSONencoder["dev"]["mf"] = "Surrbradl08", JSONencoder["dev"]["mdl"] = "0.4", - JSONencoder["dev"]["name"] = MQTT_DEVICE_NAME, + JSONencoder["dev"]["name"] = cfg.MQTTDeviceName, JSONencoder["stat_t"] = "~", JSONencoder["cmd_t"] = "~" MQTT_TOPIC_SET, JSONencoder["brightness"] = true, @@ -1283,21 +1416,42 @@ void loop() { // insert a delay to keep the framerate modest //FastLED.delay(1000 / FRAMES_PER_SECOND); delay(1000 / FRAMES_PER_SECOND); + + // save config changes only every 10 seconds + EVERY_N_SECONDS(10) { + saveConfig(save_config); + } } -void loadSettings() +void saveConfig(bool save) { + // Save configuration from RAM into EEPROM + if (save == true) { + EEPROM.begin(4095); + EEPROM.put(0, cfg ); + delay(200); + EEPROM.commit(); + EEPROM.end(); + } +} + +void loadConfig() { - brightness = EEPROM.read(0); + // Loads configuration from EEPROM into RAM + EEPROM.begin(4095); + EEPROM.get(0, cfg ); + EEPROM.end(); + + brightness = cfg.brightness; - currentPatternIndex = EEPROM.read(1); + currentPatternIndex = cfg.currentPatternIndex; if (currentPatternIndex < 0) currentPatternIndex = 0; else if (currentPatternIndex >= patternCount) currentPatternIndex = patternCount - 1; - byte r = EEPROM.read(2); - byte g = EEPROM.read(3); - byte b = EEPROM.read(4); + byte r = cfg.red; + byte g = cfg.green; + byte b = cfg.blue; if (r == 0 && g == 0 && b == 0) { @@ -1307,25 +1461,63 @@ void loadSettings() solidColor = CRGB(r, g, b); } - power = EEPROM.read(5); + power = cfg.power; - autoplay = EEPROM.read(6); - autoplayDuration = EEPROM.read(7); + autoplay = cfg.autoplay; + autoplayDuration = cfg.autoplayDuration; - currentPaletteIndex = EEPROM.read(8); + currentPaletteIndex = cfg.currentPaletteIndex; if (currentPaletteIndex < 0) currentPaletteIndex = 0; else if (currentPaletteIndex >= paletteCount) currentPaletteIndex = paletteCount - 1; - speed = EEPROM.read(9); + + speed = cfg.speed; + + if (!isValidHostname(cfg.hostname, sizeof(cfg.hostname))) { + strncpy(cfg.hostname, DEFAULT_HOSTNAME, sizeof(cfg.hostname)); + save_config = true; + } + + // fall back to default settings if hostname is invalid + if (!isValidHostname(cfg.MQTTHost, sizeof(cfg.MQTTHost))) { + cfg.MQTTEnabled = MQTT_ENABLED; + strncpy(cfg.MQTTHost, MQTT_HOSTNAME, sizeof(cfg.MQTTHost)); + cfg.MQTTPort = uint16_t(MQTT_PORT); + strncpy(cfg.MQTTUser, MQTT_USER, sizeof(cfg.MQTTUser)); + strncpy(cfg.MQTTPass, MQTT_PASS, sizeof(cfg.MQTTPass)); + strncpy(cfg.MQTTTopic, MQTT_TOPIC, sizeof(cfg.MQTTTopic)); + strncpy(cfg.MQTTDeviceName, MQTT_DEVICE_NAME, sizeof(cfg.MQTTDeviceName)); + save_config = true; + } +} + +bool isValidHostname(char *hostname_to_check, long size) +{ + for (int i = 0; i < size; i++) { + if (hostname_to_check[i] == '-' || hostname_to_check[i] == '.') + continue; + else if (hostname_to_check[i] >= '0' && hostname_to_check[i] <= '9') + continue; + else if (hostname_to_check[i] >= 'A' && hostname_to_check[i] <= 'Z') + continue; + else if (hostname_to_check[i] >= 'a' && hostname_to_check[i] <= 'z') + continue; + else if (hostname_to_check[i] == 0 && i>0) + break; + + return false; + } + + return true; } void setPower(uint8_t value) { power = value == 0 ? 0 : 1; - EEPROM.write(5, power); - EEPROM.commit(); + cfg.power = power; + save_config = true; broadcastInt("power", power); } @@ -1334,8 +1526,8 @@ void setAutoplay(uint8_t value) { autoplay = value == 0 ? 0 : 1; - EEPROM.write(6, autoplay); - EEPROM.commit(); + cfg.autoplay = autoplay; + save_config = true; broadcastInt("autoplay", autoplay); } @@ -1344,8 +1536,8 @@ void setAutoplayDuration(uint8_t value) { autoplayDuration = value; - EEPROM.write(7, autoplayDuration); - EEPROM.commit(); + cfg.autoplayDuration = autoplayDuration; + save_config = true; autoPlayTimeout = millis() + (autoplayDuration * 1000); @@ -1387,8 +1579,8 @@ void adjustPattern(bool up) currentPatternIndex = 0; if (autoplay == 0) { - EEPROM.write(1, currentPatternIndex); - EEPROM.commit(); + cfg.currentPatternIndex = currentPatternIndex; + save_config = true; } #ifdef AUTOPLAY_IGNORE_UDP_PATTERNS @@ -1409,10 +1601,9 @@ void setPattern(uint8_t value) currentPatternIndex = value; - if (autoplay != 1) { - EEPROM.write(1, currentPatternIndex); - EEPROM.commit(); - } + if (autoplay != 1) + cfg.currentPatternIndex = currentPatternIndex; + save_config = true; broadcastInt("pattern", currentPatternIndex); } @@ -1435,8 +1626,8 @@ void setPalette(uint8_t value) currentPaletteIndex = value; - EEPROM.write(8, currentPaletteIndex); - EEPROM.commit(); + cfg.currentPaletteIndex = currentPaletteIndex; + save_config = true; broadcastInt("palette", currentPaletteIndex); } @@ -1458,14 +1649,16 @@ void adjustBrightness(bool up) else if (!up && brightnessIndex > 0) brightnessIndex--; - brightness = brightnessMap[brightnessIndex]; + setBrightness(brightnessMap[brightnessIndex]); +/* brightness = brightnessMap[brightnessIndex]; FastLED.setBrightness(brightness); - EEPROM.write(0, brightness); + EEPROM.write(SETTING_BRIGTHNESS, brightness); EEPROM.commit(); broadcastInt("brightness", brightness); +*/ } void setBrightness(uint8_t value) @@ -1478,8 +1671,8 @@ void setBrightness(uint8_t value) FastLED.setBrightness(brightness); - EEPROM.write(0, brightness); - EEPROM.commit(); + cfg.brightness = brightness; + save_config = true; broadcastInt("brightness", brightness); } @@ -1492,12 +1685,27 @@ void setSpeed(uint8_t value) speed = value; - FastLED.setBrightness(brightness); + cfg.speed = speed; + save_config = true; - EEPROM.write(9, speed); - EEPROM.commit(); + broadcastInt("speed", speed); +} - broadcastInt("speed", brightness); +void setHostname(String new_hostname) +{ + int j = 0; + for (int i = 0; i < new_hostname.length() && i < sizeof(cfg.hostname); i++) { + if (new_hostname.charAt(i) == '-' or \ + (new_hostname.charAt(i) >= '0' && new_hostname.charAt(i) <= '9') or \ + (new_hostname.charAt(i) >= 'A' && new_hostname.charAt(i) <= 'Z') or \ + (new_hostname.charAt(i) >= 'a' && new_hostname.charAt(i) <= 'z')) { + + cfg.hostname[j] = new_hostname.charAt(i); + j++; + } + } + cfg.hostname[j] = '\0'; + save_config = true; } void strandTest() @@ -4372,16 +4580,16 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) { const char* ckey = o.key().c_str(); JsonVariant cv = o.value(); if (strcmp(ckey, "r") == 0) { - cr = cv.as<int>(); + cr = cv.as<uint8_t>(); } if (strcmp(ckey, "g") == 0) { - cg = cv.as<int>(); + cg = cv.as<uint8_t>(); } if (strcmp(ckey, "b") == 0) { - cb = cv.as<int>(); + cb = cv.as<uint8_t>(); } } - setSolidColor(cr, cg, cb); + setSolidColor(cr, cg, cb, false); } } mqttProcessing = false;