Version 1.0
Initial version.
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | .pio | ||||||
|  | .vscode | ||||||
|  | .DS_Store | ||||||
							
								
								
									
										29
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,2 +1,29 @@ | |||||||
| # ESP-NOW-Light-Led-Strip | # Light/led strip controller for ESP8266 | ||||||
|  |  | ||||||
|  | ESP-NOW based light/led strip controller for ESP8266. Alternate firmware for Tuya/SmartLife WiFi light/led strip controllers. | ||||||
|  |  | ||||||
|  | ## Features | ||||||
|  |  | ||||||
|  | 1. After turn on (or after rebooting) creates an access point named "ESP-NOW Light XXXXXXXXXXXX" with password "12345678" (IP 192.168.4.1). Access point will be shown during 5 minutes. The rest of the time access point is a hidden. | ||||||
|  | 2. Periodically transmission of system information (every 60 seconds), availability status (every 10 seconds) and state status (every 300 seconds) to the gateway. | ||||||
|  | 3. Saves the last state when the power is turned off. Goes to the last state when the power is turned on. | ||||||
|  | 4. Automatically adds light/led strip configuration to Home Assistan via MQTT discovery as a light. | ||||||
|  | 5. Possibility firmware update over OTA (if is allows the size of the flash memory). | ||||||
|  | 6. Web interface for settings. | ||||||
|  |    | ||||||
|  | ## Notes | ||||||
|  |  | ||||||
|  | 1. ESP-NOW mesh network based on the library [ZHNetwork](https://github.com/aZholtikov/ZHNetwork). | ||||||
|  | 2. Regardless of the status of connection to gateway the device perform ESP-NOW node function. | ||||||
|  | 3. For show the access point for setting or firmware update, send the command "update" to the device's root topic (example - "homeassistant/espnow_light/E8DB849CA148"). Access point will be shown during 5 minutes. Similarly, for restart send the command "restart". | ||||||
|  |  | ||||||
|  | ## Tested on | ||||||
|  |  | ||||||
|  | Coming soon. | ||||||
|  |  | ||||||
|  | ## Attention | ||||||
|  |  | ||||||
|  | 1. A gateway is required. For details see [ESP-NOW Gateway](https://github.com/aZholtikov/ESP-NOW-Gateway). | ||||||
|  | 2. ESP-NOW network name must be set same of all another ESP-NOW devices in network. | ||||||
|  | 3. Upload the "data" folder (with web interface) into the filesystem before flashing. | ||||||
|  | 4. For using this firmware on Tuya/SmartLife WiFi light/led strip controllers, the WiFi module must be replaced with an ESP8266 compatible module (if necessary). | ||||||
|   | |||||||
							
								
								
									
										83
									
								
								data/function.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										83
									
								
								data/function.js
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | var xmlHttp = createXmlHttpObject(); | ||||||
|  | function createXmlHttpObject() { | ||||||
|  |     if (window.XMLHttpRequest) { | ||||||
|  |         xmlHttp = new XMLHttpRequest(); | ||||||
|  |     } else { | ||||||
|  |         xmlHttp = new ActiveXObject('Microsoft.XMLHTTP'); | ||||||
|  |     } | ||||||
|  |     return xmlHttp; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function load() { | ||||||
|  |     if (xmlHttp.readyState == 0 || xmlHttp.readyState == 4) { | ||||||
|  |         xmlHttp.open('PUT', '/config.json', true); | ||||||
|  |         xmlHttp.send(null); | ||||||
|  |         xmlHttp.onload = function () { | ||||||
|  |             jsonResponse = JSON.parse(xmlHttp.responseText); | ||||||
|  |             loadBlock(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function loadBlock() { | ||||||
|  |     newData = JSON.parse(xmlHttp.responseText); | ||||||
|  |     data = document.getElementsByTagName('body')[0].innerHTML; | ||||||
|  |     var newString; | ||||||
|  |     for (var key in newData) { | ||||||
|  |         newString = data.replace(new RegExp('{{' + key + '}}', 'g'), newData[key]); | ||||||
|  |         data = newString; | ||||||
|  |     } | ||||||
|  |     document.getElementsByTagName('body')[0].innerHTML = newString; | ||||||
|  |     setFirmvareValue('version', 'firmware'); | ||||||
|  |     setGpioValue('ledTypeSelect', 'ledType'); | ||||||
|  |     setGpioValue('coldWhitePinSelect', 'coldWhitePin'); | ||||||
|  |     setGpioValue('warmWhitePinSelect', 'warmWhitePin'); | ||||||
|  |     setGpioValue('redPinSelect', 'redPin'); | ||||||
|  |     setGpioValue('greenPinSelect', 'greenPin'); | ||||||
|  |     setGpioValue('bluePinSelect', 'bluePin'); | ||||||
|  |     handleServerResponse(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getValue(id) { | ||||||
|  |     var value = document.getElementById(id).value; | ||||||
|  |     return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getSelectValue(id) { | ||||||
|  |     var select = document.getElementById(id); | ||||||
|  |     var value = select.value; | ||||||
|  |     return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function sendRequest(submit, server) { | ||||||
|  |     request = new XMLHttpRequest(); | ||||||
|  |     request.open("GET", server, true); | ||||||
|  |     request.send(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function saveSetting(submit) { | ||||||
|  |     server = "/setting?deviceName=" + getValue('deviceName') | ||||||
|  |         + "&espnowNetName=" + getValue('espnowNetName') | ||||||
|  |         + "&ledType=" + getSelectValue('ledTypeSelect') | ||||||
|  |         + "&coldWhitePin=" + getSelectValue('coldWhitePinSelect') | ||||||
|  |         + "&warmWhitePin=" + getSelectValue('warmWhitePinSelect') | ||||||
|  |         + "&redPin=" + getSelectValue('redPinSelect') | ||||||
|  |         + "&greenPin=" + getSelectValue('greenPinSelect') | ||||||
|  |         + "&bluePin=" + getSelectValue('bluePinSelect'); | ||||||
|  |     sendRequest(submit, server); | ||||||
|  |     alert("Please restart device for changes apply."); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function restart(submit) { | ||||||
|  |     server = "/restart"; | ||||||
|  |     sendRequest(submit, server); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function setFirmvareValue(id, value) { | ||||||
|  |     document.getElementById(id).innerHTML = document.getElementById(value).value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function setGpioValue(id, value) { | ||||||
|  |     var select = document.getElementById(id); | ||||||
|  |     select.value = document.getElementById(value).value; | ||||||
|  | } | ||||||
							
								
								
									
										172
									
								
								data/index.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								data/index.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | |||||||
|  | <html> | ||||||
|  |  | ||||||
|  | <head> | ||||||
|  |     <meta http-equiv="Content-type" content="text/html; charset=utf-8"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=0.9"> | ||||||
|  |     <link rel="stylesheet" href="style.css"> | ||||||
|  |     <script type="text/javascript" src="function.js"></script> | ||||||
|  |     <title>ESP-NOW Led/Light Strip</title> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body onload="load();"> | ||||||
|  |     <form class="box"> | ||||||
|  |         <h1>ESP-NOW Led/Light Strip </h1> | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <p class="text">Firmware:</p> | ||||||
|  |             <p class="text" id="version"></p> | ||||||
|  |             <input id="firmware" value="{{firmware}}" hidden /> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <p class="text">Device name:</p> | ||||||
|  |             <input id="deviceName" value="{{deviceName}}" placeholder="Name" autocomplete="off" label | ||||||
|  |                 title="ESP-NOW device name (up to 150 characters)" /> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <p class="text">ESP-NOW network name:</p> | ||||||
|  |             <input id="espnowNetName" value="{{espnowNetName}}" placeholder="Name" autocomplete="off" label | ||||||
|  |                 title="ESP-NOW network name (1 to 20 characters)" /> | ||||||
|  |         </div> | ||||||
|  |          | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <p class="text-select">Device type:</p> | ||||||
|  |             <input id="ledType" value="{{ledType}}" hidden /> | ||||||
|  |             <p><select id="ledTypeSelect"> | ||||||
|  |                     <option value="0">NONE</option> | ||||||
|  |                     <option value="1">W</option> | ||||||
|  |                     <option value="2">WW</option> | ||||||
|  |                     <option value="3">RGB</option> | ||||||
|  |                     <option value="4">RGBW</option> | ||||||
|  |                     <option value="5">RGBWW</option> | ||||||
|  |                 </select></p> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <p class="text-select">Cold white GPIO:</p> | ||||||
|  |             <input id="coldWhitePin" value="{{coldWhitePin}}" hidden /> | ||||||
|  |             <p><select id="coldWhitePinSelect"> | ||||||
|  |                     <option value="0">NONE</option> | ||||||
|  |                     <option value="1">GPIO01</option> | ||||||
|  |                     <option value="2">GPIO02</option> | ||||||
|  |                     <option value="3">GPIO03</option> | ||||||
|  |                     <option value="4">GPIO04</option> | ||||||
|  |                     <option value="5">GPIO05</option> | ||||||
|  |                     <option value="6">GPIO06</option> | ||||||
|  |                     <option value="7">GPIO07</option> | ||||||
|  |                     <option value="8">GPIO08</option> | ||||||
|  |                     <option value="9">GPIO09</option> | ||||||
|  |                     <option value="10">GPIO10</option> | ||||||
|  |                     <option value="11">GPIO11</option> | ||||||
|  |                     <option value="12">GPIO12</option> | ||||||
|  |                     <option value="13">GPIO13</option> | ||||||
|  |                     <option value="14">GPIO14</option> | ||||||
|  |                     <option value="15">GPIO15</option> | ||||||
|  |                     <option value="16">GPIO16</option> | ||||||
|  |                 </select></p> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <p class="text-select">Warm white GPIO:</p> | ||||||
|  |             <input id="warmWhitePin" value="{{warmWhitePin}}" hidden /> | ||||||
|  |             <p><select id="warmWhitePinSelect"> | ||||||
|  |                     <option value="0">NONE</option> | ||||||
|  |                     <option value="1">GPIO01</option> | ||||||
|  |                     <option value="2">GPIO02</option> | ||||||
|  |                     <option value="3">GPIO03</option> | ||||||
|  |                     <option value="4">GPIO04</option> | ||||||
|  |                     <option value="5">GPIO05</option> | ||||||
|  |                     <option value="6">GPIO06</option> | ||||||
|  |                     <option value="7">GPIO07</option> | ||||||
|  |                     <option value="8">GPIO08</option> | ||||||
|  |                     <option value="9">GPIO09</option> | ||||||
|  |                     <option value="10">GPIO10</option> | ||||||
|  |                     <option value="11">GPIO11</option> | ||||||
|  |                     <option value="12">GPIO12</option> | ||||||
|  |                     <option value="13">GPIO13</option> | ||||||
|  |                     <option value="14">GPIO14</option> | ||||||
|  |                     <option value="15">GPIO15</option> | ||||||
|  |                     <option value="16">GPIO16</option> | ||||||
|  |                 </select></p> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <p class="text-select">Red GPIO:</p> | ||||||
|  |             <input id="redPin" value="{{redPin}}" hidden /> | ||||||
|  |             <p><select id="redPinSelect"> | ||||||
|  |                     <option value="0">NONE</option> | ||||||
|  |                     <option value="1">GPIO01</option> | ||||||
|  |                     <option value="2">GPIO02</option> | ||||||
|  |                     <option value="3">GPIO03</option> | ||||||
|  |                     <option value="4">GPIO04</option> | ||||||
|  |                     <option value="5">GPIO05</option> | ||||||
|  |                     <option value="6">GPIO06</option> | ||||||
|  |                     <option value="7">GPIO07</option> | ||||||
|  |                     <option value="8">GPIO08</option> | ||||||
|  |                     <option value="9">GPIO09</option> | ||||||
|  |                     <option value="10">GPIO10</option> | ||||||
|  |                     <option value="11">GPIO11</option> | ||||||
|  |                     <option value="12">GPIO12</option> | ||||||
|  |                     <option value="13">GPIO13</option> | ||||||
|  |                     <option value="14">GPIO14</option> | ||||||
|  |                     <option value="15">GPIO15</option> | ||||||
|  |                     <option value="16">GPIO16</option> | ||||||
|  |                 </select></p> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <p class="text-select">Green GPIO:</p> | ||||||
|  |             <input id="greenPin" value="{{greenPin}}" hidden /> | ||||||
|  |             <p><select id="greenPinSelect"> | ||||||
|  |                     <option value="0">NONE</option> | ||||||
|  |                     <option value="1">GPIO01</option> | ||||||
|  |                     <option value="2">GPIO02</option> | ||||||
|  |                     <option value="3">GPIO03</option> | ||||||
|  |                     <option value="4">GPIO04</option> | ||||||
|  |                     <option value="5">GPIO05</option> | ||||||
|  |                     <option value="6">GPIO06</option> | ||||||
|  |                     <option value="7">GPIO07</option> | ||||||
|  |                     <option value="8">GPIO08</option> | ||||||
|  |                     <option value="9">GPIO09</option> | ||||||
|  |                     <option value="10">GPIO10</option> | ||||||
|  |                     <option value="11">GPIO11</option> | ||||||
|  |                     <option value="12">GPIO12</option> | ||||||
|  |                     <option value="13">GPIO13</option> | ||||||
|  |                     <option value="14">GPIO14</option> | ||||||
|  |                     <option value="15">GPIO15</option> | ||||||
|  |                     <option value="16">GPIO16</option> | ||||||
|  |                 </select></p> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <p class="text-select">Blue GPIO:</p> | ||||||
|  |             <input id="bluePin" value="{{bluePin}}" hidden /> | ||||||
|  |             <p><select id="bluePinSelect"> | ||||||
|  |                     <option value="0">NONE</option> | ||||||
|  |                     <option value="1">GPIO01</option> | ||||||
|  |                     <option value="2">GPIO02</option> | ||||||
|  |                     <option value="3">GPIO03</option> | ||||||
|  |                     <option value="4">GPIO04</option> | ||||||
|  |                     <option value="5">GPIO05</option> | ||||||
|  |                     <option value="6">GPIO06</option> | ||||||
|  |                     <option value="7">GPIO07</option> | ||||||
|  |                     <option value="8">GPIO08</option> | ||||||
|  |                     <option value="9">GPIO09</option> | ||||||
|  |                     <option value="10">GPIO10</option> | ||||||
|  |                     <option value="11">GPIO11</option> | ||||||
|  |                     <option value="12">GPIO12</option> | ||||||
|  |                     <option value="13">GPIO13</option> | ||||||
|  |                     <option value="14">GPIO14</option> | ||||||
|  |                     <option value="15">GPIO15</option> | ||||||
|  |                     <option value="16">GPIO16</option> | ||||||
|  |                 </select></p> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <div class="wrapper"> | ||||||
|  |             <input class="btn" type="submit" value="Save" onclick="saveSetting(this);"> | ||||||
|  |             <input class="btn" type="submit" value="Restart" onclick="restart(this);"> | ||||||
|  |         </div> | ||||||
|  |     </form> | ||||||
|  | </body> | ||||||
|  |  | ||||||
|  | </html> | ||||||
							
								
								
									
										94
									
								
								data/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								data/style.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | |||||||
|  | body { | ||||||
|  |     font-family: "Gill Sans", sans-serif; | ||||||
|  |     background: rgb(255, 255, 255); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .box { | ||||||
|  |     width: 400px; | ||||||
|  |     padding: 20px 20px; | ||||||
|  |     margin: 20px auto; | ||||||
|  |     background: #e0f5fb; | ||||||
|  |     box-shadow: 4px 4px 30px rgba(0, 0, 0, 0.2); | ||||||
|  |     border-radius: 10px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | h1 { | ||||||
|  |     color: rgb(65, 125, 238); | ||||||
|  |     text-align: center; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .text { | ||||||
|  |     font-weight: 600; | ||||||
|  |     flex-shrink: 0; | ||||||
|  |     margin-right: 10px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .text-select { | ||||||
|  |     width: 35%; | ||||||
|  |     font-weight: 600; | ||||||
|  |     flex-shrink: 0; | ||||||
|  |     margin-right: 10px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .wrapper { | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: space-between; | ||||||
|  |     align-items: baseline; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | input { | ||||||
|  |     width: 48%; | ||||||
|  |     min-height: 30px; | ||||||
|  |     border-radius: 5px; | ||||||
|  |     border: none; | ||||||
|  |     margin-bottom: 10px; | ||||||
|  |     padding: 0 10px; | ||||||
|  |     color: rgb(0, 0, 0); | ||||||
|  |     background: #a3e0f1; | ||||||
|  |     transition: .5s; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | select { | ||||||
|  |     width: 110px; | ||||||
|  |     min-height: 30px; | ||||||
|  |     border-radius: 5px; | ||||||
|  |     border: none; | ||||||
|  |     margin-bottom: 10px; | ||||||
|  |     padding: 0 10px; | ||||||
|  |     color: rgb(0, 0, 0); | ||||||
|  |     background: #a3e0f1; | ||||||
|  |     transition: .5s; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | input:hover { | ||||||
|  |     background: white; | ||||||
|  |     cursor: pointer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | select:hover { | ||||||
|  |     background: white; | ||||||
|  |     cursor: pointer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .btn { | ||||||
|  |     width: 48%; | ||||||
|  |     background: rgb(65, 125, 238); | ||||||
|  |     color: white; | ||||||
|  |     transition: .5s; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .btn:hover { | ||||||
|  |     background: rgb(65, 125, 238); | ||||||
|  |     opacity: 0.5; | ||||||
|  |     transform: translatey(-3px); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #deviceName, | ||||||
|  | #espnowNetName { | ||||||
|  |     width: 100%; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .wrapper.wrapper--end { | ||||||
|  |     align-items: baseline; | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | [env:esp8266] | ||||||
|  | platform = espressif8266 | ||||||
|  | board = esp12e | ||||||
|  | framework = arduino | ||||||
|  | lib_deps =  | ||||||
|  | 	https://github.com/aZholtikov/ZHNetwork | ||||||
|  | 	https://github.com/aZholtikov/ZHConfig | ||||||
|  | 	bblanchon/ArduinoJson@^6.19.4 | ||||||
|  | 	me-no-dev/ESP Async WebServer@^1.2.3 | ||||||
|  |  | ||||||
|  | [env:esp8266-ota] | ||||||
|  | platform = espressif8266 | ||||||
|  | board = esp12e | ||||||
|  | framework = arduino | ||||||
|  | upload_port = 192.168.4.1 | ||||||
|  | upload_protocol = espota | ||||||
|  | lib_deps =  | ||||||
|  | 	https://github.com/aZholtikov/ZHNetwork | ||||||
|  | 	https://github.com/aZholtikov/ZHConfig | ||||||
|  | 	bblanchon/ArduinoJson@^6.19.4 | ||||||
|  | 	me-no-dev/ESP Async WebServer@^1.2.3 | ||||||
|  |  | ||||||
|  | [env:esp8285] | ||||||
|  | platform = espressif8266 | ||||||
|  | board = esp8285 | ||||||
|  | framework = arduino | ||||||
|  | lib_deps =  | ||||||
|  | 	https://github.com/aZholtikov/ZHNetwork | ||||||
|  | 	https://github.com/aZholtikov/ZHConfig | ||||||
|  | 	bblanchon/ArduinoJson@^6.19.4 | ||||||
|  | 	me-no-dev/ESP Async WebServer@^1.2.3 | ||||||
|  |  | ||||||
|  | [env:esp8285-ota] | ||||||
|  | platform = espressif8266 | ||||||
|  | board = esp8285 | ||||||
|  | framework = arduino | ||||||
|  | upload_port = 192.168.4.1 | ||||||
|  | upload_protocol = espota | ||||||
|  | lib_deps =  | ||||||
|  | 	https://github.com/aZholtikov/ZHNetwork | ||||||
|  | 	https://github.com/aZholtikov/ZHConfig | ||||||
|  | 	bblanchon/ArduinoJson@^6.19.4 | ||||||
|  | 	me-no-dev/ESP Async WebServer@^1.2.3 | ||||||
							
								
								
									
										489
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										489
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,489 @@ | |||||||
|  | #include "ArduinoJson.h" | ||||||
|  | #include "ArduinoOTA.h" | ||||||
|  | #include "ESPAsyncWebServer.h" | ||||||
|  | #include "Ticker.h" | ||||||
|  | #include "ZHNetwork.h" | ||||||
|  | #include "ZHConfig.h" | ||||||
|  |  | ||||||
|  | void onBroadcastReceiving(const char *data, const uint8_t *sender); | ||||||
|  | void onUnicastReceiving(const char *data, const uint8_t *sender); | ||||||
|  | void onConfirmReceiving(const uint8_t *target, const bool status); | ||||||
|  |  | ||||||
|  | void loadConfig(void); | ||||||
|  | void saveConfig(void); | ||||||
|  | void setupWebServer(void); | ||||||
|  |  | ||||||
|  | void sendAttributesMessage(void); | ||||||
|  | void sendKeepAliveMessage(void); | ||||||
|  | void sendConfigMessage(void); | ||||||
|  | void sendStatusMessage(void); | ||||||
|  |  | ||||||
|  | String getValue(String data, char separator, byte index); | ||||||
|  |  | ||||||
|  | void changeLedState(void); | ||||||
|  |  | ||||||
|  | const String firmware{"1.0"}; | ||||||
|  |  | ||||||
|  | String espnowNetName{"DEFAULT"}; | ||||||
|  |  | ||||||
|  | String deviceName{"ESP-NOW Light/Led Strip"}; | ||||||
|  |  | ||||||
|  | uint8_t ledType{ENLT_NONE}; | ||||||
|  | bool ledStatus{false}; | ||||||
|  | uint8_t coldWhitePin{0}; | ||||||
|  | uint8_t warmWhitePin{0}; | ||||||
|  | uint8_t redPin{0}; | ||||||
|  | uint8_t greenPin{0}; | ||||||
|  | uint8_t bluePin{0}; | ||||||
|  |  | ||||||
|  | uint8_t brightness{255}; | ||||||
|  | uint16_t temperature{255}; | ||||||
|  | uint8_t red{255}; | ||||||
|  | uint8_t green{255}; | ||||||
|  | uint8_t blue{255}; | ||||||
|  |  | ||||||
|  | bool wasMqttAvailable{false}; | ||||||
|  |  | ||||||
|  | uint8_t gatewayMAC[6]{0}; | ||||||
|  |  | ||||||
|  | ZHNetwork myNet; | ||||||
|  | AsyncWebServer webServer(80); | ||||||
|  |  | ||||||
|  | Ticker gatewayAvailabilityCheckTimer; | ||||||
|  | bool isGatewayAvailable{false}; | ||||||
|  | void gatewayAvailabilityCheckTimerCallback(void); | ||||||
|  |  | ||||||
|  | Ticker apModeHideTimer; | ||||||
|  | void apModeHideTimerCallback(void); | ||||||
|  |  | ||||||
|  | Ticker attributesMessageTimer; | ||||||
|  | bool attributesMessageTimerSemaphore{true}; | ||||||
|  | void attributesMessageTimerCallback(void); | ||||||
|  | Ticker attributesMessageResendTimer; | ||||||
|  | bool attributesMessageResendTimerSemaphore{false}; | ||||||
|  |  | ||||||
|  | Ticker keepAliveMessageTimer; | ||||||
|  | bool keepAliveMessageTimerSemaphore{true}; | ||||||
|  | void keepAliveMessageTimerCallback(void); | ||||||
|  | Ticker keepAliveMessageResendTimer; | ||||||
|  | bool keepAliveMessageResendTimerSemaphore{false}; | ||||||
|  |  | ||||||
|  | Ticker configMessageResendTimer; | ||||||
|  | bool configMessageResendTimerSemaphore{false}; | ||||||
|  |  | ||||||
|  | Ticker statusMessageTimer; | ||||||
|  | bool statusMessageTimerSemaphore{true}; | ||||||
|  | void statusMessageTimerCallback(void); | ||||||
|  | Ticker statusMessageResendTimer; | ||||||
|  | bool statusMessageResendTimerSemaphore{false}; | ||||||
|  |  | ||||||
|  | void setup() | ||||||
|  | { | ||||||
|  |   analogWriteRange(255); | ||||||
|  |  | ||||||
|  |   SPIFFS.begin(); | ||||||
|  |  | ||||||
|  |   loadConfig(); | ||||||
|  |  | ||||||
|  |   if (coldWhitePin) | ||||||
|  |     pinMode(coldWhitePin, OUTPUT); | ||||||
|  |   if (warmWhitePin) | ||||||
|  |     pinMode(warmWhitePin, OUTPUT); | ||||||
|  |   if (redPin) | ||||||
|  |     pinMode(redPin, OUTPUT); | ||||||
|  |   if (greenPin) | ||||||
|  |     pinMode(greenPin, OUTPUT); | ||||||
|  |   if (bluePin) | ||||||
|  |     pinMode(bluePin, OUTPUT); | ||||||
|  |  | ||||||
|  |   changeLedState(); | ||||||
|  |  | ||||||
|  |   WiFi.setSleepMode(WIFI_NONE_SLEEP); | ||||||
|  |   myNet.begin(espnowNetName.c_str()); | ||||||
|  |  | ||||||
|  |   myNet.setOnBroadcastReceivingCallback(onBroadcastReceiving); | ||||||
|  |   myNet.setOnUnicastReceivingCallback(onUnicastReceiving); | ||||||
|  |   myNet.setOnConfirmReceivingCallback(onConfirmReceiving); | ||||||
|  |  | ||||||
|  |   WiFi.mode(WIFI_AP_STA); | ||||||
|  |   WiFi.softAP(("ESP-NOW Light " + myNet.getNodeMac()).c_str(), "12345678", 1, 0); | ||||||
|  |   apModeHideTimer.once(300, apModeHideTimerCallback); | ||||||
|  |  | ||||||
|  |   setupWebServer(); | ||||||
|  |  | ||||||
|  |   ArduinoOTA.begin(); | ||||||
|  |  | ||||||
|  |   attributesMessageTimer.attach(60, attributesMessageTimerCallback); | ||||||
|  |   keepAliveMessageTimer.attach(10, keepAliveMessageTimerCallback); | ||||||
|  |   statusMessageTimer.attach(300, statusMessageTimerCallback); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void loop() | ||||||
|  | { | ||||||
|  |   if (attributesMessageTimerSemaphore) | ||||||
|  |     sendAttributesMessage(); | ||||||
|  |   if (keepAliveMessageTimerSemaphore) | ||||||
|  |     sendKeepAliveMessage(); | ||||||
|  |   if (statusMessageTimerSemaphore) | ||||||
|  |     sendStatusMessage(); | ||||||
|  |   myNet.maintenance(); | ||||||
|  |   ArduinoOTA.handle(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void onBroadcastReceiving(const char *data, const byte *sender) | ||||||
|  | { | ||||||
|  |   esp_now_payload_data_t incomingData; | ||||||
|  |   memcpy(&incomingData, data, sizeof(esp_now_payload_data_t)); | ||||||
|  |   if (incomingData.deviceType != ENDT_GATEWAY) | ||||||
|  |     return; | ||||||
|  |   if (myNet.macToString(gatewayMAC) != myNet.macToString(sender) && incomingData.payloadsType == ENPT_KEEP_ALIVE) | ||||||
|  |     memcpy(gatewayMAC, sender, 6); | ||||||
|  |   if (myNet.macToString(gatewayMAC) == myNet.macToString(sender) && incomingData.payloadsType == ENPT_KEEP_ALIVE) | ||||||
|  |   { | ||||||
|  |     isGatewayAvailable = true; | ||||||
|  |     StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; | ||||||
|  |     deserializeJson(json, incomingData.message); | ||||||
|  |     bool temp = json["MQTT"] == "online" ? true : false; | ||||||
|  |     if (wasMqttAvailable != temp) | ||||||
|  |     { | ||||||
|  |       wasMqttAvailable = temp; | ||||||
|  |       if (temp) | ||||||
|  |         sendConfigMessage(); | ||||||
|  |     } | ||||||
|  |     gatewayAvailabilityCheckTimer.once(15, gatewayAvailabilityCheckTimerCallback); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void onUnicastReceiving(const char *data, const byte *sender) | ||||||
|  | { | ||||||
|  |   esp_now_payload_data_t incomingData; | ||||||
|  |   memcpy(&incomingData, data, sizeof(esp_now_payload_data_t)); | ||||||
|  |   if (incomingData.deviceType != ENDT_GATEWAY || myNet.macToString(gatewayMAC) != myNet.macToString(sender)) | ||||||
|  |     return; | ||||||
|  |   StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; | ||||||
|  |   if (incomingData.payloadsType == ENPT_SET) | ||||||
|  |   { | ||||||
|  |     deserializeJson(json, incomingData.message); | ||||||
|  |     if (json["set"]) | ||||||
|  |       ledStatus = json["set"] == "ON" ? true : false; | ||||||
|  |     if (json["brightness"]) | ||||||
|  |       brightness = json["brightness"]; | ||||||
|  |     if (json["temperature"]) | ||||||
|  |       temperature = json["temperature"]; | ||||||
|  |     if (json["rgb"]) | ||||||
|  |     { | ||||||
|  |       red = getValue(String(json["rgb"].as<String>()).substring(0, sizeof(esp_now_payload_data_t::message)).c_str(), ',', 0).toInt(); | ||||||
|  |       green = getValue(String(json["rgb"].as<String>()).substring(0, sizeof(esp_now_payload_data_t::message)).c_str(), ',', 1).toInt(); | ||||||
|  |       blue = getValue(String(json["rgb"].as<String>()).substring(0, sizeof(esp_now_payload_data_t::message)).c_str(), ',', 2).toInt(); | ||||||
|  |     } | ||||||
|  |     changeLedState(); | ||||||
|  |     sendStatusMessage(); | ||||||
|  |   } | ||||||
|  |   if (incomingData.payloadsType == ENPT_UPDATE) | ||||||
|  |   { | ||||||
|  |     WiFi.softAP(("ESP-NOW Light " + myNet.getNodeMac()).c_str(), "12345678", 1, 0); | ||||||
|  |     apModeHideTimer.once(300, apModeHideTimerCallback); | ||||||
|  |   } | ||||||
|  |   if (incomingData.payloadsType == ENPT_RESTART) | ||||||
|  |     ESP.restart(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void onConfirmReceiving(const uint8_t *target, const bool status) | ||||||
|  | { | ||||||
|  |   if (status) | ||||||
|  |   { | ||||||
|  |     if (attributesMessageResendTimerSemaphore) | ||||||
|  |     { | ||||||
|  |       attributesMessageResendTimerSemaphore = false; | ||||||
|  |       attributesMessageResendTimer.detach(); | ||||||
|  |     } | ||||||
|  |     if (keepAliveMessageResendTimerSemaphore) | ||||||
|  |     { | ||||||
|  |       keepAliveMessageResendTimerSemaphore = false; | ||||||
|  |       keepAliveMessageResendTimer.detach(); | ||||||
|  |     } | ||||||
|  |     if (configMessageResendTimerSemaphore) | ||||||
|  |     { | ||||||
|  |       configMessageResendTimerSemaphore = false; | ||||||
|  |       configMessageResendTimer.detach(); | ||||||
|  |     } | ||||||
|  |     if (statusMessageResendTimerSemaphore) | ||||||
|  |     { | ||||||
|  |       statusMessageResendTimerSemaphore = false; | ||||||
|  |       statusMessageResendTimer.detach(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void loadConfig() | ||||||
|  | { | ||||||
|  |   if (!SPIFFS.exists("/config.json")) | ||||||
|  |     saveConfig(); | ||||||
|  |   File file = SPIFFS.open("/config.json", "r"); | ||||||
|  |   String jsonFile = file.readString(); | ||||||
|  |   StaticJsonDocument<512> json; | ||||||
|  |   deserializeJson(json, jsonFile); | ||||||
|  |   espnowNetName = json["espnowNetName"].as<String>(); | ||||||
|  |   deviceName = json["deviceName"].as<String>(); | ||||||
|  |   ledType = json["ledType"]; | ||||||
|  |   ledStatus = json["ledStatus"]; | ||||||
|  |   coldWhitePin = json["coldWhitePin"]; | ||||||
|  |   warmWhitePin = json["warmWhitePin"]; | ||||||
|  |   redPin = json["redPin"]; | ||||||
|  |   greenPin = json["greenPin"]; | ||||||
|  |   bluePin = json["bluePin"]; | ||||||
|  |   brightness = json["brightness"]; | ||||||
|  |   temperature = json["temperature"]; | ||||||
|  |   red = json["red"]; | ||||||
|  |   green = json["green"]; | ||||||
|  |   blue = json["blue"]; | ||||||
|  |   file.close(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void saveConfig() | ||||||
|  | { | ||||||
|  |   StaticJsonDocument<512> json; | ||||||
|  |   json["firmware"] = firmware; | ||||||
|  |   json["espnowNetName"] = espnowNetName; | ||||||
|  |   json["deviceName"] = deviceName; | ||||||
|  |   json["ledType"] = ledType; | ||||||
|  |   json["ledStatus"] = ledStatus; | ||||||
|  |   json["coldWhitePin"] = coldWhitePin; | ||||||
|  |   json["warmWhitePin"] = warmWhitePin; | ||||||
|  |   json["redPin"] = redPin; | ||||||
|  |   json["greenPin"] = greenPin; | ||||||
|  |   json["bluePin"] = bluePin; | ||||||
|  |   json["brightness"] = brightness; | ||||||
|  |   json["temperature"] = temperature; | ||||||
|  |   json["red"] = red; | ||||||
|  |   json["green"] = green; | ||||||
|  |   json["blue"] = blue; | ||||||
|  |   json["system"] = "empty"; | ||||||
|  |   File file = SPIFFS.open("/config.json", "w"); | ||||||
|  |   serializeJsonPretty(json, file); | ||||||
|  |   file.close(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void setupWebServer() | ||||||
|  | { | ||||||
|  |   webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request) | ||||||
|  |                { request->send(SPIFFS, "/index.htm"); }); | ||||||
|  |  | ||||||
|  |   webServer.on("/setting", HTTP_GET, [](AsyncWebServerRequest *request) | ||||||
|  |                { | ||||||
|  |         ledType = request->getParam("ledType")->value().toInt(); | ||||||
|  |         coldWhitePin = request->getParam("coldWhitePin")->value().toInt(); | ||||||
|  |         warmWhitePin = request->getParam("warmWhitePin")->value().toInt(); | ||||||
|  |         redPin = request->getParam("redPin")->value().toInt(); | ||||||
|  |         greenPin = request->getParam("greenPin")->value().toInt(); | ||||||
|  |         bluePin = request->getParam("bluePin")->value().toInt(); | ||||||
|  |         deviceName = request->getParam("deviceName")->value(); | ||||||
|  |         espnowNetName = request->getParam("espnowNetName")->value(); | ||||||
|  |         request->send(200); | ||||||
|  |         saveConfig(); }); | ||||||
|  |  | ||||||
|  |   webServer.on("/restart", HTTP_GET, [](AsyncWebServerRequest *request) | ||||||
|  |                { | ||||||
|  |         request->send(200); | ||||||
|  |         ESP.restart(); }); | ||||||
|  |  | ||||||
|  |   webServer.onNotFound([](AsyncWebServerRequest *request) | ||||||
|  |                        {  | ||||||
|  |         if (SPIFFS.exists(request->url())) | ||||||
|  |         request->send(SPIFFS, request->url()); | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |         request->send(404, "text/plain", "File Not Found"); | ||||||
|  |         } }); | ||||||
|  |  | ||||||
|  |   webServer.begin(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void sendAttributesMessage() | ||||||
|  | { | ||||||
|  |   if (!isGatewayAvailable) | ||||||
|  |     return; | ||||||
|  |   attributesMessageTimerSemaphore = false; | ||||||
|  |   uint32_t secs = millis() / 1000; | ||||||
|  |   uint32_t mins = secs / 60; | ||||||
|  |   uint32_t hours = mins / 60; | ||||||
|  |   uint32_t days = hours / 24; | ||||||
|  |   esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_ATTRIBUTES}; | ||||||
|  |   StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; | ||||||
|  |   json["Type"] = "ESP-NOW Led/Light Strip"; | ||||||
|  |   json["MCU"] = "ESP8266"; | ||||||
|  |   json["MAC"] = myNet.getNodeMac(); | ||||||
|  |   json["Firmware"] = firmware; | ||||||
|  |   json["Library"] = myNet.getFirmwareVersion(); | ||||||
|  |   json["Uptime"] = "Days:" + String(days) + " Hours:" + String(hours - (days * 24)) + " Mins:" + String(mins - (hours * 60)); | ||||||
|  |   char buffer[sizeof(esp_now_payload_data_t::message)]{0}; | ||||||
|  |   serializeJsonPretty(json, buffer); | ||||||
|  |   memcpy(outgoingData.message, buffer, sizeof(esp_now_payload_data_t::message)); | ||||||
|  |   char temp[sizeof(esp_now_payload_data_t)]{0}; | ||||||
|  |   memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t)); | ||||||
|  |   myNet.sendUnicastMessage(temp, gatewayMAC, true); | ||||||
|  |  | ||||||
|  |   attributesMessageResendTimerSemaphore = true; | ||||||
|  |   attributesMessageResendTimer.once(1, sendAttributesMessage); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void sendKeepAliveMessage() | ||||||
|  | { | ||||||
|  |   if (!isGatewayAvailable) | ||||||
|  |     return; | ||||||
|  |   keepAliveMessageTimerSemaphore = false; | ||||||
|  |   esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_KEEP_ALIVE}; | ||||||
|  |   char temp[sizeof(esp_now_payload_data_t)]{0}; | ||||||
|  |   memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t)); | ||||||
|  |   myNet.sendUnicastMessage(temp, gatewayMAC, true); | ||||||
|  |  | ||||||
|  |   keepAliveMessageResendTimerSemaphore = true; | ||||||
|  |   keepAliveMessageResendTimer.once(1, sendKeepAliveMessage); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void sendConfigMessage() | ||||||
|  | { | ||||||
|  |   if (!isGatewayAvailable) | ||||||
|  |     return; | ||||||
|  |   esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_CONFIG}; | ||||||
|  |   StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; | ||||||
|  |   json["name"] = deviceName; | ||||||
|  |   json["unit"] = 1; | ||||||
|  |   json["type"] = getValueName(HACT_LIGHT); | ||||||
|  |   json["class"] = ledType; | ||||||
|  |   char buffer[sizeof(esp_now_payload_data_t::message)]{0}; | ||||||
|  |   serializeJsonPretty(json, buffer); | ||||||
|  |   memcpy(outgoingData.message, buffer, sizeof(esp_now_payload_data_t::message)); | ||||||
|  |   char temp[sizeof(esp_now_payload_data_t)]{0}; | ||||||
|  |   memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t)); | ||||||
|  |   myNet.sendUnicastMessage(temp, gatewayMAC, true); | ||||||
|  |  | ||||||
|  |   configMessageResendTimerSemaphore = true; | ||||||
|  |   configMessageResendTimer.once(5, sendConfigMessage); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void sendStatusMessage() | ||||||
|  | { | ||||||
|  |   if (!isGatewayAvailable) | ||||||
|  |     return; | ||||||
|  |   statusMessageTimerSemaphore = false; | ||||||
|  |   esp_now_payload_data_t outgoingData{ENDT_LED, ENPT_STATE}; | ||||||
|  |   StaticJsonDocument<sizeof(esp_now_payload_data_t::message)> json; | ||||||
|  |   json["state"] = ledStatus ? "ON" : "OFF"; | ||||||
|  |   json["brightness"] = brightness; | ||||||
|  |   json["temperature"] = temperature; | ||||||
|  |   json["rgb"] = String(red) + "," + String(green) + "," + String(blue); | ||||||
|  |   char buffer[sizeof(esp_now_payload_data_t::message)]{0}; | ||||||
|  |   serializeJsonPretty(json, buffer); | ||||||
|  |   memcpy(&outgoingData.message, &buffer, sizeof(esp_now_payload_data_t::message)); | ||||||
|  |   char temp[sizeof(esp_now_payload_data_t)]{0}; | ||||||
|  |   memcpy(&temp, &outgoingData, sizeof(esp_now_payload_data_t)); | ||||||
|  |   myNet.sendUnicastMessage(temp, gatewayMAC, true); | ||||||
|  |  | ||||||
|  |   statusMessageResendTimerSemaphore = true; | ||||||
|  |   statusMessageResendTimer.once(1, sendStatusMessage); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | String getValue(String data, char separator, byte index) | ||||||
|  | { | ||||||
|  |   byte found{0}; | ||||||
|  |   int strIndex[]{0, -1}; | ||||||
|  |   int maxIndex = data.length() - 1; | ||||||
|  |   for (byte i{0}; i <= maxIndex && found <= index; i++) | ||||||
|  |     if (data.charAt(i) == separator || i == maxIndex) | ||||||
|  |     { | ||||||
|  |       found++; | ||||||
|  |       strIndex[0] = strIndex[1] + 1; | ||||||
|  |       strIndex[1] = (i == maxIndex) ? i + 1 : i; | ||||||
|  |     } | ||||||
|  |   return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void changeLedState(void) | ||||||
|  | { | ||||||
|  |   if (ledStatus) | ||||||
|  |   { | ||||||
|  |     if (red == 255 && green == 255 && blue == 255) | ||||||
|  |     { | ||||||
|  |       if (ledType == ENLT_W || ledType == ENLT_RGBW) | ||||||
|  |         analogWrite(coldWhitePin, brightness); | ||||||
|  |       if (ledType == ENLT_WW || ledType == ENLT_RGBWW) | ||||||
|  |       { | ||||||
|  |         analogWrite(coldWhitePin, map(brightness, 0, 255, 0, map(temperature, 500, 153, 0, 255))); | ||||||
|  |         analogWrite(warmWhitePin, map(brightness, 0, 255, 0, map(temperature, 153, 500, 0, 255))); | ||||||
|  |       } | ||||||
|  |       if (ledType == ENLT_RGB) | ||||||
|  |       { | ||||||
|  |         analogWrite(redPin, map(red, 0, 255, 0, brightness)); | ||||||
|  |         analogWrite(greenPin, map(green, 0, 255, 0, brightness)); | ||||||
|  |         analogWrite(bluePin, map(blue, 0, 255, 0, brightness)); | ||||||
|  |       } | ||||||
|  |       if (ledType == ENLT_RGBW || ledType == ENLT_RGBWW) | ||||||
|  |       { | ||||||
|  |         digitalWrite(redPin, LOW); | ||||||
|  |         digitalWrite(greenPin, LOW); | ||||||
|  |         digitalWrite(bluePin, LOW); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       if (ledType == ENLT_W) | ||||||
|  |         analogWrite(coldWhitePin, brightness); | ||||||
|  |       if (ledType == ENLT_WW) | ||||||
|  |       { | ||||||
|  |         analogWrite(coldWhitePin, map(brightness, 0, 255, 0, map(temperature, 500, 153, 0, 255))); | ||||||
|  |         analogWrite(warmWhitePin, map(brightness, 0, 255, 0, map(temperature, 153, 500, 0, 255))); | ||||||
|  |       } | ||||||
|  |       if (ledType == ENLT_RGBW || ledType == ENLT_RGBWW) | ||||||
|  |         digitalWrite(coldWhitePin, LOW); | ||||||
|  |       if (ledType == ENLT_RGBWW) | ||||||
|  |         digitalWrite(warmWhitePin, LOW); | ||||||
|  |       if (ledType == ENLT_RGB || ledType == ENLT_RGBW || ledType == ENLT_RGBWW) | ||||||
|  |       { | ||||||
|  |         analogWrite(redPin, map(red, 0, 255, 0, brightness)); | ||||||
|  |         analogWrite(greenPin, map(green, 0, 255, 0, brightness)); | ||||||
|  |         analogWrite(bluePin, map(blue, 0, 255, 0, brightness)); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   else | ||||||
|  |   { | ||||||
|  |     if (ledType == ENLT_W || ledType == ENLT_WW || ledType == ENLT_RGBW || ledType == ENLT_RGBWW) | ||||||
|  |       digitalWrite(coldWhitePin, LOW); | ||||||
|  |     if (ledType == ENLT_WW || ledType == ENLT_RGBWW) | ||||||
|  |       digitalWrite(warmWhitePin, LOW); | ||||||
|  |     if (ledType == ENLT_RGB || ledType == ENLT_RGBW || ledType == ENLT_RGBWW) | ||||||
|  |     { | ||||||
|  |       digitalWrite(redPin, LOW); | ||||||
|  |       digitalWrite(greenPin, LOW); | ||||||
|  |       digitalWrite(bluePin, LOW); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   saveConfig(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void gatewayAvailabilityCheckTimerCallback() | ||||||
|  | { | ||||||
|  |   isGatewayAvailable = false; | ||||||
|  |   memset(gatewayMAC, 0, 6); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void apModeHideTimerCallback() | ||||||
|  | { | ||||||
|  |   WiFi.softAP(("ESP-NOW Light " + myNet.getNodeMac()).c_str(), "12345678", 1, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void attributesMessageTimerCallback() | ||||||
|  | { | ||||||
|  |   attributesMessageTimerSemaphore = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void keepAliveMessageTimerCallback() | ||||||
|  | { | ||||||
|  |   keepAliveMessageTimerSemaphore = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void statusMessageTimerCallback() | ||||||
|  | { | ||||||
|  |   statusMessageTimerSemaphore = true; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user