From a2293b929b778c64b612d3af48fe800064c73904 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sun, 27 Sep 2020 11:59:23 +0200 Subject: [PATCH 01/40] added multi instance support --- MMM-LEDStripControl.js | 80 ++++++++++++++++++++++++++++-------------- README.md | 8 +++-- ledstripcontrol.css | 1 + package.json | 2 +- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/MMM-LEDStripControl.js b/MMM-LEDStripControl.js index 7253e12..f83e752 100644 --- a/MMM-LEDStripControl.js +++ b/MMM-LEDStripControl.js @@ -20,6 +20,7 @@ Module.register('MMM-LEDStripControl', { downIcon: "fa fa-angle-down", downFastIcon: "fa fa-angle-double-down", fetchStatusInterval: 300, + instance: 0 }, suspend: function() { @@ -38,10 +39,10 @@ Module.register('MMM-LEDStripControl', { scheduleStatusUpdate(){ const self = this self.statusTimeout = setTimeout(()=>{ - self.sendNotification("LED_STRIP_CONTROL_FETCH_STATUS","dummy") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_FETCH_STATUS"],"dummy") self.statusTimeout = setTimeout(()=>{ - self.sendNotification("LED_STRIP_CONTROL_FETCH_STATUS","dummy") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_FETCH_STATUS"],"dummy") }, self.config.fetchStatusInterval * 1000) }, self.config.fetchStatusInterval * 1000) }, @@ -57,12 +58,12 @@ Module.register('MMM-LEDStripControl', { let fastUp = document.createElement('i') fastUp.className = self.config.upFastIcon+" lsc-icon lsc-fastUp "+cssClassPart - fastUp.addEventListener("click", ()=>{self.notificationReceived("LED_STRIP_CONTROL_INCREASE_VALUE",{"element":key,"step":self.curValues[key].step_u_f})}) + fastUp.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"],{"element":key,"step":self.curValues[key].step_u_f})}) wrapper.appendChild(fastUp) let up = document.createElement('i') up.className = self.config.upIcon+" lsc-icon lsc-up "+cssClassPart - up.addEventListener("click", ()=>{self.notificationReceived("LED_STRIP_CONTROL_INCREASE_VALUE",{"element":key,"step":self.curValues[key].step_u})}) + up.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"],{"element":key,"step":self.curValues[key].step_u})}) wrapper.appendChild(up) let value = document.createElement('div') @@ -86,12 +87,12 @@ Module.register('MMM-LEDStripControl', { let down = document.createElement('i') down.className = self.config.downIcon+" lsc-icon lsc-down "+cssClassPart - down.addEventListener("click", ()=>{self.notificationReceived("LED_STRIP_CONTROL_DECREASE_VALUE",{"element":key,"step":self.curValues[key].step_d})}) + down.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_DECREASE_VALUE"],{"element":key,"step":self.curValues[key].step_d})}) wrapper.appendChild(down) let fastDown = document.createElement('i') fastDown.className = self.config.downFastIcon+" lsc-icon lsc-fastDown "+cssClassPart - fastDown.addEventListener("click", ()=>{self.notificationReceived("LED_STRIP_CONTROL_DECREASE_VALUE",{"element":key,"step":self.curValues[key].step_d_f})}) + fastDown.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_DECREASE_VALUE"],{"element":key,"step":self.curValues[key].step_d_f})}) wrapper.appendChild(fastDown) return wrapper }, @@ -164,15 +165,15 @@ Module.register('MMM-LEDStripControl', { const self = this self.elements = [] let wrapper = document.createElement('div') - wrapper.className = "lsc-rootWrapper" + wrapper.className = self.instanceCssClass+" lsc-rootWrapper" let outputWrapper = document.createElement('div') - outputWrapper.className = "lsc-outputWrapper" + outputWrapper.className = "lsc-outputWrapper "+self.instanceCssClass let outputIcon = document.createElement('i') if(self.curValues["output"].value == true){ - outputIcon.className = self.config.outputOnIcon + " lsc-icon lsc-output lsc-output-on" + outputIcon.className = self.config.outputOnIcon + " lsc-icon lsc-output lsc-output-on "+self.instanceCssClass } else { - outputIcon.className = self.config.outputOffIcon + " lsc-icon lsc-output lsc-output-off" + outputIcon.className = self.config.outputOffIcon + " lsc-icon lsc-output lsc-output-off "+self.instanceCssClass } if (self.curValues["output"].selected == true){ @@ -181,22 +182,22 @@ Module.register('MMM-LEDStripControl', { outputIcon.className += " lsc-unselected" } self.curValues["output"].obj = outputIcon - outputIcon.addEventListener("click", ()=>{self.notificationReceived("LED_STRIP_CONTROL_INCREASE_VALUE",{"element":"output"})}) + outputIcon.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"],{"element":"output"})}) self.elements.push("output") outputWrapper.appendChild(outputIcon) wrapper.appendChild(outputWrapper) if (self.config.showNormalColorOptions){ - wrapper.appendChild(self.getColorDomObject("color", "Color", "lsc-ncolor")) + wrapper.appendChild(self.getColorDomObject("color", "Color", self.instanceCssClass+" lsc-ncolor")) } if (self.config.showPongColorOptions){ //color control of the pong colors - wrapper.appendChild(self.getColorDomObject("pong_color", "Pong Color", "lsc-pcolor")) + wrapper.appendChild(self.getColorDomObject("pong_color", "Pong Color", self.instanceCssClass+" lsc-pcolor")) //color control of the pong result colors - wrapper.appendChild(self.getColorDomObject("pong_result_color", "Pong Result Color", "lsc-rcolor")) + wrapper.appendChild(self.getColorDomObject("pong_result_color", "Pong Result Color", self.instanceCssClass+" lsc-rcolor")) } //pong options @@ -261,6 +262,33 @@ Module.register('MMM-LEDStripControl', { "pong_btn_delay": {"value": 2, "step_u": 0.5, "step_d": 0.5, "step_u_f": 1, "step_d_f": 1, "min": 0.5, "fractions": 1, "selected": false, "obj" : null}, }; + self.instanceCssClass = "lsc-"+self.config.instance + if (self.config.instance > 0){ + self.notifications = { + "LED_STRIP_CONTROL_FETCH_STATUS": "LED_STRIP_CONTROL_FETCH_STATUS_"+self.config.instance, + "LED_STRIP_CONTROL_INCREASE_VALUE": "LED_STRIP_CONTROL_INCREASE_VALUE_"+self.config.instance, + "LED_STRIP_CONTROL_DECREASE_VALUE": "LED_STRIP_CONTROL_DECREASE_VALUE_"+self.config.instance, + "LED_STRIP_CONTROL_OUTPUT": "LED_STRIP_CONTROL_OUTPUT_"+self.config.instance, + "LED_STRIP_CONTROL_STATUS_UPDATE": "LED_STRIP_CONTROL_STATUS_UPDATE_"+self.config.instance, + "LED_STRIP_CONTROL_TOGGLE_OUTPUT": "LED_STRIP_CONTROL_TOGGLE_OUTPUT_"+self.config.instance, + "LED_STRIP_CONTROL_NEXT_ELEMENT": "LED_STRIP_CONTROL_NEXT_ELEMENT_"+self.config.instance, + "LED_STRIP_CONTROL_PREVIOUS_ELEMENT": "LED_STRIP_CONTROL_PREVIOUS_ELEMENT_"+self.config.instance, + "LED_STRIP_CONTROL_CURRENT_CONFIG": "LED_STRIP_CONTROL_CURRENT_CONFIG_"+self.config.instance, + } + } else { + self.notifications = { + "LED_STRIP_CONTROL_FETCH_STATUS": "LED_STRIP_CONTROL_FETCH_STATUS", + "LED_STRIP_CONTROL_INCREASE_VALUE": "LED_STRIP_CONTROL_INCREASE_VALUE", + "LED_STRIP_CONTROL_DECREASE_VALUE": "LED_STRIP_CONTROL_DECREASE_VALUE", + "LED_STRIP_CONTROL_OUTPUT": "LED_STRIP_CONTROL_OUTPUT", + "LED_STRIP_CONTROL_STATUS_UPDATE": "LED_STRIP_CONTROL_STATUS_UPDATE", + "LED_STRIP_CONTROL_TOGGLE_OUTPUT": "LED_STRIP_CONTROL_TOGGLE_OUTPUT", + "LED_STRIP_CONTROL_NEXT_ELEMENT": "LED_STRIP_CONTROL_NEXT_ELEMENT", + "LED_STRIP_CONTROL_PREVIOUS_ELEMENT": "LED_STRIP_CONTROL_PREVIOUS_ELEMENT", + "LED_STRIP_CONTROL_CURRENT_CONFIG": "LED_STRIP_CONTROL_CURRENT_CONFIG", + } + } + for (let key in self.curValues){ console.log("Checking config for key: "+key) if (typeof self.config[key] !== "undefined"){ @@ -308,7 +336,7 @@ Module.register('MMM-LEDStripControl', { notificationReceived: function (notification, payload) { const self = this - if (notification === "LED_STRIP_CONTROL_NEXT_ELEMENT"){ + if (notification === self.notifications["LED_STRIP_CONTROL_NEXT_ELEMENT"]){ console.log("Changing to next element") self.curValues[self.elements[self.selectedElement]].selected = false self.selectedElement += 1 @@ -319,7 +347,7 @@ Module.register('MMM-LEDStripControl', { console.log("Changing to element: "+self.selectedElement+ " which is: "+self.elements[self.selectedElement]) self.curValues[self.elements[self.selectedElement]].selected = true self.updateDom() - } else if (notification === "LED_STRIP_CONTROL_PREVIOUS_ELEMENT"){ + } else if (notification === self.notifications["LED_STRIP_CONTROL_PREVIOUS_ELEMENT"]){ self.curValues[self.elements[self.selectedElement]].selected = false self.selectedElement -= 1 @@ -329,7 +357,7 @@ Module.register('MMM-LEDStripControl', { console.log("Changing to element: "+self.selectedElement+ " which is: "+self.elements[self.selectedElement]) self.curValues[self.elements[self.selectedElement]].selected = true self.updateDom() - } else if (notification === "LED_STRIP_CONTROL_DECREASE_VALUE"){ + } else if (notification === self.notifications["LED_STRIP_CONTROL_DECREASE_VALUE"]){ let abort = false if (typeof payload.element !== "undefined"){ if (self.elements[self.selectedElement] !== payload.element){ @@ -367,9 +395,9 @@ Module.register('MMM-LEDStripControl', { if (self.elements[self.selectedElement] === "output"){ if(self.curValues[self.elements[self.selectedElement]].value == true){ - self.sendNotification("LED_STRIP_CONTROL_OUTPUT", "on") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "on") } else { - self.sendNotification("LED_STRIP_CONTROL_OUTPUT", "off") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "off") } } else { @@ -377,7 +405,7 @@ Module.register('MMM-LEDStripControl', { } } - } else if (notification === "LED_STRIP_CONTROL_INCREASE_VALUE"){ + } else if (notification === self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"]){ let abort = false if (typeof payload.element !== "undefined"){ if (self.elements[self.selectedElement] !== payload.element){ @@ -419,19 +447,19 @@ Module.register('MMM-LEDStripControl', { self.updateDom() if (self.elements[self.selectedElement] === "output"){ if(self.curValues[self.elements[self.selectedElement]].value == true){ - self.sendNotification("LED_STRIP_CONTROL_OUTPUT", "on") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "on") } else { - self.sendNotification("LED_STRIP_CONTROL_OUTPUT", "off") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "off") } } else { self.sendConfigurationNotification() } } - } else if (notification === "LED_STRIP_CONTROL_STATUS_UPDATE"){ + } else if (notification === self.notifications["LED_STRIP_CONTROL_STATUS_UPDATE"]){ self.updateValuesToNotificationPayload(payload) - } else if (notification === "LED_STRIP_CONTROL_TOGGLE_OUTPUT"){ - self.notificationReceived("LED_STRIP_CONTROL_INCREASE_VALUE", {"element":"output"}) + } else if (notification === self.notifications["LED_STRIP_CONTROL_TOGGLE_OUTPUT"]){ + self.notificationReceived(self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"], {"element":"output"}) } }, @@ -467,7 +495,7 @@ Module.register('MMM-LEDStripControl', { } console.log("Sending current config.") - self.sendNotification("LED_STRIP_CONTROL_CURRENT_CONFIG", JSON.stringify(curConfigArray)) + self.sendNotification(self.notifications["LED_STRIP_CONTROL_CURRENT_CONFIG"], JSON.stringify(curConfigArray)) }, updateValuesToNotificationPayload: function(newValues){ diff --git a/README.md b/README.md index 772249a..74daf3d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# MMM-LEDStripControl ## +# MMM-LEDStripControl # This module controls a led strip (in my case a WS2801 strip with 160 leds) with notifications that are converted to MQTT messages with help of the module MMM-MQTTbridge of sergge1 ([https://github.com/sergge1/MMM-MQTTbridge]). The led strip will be controlled with a Python based script that runs on a second Raspberry Pi which is connected to the network and registers to the MQTT topics. The different configuration options of the led strip are grouped into element groups. It is possible to hide unneeded groups. -The current active element is marked with an red square. The active element can be changed either by touch or notification. Also the values can be changed by notification or touch. The touch icons provide to different steppings for up and down. +The current active element is marked with an red square. The active element can be changed either by touch or notification. Also the values can be changed by notification or touch. The touch icons provide two different steppings for up and down. ## Screenshots ## ### All options visible ### @@ -125,6 +125,9 @@ Basically you do not need to configure anything more than this to get the module }, }, ``` + +This module supports multi instance. If you want to add more than one instance to the mirror do not forget to set the "instance" option which will be explained in the next section! + ### General ### If you like you can change some options: @@ -141,6 +144,7 @@ If you like you can change some options: | upFastIcon | You may like to change the icon of the fast up symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-double-up" | | downIcon | You may like to change the icon of the down symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-down" | | downFastIcon | You may like to change the icon of fast down symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-double-down" | +| instance | If you want to add more than one instance of this module please specify an instance number with this variable. All notifications will be suffixed with "_"+instance (i.e. "LED_STRIP_CONTROL_NEXT_ELEMENT_1") and each element gets an css class "lsc-"+instance. The instance with number 0 (default) will react to and sends notifications without suffix! | Integer | 0 | ### Min/Max and Stepping ### To change the min/max values or the stepping the elements get increased (up -> u) or decreased (down -> d) you can add an partly configuration for each element. You only need to provide the values that you want to change for the elements you want to change of: diff --git a/ledstripcontrol.css b/ledstripcontrol.css index 328ff72..03cef70 100644 --- a/ledstripcontrol.css +++ b/ledstripcontrol.css @@ -5,6 +5,7 @@ font-size: 0px; width: 750px; justify-content: center; + text-align: center; } .lsc-output.lsc-icon{ diff --git a/package.json b/package.json index ecc78d3..0f25545 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "MMM-LEDStripControl", - "version": "0.0.1", + "version": "0.0.2", "description": "", "main": "MMM-LEDStripControl", "dependencies": {}, From 18eff46dee6cd3078707e9ae734d3c90cc640c41 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Thu, 3 Dec 2020 10:18:27 +0100 Subject: [PATCH 02/40] added instanceCss option to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 74daf3d..6e3dd3a 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ If you like you can change some options: | downIcon | You may like to change the icon of the down symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-down" | | downFastIcon | You may like to change the icon of fast down symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-double-down" | | instance | If you want to add more than one instance of this module please specify an instance number with this variable. All notifications will be suffixed with "_"+instance (i.e. "LED_STRIP_CONTROL_NEXT_ELEMENT_1") and each element gets an css class "lsc-"+instance. The instance with number 0 (default) will react to and sends notifications without suffix! | Integer | 0 | +| instanceCssClass | All elements if this instance get this css class added. If you like to control the same strip but with two instances of the module (i.e. because you use the profile or pages module) you can leave the instance number as it is and only change the css stuff if you like (i.e. smaller module) | String | "lsc-"+instance (i.e. "lsc-0") | ### Min/Max and Stepping ### To change the min/max values or the stepping the elements get increased (up -> u) or decreased (down -> d) you can add an partly configuration for each element. You only need to provide the values that you want to change for the elements you want to change of: From 86fe12838d5d7f8e0a271adc5a1e16b9cef02344 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Thu, 3 Dec 2020 10:19:22 +0100 Subject: [PATCH 03/40] added a new option instanceCss --- MMM-LEDStripControl.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/MMM-LEDStripControl.js b/MMM-LEDStripControl.js index f83e752..23d224f 100644 --- a/MMM-LEDStripControl.js +++ b/MMM-LEDStripControl.js @@ -20,7 +20,8 @@ Module.register('MMM-LEDStripControl', { downIcon: "fa fa-angle-down", downFastIcon: "fa fa-angle-double-down", fetchStatusInterval: 300, - instance: 0 + instance: 0, + instanceCssClass: null }, suspend: function() { @@ -39,9 +40,11 @@ Module.register('MMM-LEDStripControl', { scheduleStatusUpdate(){ const self = this self.statusTimeout = setTimeout(()=>{ + console.log(self.name+": "+"Fetching current status!") self.sendNotification(self.notifications["LED_STRIP_CONTROL_FETCH_STATUS"],"dummy") self.statusTimeout = setTimeout(()=>{ + console.log(self.name+": "+"Fetching current status!") self.sendNotification(self.notifications["LED_STRIP_CONTROL_FETCH_STATUS"],"dummy") }, self.config.fetchStatusInterval * 1000) }, self.config.fetchStatusInterval * 1000) @@ -262,7 +265,12 @@ Module.register('MMM-LEDStripControl', { "pong_btn_delay": {"value": 2, "step_u": 0.5, "step_d": 0.5, "step_u_f": 1, "step_d_f": 1, "min": 0.5, "fractions": 1, "selected": false, "obj" : null}, }; - self.instanceCssClass = "lsc-"+self.config.instance + if (self.config.instanceCssClass == null){ + self.instanceCssClass = "lsc-"+self.config.instance + } else { + self.instanceCssClass = self.config.instanceCssClass + } + if (self.config.instance > 0){ self.notifications = { "LED_STRIP_CONTROL_FETCH_STATUS": "LED_STRIP_CONTROL_FETCH_STATUS_"+self.config.instance, @@ -329,8 +337,9 @@ Module.register('MMM-LEDStripControl', { self.scheduleStatusUpdate() setTimeout(()=>{ - self.sendNotification("LED_STRIP_CONTROL_FETCH_STATUS","dummy") - }, 1000) + console.log(self.name+": "+"Fetching current status with noti: "+self.notifications["LED_STRIP_CONTROL_FETCH_STATUS"]) + self.sendNotification(self.notifications["LED_STRIP_CONTROL_FETCH_STATUS"],"dummy") + }, 10000) }, notificationReceived: function (notification, payload) { @@ -395,8 +404,10 @@ Module.register('MMM-LEDStripControl', { if (self.elements[self.selectedElement] === "output"){ if(self.curValues[self.elements[self.selectedElement]].value == true){ + console.log(self.name+": "+"Switch the lights on") self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "on") } else { + console.log(self.name+": "+"Switch the lights off") self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "off") } @@ -447,8 +458,10 @@ Module.register('MMM-LEDStripControl', { self.updateDom() if (self.elements[self.selectedElement] === "output"){ if(self.curValues[self.elements[self.selectedElement]].value == true){ + console.log(self.name+": "+"Switch the lights on") self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "on") } else { + console.log(self.name+": "+"Switch the lights off") self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "off") } @@ -494,7 +507,7 @@ Module.register('MMM-LEDStripControl', { } } - console.log("Sending current config.") + console.log(self.name+": "+"Sending current config") self.sendNotification(self.notifications["LED_STRIP_CONTROL_CURRENT_CONFIG"], JSON.stringify(curConfigArray)) }, From fc51a0921e0cfd261209e8cac43efe50cae6226b Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Fri, 23 Apr 2021 21:32:32 +0200 Subject: [PATCH 04/40] added an example of HowTo connect an WS2813 (WS2815) led strip to an ESP32 board an control it with this module. --- .../ESP32LedStripWithPongAndMqtt.ino | 682 ++++++++++++++++++ 1 file changed, 682 insertions(+) create mode 100644 examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino new file mode 100644 index 0000000..feae2b4 --- /dev/null +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -0,0 +1,682 @@ +#include +#include +#include +#include + +#define MAX_LEDS 300 +#define NUM_LEDS 300 +#define NUM_PONG_LEDS 10 +#define DATA_PIN 14 +#define CLOCK_PIN 14 +#define BTN_1_GPIO 23 +#define BTN_2_GPIO 22 +#define BTN_DEBOUNCE_DELAY 200 +#define PONG_BTN_DELAY 2.000 +#define PONG_MAX_WINS 2 +#define PONG_TOLERANCE 2 +#define PONG_INIT_LED_DELAY 0.500 +#define PONG_DEC_PER_RUN 0.05 +#define PONG_MIN_LED_DELAY 0.02 +#define PONG_RESULT_DELAY_DURING 2.0 +#define PONG_RESULT_DELAY_AFTER 5.0 + +CRGB leds[MAX_LEDS]; + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* MQTT_BROKER = "ENTER_MQTT_BROKER_ADDRESS_HERE"; +const char* MQTT_USER = "ENTER_MQTT_USER_HERE"; +const char* MQTT_PASS = "ENTER_MQTT_PASSWORD_HERE"; +const String clientName = "ESP_LED"; +const String topicId = "esp_led"; +long interval = 10000; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +int reverseMode=0; +int cur_pixel=0; +int btn_one_state = 0; +long btn_one_last_pressed = 0; +int btn_two_state = 0; +long btn_two_last_pressed = 0; + +int color_r = 255; +int color_g = 255; +int color_b = 255; +int stripe_mode = 0; +boolean stripe_on = false; + +float pong_init_delay = PONG_INIT_LED_DELAY; +float cur_pong_delay = pong_init_delay; +int num_pong_leds = NUM_PONG_LEDS; +int pong_max_wins = PONG_MAX_WINS; +float pong_wins_delay_during = PONG_RESULT_DELAY_DURING; +float pong_wins_delay_after = PONG_RESULT_DELAY_AFTER; +float pong_min_delay = PONG_MIN_LED_DELAY; +float pong_dec_per_run = PONG_DEC_PER_RUN; +float pong_btn_delay = PONG_BTN_DELAY; +int pong_tolerance = PONG_TOLERANCE; +int pong_color_r = 0; +int pong_color_g = 0; +int pong_color_b = 255; +int pong_result_color_r = 0; +int pong_result_color_g = 255; +int pong_result_color_b = 0; +int player_one_wins = 0; +int player_successfull_one_press = 0; +int player_two_wins = 0; +int player_successfull_two_press = 0; + +int publish_status_after_every_config_change = 1; +int publish_status_if_toggled = 1; +int publish_status_at_start = 1; + +void publish_current_status(){ + StaticJsonDocument<1024> doc; + if (client.connected()){ + doc["pong"]["btn_delay"] = pong_btn_delay; + doc["pong"]["init_delay"] = pong_init_delay; + doc["pong"]["min_delay"] = pong_min_delay; + doc["pong"]["dec_per_run"] = pong_dec_per_run; + doc["pong"]["num_leds"] = num_pong_leds; + doc["pong"]["max_wins"] = pong_max_wins; + doc["pong"]["tolerance"] = pong_tolerance; + doc["pong"]["result_delay_during"] = pong_wins_delay_during; + doc["pong"]["result_delay_after"] = pong_wins_delay_after; + doc["pong"]["color_r"] = pong_color_r; + doc["pong"]["color_g"] = pong_color_g; + doc["pong"]["color_b"] = pong_color_b; + doc["pong"]["result_color_r"] = pong_result_color_r; + doc["pong"]["result_color_g"] = pong_result_color_g; + doc["pong"]["result_color_b"] = pong_result_color_b; + doc["output"] = stripe_on; + doc["mode"] = stripe_mode; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + client.publish((topicId+"/status").c_str(), buffer, n); + } +} + +void fixConfigValues(){ + if (pong_btn_delay < 0){ + pong_btn_delay = 0; + } + + if (pong_init_delay < pong_min_delay){ + pong_init_delay = pong_min_delay; + } + + if (pong_min_delay < 0){ + pong_min_delay = 0; + } + + if (pong_dec_per_run < 0){ + pong_dec_per_run = 0; + } + + if (num_pong_leds > MAX_LEDS){ + num_pong_leds = MAX_LEDS; + } + + if (pong_max_wins > num_pong_leds){ + pong_max_wins = num_pong_leds; + } + + if (pong_wins_delay_during < 0){ + pong_wins_delay_during = 0; + } + + if (pong_wins_delay_after < 0){ + pong_wins_delay_after = 0; + } + + if (pong_result_color_r > 255){ + pong_result_color_r = 255; + } else if (pong_result_color_r < 0){ + pong_result_color_r = 0; + } + + if (pong_result_color_g > 255){ + pong_result_color_g = 255; + } else if (pong_result_color_g < 0){ + pong_result_color_g = 0; + } + + if (pong_result_color_b > 255){ + pong_result_color_b = 255; + } else if (pong_result_color_b < 0){ + pong_result_color_b = 0; + } + + if (pong_tolerance < 0){ + pong_tolerance = 0; + } + + if (pong_tolerance > (num_pong_leds -1)){ + pong_tolerance = num_pong_leds -1; + } + + if (pong_color_r > 255){ + pong_color_r = 255; + } else if (pong_color_r < 0){ + pong_color_r = 0; + } + + if (pong_color_g > 255){ + pong_color_g = 255; + } else if (pong_color_g < 0){ + pong_color_g = 0; + } + + if (pong_color_b > 255){ + pong_color_b = 255; + } else if (pong_color_b < 0){ + pong_color_b = 0; + } + + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.print(topic); + Serial.print(". Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". + // Changes the output state according to the message + if (String(topic) == topicId+"/output") { + Serial.print("Changing output to "); + if(messageTemp == "on"){ + Serial.println("on"); + toggle_leds(1); + } + else if(messageTemp == "off"){ + Serial.println("off"); + toggle_leds(0); + } else { + Serial.println("toggle"); + toggle_leds(-1); + } + } else if (String(topic) == topicId+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + int cur_int_tmp_value = -1; + float cur_float_tmp_value = -1; + boolean cur_bool_tmp_value = false; + if (!err){ + + if(doc["pong"]["btn_delay"]){ + pong_btn_delay = doc["pong"]["btn_delay"].as(); + } + + if(doc["pong"]["init_delay"]){ + pong_init_delay = doc["pong"]["init_delay"].as(); + } + + if(doc["pong"]["min_delay"]){ + pong_min_delay = doc["pong"]["min_delay"].as(); + } + + if(doc["pong"]["dec_per_run"]){ + pong_dec_per_run = doc["pong"]["dec_per_run"].as(); + } + + num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; + pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; + pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; + + if(doc["pong"]["result_delay_during"]){ + pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); + } + + if(doc["pong"]["result_delay_after"]){ + pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); + } + + pong_color_r = doc["pong"]["color_r"] | pong_color_r; + pong_color_g = doc["pong"]["color_g"] | pong_color_g; + pong_color_b = doc["pong"]["color_b"] | pong_color_b; + + pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; + pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; + pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; + + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + } + + } else if (String(topic) == topicId+"/pong/btn_delay"){ + pong_btn_delay = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/init_delay"){ + pong_init_delay = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/min_delay"){ + pong_min_delay = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/dec_per_run"){ + pong_dec_per_run = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/num_leds"){ + num_pong_leds = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/max_wins"){ + pong_max_wins = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/result/delay/during"){ + pong_wins_delay_during = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/result/delay/after"){ + pong_wins_delay_after = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/result/color/r"){ + pong_result_color_r = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/result/color/g"){ + pong_result_color_g = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/result/color/b"){ + pong_result_color_b = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/tolerance"){ + pong_tolerance = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/color/r"){ + pong_color_r = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/color/g"){ + pong_color_g = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/color/b"){ + pong_color_b = messageTemp.toInt(); + } else if (String(topic) == topicId+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topicId+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topicId+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topicId+"/get_status"){ + publish_current_status(); + } + + fixConfigValues(); + + if ((String(topic) != topicId+"/output") && + (String(topic) != topicId+"/get_status") && + (stripe_mode == 0)){ + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } +} + +void setup() { + client.setBufferSize(512); + Serial.begin(115200); + setup_wifi(); + client.setServer(MQTT_BROKER, 1883); + reconnect(); + client.setCallback(callback); + + if (publish_status_at_start){ + publish_current_status(); + } + + + delay(200); + FastLED.addLeds(leds, MAX_LEDS); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + FastLED.show(); + delay(50); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::White; + } + FastLED.show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + FastLED.show(); + + pinMode(BTN_1_GPIO, INPUT); + pinMode(BTN_2_GPIO, INPUT); + + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, LOW); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, LOW); + delay(500); +} + +void setup_wifi() { + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void btn_one_pressed(){ + long cur_time = millis(); + if((cur_time - btn_one_last_pressed) > BTN_DEBOUNCE_DELAY){ + btn_one_last_pressed = cur_time; + btn_one_state = 1; + } +} + +void btn_two_pressed(){ + long cur_time = millis(); + if((cur_time - btn_two_last_pressed) > BTN_DEBOUNCE_DELAY){ + btn_two_last_pressed = cur_time; + btn_two_state = 1; + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(clientName.c_str(), MQTT_USER, MQTT_PASS)) { + Serial.println("connected"); + // Subscribe + Serial.print("Subscribing with topicId: "); + Serial.println(topicId); + client.subscribe((topicId+"/get_status").c_str()); + client.subscribe((topicId+"/config").c_str()); + client.subscribe((topicId+"/output").c_str()); + client.subscribe((topicId+"/pong/btn_delay").c_str()); + client.subscribe((topicId+"/pong/init_delay").c_str()); + client.subscribe((topicId+"/pong/min_delay").c_str()); + client.subscribe((topicId+"/pong/dec_per_run").c_str()); + client.subscribe((topicId+"/pong/num_leds").c_str()); + client.subscribe((topicId+"/pong/max_wins").c_str()); + client.subscribe((topicId+"/pong/result/delay/during").c_str()); + client.subscribe((topicId+"/pong/result/delay/after").c_str()); + client.subscribe((topicId+"/pong/result/color/r").c_str()); + client.subscribe((topicId+"/pong/result/color/g").c_str()); + client.subscribe((topicId+"/pong/result/color/b").c_str()); + client.subscribe((topicId+"/pong/tolerance").c_str()); + client.subscribe((topicId+"/pong/color/r").c_str()); + client.subscribe((topicId+"/pong/color/g").c_str()); + client.subscribe((topicId+"/pong/color/b").c_str()); + client.subscribe((topicId+"/color/r").c_str()); + client.subscribe((topicId+"/color/g").c_str()); + client.subscribe((topicId+"/color/b").c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void toggle_leds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i].r = color_r; + leds[i].g = color_g; + leds[i].b = color_b; + } + stripe_on = true; + } else { + for (int i = 0; i< NUM_LEDS; i++){ + leds[i] = CRGB::Black; + } + stripe_on = false; + } + + FastLED.show(); +} + +void switchToPongMode(){ + btn_one_state = 0; + btn_two_state = 0; + stripe_mode = 1; + player_one_wins = 0; + player_two_wins = 0; + cur_pixel = 0; + cur_pong_delay = pong_init_delay; + + for (int i = 0; i< NUM_LEDS; i++){ + leds[i] = CRGB::Black; + } + FastLED.show(); + delay(1000); + for (int i = 0; i< num_pong_leds; i++){ + leds[i].r = pong_color_r; + leds[i].g = pong_color_g; + leds[i].b = pong_color_b; + } + FastLED.show(); + delay(1000); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i] = CRGB::Black; + } + FastLED.show(); + delay(1000); +} + +void displayResult(float cur_delay){ + delay(500); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i] = CRGB::Black; + } + + for (int i = 0; i < player_one_wins; i++){ + leds[i].r = pong_result_color_r; + leds[i].g = pong_result_color_g; + leds[i].b = pong_result_color_b; + } + + for (int i = (num_pong_leds - 1); i > ((num_pong_leds-1)-player_two_wins); i--){ + leds[i].r = pong_result_color_r; + leds[i].g = pong_result_color_g; + leds[i].b = pong_result_color_b; + } + FastLED.show(); + delay(cur_delay*1000); +} + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (stripe_mode == 0){ + if (btn_two_state == 1){ + btn_two_state = 0; + Serial.println("Button two pressed."); + if ((btn_two_last_pressed - btn_one_last_pressed) < pong_btn_delay){ + Serial.println("Switching to pong mode."); + switchToPongMode(); + } else { + Serial.println("Toggling led stripe."); + toggle_leds(-1); + } + } + + if (btn_one_state == 1){ + btn_one_state = 0; + Serial.println("Button one pressed. Toggling led stripe."); + toggle_leds(-1); + } + } else if (stripe_mode == 1){ + for (int i=0; i < NUM_LEDS; i++){ + leds[i] = CRGB::Black; + } + + leds[cur_pixel].r = pong_color_r; + leds[cur_pixel].g = pong_color_g; + leds[cur_pixel].b = pong_color_b; + FastLED.show(); + + delay(cur_pong_delay*1000); + + int abortRun = 0; + int player_one_miss = 0; + + if (player_successfull_one_press == 0){ + if(btn_one_state == 1){ + btn_one_state = 0; + if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= 0)){ + player_one_miss = 1; + } else { + player_successfull_one_press = 1; + } + } else if ((reverseMode == 1) && (cur_pixel == 0)){ + player_one_miss = 1; + } + } else { + btn_one_state = 0; + } + + if(player_one_miss == 1){ + abortRun = 1; + player_two_wins += 1; + if(player_two_wins >= pong_max_wins){ + stripe_mode = 0; + displayResult(pong_wins_delay_after); + toggle_leds(0); + } else { + displayResult(pong_wins_delay_during); + cur_pixel = 0; + reverseMode = 0; + cur_pong_delay = pong_init_delay; + } + } + + int player_two_miss = 0; + + if (player_successfull_two_press == 0){ + if(btn_two_state == 1){ + btn_two_state = 0; + if ((reverseMode == 1) or ((cur_pixel + pong_tolerance) <= (num_pong_leds-1))){ + player_two_miss = 1; + } else { + player_successfull_two_press = 1; + } + } else if ((reverseMode == 0) && (cur_pixel == (num_pong_leds-1))){ + player_two_miss = 1; + } + } else { + btn_two_state = 0; + } + + if(player_two_miss == 1){ + abortRun = 1; + player_one_wins += 1; + if(player_one_wins >= pong_max_wins){ + stripe_mode = 0; + displayResult(pong_wins_delay_after); + toggle_leds(0); + btn_two_state = 0; + btn_one_state = 0; + player_successfull_one_press = 0; + player_successfull_two_press = 0; + } else { + displayResult(pong_wins_delay_during); + cur_pixel = 0; + reverseMode = 0; + btn_two_state = 0; + btn_one_state = 0; + player_successfull_one_press = 0; + player_successfull_two_press = 0; + cur_pong_delay = pong_init_delay; + } + } + + + if (abortRun == 0){ + if (reverseMode == 1){ + cur_pixel -= 1; + if (cur_pixel < 0){ + reverseMode = 0; + player_successfull_one_press = 0; + cur_pixel = 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } else { + cur_pixel += 1; + if (cur_pixel > (num_pong_leds-1)){ + player_successfull_two_press = 0; + cur_pixel = num_pong_leds-2; + reverseMode = 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } + } + } +} From 267f44e3204ea1134dc1412fe4a4d4038df5ca09 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sat, 24 Apr 2021 15:00:42 +0200 Subject: [PATCH 05/40] modified the ESP32 example to react on FALLING signal if buttons are pressed; added hardware and software configuration to the ESP32 example. --- .../ESP32LedStripWithPongAndMqtt.ino | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index feae2b4..e166ed5 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -1,3 +1,18 @@ +//LED Strip: BTF-LIGHTING WS2815 -> https://www.amazon.de/gp/product/B07LG5ZT9C/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1 +//Power Supply: HuaTec LED Trafo 12V 120W -> https://www.amazon.de/gp/product/B0829817YM/ref=ppx_yo_dt_b_asin_image_o09_s00?ie=UTF8&psc=1 +//Step-Down-Module: AZDelivery XL4015 -> https://www.amazon.de/gp/product/B07SRXR1VT/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1 +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//2 x Tactile Push Button (Something like https://www.amazon.de/gp/product/B078ZDK6KZ/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) +//2 x Capacitor 0.1 Mikrofarad +//2 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 1.0.6 +//Libs: +// FastLED by Daniel Garcia Version 3.3.3 +// PubSubClient by Nick O'Leary Version 2.8.0 +// ArduinoJson by Benoit Blanchon Version 6.17.3 + #include #include #include @@ -10,7 +25,7 @@ #define CLOCK_PIN 14 #define BTN_1_GPIO 23 #define BTN_2_GPIO 22 -#define BTN_DEBOUNCE_DELAY 200 +#define BTN_DEBOUNCE_DELAY 500 #define PONG_BTN_DELAY 2.000 #define PONG_MAX_WINS 2 #define PONG_TOLERANCE 2 @@ -24,12 +39,11 @@ CRGB leds[MAX_LEDS]; const char* SSID = "ENTER_WIFI_SSID_HERE"; const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* MQTT_BROKER = "ENTER_MQTT_BROKER_ADDRESS_HERE"; -const char* MQTT_USER = "ENTER_MQTT_USER_HERE"; +const char* MQTT_BROKER = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* MQTT_USER = "ENTER_MQTT_USERNAME_HERE"; const char* MQTT_PASS = "ENTER_MQTT_PASSWORD_HERE"; const String clientName = "ESP_LED"; const String topicId = "esp_led"; -long interval = 10000; WiFiClient espClient; PubSubClient client(espClient); @@ -348,7 +362,7 @@ void setup() { delay(200); - FastLED.addLeds(leds, MAX_LEDS); + FastLED.addLeds(leds, MAX_LEDS); for (int i=0; i < MAX_LEDS; i++){ leds[i] = CRGB::Black; } @@ -367,8 +381,8 @@ void setup() { pinMode(BTN_1_GPIO, INPUT); pinMode(BTN_2_GPIO, INPUT); - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, LOW); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, LOW); + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, FALLING); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, FALLING); delay(500); } @@ -553,10 +567,13 @@ void loop() { if (btn_two_state == 1){ btn_two_state = 0; Serial.println("Button two pressed."); - if ((btn_two_last_pressed - btn_one_last_pressed) < pong_btn_delay){ + if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ Serial.println("Switching to pong mode."); switchToPongMode(); } else { + Serial.println(btn_two_last_pressed); + Serial.println(btn_one_last_pressed); + Serial.println(pong_btn_delay); Serial.println("Toggling led stripe."); toggle_leds(-1); } From ec4fd2afbfbbe94e305db431116afe8425d9b4af Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sat, 24 Apr 2021 19:30:03 +0200 Subject: [PATCH 06/40] fixed some small issues in ESP32 example, added periodic refresh and publish of current config if leds get toggled --- .../ESP32LedStripWithPongAndMqtt.ino | 64 ++++++++++++------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index e166ed5..7b229a8 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -9,10 +9,9 @@ //Arduino Version: 1.8.13 //Board Firmware: ESP32 by Espressif Systems Version 1.0.6 //Libs: -// FastLED by Daniel Garcia Version 3.3.3 +// FastLED by Daniel Garcia Version 3.4.0 // PubSubClient by Nick O'Leary Version 2.8.0 // ArduinoJson by Benoit Blanchon Version 6.17.3 - #include #include #include @@ -22,7 +21,6 @@ #define NUM_LEDS 300 #define NUM_PONG_LEDS 10 #define DATA_PIN 14 -#define CLOCK_PIN 14 #define BTN_1_GPIO 23 #define BTN_2_GPIO 22 #define BTN_DEBOUNCE_DELAY 500 @@ -34,6 +32,7 @@ #define PONG_MIN_LED_DELAY 0.02 #define PONG_RESULT_DELAY_DURING 2.0 #define PONG_RESULT_DELAY_AFTER 5.0 +#define REFRESH_INTERVAL 10000 CRGB leds[MAX_LEDS]; @@ -51,6 +50,8 @@ long lastMsg = 0; char msg[50]; int value = 0; +long last_refresh = 0; + int reverseMode=0; int cur_pixel=0; int btn_one_state = 0; @@ -58,6 +59,7 @@ long btn_one_last_pressed = 0; int btn_two_state = 0; long btn_two_last_pressed = 0; + int color_r = 255; int color_g = 255; int color_b = 255; @@ -360,26 +362,28 @@ void setup() { publish_current_status(); } - - delay(200); FastLED.addLeds(leds, MAX_LEDS); for (int i=0; i < MAX_LEDS; i++){ leds[i] = CRGB::Black; } FastLED.show(); + FastLED.show(); delay(50); for (int i=0; i < MAX_LEDS; i++){ leds[i] = CRGB::White; } FastLED.show(); + FastLED.show(); delay(200); for (int i=0; i < MAX_LEDS; i++){ leds[i] = CRGB::Black; } FastLED.show(); + FastLED.show(); pinMode(BTN_1_GPIO, INPUT); pinMode(BTN_2_GPIO, INPUT); + pinMode(DATA_PIN, OUTPUT); attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, FALLING); attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, FALLING); @@ -502,6 +506,10 @@ void toggle_leds(int to_state){ } FastLED.show(); + FastLED.show(); + if (publish_status_if_toggled == 1){ + publish_current_status(); + } } void switchToPongMode(){ @@ -517,6 +525,7 @@ void switchToPongMode(){ leds[i] = CRGB::Black; } FastLED.show(); + FastLED.show(); delay(1000); for (int i = 0; i< num_pong_leds; i++){ leds[i].r = pong_color_r; @@ -524,11 +533,13 @@ void switchToPongMode(){ leds[i].b = pong_color_b; } FastLED.show(); + FastLED.show(); delay(1000); for (int i = 0; i< NUM_LEDS; i++){ leds[i] = CRGB::Black; } FastLED.show(); + FastLED.show(); delay(1000); } @@ -550,6 +561,7 @@ void displayResult(float cur_delay){ leds[i].b = pong_result_color_b; } FastLED.show(); + FastLED.show(); delay(cur_delay*1000); } @@ -564,25 +576,32 @@ void loop() { client.loop(); if (stripe_mode == 0){ - if (btn_two_state == 1){ - btn_two_state = 0; - Serial.println("Button two pressed."); - if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ - Serial.println("Switching to pong mode."); - switchToPongMode(); - } else { - Serial.println(btn_two_last_pressed); - Serial.println(btn_one_last_pressed); - Serial.println(pong_btn_delay); - Serial.println("Toggling led stripe."); + if ((btn_one_state == 1) or (btn_two_state == 1)){ + if (btn_two_state == 1){ + btn_two_state = 0; + Serial.println("Button two pressed."); + if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switchToPongMode(); + } else { + Serial.println(btn_two_last_pressed); + Serial.println(btn_one_last_pressed); + Serial.println(pong_btn_delay); + Serial.println("Toggling led stripe."); + toggle_leds(-1); + } + } + + if (btn_one_state == 1){ + btn_one_state = 0; + Serial.println("Button one pressed. Toggling led stripe."); toggle_leds(-1); } - } - - if (btn_one_state == 1){ - btn_one_state = 0; - Serial.println("Button one pressed. Toggling led stripe."); - toggle_leds(-1); + } else { + if((millis() - last_refresh) > REFRESH_INTERVAL){ + FastLED.show(); + FastLED.show(); + } } } else if (stripe_mode == 1){ for (int i=0; i < NUM_LEDS; i++){ @@ -592,6 +611,7 @@ void loop() { leds[cur_pixel].r = pong_color_r; leds[cur_pixel].g = pong_color_g; leds[cur_pixel].b = pong_color_b; + FastLED.show(); FastLED.show(); delay(cur_pong_delay*1000); From 5752c3e5a867de5a240cc7da56876ff298369077 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sun, 25 Apr 2021 13:00:45 +0200 Subject: [PATCH 07/40] added support of sending button presses via MQTT to the ESP32 example --- .../ESP32LedStripWithPongAndMqtt.ino | 232 ++++++++++-------- 1 file changed, 123 insertions(+), 109 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index 7b229a8..de8a321 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -229,125 +229,138 @@ void callback(char* topic, byte* message, unsigned int length) { messageTemp += (char)message[i]; } Serial.println(); - // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". - // Changes the output state according to the message - if (String(topic) == topicId+"/output") { - Serial.print("Changing output to "); - if(messageTemp == "on"){ - Serial.println("on"); - toggle_leds(1); - } - else if(messageTemp == "off"){ - Serial.println("off"); - toggle_leds(0); - } else { - Serial.println("toggle"); - toggle_leds(-1); - } - } else if (String(topic) == topicId+"/config"){ - StaticJsonDocument<1024> doc; - DeserializationError err = deserializeJson(doc, messageTemp); - int cur_int_tmp_value = -1; - float cur_float_tmp_value = -1; - boolean cur_bool_tmp_value = false; - if (!err){ - - if(doc["pong"]["btn_delay"]){ - pong_btn_delay = doc["pong"]["btn_delay"].as(); - } - if(doc["pong"]["init_delay"]){ - pong_init_delay = doc["pong"]["init_delay"].as(); + if (! (String(topic) == topicId+"/btn") ) { + // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". + // Changes the output state according to the message + if (String(topic) == topicId+"/output") { + Serial.print("Changing output to "); + if(messageTemp == "on"){ + Serial.println("on"); + toggle_leds(1); } - - if(doc["pong"]["min_delay"]){ - pong_min_delay = doc["pong"]["min_delay"].as(); + else if(messageTemp == "off"){ + Serial.println("off"); + toggle_leds(0); + } else { + Serial.println("toggle"); + toggle_leds(-1); } - - if(doc["pong"]["dec_per_run"]){ - pong_dec_per_run = doc["pong"]["dec_per_run"].as(); + } else if (String(topic) == topicId+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + int cur_int_tmp_value = -1; + float cur_float_tmp_value = -1; + boolean cur_bool_tmp_value = false; + if (!err){ + + if(doc["pong"]["btn_delay"]){ + pong_btn_delay = doc["pong"]["btn_delay"].as(); + } + + if(doc["pong"]["init_delay"]){ + pong_init_delay = doc["pong"]["init_delay"].as(); + } + + if(doc["pong"]["min_delay"]){ + pong_min_delay = doc["pong"]["min_delay"].as(); + } + + if(doc["pong"]["dec_per_run"]){ + pong_dec_per_run = doc["pong"]["dec_per_run"].as(); + } + + num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; + pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; + pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; + + if(doc["pong"]["result_delay_during"]){ + pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); + } + + if(doc["pong"]["result_delay_after"]){ + pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); + } + + pong_color_r = doc["pong"]["color_r"] | pong_color_r; + pong_color_g = doc["pong"]["color_g"] | pong_color_g; + pong_color_b = doc["pong"]["color_b"] | pong_color_b; + + pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; + pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; + pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; + + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; } - num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; - pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; - pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; - - if(doc["pong"]["result_delay_during"]){ - pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); - } - - if(doc["pong"]["result_delay_after"]){ - pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); + } else if (String(topic) == topicId+"/pong/btn_delay"){ + pong_btn_delay = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/init_delay"){ + pong_init_delay = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/min_delay"){ + pong_min_delay = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/dec_per_run"){ + pong_dec_per_run = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/num_leds"){ + num_pong_leds = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/max_wins"){ + pong_max_wins = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/result/delay/during"){ + pong_wins_delay_during = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/result/delay/after"){ + pong_wins_delay_after = messageTemp.toFloat(); + } else if (String(topic) == topicId+"/pong/result/color/r"){ + pong_result_color_r = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/result/color/g"){ + pong_result_color_g = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/result/color/b"){ + pong_result_color_b = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/tolerance"){ + pong_tolerance = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/color/r"){ + pong_color_r = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/color/g"){ + pong_color_g = messageTemp.toInt(); + } else if (String(topic) == topicId+"/pong/color/b"){ + pong_color_b = messageTemp.toInt(); + } else if (String(topic) == topicId+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topicId+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topicId+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topicId+"/get_status"){ + publish_current_status(); + } + + fixConfigValues(); + + if ((String(topic) != topicId+"/output") && + (String(topic) != topicId+"/get_status") && + (stripe_mode == 0)){ + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); } - - pong_color_r = doc["pong"]["color_r"] | pong_color_r; - pong_color_g = doc["pong"]["color_g"] | pong_color_g; - pong_color_b = doc["pong"]["color_b"] | pong_color_b; - - pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; - pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; - pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; - - color_r = doc["color_r"] | color_r; - color_g = doc["color_g"] | color_g; - color_b = doc["color_b"] | color_b; } - - } else if (String(topic) == topicId+"/pong/btn_delay"){ - pong_btn_delay = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/init_delay"){ - pong_init_delay = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/min_delay"){ - pong_min_delay = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/dec_per_run"){ - pong_dec_per_run = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/num_leds"){ - num_pong_leds = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/max_wins"){ - pong_max_wins = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/result/delay/during"){ - pong_wins_delay_during = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/result/delay/after"){ - pong_wins_delay_after = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/result/color/r"){ - pong_result_color_r = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/result/color/g"){ - pong_result_color_g = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/result/color/b"){ - pong_result_color_b = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/tolerance"){ - pong_tolerance = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/color/r"){ - pong_color_r = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/color/g"){ - pong_color_g = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/color/b"){ - pong_color_b = messageTemp.toInt(); - } else if (String(topic) == topicId+"/color/r"){ - color_r = messageTemp.toInt(); - } else if (String(topic) == topicId+"/color/g"){ - color_g = messageTemp.toInt(); - } else if (String(topic) == topicId+"/color/b"){ - color_b = messageTemp.toInt(); - } else if (String(topic) == topicId+"/get_status"){ - publish_current_status(); - } - - fixConfigValues(); - - if ((String(topic) != topicId+"/output") && - (String(topic) != topicId+"/get_status") && - (stripe_mode == 0)){ - if (stripe_on){ - toggle_leds(1); + + if(publish_status_after_every_config_change){ + publish_current_status(); + } + } else { + Serial.println("Button press via mqtt"); + Serial.println(messageTemp); + if (messageTemp.toInt() == 2 ){ + btn_two_last_pressed = millis();; + btn_two_state = 1; } else { - toggle_leds(0); + btn_one_last_pressed = millis();; + btn_one_state = 1; } } - - if(publish_status_after_every_config_change){ - publish_current_status(); - } } void setup() { @@ -467,6 +480,7 @@ void reconnect() { client.subscribe((topicId+"/color/r").c_str()); client.subscribe((topicId+"/color/g").c_str()); client.subscribe((topicId+"/color/b").c_str()); + client.subscribe((topicId+"/btn").c_str()); } else { Serial.print("failed, rc="); Serial.print(client.state()); From ccc39d05ab3bbd22027c32631cf624b928639d27 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sun, 25 Apr 2021 14:35:37 +0200 Subject: [PATCH 08/40] added option to publish the results during and after the game to ESP32 example --- .../ESP32LedStripWithPongAndMqtt.ino | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index de8a321..614f918 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -90,6 +90,7 @@ int player_successfull_two_press = 0; int publish_status_after_every_config_change = 1; int publish_status_if_toggled = 1; int publish_status_at_start = 1; +int publish_results_at_display = 1; void publish_current_status(){ StaticJsonDocument<1024> doc; @@ -122,6 +123,18 @@ void publish_current_status(){ } } +void publish_results(){ + StaticJsonDocument<100> doc; + if (client.connected()){ + doc["result_player_one"] = player_one_wins; + doc["result_player_two"] = player_two_wins; + } + char buffer[100]; + + size_t n = serializeJson(doc, buffer); + client.publish((topicId+"/results").c_str(), buffer, n); +} + void fixConfigValues(){ if (pong_btn_delay < 0){ pong_btn_delay = 0; @@ -526,14 +539,19 @@ void toggle_leds(int to_state){ } } -void switchToPongMode(){ +void reset_pong_vars(){ btn_one_state = 0; btn_two_state = 0; - stripe_mode = 1; player_one_wins = 0; player_two_wins = 0; cur_pixel = 0; cur_pong_delay = pong_init_delay; +} + +void switch_to_pong_mode(){ + reset_pong_vars(); + + stripe_mode = 1; for (int i = 0; i< NUM_LEDS; i++){ leds[i] = CRGB::Black; @@ -557,7 +575,7 @@ void switchToPongMode(){ delay(1000); } -void displayResult(float cur_delay){ +void display_result(float cur_delay){ delay(500); for (int i = 0; i< NUM_LEDS; i++){ leds[i] = CRGB::Black; @@ -596,7 +614,7 @@ void loop() { Serial.println("Button two pressed."); if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ Serial.println("Switching to pong mode."); - switchToPongMode(); + switch_to_pong_mode(); } else { Serial.println(btn_two_last_pressed); Serial.println(btn_one_last_pressed); @@ -653,10 +671,21 @@ void loop() { player_two_wins += 1; if(player_two_wins >= pong_max_wins){ stripe_mode = 0; - displayResult(pong_wins_delay_after); + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + if (publish_results_at_display == 1){ + reset_pong_vars(); + publish_results(); + } + toggle_leds(0); } else { - displayResult(pong_wins_delay_during); + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); cur_pixel = 0; reverseMode = 0; cur_pong_delay = pong_init_delay; @@ -685,14 +714,24 @@ void loop() { player_one_wins += 1; if(player_one_wins >= pong_max_wins){ stripe_mode = 0; - displayResult(pong_wins_delay_after); + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + if (publish_results_at_display == 1){ + reset_pong_vars(); + publish_results(); + } toggle_leds(0); btn_two_state = 0; btn_one_state = 0; player_successfull_one_press = 0; player_successfull_two_press = 0; } else { - displayResult(pong_wins_delay_during); + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); cur_pixel = 0; reverseMode = 0; btn_two_state = 0; From 466896142f338165f0f57e12f33b8fac6ef95c16 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Mon, 26 Apr 2021 11:42:43 +0200 Subject: [PATCH 09/40] removed debug output in ESP32 example --- .../ESP32LedStripWithPongAndMqtt.ino | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index 614f918..6de3ab3 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -616,9 +616,6 @@ void loop() { Serial.println("Switching to pong mode."); switch_to_pong_mode(); } else { - Serial.println(btn_two_last_pressed); - Serial.println(btn_one_last_pressed); - Serial.println(pong_btn_delay); Serial.println("Toggling led stripe."); toggle_leds(-1); } From 13b7f36ebd3923d6f81a240d0647f240306a2436 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Mon, 26 Apr 2021 11:44:20 +0200 Subject: [PATCH 10/40] Added an example which uses an Heltec Wifi-Kit 8 (ESP8266 with OLED and Battery controller) board to connect an button, send clicks via MQTT and display the pong results on the oled; --- .../MQTTButtonOnEsp8266.ino | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino diff --git a/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino b/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino new file mode 100644 index 0000000..c0af3c4 --- /dev/null +++ b/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino @@ -0,0 +1,200 @@ +#include +#include +#include +#include + +#define BTN_DEBOUNCE_DELAY 500 +#define DISPLAY_TIME_AFTER_LAST_ACTION 30000 +#define DISPLAY_REFRESH_INTERVAL 1000 +#define RESULT_STRING_SIZE 10 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* MQTT_BROKER = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* MQTT_USER = "ENTER_MQTT_USERNAME_HERE"; +const char* MQTT_PASS = "ENTER_MQTT_PASSWORD_HERE"; +const String targetMsg = "1"; + + +const String clientName = "ESP_BTN"+targetMsg; +const String targetId = "raspled"; +const String targetBtnId = targetId+"/btn"; +const String targetResultId = targetId+"/results"; +char result_player_one[RESULT_STRING_SIZE] = "0"; +char result_player_two[RESULT_STRING_SIZE] = "0"; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +int btn_pin = 2; +bool btn_state = false; +long btn_last_pressed = 0; +long last_action = 0; +long display_last_refresh = 0; + +void publish_button_pressed(){ + client.publish(targetBtnId.c_str(), targetMsg.c_str()); +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.println(topic); + Serial.print("Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (String(topic) == targetResultId){ + StaticJsonDocument<256> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + + if (!err){ + Serial.println("Setting new results"); + last_action = millis(); + + char cstr[10]; + itoa(doc["result_player_one"].as(), cstr, RESULT_STRING_SIZE); + strlcpy(result_player_one, cstr, RESULT_STRING_SIZE); + + char cstr2[10]; + itoa(doc["result_player_two"].as(), cstr2, RESULT_STRING_SIZE); + strlcpy(result_player_two, cstr2, RESULT_STRING_SIZE); + } + } +} + +void ICACHE_RAM_ATTR btn_pressed(){ + long cur_time = millis(); + if((cur_time - btn_last_pressed) > BTN_DEBOUNCE_DELAY){ + btn_last_pressed = cur_time; + last_action = cur_time; + btn_state = true; + } +} + +void setup() { + client.setBufferSize(256); + Serial.begin(115200); + + Heltec.begin(); + Heltec.display->clear(); + + Heltec.display->setContrast(255); + Heltec.display->setFont(ArialMT_Plain_24); + Heltec.display->display(); + + setup_wifi(); + client.setServer(MQTT_BROKER, 1883); + reconnect(); + client.setCallback(callback); + + pinMode(digitalPinToInterrupt(btn_pin), INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(btn_pin), btn_pressed, FALLING); + display_results(); + delay(50); +} + +void display_results(){ + Heltec.display->clear(); + Heltec.display->setFont(ArialMT_Plain_10); + Heltec.display->drawString(0,0,targetMsg); + Heltec.display->drawString(50,0,"Results"); + Heltec.display->setFont(ArialMT_Plain_24); + Heltec.display->drawString(30,10,result_player_one); + Heltec.display->drawString(65,10,":"); + Heltec.display->drawString(90,10,result_player_two); + Heltec.display->display(); +} + +void setup_wifi() { + WiFi.disconnect(); + WiFi.mode(WIFI_OFF); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(clientName.c_str(), MQTT_USER, MQTT_PASS)) { + Serial.println("connected"); + // Subscribe + Serial.println("Subscribing for topicId: "+targetResultId); + client.subscribe((targetResultId).c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void loop() { + boolean display_cleared = false; + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (btn_state == 1){ + Serial.println("Sending button press"); + publish_button_pressed(); + btn_state = false; + } + + //DISPLAY_REFRESH_INTERVAL + //display_last_refresh + long cur_time = millis(); + if ((cur_time - last_action) <= DISPLAY_TIME_AFTER_LAST_ACTION) { + if ((cur_time - display_last_refresh) > DISPLAY_REFRESH_INTERVAL) { + display_results(); + display_cleared = false; + display_last_refresh = cur_time; + } + } else { + if (!display_cleared){ + Heltec.display->clear(); + Heltec.display->display(); + display_cleared = true; + } + } +} From ce9c95eaa47cbe227ec474503bd324e60bae51ea Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Mon, 26 Apr 2021 12:45:25 +0200 Subject: [PATCH 11/40] added an option to disable the hardware buttons via MQTT to the ESP32 example --- .../ESP32LedStripWithPongAndMqtt.ino | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index 6de3ab3..0e7ac66 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -58,6 +58,7 @@ int btn_one_state = 0; long btn_one_last_pressed = 0; int btn_two_state = 0; long btn_two_last_pressed = 0; +int disable_hardware_btns = 0; int color_r = 255; @@ -346,7 +347,23 @@ void callback(char* topic, byte* message, unsigned int length) { color_b = messageTemp.toInt(); } else if (String(topic) == topicId+"/get_status"){ publish_current_status(); - } + } else if (String(topic) == topicId+"/disable_btns"){ + if (messageTemp.toInt() == 1){ + if (disable_hardware_btns != 1){ + disable_hardware_btns = 1; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (disable_hardware_btns != 0){ + disable_hardware_btns = 0; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, FALLING); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, FALLING); + Serial.println("Enable Hardware Buttons"); + } + } + } fixConfigValues(); @@ -494,6 +511,7 @@ void reconnect() { client.subscribe((topicId+"/color/g").c_str()); client.subscribe((topicId+"/color/b").c_str()); client.subscribe((topicId+"/btn").c_str()); + client.subscribe((topicId+"/disable_btns").c_str()); } else { Serial.print("failed, rc="); Serial.print(client.state()); From a9c5876f9ce858a15a467fdb170a25f83ca67b52 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Mon, 26 Apr 2021 14:51:24 +0200 Subject: [PATCH 12/40] fixed button state not being resetted after a missed led during pong mode in ESP32 example --- .../ESP32LedStripWithPongAndMqtt.ino | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index 0e7ac66..6b0289a 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -696,6 +696,10 @@ void loop() { } toggle_leds(0); + btn_two_state = 0; + btn_one_state = 0; + player_successfull_one_press = 0; + player_successfull_two_press = 0; } else { if (publish_results_at_display == 1){ publish_results(); @@ -703,6 +707,10 @@ void loop() { display_result(pong_wins_delay_during); cur_pixel = 0; reverseMode = 0; + btn_two_state = 0; + btn_one_state = 0; + player_successfull_one_press = 0; + player_successfull_two_press = 0; cur_pong_delay = pong_init_delay; } } From c632e6cc5f2bb4014a33bd11ccb3b2d2d3525e2f Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 27 Apr 2021 09:05:46 +0200 Subject: [PATCH 13/40] modified ESP32 example to fetch all messages before resetting state in pong mode; Otherwhise button presses could be cached and lead to wrong results; modified ESP32 example to activate pong mode by pressing the two buttons within a specific delay in arbitrary order; --- .../ESP32LedStripWithPongAndMqtt.ino | 86 +++++++++++-------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index 6b0289a..d912325 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -87,12 +87,17 @@ int player_one_wins = 0; int player_successfull_one_press = 0; int player_two_wins = 0; int player_successfull_two_press = 0; +int player_one_miss = 0; +int player_two_miss = 0; +int abortRun = 0; +bool player_one_hit_first = true; int publish_status_after_every_config_change = 1; int publish_status_if_toggled = 1; int publish_status_at_start = 1; int publish_results_at_display = 1; + void publish_current_status(){ StaticJsonDocument<1024> doc; if (client.connected()){ @@ -557,17 +562,38 @@ void toggle_leds(int to_state){ } } -void reset_pong_vars(){ +void reset_pong_vars(bool during, bool oneHitFirst){ + Serial.print("Resetting pong vars ("); + Serial.print(during); + Serial.print("/"); + Serial.print(oneHitFirst); + Serial.println(")"); + client.loop(); + player_one_miss = 0; + player_two_miss = 0; btn_one_state = 0; btn_two_state = 0; - player_one_wins = 0; - player_two_wins = 0; - cur_pixel = 0; + player_successfull_one_press = 0; + player_successfull_two_press = 0; cur_pong_delay = pong_init_delay; + + if (!during){ + player_one_wins = 0; + player_two_wins = 0; + } + + if (oneHitFirst){ + cur_pixel = 0; + reverseMode = 0; + } else { + cur_pixel = num_pong_leds-1; + reverseMode = 1; + } } -void switch_to_pong_mode(){ - reset_pong_vars(); +void switch_to_pong_mode(bool oneHitFirst){ + Serial.println("Switching to pong mode"); + reset_pong_vars(false, oneHitFirst); stripe_mode = 1; @@ -594,6 +620,7 @@ void switch_to_pong_mode(){ } void display_result(float cur_delay){ + Serial.println("Displaying results"); delay(500); for (int i = 0; i< NUM_LEDS; i++){ leds[i] = CRGB::Black; @@ -628,11 +655,12 @@ void loop() { if (stripe_mode == 0){ if ((btn_one_state == 1) or (btn_two_state == 1)){ if (btn_two_state == 1){ + player_one_hit_first = true; btn_two_state = 0; Serial.println("Button two pressed."); if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ Serial.println("Switching to pong mode."); - switch_to_pong_mode(); + switch_to_pong_mode(player_one_hit_first); } else { Serial.println("Toggling led stripe."); toggle_leds(-1); @@ -640,9 +668,15 @@ void loop() { } if (btn_one_state == 1){ + player_one_hit_first = false; btn_one_state = 0; - Serial.println("Button one pressed. Toggling led stripe."); - toggle_leds(-1); + if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Button one pressed. Toggling led stripe."); + toggle_leds(-1); + } } } else { if((millis() - last_refresh) > REFRESH_INTERVAL){ @@ -662,9 +696,9 @@ void loop() { FastLED.show(); delay(cur_pong_delay*1000); - - int abortRun = 0; - int player_one_miss = 0; + + abortRun = 0; + player_one_miss = 0; if (player_successfull_one_press == 0){ if(btn_one_state == 1){ @@ -690,16 +724,12 @@ void loop() { publish_results(); } display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); if (publish_results_at_display == 1){ - reset_pong_vars(); publish_results(); } toggle_leds(0); - btn_two_state = 0; - btn_one_state = 0; - player_successfull_one_press = 0; - player_successfull_two_press = 0; } else { if (publish_results_at_display == 1){ publish_results(); @@ -707,15 +737,11 @@ void loop() { display_result(pong_wins_delay_during); cur_pixel = 0; reverseMode = 0; - btn_two_state = 0; - btn_one_state = 0; - player_successfull_one_press = 0; - player_successfull_two_press = 0; - cur_pong_delay = pong_init_delay; + reset_pong_vars(true, player_one_hit_first); } } - int player_two_miss = 0; + player_two_miss = 0; if (player_successfull_two_press == 0){ if(btn_two_state == 1){ @@ -741,27 +767,17 @@ void loop() { publish_results(); } display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); if (publish_results_at_display == 1){ - reset_pong_vars(); publish_results(); } toggle_leds(0); - btn_two_state = 0; - btn_one_state = 0; - player_successfull_one_press = 0; - player_successfull_two_press = 0; } else { if (publish_results_at_display == 1){ publish_results(); } display_result(pong_wins_delay_during); - cur_pixel = 0; - reverseMode = 0; - btn_two_state = 0; - btn_one_state = 0; - player_successfull_one_press = 0; - player_successfull_two_press = 0; - cur_pong_delay = pong_init_delay; + reset_pong_vars(true, player_one_hit_first); } } From b2def4fda47a5dae064a887ef136f326b83149eb Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 27 Apr 2021 10:11:38 +0200 Subject: [PATCH 14/40] added option to change the starting position of the pong running light after each run during a match --- .../ESP32LedStripWithPongAndMqtt.ino | 145 ++++++++++-------- 1 file changed, 77 insertions(+), 68 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index d912325..96e29cf 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -17,7 +17,7 @@ #include #include -#define MAX_LEDS 300 +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. #define NUM_LEDS 300 #define NUM_PONG_LEDS 10 #define DATA_PIN 14 @@ -38,11 +38,11 @@ CRGB leds[MAX_LEDS]; const char* SSID = "ENTER_WIFI_SSID_HERE"; const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* MQTT_BROKER = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* MQTT_USER = "ENTER_MQTT_USERNAME_HERE"; -const char* MQTT_PASS = "ENTER_MQTT_PASSWORD_HERE"; -const String clientName = "ESP_LED"; -const String topicId = "esp_led"; +const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const String client_name = "ESP_LED"; +const String topic_id = "esp_led"; WiFiClient espClient; PubSubClient client(espClient); @@ -91,6 +91,7 @@ int player_one_miss = 0; int player_two_miss = 0; int abortRun = 0; bool player_one_hit_first = true; +bool change_start_led_during_match = true; int publish_status_after_every_config_change = 1; int publish_status_if_toggled = 1; @@ -125,7 +126,7 @@ void publish_current_status(){ char buffer[1024]; size_t n = serializeJson(doc, buffer); - client.publish((topicId+"/status").c_str(), buffer, n); + client.publish((topic_id+"/status").c_str(), buffer, n); } } @@ -138,7 +139,7 @@ void publish_results(){ char buffer[100]; size_t n = serializeJson(doc, buffer); - client.publish((topicId+"/results").c_str(), buffer, n); + client.publish((topic_id+"/results").c_str(), buffer, n); } void fixConfigValues(){ @@ -158,8 +159,8 @@ void fixConfigValues(){ pong_dec_per_run = 0; } - if (num_pong_leds > MAX_LEDS){ - num_pong_leds = MAX_LEDS; + if (num_pong_leds > NUM_LEDS){ + num_pong_leds = NUM_LEDS; } if (pong_max_wins > num_pong_leds){ @@ -249,10 +250,10 @@ void callback(char* topic, byte* message, unsigned int length) { } Serial.println(); - if (! (String(topic) == topicId+"/btn") ) { + if (! (String(topic) == topic_id+"/btn") ) { // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". // Changes the output state according to the message - if (String(topic) == topicId+"/output") { + if (String(topic) == topic_id+"/output") { Serial.print("Changing output to "); if(messageTemp == "on"){ Serial.println("on"); @@ -265,7 +266,7 @@ void callback(char* topic, byte* message, unsigned int length) { Serial.println("toggle"); toggle_leds(-1); } - } else if (String(topic) == topicId+"/config"){ + } else if (String(topic) == topic_id+"/config"){ StaticJsonDocument<1024> doc; DeserializationError err = deserializeJson(doc, messageTemp); int cur_int_tmp_value = -1; @@ -314,45 +315,45 @@ void callback(char* topic, byte* message, unsigned int length) { color_b = doc["color_b"] | color_b; } - } else if (String(topic) == topicId+"/pong/btn_delay"){ + } else if (String(topic) == topic_id+"/pong/btn_delay"){ pong_btn_delay = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/init_delay"){ + } else if (String(topic) == topic_id+"/pong/init_delay"){ pong_init_delay = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/min_delay"){ + } else if (String(topic) == topic_id+"/pong/min_delay"){ pong_min_delay = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/dec_per_run"){ + } else if (String(topic) == topic_id+"/pong/dec_per_run"){ pong_dec_per_run = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/num_leds"){ + } else if (String(topic) == topic_id+"/pong/num_leds"){ num_pong_leds = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/max_wins"){ + } else if (String(topic) == topic_id+"/pong/max_wins"){ pong_max_wins = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/result/delay/during"){ + } else if (String(topic) == topic_id+"/pong/result/delay/during"){ pong_wins_delay_during = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/result/delay/after"){ + } else if (String(topic) == topic_id+"/pong/result/delay/after"){ pong_wins_delay_after = messageTemp.toFloat(); - } else if (String(topic) == topicId+"/pong/result/color/r"){ + } else if (String(topic) == topic_id+"/pong/result/color/r"){ pong_result_color_r = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/result/color/g"){ + } else if (String(topic) == topic_id+"/pong/result/color/g"){ pong_result_color_g = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/result/color/b"){ + } else if (String(topic) == topic_id+"/pong/result/color/b"){ pong_result_color_b = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/tolerance"){ + } else if (String(topic) == topic_id+"/pong/tolerance"){ pong_tolerance = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/color/r"){ + } else if (String(topic) == topic_id+"/pong/color/r"){ pong_color_r = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/color/g"){ + } else if (String(topic) == topic_id+"/pong/color/g"){ pong_color_g = messageTemp.toInt(); - } else if (String(topic) == topicId+"/pong/color/b"){ + } else if (String(topic) == topic_id+"/pong/color/b"){ pong_color_b = messageTemp.toInt(); - } else if (String(topic) == topicId+"/color/r"){ + } else if (String(topic) == topic_id+"/color/r"){ color_r = messageTemp.toInt(); - } else if (String(topic) == topicId+"/color/g"){ + } else if (String(topic) == topic_id+"/color/g"){ color_g = messageTemp.toInt(); - } else if (String(topic) == topicId+"/color/b"){ + } else if (String(topic) == topic_id+"/color/b"){ color_b = messageTemp.toInt(); - } else if (String(topic) == topicId+"/get_status"){ + } else if (String(topic) == topic_id+"/get_status"){ publish_current_status(); - } else if (String(topic) == topicId+"/disable_btns"){ + } else if (String(topic) == topic_id+"/disable_btns"){ if (messageTemp.toInt() == 1){ if (disable_hardware_btns != 1){ disable_hardware_btns = 1; @@ -372,8 +373,8 @@ void callback(char* topic, byte* message, unsigned int length) { fixConfigValues(); - if ((String(topic) != topicId+"/output") && - (String(topic) != topicId+"/get_status") && + if ((String(topic) != topic_id+"/output") && + (String(topic) != topic_id+"/get_status") && (stripe_mode == 0)){ if (stripe_on){ toggle_leds(1); @@ -402,7 +403,7 @@ void setup() { client.setBufferSize(512); Serial.begin(115200); setup_wifi(); - client.setServer(MQTT_BROKER, 1883); + client.setServer(mqtt_broker, 1883); reconnect(); client.setCallback(callback); @@ -417,7 +418,7 @@ void setup() { FastLED.show(); FastLED.show(); delay(50); - for (int i=0; i < MAX_LEDS; i++){ + for (int i=0; i < NUM_LEDS; i++){ leds[i] = CRGB::White; } FastLED.show(); @@ -489,34 +490,34 @@ void reconnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect - if (client.connect(clientName.c_str(), MQTT_USER, MQTT_PASS)) { + if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { Serial.println("connected"); // Subscribe - Serial.print("Subscribing with topicId: "); - Serial.println(topicId); - client.subscribe((topicId+"/get_status").c_str()); - client.subscribe((topicId+"/config").c_str()); - client.subscribe((topicId+"/output").c_str()); - client.subscribe((topicId+"/pong/btn_delay").c_str()); - client.subscribe((topicId+"/pong/init_delay").c_str()); - client.subscribe((topicId+"/pong/min_delay").c_str()); - client.subscribe((topicId+"/pong/dec_per_run").c_str()); - client.subscribe((topicId+"/pong/num_leds").c_str()); - client.subscribe((topicId+"/pong/max_wins").c_str()); - client.subscribe((topicId+"/pong/result/delay/during").c_str()); - client.subscribe((topicId+"/pong/result/delay/after").c_str()); - client.subscribe((topicId+"/pong/result/color/r").c_str()); - client.subscribe((topicId+"/pong/result/color/g").c_str()); - client.subscribe((topicId+"/pong/result/color/b").c_str()); - client.subscribe((topicId+"/pong/tolerance").c_str()); - client.subscribe((topicId+"/pong/color/r").c_str()); - client.subscribe((topicId+"/pong/color/g").c_str()); - client.subscribe((topicId+"/pong/color/b").c_str()); - client.subscribe((topicId+"/color/r").c_str()); - client.subscribe((topicId+"/color/g").c_str()); - client.subscribe((topicId+"/color/b").c_str()); - client.subscribe((topicId+"/btn").c_str()); - client.subscribe((topicId+"/disable_btns").c_str()); + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + client.subscribe((topic_id+"/get_status").c_str()); + client.subscribe((topic_id+"/config").c_str()); + client.subscribe((topic_id+"/output").c_str()); + client.subscribe((topic_id+"/pong/btn_delay").c_str()); + client.subscribe((topic_id+"/pong/init_delay").c_str()); + client.subscribe((topic_id+"/pong/min_delay").c_str()); + client.subscribe((topic_id+"/pong/dec_per_run").c_str()); + client.subscribe((topic_id+"/pong/num_leds").c_str()); + client.subscribe((topic_id+"/pong/max_wins").c_str()); + client.subscribe((topic_id+"/pong/result/delay/during").c_str()); + client.subscribe((topic_id+"/pong/result/delay/after").c_str()); + client.subscribe((topic_id+"/pong/result/color/r").c_str()); + client.subscribe((topic_id+"/pong/result/color/g").c_str()); + client.subscribe((topic_id+"/pong/result/color/b").c_str()); + client.subscribe((topic_id+"/pong/tolerance").c_str()); + client.subscribe((topic_id+"/pong/color/r").c_str()); + client.subscribe((topic_id+"/pong/color/g").c_str()); + client.subscribe((topic_id+"/pong/color/b").c_str()); + client.subscribe((topic_id+"/color/r").c_str()); + client.subscribe((topic_id+"/color/g").c_str()); + client.subscribe((topic_id+"/color/b").c_str()); + client.subscribe((topic_id+"/btn").c_str()); + client.subscribe((topic_id+"/disable_btns").c_str()); } else { Serial.print("failed, rc="); Serial.print(client.state()); @@ -549,7 +550,7 @@ void toggle_leds(int to_state){ } stripe_on = true; } else { - for (int i = 0; i< NUM_LEDS; i++){ + for (int i = 0; i< MAX_LEDS; i++){ leds[i] = CRGB::Black; } stripe_on = false; @@ -579,7 +580,9 @@ void reset_pong_vars(bool during, bool oneHitFirst){ if (!during){ player_one_wins = 0; - player_two_wins = 0; + player_two_wins = 0; + btn_one_last_pressed = 0; + btn_two_last_pressed = 0; } if (oneHitFirst){ @@ -597,7 +600,7 @@ void switch_to_pong_mode(bool oneHitFirst){ stripe_mode = 1; - for (int i = 0; i< NUM_LEDS; i++){ + for (int i = 0; i< MAX_LEDS; i++){ leds[i] = CRGB::Black; } FastLED.show(); @@ -611,7 +614,7 @@ void switch_to_pong_mode(bool oneHitFirst){ FastLED.show(); FastLED.show(); delay(1000); - for (int i = 0; i< NUM_LEDS; i++){ + for (int i = 0; i< MAX_LEDS; i++){ leds[i] = CRGB::Black; } FastLED.show(); @@ -622,7 +625,7 @@ void switch_to_pong_mode(bool oneHitFirst){ void display_result(float cur_delay){ Serial.println("Displaying results"); delay(500); - for (int i = 0; i< NUM_LEDS; i++){ + for (int i = 0; i< MAX_LEDS; i++){ leds[i] = CRGB::Black; } @@ -737,6 +740,9 @@ void loop() { display_result(pong_wins_delay_during); cur_pixel = 0; reverseMode = 0; + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } reset_pong_vars(true, player_one_hit_first); } } @@ -777,6 +783,9 @@ void loop() { publish_results(); } display_result(pong_wins_delay_during); + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } reset_pong_vars(true, player_one_hit_first); } } From 62502cf993652ec2e21ccd77b054a0229ac5e7da Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 27 Apr 2021 14:05:44 +0200 Subject: [PATCH 15/40] small changes in ESP32 example --- .../ESP32LedStripWithPongAndMqtt.ino | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index 96e29cf..69e78ca 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -583,6 +583,7 @@ void reset_pong_vars(bool during, bool oneHitFirst){ player_two_wins = 0; btn_one_last_pressed = 0; btn_two_last_pressed = 0; + stripe_mode = 0; } if (oneHitFirst){ @@ -722,7 +723,6 @@ void loop() { abortRun = 1; player_two_wins += 1; if(player_two_wins >= pong_max_wins){ - stripe_mode = 0; if (publish_results_at_display == 1){ publish_results(); } @@ -730,8 +730,7 @@ void loop() { reset_pong_vars(false, player_one_hit_first); if (publish_results_at_display == 1){ publish_results(); - } - + } toggle_leds(0); } else { if (publish_results_at_display == 1){ @@ -768,7 +767,6 @@ void loop() { abortRun = 1; player_one_wins += 1; if(player_one_wins >= pong_max_wins){ - stripe_mode = 0; if (publish_results_at_display == 1){ publish_results(); } From 66c259b13377c92e39a0da86c1a80bc51c65c44a Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 27 Apr 2021 15:52:21 +0200 Subject: [PATCH 16/40] added new example of an button sending data via MQTT connected to a ESP8266 controller. If an maximum interval is reached the controller changes into deep sleep mode; --- .../MQTTButtonOnEsp8266DeepSleep.ino | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino diff --git a/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino b/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino new file mode 100644 index 0000000..9f03e84 --- /dev/null +++ b/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino @@ -0,0 +1,211 @@ +#include +#include +#include +#include + +#define BTN_DEBOUNCE_DELAY 500 +#define DISPLAY_TIME_AFTER_LAST_ACTION 30000 +#define DEEP_SLEEP_AFTER_LAST_ACTION 60000 +#define DISPLAY_REFRESH_INTERVAL 1000 +#define RESULT_STRING_SIZE 10 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* MQTT_BROKER = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* MQTT_USER = "ENTER_MQTT_USERNAME_HERE"; +const char* MQTT_PASS = "ENTER_MQTT_PASSWORD_HERE"; +const String targetMsg = "1"; + + +const String clientName = "ESP_BTN"+targetMsg; +const String targetId = "raspled"; +const String targetBtnId = targetId+"/btn"; +const String targetResultId = targetId+"/results"; +char result_player_one[RESULT_STRING_SIZE] = "0"; +char result_player_two[RESULT_STRING_SIZE] = "0"; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +int btn_pin = 2; +bool btn_state = false; +long btn_last_pressed = 0; +long last_action = 0; +long display_last_refresh = 0; + +void publish_button_pressed(){ + client.publish(targetBtnId.c_str(), targetMsg.c_str()); +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.println(topic); + Serial.print("Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (String(topic) == targetResultId){ + StaticJsonDocument<256> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + + if (!err){ + Serial.println("Setting new results"); + last_action = millis(); + + char cstr[10]; + itoa(doc["result_player_one"].as(), cstr, RESULT_STRING_SIZE); + strlcpy(result_player_one, cstr, RESULT_STRING_SIZE); + + char cstr2[10]; + itoa(doc["result_player_two"].as(), cstr2, RESULT_STRING_SIZE); + strlcpy(result_player_two, cstr2, RESULT_STRING_SIZE); + } + } +} + +void ICACHE_RAM_ATTR btn_pressed(){ + long cur_time = millis(); + if((cur_time - btn_last_pressed) > BTN_DEBOUNCE_DELAY){ + btn_last_pressed = cur_time; + last_action = cur_time; + btn_state = true; + } +} + +void setup() { + client.setBufferSize(256); + Serial.begin(115200); + + Heltec.begin(); + Heltec.display->clear(); + + Heltec.display->setContrast(255); + Heltec.display->setFont(ArialMT_Plain_24); + Heltec.display->display(); + + setup_wifi(); + client.setServer(MQTT_BROKER, 1883); + reconnect(); + client.setCallback(callback); + + pinMode(digitalPinToInterrupt(btn_pin), INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(btn_pin), btn_pressed, FALLING); + display_results(); + delay(50); +} + +void display_results(){ + Heltec.display->clear(); + Heltec.display->setFont(ArialMT_Plain_10); + Heltec.display->drawString(0,0,targetMsg); + Heltec.display->drawString(50,0,"Results"); + Heltec.display->setFont(ArialMT_Plain_24); + Heltec.display->drawString(30,10,result_player_one); + Heltec.display->drawString(65,10,":"); + Heltec.display->drawString(90,10,result_player_two); + Heltec.display->display(); +} + +void setup_wifi() { + WiFi.disconnect(); + WiFi.mode(WIFI_OFF); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(clientName.c_str(), MQTT_USER, MQTT_PASS)) { + Serial.println("connected"); + // Subscribe + Serial.println("Subscribing for topicId: "+targetResultId); + client.subscribe((targetResultId).c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void loop() { + boolean display_cleared = false; + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (btn_state == 1){ + Serial.println("Sending button press"); + publish_button_pressed(); + btn_state = false; + } + + //DISPLAY_REFRESH_INTERVAL + //display_last_refresh + long cur_time = millis(); + if ((cur_time - last_action) <= DISPLAY_TIME_AFTER_LAST_ACTION) { + if ((cur_time - display_last_refresh) > DISPLAY_REFRESH_INTERVAL) { + display_results(); + display_cleared = false; + display_last_refresh = cur_time; + } + } else { + if (!display_cleared){ + Heltec.display->clear(); + Heltec.display->display(); + display_cleared = true; + } + } + + if ((cur_time - last_action) > DEEP_SLEEP_AFTER_LAST_ACTION){ + startDeepSleep(0); + } +} + +void startDeepSleep(long wakeUpInterval){ + Serial.println("Going to deep sleep..."); + ESP.deepSleep(wakeUpInterval); + yield(); +} From 51d672c22ed2e1b5601a29fb2000999bb3630a99 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 27 Apr 2021 16:32:51 +0200 Subject: [PATCH 17/40] added option to display a button to disable/enable the hardware buttons of the led strip --- MMM-LEDStripControl.js | 50 +++++++++++++++++++++++++++++++++++++++++- ledstripcontrol.css | 4 ++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/MMM-LEDStripControl.js b/MMM-LEDStripControl.js index 23d224f..a289cf9 100644 --- a/MMM-LEDStripControl.js +++ b/MMM-LEDStripControl.js @@ -13,8 +13,11 @@ Module.register('MMM-LEDStripControl', { showNormalColorOptions: true, showPongColorOptions: true, showColorIndicators: true, + showHardwareBtnDisabler: false, outputOnIcon: "fa fa-lightbulb-o", outputOffIcon: "fa fa-lightbulb-o", + hdwBtnEnabledIcon: "fa fa-lock", + hdwBtnDisabledIcon: "fa fa-unlock", upIcon: "fa fa-angle-up", upFastIcon: "fa fa-angle-double-up", downIcon: "fa fa-angle-down", @@ -227,6 +230,29 @@ Module.register('MMM-LEDStripControl', { wrapper.append(self.getOptionsDomObject("Pong Delay", pDelayOptionsElements, "lsc-pdelay")) } + if (self.config.showHardwareBtnDisabler){ + let hdwBtnWrapper = document.createElement('div') + hdwBtnWrapper.className = "lsc-hdwBtnWrapper "+self.instanceCssClass + let hdwBtnIcon = document.createElement('i') + if(self.curValues["hdwBtn"].value == true){ + hdwBtnIcon.className = self.config.hdwBtnEnabledIcon + " lsc-icon lsc-hdwBtn lsc-hdwBtn-disabled "+self.instanceCssClass + } else { + hdwBtnIcon.className = self.config.hdwBtnDisabledIcon + " lsc-icon lsc-hdwBtn lsc-hdwBtn-enabled "+self.instanceCssClass + } + + if (self.curValues["hdwBtn"].selected == true){ + hdwBtnIcon.className += " lsc-selected" + } else { + hdwBtnIcon.className += " lsc-unselected" + } + self.curValues["hdwBtn"].obj = hdwBtnIcon + hdwBtnIcon.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"],{"element":"hdwBtn"})}) + self.elements.push("hdwBtn") + + hdwBtnWrapper.appendChild(hdwBtnIcon) + wrapper.appendChild(hdwBtnWrapper) + } + return wrapper; }, @@ -240,6 +266,8 @@ Module.register('MMM-LEDStripControl', { self.curValues = { "output" : {"value":false, "selected": true, "obj" : null}, + "hdwBtn" : {"value":false, "obj" : null}, + "color_r" : {"value":255, "step_u": 5, "step_d": 5, "step_u_f": 15, "step_d_f": 15, "min": 0, "max": 255, "selected": false, "obj" : null}, "color_g" : {"value":255, "step_u": 5, "step_d": 5, "step_u_f": 15, "step_d_f": 15, "min": 0, "max": 255, "selected": false, "obj" : null}, "color_b" : {"value":255, "step_u": 5, "step_d": 5, "step_u_f": 15, "step_d_f": 15, "min": 0, "max": 255, "selected": false, "obj" : null}, @@ -282,6 +310,7 @@ Module.register('MMM-LEDStripControl', { "LED_STRIP_CONTROL_NEXT_ELEMENT": "LED_STRIP_CONTROL_NEXT_ELEMENT_"+self.config.instance, "LED_STRIP_CONTROL_PREVIOUS_ELEMENT": "LED_STRIP_CONTROL_PREVIOUS_ELEMENT_"+self.config.instance, "LED_STRIP_CONTROL_CURRENT_CONFIG": "LED_STRIP_CONTROL_CURRENT_CONFIG_"+self.config.instance, + "LED_STRIP_CONTROL_HDWBTN": "LED_STRIP_CONTROL_HDWBTN_"+self.config.instance, } } else { self.notifications = { @@ -294,6 +323,7 @@ Module.register('MMM-LEDStripControl', { "LED_STRIP_CONTROL_NEXT_ELEMENT": "LED_STRIP_CONTROL_NEXT_ELEMENT", "LED_STRIP_CONTROL_PREVIOUS_ELEMENT": "LED_STRIP_CONTROL_PREVIOUS_ELEMENT", "LED_STRIP_CONTROL_CURRENT_CONFIG": "LED_STRIP_CONTROL_CURRENT_CONFIG", + "LED_STRIP_CONTROL_HDWBTN": "LED_STRIP_CONTROL_HDWBTN", } } @@ -411,6 +441,15 @@ Module.register('MMM-LEDStripControl', { self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "off") } + } else if (self.elements[self.selectedElement] === "hdwBtn"){ + if(self.curValues[self.elements[self.selectedElement]].value == true){ + console.log(self.name+": "+"Disable hdw buttons") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_HDWBTN"], "1") + } else { + console.log(self.name+": "+"Enable hdw buttons") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_HDWBTN"], "0") + } + } else { self.sendConfigurationNotification() } @@ -465,6 +504,15 @@ Module.register('MMM-LEDStripControl', { self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "off") } + } else if (self.elements[self.selectedElement] === "hdwBtn"){ + if(self.curValues[self.elements[self.selectedElement]].value == true){ + console.log(self.name+": "+"Disable hdw buttons") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_HDWBTN"], "1") + } else { + console.log(self.name+": "+"Enable hdw buttons") + self.sendNotification(self.notifications["LED_STRIP_CONTROL_HDWBTN"], "0") + } + } else { self.sendConfigurationNotification() } @@ -497,7 +545,7 @@ Module.register('MMM-LEDStripControl', { } } else { - if(curName !== "output"){ + if((curName !== "output") && (curName !== "hdwBtn")){ if (typeof self.curValues[curName].fractions !== "undefined"){ curConfigArray[curName] = Number.parseFloat(self.curValues[curName].value).toFixed(self.curValues[curName].fractions) } else { diff --git a/ledstripcontrol.css b/ledstripcontrol.css index 03cef70..8d5fa9e 100644 --- a/ledstripcontrol.css +++ b/ledstripcontrol.css @@ -12,6 +12,10 @@ padding: 5px; } +.lsc-hdwbtn.lsc-icon{ + padding: 5px; +} + .lsc-color-header, .lsc-options-header { font-size: 20px; } From cfd3ba3ba9f5d51e8d55698e225bcda269a33b09 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 27 Apr 2021 21:12:12 +0200 Subject: [PATCH 18/40] reworked the option to enable/disable the hardware buttons. Now the option is send in the "normal" config and not as an separate topic. reworked the option of disabling the hardware buttons in the ESP32 example. --- MMM-LEDStripControl.js | 57 +++++++------------ README.md | 3 + .../ESP32LedStripWithPongAndMqtt.ino | 36 +++++++++--- ledstripcontrol.css | 2 +- 4 files changed, 52 insertions(+), 46 deletions(-) diff --git a/MMM-LEDStripControl.js b/MMM-LEDStripControl.js index a289cf9..87bddc8 100644 --- a/MMM-LEDStripControl.js +++ b/MMM-LEDStripControl.js @@ -13,11 +13,11 @@ Module.register('MMM-LEDStripControl', { showNormalColorOptions: true, showPongColorOptions: true, showColorIndicators: true, - showHardwareBtnDisabler: false, + showHardwareButtonOption: false, outputOnIcon: "fa fa-lightbulb-o", outputOffIcon: "fa fa-lightbulb-o", - hdwBtnEnabledIcon: "fa fa-lock", - hdwBtnDisabledIcon: "fa fa-unlock", + hdwBtnEnabledIcon: "fa fa-link", + hdwBtnDisabledIcon: "fa fa-chain-broken", upIcon: "fa fa-angle-up", upFastIcon: "fa fa-angle-double-up", downIcon: "fa fa-angle-down", @@ -230,24 +230,24 @@ Module.register('MMM-LEDStripControl', { wrapper.append(self.getOptionsDomObject("Pong Delay", pDelayOptionsElements, "lsc-pdelay")) } - if (self.config.showHardwareBtnDisabler){ + if (self.config.showHardwareButtonOption){ let hdwBtnWrapper = document.createElement('div') - hdwBtnWrapper.className = "lsc-hdwBtnWrapper "+self.instanceCssClass + hdwBtnWrapper.className = "lsc-hdwBtnWrapper "+self.instanceCssClass let hdwBtnIcon = document.createElement('i') - if(self.curValues["hdwBtn"].value == true){ - hdwBtnIcon.className = self.config.hdwBtnEnabledIcon + " lsc-icon lsc-hdwBtn lsc-hdwBtn-disabled "+self.instanceCssClass + if(self.curValues["hardware_buttons_enabled"].value == true){ + hdwBtnIcon.className = self.config.hdwBtnEnabledIcon + " lsc-icon lsc-hdwBtn lsc-hdwBtn-enabled "+self.instanceCssClass } else { - hdwBtnIcon.className = self.config.hdwBtnDisabledIcon + " lsc-icon lsc-hdwBtn lsc-hdwBtn-enabled "+self.instanceCssClass + hdwBtnIcon.className = self.config.hdwBtnDisabledIcon + " lsc-icon lsc-hdwBtn lsc-hdwBtn-disabled "+self.instanceCssClass } - if (self.curValues["hdwBtn"].selected == true){ + if (self.curValues["hardware_buttons_enabled"].selected == true){ hdwBtnIcon.className += " lsc-selected" } else { hdwBtnIcon.className += " lsc-unselected" } - self.curValues["hdwBtn"].obj = hdwBtnIcon - hdwBtnIcon.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"],{"element":"hdwBtn"})}) - self.elements.push("hdwBtn") + self.curValues["hardware_buttons_enabled"].obj = hdwBtnIcon + hdwBtnIcon.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"],{"element":"hardware_buttons_enabled"})}) + self.elements.push("hardware_buttons_enabled") hdwBtnWrapper.appendChild(hdwBtnIcon) wrapper.appendChild(hdwBtnWrapper) @@ -266,7 +266,7 @@ Module.register('MMM-LEDStripControl', { self.curValues = { "output" : {"value":false, "selected": true, "obj" : null}, - "hdwBtn" : {"value":false, "obj" : null}, + "hardware_buttons_enabled" : {"value":true, "obj" : null}, "color_r" : {"value":255, "step_u": 5, "step_d": 5, "step_u_f": 15, "step_d_f": 15, "min": 0, "max": 255, "selected": false, "obj" : null}, "color_g" : {"value":255, "step_u": 5, "step_d": 5, "step_u_f": 15, "step_d_f": 15, "min": 0, "max": 255, "selected": false, "obj" : null}, @@ -441,15 +441,6 @@ Module.register('MMM-LEDStripControl', { self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "off") } - } else if (self.elements[self.selectedElement] === "hdwBtn"){ - if(self.curValues[self.elements[self.selectedElement]].value == true){ - console.log(self.name+": "+"Disable hdw buttons") - self.sendNotification(self.notifications["LED_STRIP_CONTROL_HDWBTN"], "1") - } else { - console.log(self.name+": "+"Enable hdw buttons") - self.sendNotification(self.notifications["LED_STRIP_CONTROL_HDWBTN"], "0") - } - } else { self.sendConfigurationNotification() } @@ -503,16 +494,6 @@ Module.register('MMM-LEDStripControl', { console.log(self.name+": "+"Switch the lights off") self.sendNotification(self.notifications["LED_STRIP_CONTROL_OUTPUT"], "off") } - - } else if (self.elements[self.selectedElement] === "hdwBtn"){ - if(self.curValues[self.elements[self.selectedElement]].value == true){ - console.log(self.name+": "+"Disable hdw buttons") - self.sendNotification(self.notifications["LED_STRIP_CONTROL_HDWBTN"], "1") - } else { - console.log(self.name+": "+"Enable hdw buttons") - self.sendNotification(self.notifications["LED_STRIP_CONTROL_HDWBTN"], "0") - } - } else { self.sendConfigurationNotification() } @@ -545,11 +526,15 @@ Module.register('MMM-LEDStripControl', { } } else { - if((curName !== "output") && (curName !== "hdwBtn")){ - if (typeof self.curValues[curName].fractions !== "undefined"){ - curConfigArray[curName] = Number.parseFloat(self.curValues[curName].value).toFixed(self.curValues[curName].fractions) + if(curName !== "output"){ + if (typeof self.curValues[curName] === "number"){ + if (typeof self.curValues[curName].fractions !== "undefined"){ + curConfigArray[curName] = Number.parseFloat(self.curValues[curName].value).toFixed(self.curValues[curName].fractions) + } else { + curConfigArray[curName] = Number.parseInt(self.curValues[curName].value) + } } else { - curConfigArray[curName] = Number.parseInt(self.curValues[curName].value) + curConfigArray[curName] = self.curValues[curName].value } } } diff --git a/README.md b/README.md index 6e3dd3a..df928ee 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,7 @@ If you like you can change some options: | showNormalColorOptions | Should the color options of the normal operating color be visible? | Boolean | true | | showPongColorOptions | Should the color options of the pong game be visible? | Boolean | true | | showPongOptions | Should the additional options of the pong game be visible? | Boolean | true | +| showHardwareButtonOption | Should an option to disable the hardware buttons be visible? | Boolean | false | | fetchStatusInterval | The script sends a request to get the current configuration of the strip at the startup and in regular intervals. Normally the strip should send the configuration every time it gets switched on or off. If you do not plan to change the color values with an other module than this one you can set this value to a high one. The unit is seconds. | Integer | 300 | | outputOnIcon | You may like to change the icon of the output state to a different one. This one will be displayed if the strip is switched on. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-lightbulb-o" | | outputOffIcon | You may like to change the icon of the output state to a different one. This one will be displayed if the strip is switched off. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-lightbulb-o" | @@ -144,6 +145,8 @@ If you like you can change some options: | upFastIcon | You may like to change the icon of the fast up symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-double-up" | | downIcon | You may like to change the icon of the down symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-down" | | downFastIcon | You may like to change the icon of fast down symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-double-down" | +| hdwBtnEnabledIcon | You may like to change the icon which is displayed if the hardware buttons are enabled. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-link" | +| hddwBtnDisabledIcon | You may like to change the icon which is displayed if the hardware buttons are disabled. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-chain-broken" | | instance | If you want to add more than one instance of this module please specify an instance number with this variable. All notifications will be suffixed with "_"+instance (i.e. "LED_STRIP_CONTROL_NEXT_ELEMENT_1") and each element gets an css class "lsc-"+instance. The instance with number 0 (default) will react to and sends notifications without suffix! | Integer | 0 | | instanceCssClass | All elements if this instance get this css class added. If you like to control the same strip but with two instances of the module (i.e. because you use the profile or pages module) you can leave the instance number as it is and only change the css stuff if you like (i.e. smaller module) | String | "lsc-"+instance (i.e. "lsc-0") | diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index 69e78ca..c58f5e2 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -58,7 +58,7 @@ int btn_one_state = 0; long btn_one_last_pressed = 0; int btn_two_state = 0; long btn_two_last_pressed = 0; -int disable_hardware_btns = 0; +bool enable_hardware_btns = true; int color_r = 255; @@ -100,6 +100,7 @@ int publish_results_at_display = 1; void publish_current_status(){ + Serial.println("Publishing current status"); StaticJsonDocument<1024> doc; if (client.connected()){ doc["pong"]["btn_delay"] = pong_btn_delay; @@ -122,6 +123,7 @@ void publish_current_status(){ doc["color_r"] = color_r; doc["color_g"] = color_g; doc["color_b"] = color_b; + doc["hardware_buttons_enabled"] = enable_hardware_btns; char buffer[1024]; @@ -269,9 +271,6 @@ void callback(char* topic, byte* message, unsigned int length) { } else if (String(topic) == topic_id+"/config"){ StaticJsonDocument<1024> doc; DeserializationError err = deserializeJson(doc, messageTemp); - int cur_int_tmp_value = -1; - float cur_float_tmp_value = -1; - boolean cur_bool_tmp_value = false; if (!err){ if(doc["pong"]["btn_delay"]){ @@ -313,6 +312,25 @@ void callback(char* topic, byte* message, unsigned int length) { color_r = doc["color_r"] | color_r; color_g = doc["color_g"] | color_g; color_b = doc["color_b"] | color_b; + + if (doc.containsKey("hardware_buttons_enabled")){ + if (!doc["hardware_buttons_enabled"]){ + if (enable_hardware_btns){ + enable_hardware_btns = false; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (!enable_hardware_btns){ + enable_hardware_btns = true; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, FALLING); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, FALLING); + Serial.println("Enable Hardware Buttons"); + } + } + } + } } else if (String(topic) == topic_id+"/pong/btn_delay"){ @@ -353,17 +371,17 @@ void callback(char* topic, byte* message, unsigned int length) { color_b = messageTemp.toInt(); } else if (String(topic) == topic_id+"/get_status"){ publish_current_status(); - } else if (String(topic) == topic_id+"/disable_btns"){ + } else if (String(topic) == topic_id+"/hardware_buttons_enabled"){ if (messageTemp.toInt() == 1){ - if (disable_hardware_btns != 1){ - disable_hardware_btns = 1; + if (enable_hardware_btns){ + enable_hardware_btns = false; detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); Serial.println("Disable Hardware Buttons"); } } else { - if (disable_hardware_btns != 0){ - disable_hardware_btns = 0; + if (!enable_hardware_btns){ + enable_hardware_btns = true; attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, FALLING); attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, FALLING); Serial.println("Enable Hardware Buttons"); diff --git a/ledstripcontrol.css b/ledstripcontrol.css index 8d5fa9e..b206cb2 100644 --- a/ledstripcontrol.css +++ b/ledstripcontrol.css @@ -12,7 +12,7 @@ padding: 5px; } -.lsc-hdwbtn.lsc-icon{ +.lsc-hdwBtn.lsc-icon{ padding: 5px; } From 8bc818731a88810b803d67d94a1f82fbce8111c1 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Wed, 28 Apr 2021 20:55:27 +0200 Subject: [PATCH 19/40] added an brightness option to the ESP32 example --- .../ESP32LedStripWithPongAndMqtt.ino | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index c58f5e2..c4f358e 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -61,6 +61,7 @@ long btn_two_last_pressed = 0; bool enable_hardware_btns = true; +int brightness = 255; int color_r = 255; int color_g = 255; int color_b = 255; @@ -120,6 +121,7 @@ void publish_current_status(){ doc["pong"]["result_color_b"] = pong_result_color_b; doc["output"] = stripe_on; doc["mode"] = stripe_mode; + doc["brightness"] = brightness; doc["color_r"] = color_r; doc["color_g"] = color_g; doc["color_b"] = color_b; @@ -238,6 +240,12 @@ void fixConfigValues(){ } else if (color_b < 0){ color_b = 0; } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } } void callback(char* topic, byte* message, unsigned int length) { @@ -313,6 +321,8 @@ void callback(char* topic, byte* message, unsigned int length) { color_g = doc["color_g"] | color_g; color_b = doc["color_b"] | color_b; + brightness = doc["brightness"] | brightness; + if (doc.containsKey("hardware_buttons_enabled")){ if (!doc["hardware_buttons_enabled"]){ if (enable_hardware_btns){ @@ -369,6 +379,8 @@ void callback(char* topic, byte* message, unsigned int length) { color_g = messageTemp.toInt(); } else if (String(topic) == topic_id+"/color/b"){ color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = messageTemp.toInt(); } else if (String(topic) == topic_id+"/get_status"){ publish_current_status(); } else if (String(topic) == topic_id+"/hardware_buttons_enabled"){ @@ -416,6 +428,12 @@ void callback(char* topic, byte* message, unsigned int length) { } } } + +void show(){ + FastLED.setBrightness(brightness); + FastLED.show(); + FastLED.show(); +} void setup() { client.setBufferSize(512); @@ -433,20 +451,17 @@ void setup() { for (int i=0; i < MAX_LEDS; i++){ leds[i] = CRGB::Black; } - FastLED.show(); - FastLED.show(); + show(); delay(50); for (int i=0; i < NUM_LEDS; i++){ leds[i] = CRGB::White; } - FastLED.show(); - FastLED.show(); + show(); delay(200); for (int i=0; i < MAX_LEDS; i++){ leds[i] = CRGB::Black; } - FastLED.show(); - FastLED.show(); + show(); pinMode(BTN_1_GPIO, INPUT); pinMode(BTN_2_GPIO, INPUT); @@ -574,8 +589,7 @@ void toggle_leds(int to_state){ stripe_on = false; } - FastLED.show(); - FastLED.show(); + show(); if (publish_status_if_toggled == 1){ publish_current_status(); } @@ -622,22 +636,19 @@ void switch_to_pong_mode(bool oneHitFirst){ for (int i = 0; i< MAX_LEDS; i++){ leds[i] = CRGB::Black; } - FastLED.show(); - FastLED.show(); + show(); delay(1000); for (int i = 0; i< num_pong_leds; i++){ leds[i].r = pong_color_r; leds[i].g = pong_color_g; leds[i].b = pong_color_b; } - FastLED.show(); - FastLED.show(); + show(); delay(1000); for (int i = 0; i< MAX_LEDS; i++){ leds[i] = CRGB::Black; } - FastLED.show(); - FastLED.show(); + show(); delay(1000); } @@ -659,8 +670,7 @@ void display_result(float cur_delay){ leds[i].g = pong_result_color_g; leds[i].b = pong_result_color_b; } - FastLED.show(); - FastLED.show(); + show(); delay(cur_delay*1000); } @@ -702,8 +712,7 @@ void loop() { } } else { if((millis() - last_refresh) > REFRESH_INTERVAL){ - FastLED.show(); - FastLED.show(); + show(); } } } else if (stripe_mode == 1){ @@ -713,9 +722,8 @@ void loop() { leds[cur_pixel].r = pong_color_r; leds[cur_pixel].g = pong_color_g; - leds[cur_pixel].b = pong_color_b; - FastLED.show(); - FastLED.show(); + leds[cur_pixel].b = pong_color_b; + show(); delay(cur_pong_delay*1000); From e6fe5b2b2260972226f539a858cf7452e4827461 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Wed, 28 Apr 2021 20:59:20 +0200 Subject: [PATCH 20/40] added an option to control the brightness of the strip --- MMM-LEDStripControl.js | 69 ++++++++++++++++++++++++++++++++++++++++++ README.md | 5 +++ ledstripcontrol.css | 14 ++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/MMM-LEDStripControl.js b/MMM-LEDStripControl.js index 87bddc8..199d4e1 100644 --- a/MMM-LEDStripControl.js +++ b/MMM-LEDStripControl.js @@ -14,14 +14,20 @@ Module.register('MMM-LEDStripControl', { showPongColorOptions: true, showColorIndicators: true, showHardwareButtonOption: false, + showBrightnessOption: false, outputOnIcon: "fa fa-lightbulb-o", outputOffIcon: "fa fa-lightbulb-o", hdwBtnEnabledIcon: "fa fa-link", hdwBtnDisabledIcon: "fa fa-chain-broken", upIcon: "fa fa-angle-up", upFastIcon: "fa fa-angle-double-up", + leftIcon: "fa fa-angle-left", + leftFastIcon: "fa fa-angle-double-left", downIcon: "fa fa-angle-down", downFastIcon: "fa fa-angle-double-down", + rightIcon: "fa fa-angle-right", + rightFastIcon: "fa fa-angle-double-right", + horizontalOptions: false, fetchStatusInterval: 300, instance: 0, instanceCssClass: null @@ -103,6 +109,53 @@ Module.register('MMM-LEDStripControl', { return wrapper }, + getLeftRightElement: function(key, cssClassPart){ + const self = this + let wrapper = document.createElement('div') + wrapper.className="lsc-left-right-wrapper "+cssClassPart + + let fastLeft = document.createElement('i') + fastLeft.className = self.config.leftFastIcon+" lsc-icon lsc-fastLeft "+cssClassPart + fastLeft.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_DECREASE_VALUE"],{"element":key,"step":self.curValues[key].step_d_f})}) + wrapper.appendChild(fastLeft) + + let left = document.createElement('i') + left.className = self.config.leftIcon+" lsc-icon lsc-left "+cssClassPart + left.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_DECREASE_VALUE"],{"element":key,"step":self.curValues[key].step_d})}) + wrapper.appendChild(left) + + let value = document.createElement('div') + value.className = "lsc-value "+cssClassPart + + if (self.curValues[key].selected == true){ + value.className += " lsc-selected" + } else { + value.className += " lsc-unselected" + } + + self.curValues[key].obj = value + self.elements.push(key) + if (typeof self.curValues[key].fractions !== "undefined"){ + value.innerHTML = Number.parseFloat(self.curValues[key].value).toFixed(self.curValues[key].fractions) + } else { + value.innerHTML = self.curValues[key].value + } + + wrapper.appendChild(value) + + let right = document.createElement('i') + right.className = self.config.rightIcon+" lsc-icon lsc-right "+cssClassPart + right.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"],{"element":key,"step":self.curValues[key].step_u})}) + wrapper.appendChild(right) + + let fastRight = document.createElement('i') + fastRight.className = self.config.rightFastIcon+" lsc-icon lsc-fastRight "+cssClassPart + fastRight.addEventListener("click", ()=>{self.notificationReceived(self.notifications["LED_STRIP_CONTROL_INCREASE_VALUE"],{"element":key,"step":self.curValues[key].step_u_f})}) + wrapper.appendChild(fastRight) + + return wrapper + }, + getColorDomObject: function(keyPrefix, header, cssClassPart){ const self = this let colorWrapper = document.createElement('div') @@ -121,6 +174,7 @@ Module.register('MMM-LEDStripControl', { let colorOuterWrapper = document.createElement('div') colorOuterWrapper.className = "lsc-colorOuterWrapper "+cssClassPart + //color red colorOuterWrapper.appendChild(self.getUpDownElement(keyPrefix+"_r", cssClassPart+"-red")) @@ -194,6 +248,19 @@ Module.register('MMM-LEDStripControl', { outputWrapper.appendChild(outputIcon) wrapper.appendChild(outputWrapper) + if (self.config.showBrightnessOption){ + let brightnessWrapper = document.createElement('div') + brightnessWrapper.className = "lsc-brightnessWrapper "+self.instanceCssClass + let brightnessInnerWrapper = document.createElement('div') + brightnessInnerWrapper.className = "lsc-brightnessInnerWrapper "+self.instanceCssClass + let brightness = self.getLeftRightElement("brightness", self.instanceCssClass+" lsc-brightness") + self.curValues["brightness"].obj = brightness + self.elements.push("brightness") + brightnessInnerWrapper.appendChild(brightness) + brightnessWrapper.appendChild(brightnessInnerWrapper) + wrapper.appendChild(brightnessWrapper) + } + if (self.config.showNormalColorOptions){ wrapper.appendChild(self.getColorDomObject("color", "Color", self.instanceCssClass+" lsc-ncolor")) } @@ -266,6 +333,8 @@ Module.register('MMM-LEDStripControl', { self.curValues = { "output" : {"value":false, "selected": true, "obj" : null}, + "brightness" : {"value":255, "step_u": 5, "step_d": 5, "step_u_f": 15, "step_d_f": 15, "min": 0, "max": 255, "selected": false, "obj" : null}, + "hardware_buttons_enabled" : {"value":true, "obj" : null}, "color_r" : {"value":255, "step_u": 5, "step_d": 5, "step_u_f": 15, "step_d_f": 15, "min": 0, "max": 255, "selected": false, "obj" : null}, diff --git a/README.md b/README.md index df928ee..2d62bbe 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ If you like you can change some options: | showPongColorOptions | Should the color options of the pong game be visible? | Boolean | true | | showPongOptions | Should the additional options of the pong game be visible? | Boolean | true | | showHardwareButtonOption | Should an option to disable the hardware buttons be visible? | Boolean | false | +| showBrightnessOption | Should an option to control the brightness be displayed? | Boolean | false | | fetchStatusInterval | The script sends a request to get the current configuration of the strip at the startup and in regular intervals. Normally the strip should send the configuration every time it gets switched on or off. If you do not plan to change the color values with an other module than this one you can set this value to a high one. The unit is seconds. | Integer | 300 | | outputOnIcon | You may like to change the icon of the output state to a different one. This one will be displayed if the strip is switched on. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-lightbulb-o" | | outputOffIcon | You may like to change the icon of the output state to a different one. This one will be displayed if the strip is switched off. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-lightbulb-o" | @@ -145,6 +146,10 @@ If you like you can change some options: | upFastIcon | You may like to change the icon of the fast up symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-double-up" | | downIcon | You may like to change the icon of the down symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-down" | | downFastIcon | You may like to change the icon of fast down symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-double-down" | +| leftIcon | You may like to change the icon of the left symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-left" | +| leftFastIcon | You may like to change the icon of the fast left symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-double-left" | +| rightIcon | You may like to change the icon of the right symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-right" | +| rightFastIcon | You may like to change the icon of the fast right symbol. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-angle-double-right" | | hdwBtnEnabledIcon | You may like to change the icon which is displayed if the hardware buttons are enabled. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-link" | | hddwBtnDisabledIcon | You may like to change the icon which is displayed if the hardware buttons are disabled. Any free Font-Awesome 4.7 icon can be used. | String | "fa fa-chain-broken" | | instance | If you want to add more than one instance of this module please specify an instance number with this variable. All notifications will be suffixed with "_"+instance (i.e. "LED_STRIP_CONTROL_NEXT_ELEMENT_1") and each element gets an css class "lsc-"+instance. The instance with number 0 (default) will react to and sends notifications without suffix! | Integer | 0 | diff --git a/ledstripcontrol.css b/ledstripcontrol.css index b206cb2..4507472 100644 --- a/ledstripcontrol.css +++ b/ledstripcontrol.css @@ -41,6 +41,12 @@ align-items: center; } +.lsc-left-right-wrapper { + display:flex; + flex-direction: row; + align-items: center; +} + .lsc-colorIndicator { border-radius: 5px; min-height: 20px; @@ -65,10 +71,16 @@ border-radius: 5px; } -.lsc-outputWrapper { +.lsc-outputWrapper, .lsc-brightnessWrapper { width: 100%; } +.lsc-brightnessWrapper { + display:flex; + flex-direction: column; + align-items: center; +} + .lsc-output-on { color: rgb(228, 214, 19); } From 90b60af870a082bedd920ed87b4edf51e3b99f8f Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Wed, 28 Apr 2021 21:16:38 +0200 Subject: [PATCH 21/40] modifed the margin of the control items of the brightness option element --- ledstripcontrol.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ledstripcontrol.css b/ledstripcontrol.css index 4507472..a0ce6ff 100644 --- a/ledstripcontrol.css +++ b/ledstripcontrol.css @@ -87,4 +87,10 @@ .lsc-output-off { color: rgb(99, 95, 48); +} + +.lsc-left, .lsc-fastLeft, .lsc-right, .lsc-fastRight { + min-width: 0px; + margin-left: 10px; + margin-right: 10px; } \ No newline at end of file From 4eb847c6c8d142fffd19c0735ca0193c9c582aea Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Fri, 30 Apr 2021 12:13:09 +0200 Subject: [PATCH 22/40] added a small delay before resetting all variables while switching to pong mode to avoid button bouncing --- .../ESP32LedStripWithPongAndMqtt.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index c4f358e..5793089 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -35,7 +35,7 @@ #define REFRESH_INTERVAL 10000 CRGB leds[MAX_LEDS]; - + const char* SSID = "ENTER_WIFI_SSID_HERE"; const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; @@ -629,6 +629,7 @@ void reset_pong_vars(bool during, bool oneHitFirst){ void switch_to_pong_mode(bool oneHitFirst){ Serial.println("Switching to pong mode"); + delay(500); reset_pong_vars(false, oneHitFirst); stripe_mode = 1; From bdef3821f3a16356746ac5e3a8966d8b900da369 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sat, 1 May 2021 12:37:09 +0200 Subject: [PATCH 23/40] modified the ESP32LedStripWithPongAndMqtt example to load settings with an external ".h" file; added an example ".h" file as well; --- .../ESP32LedStripWithPongAndMqtt/.gitignore | 1 + .../ESP32LedStripWithPongAndMqtt.ino | 26 +------------------ .../settings.example.h | 24 +++++++++++++++++ 3 files changed, 26 insertions(+), 25 deletions(-) create mode 100644 examples/ESP32LedStripWithPongAndMqtt/.gitignore create mode 100644 examples/ESP32LedStripWithPongAndMqtt/settings.example.h diff --git a/examples/ESP32LedStripWithPongAndMqtt/.gitignore b/examples/ESP32LedStripWithPongAndMqtt/.gitignore new file mode 100644 index 0000000..ec75a8e --- /dev/null +++ b/examples/ESP32LedStripWithPongAndMqtt/.gitignore @@ -0,0 +1 @@ +settings.h diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index 5793089..d73ae06 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -16,33 +16,9 @@ #include #include #include - -#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. -#define NUM_LEDS 300 -#define NUM_PONG_LEDS 10 -#define DATA_PIN 14 -#define BTN_1_GPIO 23 -#define BTN_2_GPIO 22 -#define BTN_DEBOUNCE_DELAY 500 -#define PONG_BTN_DELAY 2.000 -#define PONG_MAX_WINS 2 -#define PONG_TOLERANCE 2 -#define PONG_INIT_LED_DELAY 0.500 -#define PONG_DEC_PER_RUN 0.05 -#define PONG_MIN_LED_DELAY 0.02 -#define PONG_RESULT_DELAY_DURING 2.0 -#define PONG_RESULT_DELAY_AFTER 5.0 -#define REFRESH_INTERVAL 10000 +#include "settings.h" CRGB leds[MAX_LEDS]; - -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; -const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; -const String client_name = "ESP_LED"; -const String topic_id = "esp_led"; WiFiClient espClient; PubSubClient client(espClient); diff --git a/examples/ESP32LedStripWithPongAndMqtt/settings.example.h b/examples/ESP32LedStripWithPongAndMqtt/settings.example.h new file mode 100644 index 0000000..2945e00 --- /dev/null +++ b/examples/ESP32LedStripWithPongAndMqtt/settings.example.h @@ -0,0 +1,24 @@ +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. +#define NUM_LEDS 300 +#define NUM_PONG_LEDS 10 +#define DATA_PIN 14 +#define BTN_1_GPIO 23 +#define BTN_2_GPIO 22 +#define BTN_DEBOUNCE_DELAY 500 +#define PONG_BTN_DELAY 2.000 +#define PONG_MAX_WINS 2 +#define PONG_TOLERANCE 2 +#define PONG_INIT_LED_DELAY 0.500 +#define PONG_DEC_PER_RUN 0.05 +#define PONG_MIN_LED_DELAY 0.02 +#define PONG_RESULT_DELAY_DURING 2.0 +#define PONG_RESULT_DELAY_AFTER 5.0 +#define REFRESH_INTERVAL 10000 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const String client_name = "ESP_LED"; +const String topic_id = "esp_led"; From 3ad9458f3d63fffd3db3edb4b73d5a951efd90ed Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sat, 1 May 2021 12:46:13 +0200 Subject: [PATCH 24/40] modified the MQTTButtonOnEsp8266 example to use an external "settings.h" file and added an example ".h" file --- examples/MQTTButtonOnEsp8266/.gitignore | 1 + .../MQTTButtonOnEsp8266.ino | 18 +----------------- .../MQTTButtonOnEsp8266/settings.example.h | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 examples/MQTTButtonOnEsp8266/.gitignore create mode 100644 examples/MQTTButtonOnEsp8266/settings.example.h diff --git a/examples/MQTTButtonOnEsp8266/.gitignore b/examples/MQTTButtonOnEsp8266/.gitignore new file mode 100644 index 0000000..ec75a8e --- /dev/null +++ b/examples/MQTTButtonOnEsp8266/.gitignore @@ -0,0 +1 @@ +settings.h diff --git a/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino b/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino index c0af3c4..457f11e 100644 --- a/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino +++ b/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino @@ -2,24 +2,8 @@ #include #include #include +#include "settings.h" -#define BTN_DEBOUNCE_DELAY 500 -#define DISPLAY_TIME_AFTER_LAST_ACTION 30000 -#define DISPLAY_REFRESH_INTERVAL 1000 -#define RESULT_STRING_SIZE 10 - -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* MQTT_BROKER = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* MQTT_USER = "ENTER_MQTT_USERNAME_HERE"; -const char* MQTT_PASS = "ENTER_MQTT_PASSWORD_HERE"; -const String targetMsg = "1"; - - -const String clientName = "ESP_BTN"+targetMsg; -const String targetId = "raspled"; -const String targetBtnId = targetId+"/btn"; -const String targetResultId = targetId+"/results"; char result_player_one[RESULT_STRING_SIZE] = "0"; char result_player_two[RESULT_STRING_SIZE] = "0"; diff --git a/examples/MQTTButtonOnEsp8266/settings.example.h b/examples/MQTTButtonOnEsp8266/settings.example.h new file mode 100644 index 0000000..4404e1c --- /dev/null +++ b/examples/MQTTButtonOnEsp8266/settings.example.h @@ -0,0 +1,15 @@ +#define BTN_DEBOUNCE_DELAY 500 +#define DISPLAY_TIME_AFTER_LAST_ACTION 30000 +#define DISPLAY_REFRESH_INTERVAL 1000 +#define RESULT_STRING_SIZE 10 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* MQTT_BROKER = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* MQTT_USER = "ENTER_MQTT_USERNAME_HERE"; +const char* MQTT_PASS = "ENTER_MQTT_PASSWORD_HERE"; +const String targetId = "raspled"; +const String targetMsg = "1"; +const String clientName = "ESP_BTN"+targetMsg; +const String targetBtnId = targetId+"/btn"; +const String targetResultId = targetId+"/results"; From 9568d1aaa80b1971b149e00561bbffaa3b49625d Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sat, 1 May 2021 12:50:15 +0200 Subject: [PATCH 25/40] modified the MQTTButtonOnESP8266DeepSleep example to use an external "settings.h" file; added an example ".h" file --- .../MQTTButtonOnEsp8266DeepSleep/.gitignore | 1 + .../MQTTButtonOnEsp8266DeepSleep.ino | 19 +------------------ .../settings.example.h | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 examples/MQTTButtonOnEsp8266DeepSleep/.gitignore create mode 100644 examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h diff --git a/examples/MQTTButtonOnEsp8266DeepSleep/.gitignore b/examples/MQTTButtonOnEsp8266DeepSleep/.gitignore new file mode 100644 index 0000000..ec75a8e --- /dev/null +++ b/examples/MQTTButtonOnEsp8266DeepSleep/.gitignore @@ -0,0 +1 @@ +settings.h diff --git a/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino b/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino index 9f03e84..ca9ac46 100644 --- a/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino +++ b/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino @@ -2,25 +2,8 @@ #include #include #include +#include "settings.h" -#define BTN_DEBOUNCE_DELAY 500 -#define DISPLAY_TIME_AFTER_LAST_ACTION 30000 -#define DEEP_SLEEP_AFTER_LAST_ACTION 60000 -#define DISPLAY_REFRESH_INTERVAL 1000 -#define RESULT_STRING_SIZE 10 - -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* MQTT_BROKER = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* MQTT_USER = "ENTER_MQTT_USERNAME_HERE"; -const char* MQTT_PASS = "ENTER_MQTT_PASSWORD_HERE"; -const String targetMsg = "1"; - - -const String clientName = "ESP_BTN"+targetMsg; -const String targetId = "raspled"; -const String targetBtnId = targetId+"/btn"; -const String targetResultId = targetId+"/results"; char result_player_one[RESULT_STRING_SIZE] = "0"; char result_player_two[RESULT_STRING_SIZE] = "0"; diff --git a/examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h b/examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h new file mode 100644 index 0000000..33f2f9b --- /dev/null +++ b/examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h @@ -0,0 +1,19 @@ +#define BTN_DEBOUNCE_DELAY 500 +#define DISPLAY_TIME_AFTER_LAST_ACTION 30000 +#define DEEP_SLEEP_AFTER_LAST_ACTION 60000 +#define DISPLAY_REFRESH_INTERVAL 1000 +#define RESULT_STRING_SIZE 10 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* MQTT_BROKER = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* MQTT_USER = "ENTER_MQTT_USERNAME_HERE"; +const char* MQTT_PASS = "ENTER_MQTT_PASSWORD_HERE"; +const String targetMsg = "1"; + + +const String clientName = "ESP_BTN"+targetMsg; +const String targetId = "raspled"; +const String targetBtnId = targetId+"/btn"; +const String targetResultId = targetId+"/results"; + From 06449b445910d18a767dbd3fe8dd266c84256f66 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sat, 1 May 2021 13:00:02 +0200 Subject: [PATCH 26/40] moved button_pin option to the new settings.h file in MQTTButton examples --- examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino | 1 - examples/MQTTButtonOnEsp8266/settings.example.h | 2 ++ .../MQTTButtonOnEsp8266DeepSleep.ino | 1 - examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h | 1 + 4 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino b/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino index 457f11e..7747a67 100644 --- a/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino +++ b/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino @@ -13,7 +13,6 @@ long lastMsg = 0; char msg[50]; int value = 0; -int btn_pin = 2; bool btn_state = false; long btn_last_pressed = 0; long last_action = 0; diff --git a/examples/MQTTButtonOnEsp8266/settings.example.h b/examples/MQTTButtonOnEsp8266/settings.example.h index 4404e1c..5730eb9 100644 --- a/examples/MQTTButtonOnEsp8266/settings.example.h +++ b/examples/MQTTButtonOnEsp8266/settings.example.h @@ -13,3 +13,5 @@ const String targetMsg = "1"; const String clientName = "ESP_BTN"+targetMsg; const String targetBtnId = targetId+"/btn"; const String targetResultId = targetId+"/results"; + +int btn_pin = 2; diff --git a/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino b/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino index ca9ac46..0316d0f 100644 --- a/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino +++ b/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino @@ -13,7 +13,6 @@ long lastMsg = 0; char msg[50]; int value = 0; -int btn_pin = 2; bool btn_state = false; long btn_last_pressed = 0; long last_action = 0; diff --git a/examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h b/examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h index 33f2f9b..02665de 100644 --- a/examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h +++ b/examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h @@ -17,3 +17,4 @@ const String targetId = "raspled"; const String targetBtnId = targetId+"/btn"; const String targetResultId = targetId+"/results"; +int btn_pin = 2; From cbee34f113a735be8e741e6ba395946a407e52be Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sun, 2 May 2021 14:04:55 +0200 Subject: [PATCH 27/40] extended the ESP32LedSTripWithPongAndMqtt example to support long button presses to change the brightness; --- .../ESP32LedStripWithPongAndMqtt.ino | 148 ++++++++++++++---- .../settings.example.h | 3 + 2 files changed, 124 insertions(+), 27 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index d73ae06..69d1d0b 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -31,13 +31,18 @@ long last_refresh = 0; int reverseMode=0; int cur_pixel=0; int btn_one_state = 0; +int btn_one_long_state = 0; long btn_one_last_pressed = 0; +long btn_one_last_released = -1; int btn_two_state = 0; +int btn_two_long_state = 0; long btn_two_last_pressed = 0; +long btn_two_last_released = -1; bool enable_hardware_btns = true; int brightness = 255; +int brightness_decrease = true; int color_r = 255; int color_g = 255; int color_b = 255; @@ -310,8 +315,8 @@ void callback(char* topic, byte* message, unsigned int length) { } else { if (!enable_hardware_btns){ enable_hardware_btns = true; - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, FALLING); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, FALLING); + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); Serial.println("Enable Hardware Buttons"); } } @@ -370,8 +375,8 @@ void callback(char* topic, byte* message, unsigned int length) { } else { if (!enable_hardware_btns){ enable_hardware_btns = true; - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, FALLING); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, FALLING); + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); Serial.println("Enable Hardware Buttons"); } } @@ -443,8 +448,8 @@ void setup() { pinMode(BTN_2_GPIO, INPUT); pinMode(DATA_PIN, OUTPUT); - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_pressed, FALLING); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_pressed, FALLING); + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); delay(500); } @@ -478,19 +483,35 @@ void setup_wifi() { Serial.println(WiFi.localIP()); } -void btn_one_pressed(){ +void btn_one_changed(){ long cur_time = millis(); if((cur_time - btn_one_last_pressed) > BTN_DEBOUNCE_DELAY){ - btn_one_last_pressed = cur_time; - btn_one_state = 1; + if (digitalRead(BTN_1_GPIO) == LOW){ + btn_one_last_pressed = cur_time; + btn_one_state = 1; + } else{ + btn_one_last_released = cur_time; + } + } else{ + if (digitalRead(BTN_1_GPIO) == HIGH){ + btn_one_last_released = cur_time; + } } } -void btn_two_pressed(){ +void btn_two_changed(){ long cur_time = millis(); if((cur_time - btn_two_last_pressed) > BTN_DEBOUNCE_DELAY){ - btn_two_last_pressed = cur_time; - btn_two_state = 1; + if (digitalRead(BTN_2_GPIO) == LOW){ + btn_two_last_pressed = cur_time; + btn_two_state = 1; + } else{ + btn_two_last_released = cur_time; + } + } else { + if (digitalRead(BTN_2_GPIO) == HIGH){ + btn_two_last_released = cur_time; + } } } @@ -651,6 +672,28 @@ void display_result(float cur_delay){ delay(cur_delay*1000); } +void changeBrightness(){ + if (brightness_decrease){ + //Serial.println("Decrease brightness"); + brightness = brightness - BRIGHTNESS_CHANGE_VALUE; + if (brightness <= 0){ + brightness = 0; + //Serial.println("Smallest value reached"); + brightness_decrease = !brightness_decrease; + } + } else { + //Serial.println("Increase brightness"); + brightness = brightness + BRIGHTNESS_CHANGE_VALUE; + if (brightness >= 255){ + brightness = 255; + //Serial.println("Max value reached"); + brightness_decrease = !brightness_decrease; + } + } + + show(); +} + void loop() { if (WiFi.status() != WL_CONNECTED) { setup_wifi(); @@ -663,28 +706,79 @@ void loop() { if (stripe_mode == 0){ if ((btn_one_state == 1) or (btn_two_state == 1)){ + //Serial.println("btn one or two pressed"); if (btn_two_state == 1){ - player_one_hit_first = true; - btn_two_state = 0; - Serial.println("Button two pressed."); - if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ - Serial.println("Switching to pong mode."); - switch_to_pong_mode(player_one_hit_first); + //Serial.println("btn_two_state == 1"); + //Serial.println(btn_two_last_released); + //Serial.println(btn_two_last_pressed); + if ((btn_two_last_released >= btn_two_last_pressed) or (!stripe_on)){ + //Serial.println("btn_two currently is not pressed"); + if (btn_two_long_state == 0){ + //Serial.println("btn_two had no long press"); + player_one_hit_first = true; + btn_two_state = 0; + //Serial.println("Button two pressed."); + if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Toggling led stripe."); + toggle_leds(-1); + } + } else { + //Serial.println("btn_two had long press"); + btn_two_long_state = 0; + btn_two_state = 0; + } } else { - Serial.println("Toggling led stripe."); - toggle_leds(-1); + //button still pressed. Maybe a long press? + if ((millis() - btn_two_last_pressed) > BTN_LONG_PRESS_DELAY){ + //Serial.println("btn_two long press detected"); + btn_two_long_state = 1; + changeBrightness(); + publish_current_status(); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } else { + //Serial.println("btn_two still pressed"); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } } } if (btn_one_state == 1){ - player_one_hit_first = false; - btn_one_state = 0; - if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ - Serial.println("Switching to pong mode."); - switch_to_pong_mode(player_one_hit_first); + //Serial.println("btn_one_state == 1"); + //Serial.println(btn_one_last_released); + //Serial.println(btn_one_last_pressed); + if ((btn_one_last_released >= btn_one_last_pressed) or (!stripe_on)){ + //Serial.println("btn_one currently is not pressed"); + if (btn_one_long_state == 0){ + //Serial.println("btn_one had no long press"); + player_one_hit_first = false; + btn_one_state = 0; + if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Button one pressed. Toggling led stripe."); + toggle_leds(-1); + } + } else { + //Serial.println("btn_one had long press"); + btn_one_long_state = 0; + btn_one_state = 0; + } } else { - Serial.println("Button one pressed. Toggling led stripe."); - toggle_leds(-1); + //button still pressed. Maybe a long press? + if ((millis() - btn_one_last_pressed) > BTN_LONG_PRESS_DELAY){ + //Serial.println("btn_one long press detected"); + btn_one_long_state = 1; + changeBrightness(); + publish_current_status(); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } else { + //Serial.println("btn_one still pressed"); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } } } } else { diff --git a/examples/ESP32LedStripWithPongAndMqtt/settings.example.h b/examples/ESP32LedStripWithPongAndMqtt/settings.example.h index 2945e00..1014e5d 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/settings.example.h +++ b/examples/ESP32LedStripWithPongAndMqtt/settings.example.h @@ -5,6 +5,9 @@ #define BTN_1_GPIO 23 #define BTN_2_GPIO 22 #define BTN_DEBOUNCE_DELAY 500 +#define BTN_LONG_PRESS_DELAY 1000 +#define BRIGHTNESS_CHANGE_INTERVAL 50 +#define BRIGHTNESS_CHANGE_VALUE 5 #define PONG_BTN_DELAY 2.000 #define PONG_MAX_WINS 2 #define PONG_TOLERANCE 2 From 2a5f6f8b2811e8ca951a60d3536fd68b6faa4421 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sun, 2 May 2021 14:29:39 +0200 Subject: [PATCH 28/40] fixed MQTT buttons not functional in ESP32LedStripWithPongAndMqtt example --- .../ESP32LedStripWithPongAndMqtt.ino | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index 69d1d0b..d1e4c0a 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -401,10 +401,12 @@ void callback(char* topic, byte* message, unsigned int length) { Serial.println("Button press via mqtt"); Serial.println(messageTemp); if (messageTemp.toInt() == 2 ){ - btn_two_last_pressed = millis();; + btn_two_last_pressed = millis(); + btn_two_last_released = btn_two_last_pressed; btn_two_state = 1; } else { - btn_one_last_pressed = millis();; + btn_one_last_pressed = millis(); + btn_one_last_released = btn_one_last_pressed; btn_one_state = 1; } } From 3716b3d12802afe1fcd929e08ae902f9965c4236 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Wed, 5 May 2021 12:17:24 +0200 Subject: [PATCH 29/40] added possibility to set a led to start pong at if the start should not be at the beginning of the strip; --- .../ESP32LedStripWithPongAndMqtt.ino | 17 +++++++++-------- .../settings.example.h | 1 + 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index d1e4c0a..f68d0de 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -52,6 +52,7 @@ boolean stripe_on = false; float pong_init_delay = PONG_INIT_LED_DELAY; float cur_pong_delay = pong_init_delay; int num_pong_leds = NUM_PONG_LEDS; +int pong_start_led = PONG_START_LED; int pong_max_wins = PONG_MAX_WINS; float pong_wins_delay_during = PONG_RESULT_DELAY_DURING; float pong_wins_delay_after = PONG_RESULT_DELAY_AFTER; @@ -618,7 +619,7 @@ void reset_pong_vars(bool during, bool oneHitFirst){ } if (oneHitFirst){ - cur_pixel = 0; + cur_pixel = pong_start_led; reverseMode = 0; } else { cur_pixel = num_pong_leds-1; @@ -638,7 +639,7 @@ void switch_to_pong_mode(bool oneHitFirst){ } show(); delay(1000); - for (int i = 0; i< num_pong_leds; i++){ + for (int i = pong_start_led; i< num_pong_leds; i++){ leds[i].r = pong_color_r; leds[i].g = pong_color_g; leds[i].b = pong_color_b; @@ -659,7 +660,7 @@ void display_result(float cur_delay){ leds[i] = CRGB::Black; } - for (int i = 0; i < player_one_wins; i++){ + for (int i = pong_start_led; i < player_one_wins+pong_start_led; i++){ leds[i].r = pong_result_color_r; leds[i].g = pong_result_color_g; leds[i].b = pong_result_color_b; @@ -806,12 +807,12 @@ void loop() { if (player_successfull_one_press == 0){ if(btn_one_state == 1){ btn_one_state = 0; - if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= 0)){ + if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= pong_start_led)){ player_one_miss = 1; } else { player_successfull_one_press = 1; } - } else if ((reverseMode == 1) && (cur_pixel == 0)){ + } else if ((reverseMode == 1) && (cur_pixel == pong_start_led)){ player_one_miss = 1; } } else { @@ -836,7 +837,7 @@ void loop() { publish_results(); } display_result(pong_wins_delay_during); - cur_pixel = 0; + cur_pixel = pong_start_led; reverseMode = 0; if (change_start_led_during_match){ player_one_hit_first = !player_one_hit_first; @@ -891,10 +892,10 @@ void loop() { if (abortRun == 0){ if (reverseMode == 1){ cur_pixel -= 1; - if (cur_pixel < 0){ + if (cur_pixel < pong_start_led){ reverseMode = 0; player_successfull_one_press = 0; - cur_pixel = 1; + cur_pixel = pong_start_led + 1; cur_pong_delay = cur_pong_delay - pong_dec_per_run; if (cur_pong_delay < pong_min_delay){ cur_pong_delay = pong_min_delay; diff --git a/examples/ESP32LedStripWithPongAndMqtt/settings.example.h b/examples/ESP32LedStripWithPongAndMqtt/settings.example.h index 1014e5d..f73d893 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/settings.example.h +++ b/examples/ESP32LedStripWithPongAndMqtt/settings.example.h @@ -8,6 +8,7 @@ #define BTN_LONG_PRESS_DELAY 1000 #define BRIGHTNESS_CHANGE_INTERVAL 50 #define BRIGHTNESS_CHANGE_VALUE 5 +#define PONG_START_LED 0 #define PONG_BTN_DELAY 2.000 #define PONG_MAX_WINS 2 #define PONG_TOLERANCE 2 From c1b195e0115b010618ff3154de9540ed9727bea3 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sun, 20 Jun 2021 17:50:56 +0200 Subject: [PATCH 30/40] added an example of an ESP32 based MQTT enabled Led controller which supports over the air (ota) updates of the firmware --- .../.gitignore | 2 + .../ESP32LedStripWithPongAndMqtt.ino | 1005 +++++++++++++++++ .../settings.example.h | 29 + .../ESP32LedStripWithPongAndMqtt/.gitignore | 1 + .../settings.example.h | 1 + 5 files changed, 1038 insertions(+) create mode 100644 examples/ESP32LedStripOTAWithPongAndMqtt/.gitignore create mode 100644 examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino create mode 100644 examples/ESP32LedStripOTAWithPongAndMqtt/settings.example.h diff --git a/examples/ESP32LedStripOTAWithPongAndMqtt/.gitignore b/examples/ESP32LedStripOTAWithPongAndMqtt/.gitignore new file mode 100644 index 0000000..0e95883 --- /dev/null +++ b/examples/ESP32LedStripOTAWithPongAndMqtt/.gitignore @@ -0,0 +1,2 @@ +settings.h +*.bin diff --git a/examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino new file mode 100644 index 0000000..27777c1 --- /dev/null +++ b/examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -0,0 +1,1005 @@ +//LED Strip: BTF-LIGHTING WS2815 -> https://www.amazon.de/gp/product/B07LG5ZT9C/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1 +//Power Supply: HuaTec LED Trafo 12V 120W -> https://www.amazon.de/gp/product/B0829817YM/ref=ppx_yo_dt_b_asin_image_o09_s00?ie=UTF8&psc=1 +//Step-Down-Module: AZDelivery XL4015 -> https://www.amazon.de/gp/product/B07SRXR1VT/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1 +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//2 x Tactile Push Button (Something like https://www.amazon.de/gp/product/B078ZDK6KZ/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) +//2 x Capacitor 0.1 Mikrofarad +//2 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 1.0.6 +//Libs: +// FastLED by Daniel Garcia Version 3.4.0 +// PubSubClient by Nick O'Leary Version 2.8.0 +// ArduinoJson by Benoit Blanchon Version 6.17.3 +#include +#include +#include +#include +#include "settings.h" +#include +#include +#include +#include + +CRGB leds[MAX_LEDS]; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +long last_refresh = 0; + +int reverseMode=0; +int cur_pixel=0; +int btn_one_state = 0; +int btn_one_long_state = 0; +long btn_one_last_pressed = 0; +long btn_one_last_released = -1; +int btn_two_state = 0; +int btn_two_long_state = 0; +long btn_two_last_pressed = 0; +long btn_two_last_released = -1; +bool enable_hardware_btns = true; + + +int brightness = 255; +int brightness_decrease = true; +int color_r = 255; +int color_g = 255; +int color_b = 255; +int stripe_mode = 0; +boolean stripe_on = false; + +float pong_init_delay = PONG_INIT_LED_DELAY; +float cur_pong_delay = pong_init_delay; +int num_pong_leds = NUM_PONG_LEDS; +int pong_start_led = PONG_START_LED; +int pong_max_wins = PONG_MAX_WINS; +float pong_wins_delay_during = PONG_RESULT_DELAY_DURING; +float pong_wins_delay_after = PONG_RESULT_DELAY_AFTER; +float pong_min_delay = PONG_MIN_LED_DELAY; +float pong_dec_per_run = PONG_DEC_PER_RUN; +float pong_btn_delay = PONG_BTN_DELAY; +int pong_tolerance = PONG_TOLERANCE; +int pong_color_r = 0; +int pong_color_g = 0; +int pong_color_b = 255; +int pong_result_color_r = 0; +int pong_result_color_g = 255; +int pong_result_color_b = 0; +int player_one_wins = 0; +int player_successfull_one_press = 0; +int player_two_wins = 0; +int player_successfull_two_press = 0; +int player_one_miss = 0; +int player_two_miss = 0; +int abortRun = 0; +bool player_one_hit_first = true; +bool change_start_led_during_match = true; + +int publish_status_after_every_config_change = 1; +int publish_status_if_toggled = 1; +int publish_status_at_start = 1; +int publish_results_at_display = 1; + +WebServer server(80); + +/* + * Server Index Page + */ + +const char* serverIndex = +"" +"
" + "" + "" + "
" + "
progress: 0%
" + ""; + + +void publish_current_status(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (client.connected()){ + doc["pong"]["btn_delay"] = pong_btn_delay; + doc["pong"]["init_delay"] = pong_init_delay; + doc["pong"]["min_delay"] = pong_min_delay; + doc["pong"]["dec_per_run"] = pong_dec_per_run; + doc["pong"]["num_leds"] = num_pong_leds; + doc["pong"]["max_wins"] = pong_max_wins; + doc["pong"]["tolerance"] = pong_tolerance; + doc["pong"]["result_delay_during"] = pong_wins_delay_during; + doc["pong"]["result_delay_after"] = pong_wins_delay_after; + doc["pong"]["color_r"] = pong_color_r; + doc["pong"]["color_g"] = pong_color_g; + doc["pong"]["color_b"] = pong_color_b; + doc["pong"]["result_color_r"] = pong_result_color_r; + doc["pong"]["result_color_g"] = pong_result_color_g; + doc["pong"]["result_color_b"] = pong_result_color_b; + doc["output"] = stripe_on; + doc["mode"] = stripe_mode; + doc["brightness"] = brightness; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + doc["hardware_buttons_enabled"] = enable_hardware_btns; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/status").c_str(), buffer, n); + } +} + +void publish_results(){ + StaticJsonDocument<100> doc; + if (client.connected()){ + doc["result_player_one"] = player_one_wins; + doc["result_player_two"] = player_two_wins; + } + char buffer[100]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/results").c_str(), buffer, n); +} + +void fixConfigValues(){ + if (pong_btn_delay < 0){ + pong_btn_delay = 0; + } + + if (pong_init_delay < pong_min_delay){ + pong_init_delay = pong_min_delay; + } + + if (pong_min_delay < 0){ + pong_min_delay = 0; + } + + if (pong_dec_per_run < 0){ + pong_dec_per_run = 0; + } + + if (num_pong_leds > NUM_LEDS){ + num_pong_leds = NUM_LEDS; + } + + if (pong_max_wins > num_pong_leds){ + pong_max_wins = num_pong_leds; + } + + if (pong_wins_delay_during < 0){ + pong_wins_delay_during = 0; + } + + if (pong_wins_delay_after < 0){ + pong_wins_delay_after = 0; + } + + if (pong_result_color_r > 255){ + pong_result_color_r = 255; + } else if (pong_result_color_r < 0){ + pong_result_color_r = 0; + } + + if (pong_result_color_g > 255){ + pong_result_color_g = 255; + } else if (pong_result_color_g < 0){ + pong_result_color_g = 0; + } + + if (pong_result_color_b > 255){ + pong_result_color_b = 255; + } else if (pong_result_color_b < 0){ + pong_result_color_b = 0; + } + + if (pong_tolerance < 0){ + pong_tolerance = 0; + } + + if (pong_tolerance > (num_pong_leds -1)){ + pong_tolerance = num_pong_leds -1; + } + + if (pong_color_r > 255){ + pong_color_r = 255; + } else if (pong_color_r < 0){ + pong_color_r = 0; + } + + if (pong_color_g > 255){ + pong_color_g = 255; + } else if (pong_color_g < 0){ + pong_color_g = 0; + } + + if (pong_color_b > 255){ + pong_color_b = 255; + } else if (pong_color_b < 0){ + pong_color_b = 0; + } + + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.print(topic); + Serial.print(". Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (! (String(topic) == topic_id+"/btn") ) { + // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". + // Changes the output state according to the message + if (String(topic) == topic_id+"/output") { + Serial.print("Changing output to "); + if(messageTemp == "on"){ + Serial.println("on"); + toggle_leds(1); + } + else if(messageTemp == "off"){ + Serial.println("off"); + toggle_leds(0); + } else { + Serial.println("toggle"); + toggle_leds(-1); + } + } else if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + if (!err){ + + if(doc["pong"]["btn_delay"]){ + pong_btn_delay = doc["pong"]["btn_delay"].as(); + } + + if(doc["pong"]["init_delay"]){ + pong_init_delay = doc["pong"]["init_delay"].as(); + } + + if(doc["pong"]["min_delay"]){ + pong_min_delay = doc["pong"]["min_delay"].as(); + } + + if(doc["pong"]["dec_per_run"]){ + pong_dec_per_run = doc["pong"]["dec_per_run"].as(); + } + + num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; + pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; + pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; + + if(doc["pong"]["result_delay_during"]){ + pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); + } + + if(doc["pong"]["result_delay_after"]){ + pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); + } + + pong_color_r = doc["pong"]["color_r"] | pong_color_r; + pong_color_g = doc["pong"]["color_g"] | pong_color_g; + pong_color_b = doc["pong"]["color_b"] | pong_color_b; + + pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; + pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; + pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; + + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + + brightness = doc["brightness"] | brightness; + + if (doc.containsKey("hardware_buttons_enabled")){ + if (!doc["hardware_buttons_enabled"]){ + if (enable_hardware_btns){ + enable_hardware_btns = false; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (!enable_hardware_btns){ + enable_hardware_btns = true; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); + Serial.println("Enable Hardware Buttons"); + } + } + } + + } + + } else if (String(topic) == topic_id+"/pong/btn_delay"){ + pong_btn_delay = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/init_delay"){ + pong_init_delay = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/min_delay"){ + pong_min_delay = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/dec_per_run"){ + pong_dec_per_run = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/num_leds"){ + num_pong_leds = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/max_wins"){ + pong_max_wins = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/result/delay/during"){ + pong_wins_delay_during = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/result/delay/after"){ + pong_wins_delay_after = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/result/color/r"){ + pong_result_color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/result/color/g"){ + pong_result_color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/result/color/b"){ + pong_result_color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/tolerance"){ + pong_tolerance = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/color/r"){ + pong_color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/color/g"){ + pong_color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/color/b"){ + pong_color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publish_current_status(); + } else if (String(topic) == topic_id+"/hardware_buttons_enabled"){ + if (messageTemp.toInt() == 1){ + if (enable_hardware_btns){ + enable_hardware_btns = false; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (!enable_hardware_btns){ + enable_hardware_btns = true; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); + Serial.println("Enable Hardware Buttons"); + } + } + } + + fixConfigValues(); + + if ((String(topic) != topic_id+"/output") && + (String(topic) != topic_id+"/get_status") && + (stripe_mode == 0)){ + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } + } else { + Serial.println("Button press via mqtt"); + Serial.println(messageTemp); + if (messageTemp.toInt() == 2 ){ + btn_two_last_pressed = millis(); + btn_two_last_released = btn_two_last_pressed; + btn_two_state = 1; + } else { + btn_one_last_pressed = millis(); + btn_one_last_released = btn_one_last_pressed; + btn_one_state = 1; + } + } +} + +void show(){ + FastLED.setBrightness(brightness); + FastLED.show(); + FastLED.show(); +} + +void setup() { + client.setBufferSize(512); + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_broker, 1883); + reconnect(); + client.setCallback(callback); + + if (publish_status_at_start){ + publish_current_status(); + } + + FastLED.addLeds(leds, MAX_LEDS); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + leds[i] = CRGB::White; + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + + pinMode(BTN_1_GPIO, INPUT); + pinMode(BTN_2_GPIO, INPUT); + pinMode(DATA_PIN, OUTPUT); + + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); + delay(500); + + /*use mdns for host_name name resolution*/ + if (!MDNS.begin(host_name)) { //http://ESP_LED + Serial.println("Error setting up MDNS responder!"); + while (1) { + delay(1000); + } + } + Serial.println("mDNS responder started"); + server.on("/", HTTP_GET, []() { + server.sendHeader("Connection", "close"); + server.send(200, "text/html", serverIndex); + }); + /*handling uploading firmware file */ + server.on("/update", HTTP_POST, []() { + server.sendHeader("Connection", "close"); + server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); + ESP.restart(); + }, []() { + HTTPUpload& upload = server.upload(); + if (upload.status == UPLOAD_FILE_START) { + Serial.printf("Update: %s\n", upload.filename.c_str()); + if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size + Update.printError(Serial); + } + } else if (upload.status == UPLOAD_FILE_WRITE) { + /* flashing firmware to ESP*/ + if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { + Update.printError(Serial); + } + } else if (upload.status == UPLOAD_FILE_END) { + if (Update.end(true)) { //true to set the size to the current progress + Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); + } else { + Update.printError(Serial); + } + } + }); + server.begin(); +} + +void setup_wifi() { + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void btn_one_changed(){ + long cur_time = millis(); + if((cur_time - btn_one_last_pressed) > BTN_DEBOUNCE_DELAY){ + if (digitalRead(BTN_1_GPIO) == LOW){ + btn_one_last_pressed = cur_time; + btn_one_state = 1; + } else{ + btn_one_last_released = cur_time; + } + } else{ + if (digitalRead(BTN_1_GPIO) == HIGH){ + btn_one_last_released = cur_time; + } + } +} + +void btn_two_changed(){ + long cur_time = millis(); + if((cur_time - btn_two_last_pressed) > BTN_DEBOUNCE_DELAY){ + if (digitalRead(BTN_2_GPIO) == LOW){ + btn_two_last_pressed = cur_time; + btn_two_state = 1; + } else{ + btn_two_last_released = cur_time; + } + } else { + if (digitalRead(BTN_2_GPIO) == HIGH){ + btn_two_last_released = cur_time; + } + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { + Serial.println("connected"); + // Subscribe + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + client.subscribe((topic_id+"/get_status").c_str()); + client.subscribe((topic_id+"/config").c_str()); + client.subscribe((topic_id+"/output").c_str()); + client.subscribe((topic_id+"/pong/btn_delay").c_str()); + client.subscribe((topic_id+"/pong/init_delay").c_str()); + client.subscribe((topic_id+"/pong/min_delay").c_str()); + client.subscribe((topic_id+"/pong/dec_per_run").c_str()); + client.subscribe((topic_id+"/pong/num_leds").c_str()); + client.subscribe((topic_id+"/pong/max_wins").c_str()); + client.subscribe((topic_id+"/pong/result/delay/during").c_str()); + client.subscribe((topic_id+"/pong/result/delay/after").c_str()); + client.subscribe((topic_id+"/pong/result/color/r").c_str()); + client.subscribe((topic_id+"/pong/result/color/g").c_str()); + client.subscribe((topic_id+"/pong/result/color/b").c_str()); + client.subscribe((topic_id+"/pong/tolerance").c_str()); + client.subscribe((topic_id+"/pong/color/r").c_str()); + client.subscribe((topic_id+"/pong/color/g").c_str()); + client.subscribe((topic_id+"/pong/color/b").c_str()); + client.subscribe((topic_id+"/color/r").c_str()); + client.subscribe((topic_id+"/color/g").c_str()); + client.subscribe((topic_id+"/color/b").c_str()); + client.subscribe((topic_id+"/btn").c_str()); + client.subscribe((topic_id+"/disable_btns").c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void toggle_leds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i].r = color_r; + leds[i].g = color_g; + leds[i].b = color_b; + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + stripe_on = false; + } + + show(); + if (publish_status_if_toggled == 1){ + publish_current_status(); + } +} + +void reset_pong_vars(bool during, bool oneHitFirst){ + Serial.print("Resetting pong vars ("); + Serial.print(during); + Serial.print("/"); + Serial.print(oneHitFirst); + Serial.println(")"); + client.loop(); + player_one_miss = 0; + player_two_miss = 0; + btn_one_state = 0; + btn_two_state = 0; + player_successfull_one_press = 0; + player_successfull_two_press = 0; + cur_pong_delay = pong_init_delay; + + if (!during){ + player_one_wins = 0; + player_two_wins = 0; + btn_one_last_pressed = 0; + btn_two_last_pressed = 0; + stripe_mode = 0; + } + + if (oneHitFirst){ + cur_pixel = pong_start_led; + reverseMode = 0; + } else { + cur_pixel = num_pong_leds-1; + reverseMode = 1; + } +} + +void switch_to_pong_mode(bool oneHitFirst){ + Serial.println("Switching to pong mode"); + delay(500); + reset_pong_vars(false, oneHitFirst); + + stripe_mode = 1; + + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(1000); + for (int i = pong_start_led; i< num_pong_leds; i++){ + leds[i].r = pong_color_r; + leds[i].g = pong_color_g; + leds[i].b = pong_color_b; + } + show(); + delay(1000); + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(1000); +} + +void display_result(float cur_delay){ + Serial.println("Displaying results"); + delay(500); + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + + for (int i = pong_start_led; i < player_one_wins+pong_start_led; i++){ + leds[i].r = pong_result_color_r; + leds[i].g = pong_result_color_g; + leds[i].b = pong_result_color_b; + } + + for (int i = (num_pong_leds - 1); i > ((num_pong_leds-1)-player_two_wins); i--){ + leds[i].r = pong_result_color_r; + leds[i].g = pong_result_color_g; + leds[i].b = pong_result_color_b; + } + show(); + delay(cur_delay*1000); +} + +void changeBrightness(){ + if (brightness_decrease){ + //Serial.println("Decrease brightness"); + brightness = brightness - BRIGHTNESS_CHANGE_VALUE; + if (brightness <= 0){ + brightness = 0; + //Serial.println("Smallest value reached"); + brightness_decrease = !brightness_decrease; + } + } else { + //Serial.println("Increase brightness"); + brightness = brightness + BRIGHTNESS_CHANGE_VALUE; + if (brightness >= 255){ + brightness = 255; + //Serial.println("Max value reached"); + brightness_decrease = !brightness_decrease; + } + } + + show(); +} + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (stripe_mode == 0){ + server.handleClient(); + if ((btn_one_state == 1) or (btn_two_state == 1)){ + //Serial.println("btn one or two pressed"); + if (btn_two_state == 1){ + //Serial.println("btn_two_state == 1"); + //Serial.println(btn_two_last_released); + //Serial.println(btn_two_last_pressed); + if ((btn_two_last_released >= btn_two_last_pressed) or (!stripe_on)){ + //Serial.println("btn_two currently is not pressed"); + if (btn_two_long_state == 0){ + //Serial.println("btn_two had no long press"); + player_one_hit_first = true; + btn_two_state = 0; + //Serial.println("Button two pressed."); + if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Toggling led stripe."); + toggle_leds(-1); + } + } else { + //Serial.println("btn_two had long press"); + btn_two_long_state = 0; + btn_two_state = 0; + } + } else { + //button still pressed. Maybe a long press? + if ((millis() - btn_two_last_pressed) > BTN_LONG_PRESS_DELAY){ + //Serial.println("btn_two long press detected"); + btn_two_long_state = 1; + changeBrightness(); + publish_current_status(); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } else { + //Serial.println("btn_two still pressed"); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } + } + } + + if (btn_one_state == 1){ + //Serial.println("btn_one_state == 1"); + //Serial.println(btn_one_last_released); + //Serial.println(btn_one_last_pressed); + if ((btn_one_last_released >= btn_one_last_pressed) or (!stripe_on)){ + //Serial.println("btn_one currently is not pressed"); + if (btn_one_long_state == 0){ + //Serial.println("btn_one had no long press"); + player_one_hit_first = false; + btn_one_state = 0; + if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Button one pressed. Toggling led stripe."); + toggle_leds(-1); + } + } else { + //Serial.println("btn_one had long press"); + btn_one_long_state = 0; + btn_one_state = 0; + } + } else { + //button still pressed. Maybe a long press? + if ((millis() - btn_one_last_pressed) > BTN_LONG_PRESS_DELAY){ + //Serial.println("btn_one long press detected"); + btn_one_long_state = 1; + changeBrightness(); + publish_current_status(); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } else { + //Serial.println("btn_one still pressed"); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } + } + } + } else { + if((millis() - last_refresh) > REFRESH_INTERVAL){ + show(); + } + } + } else if (stripe_mode == 1){ + for (int i=0; i < NUM_LEDS; i++){ + leds[i] = CRGB::Black; + } + + leds[cur_pixel].r = pong_color_r; + leds[cur_pixel].g = pong_color_g; + leds[cur_pixel].b = pong_color_b; + show(); + + delay(cur_pong_delay*1000); + + abortRun = 0; + player_one_miss = 0; + + if (player_successfull_one_press == 0){ + if(btn_one_state == 1){ + btn_one_state = 0; + if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= pong_start_led)){ + player_one_miss = 1; + } else { + player_successfull_one_press = 1; + } + } else if ((reverseMode == 1) && (cur_pixel == pong_start_led)){ + player_one_miss = 1; + } + } else { + btn_one_state = 0; + } + + if(player_one_miss == 1){ + abortRun = 1; + player_two_wins += 1; + if(player_two_wins >= pong_max_wins){ + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); + if (publish_results_at_display == 1){ + publish_results(); + } + toggle_leds(0); + } else { + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); + cur_pixel = pong_start_led; + reverseMode = 0; + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } + reset_pong_vars(true, player_one_hit_first); + } + } + + player_two_miss = 0; + + if (player_successfull_two_press == 0){ + if(btn_two_state == 1){ + btn_two_state = 0; + if ((reverseMode == 1) or ((cur_pixel + pong_tolerance) <= (num_pong_leds-1))){ + player_two_miss = 1; + } else { + player_successfull_two_press = 1; + } + } else if ((reverseMode == 0) && (cur_pixel == (num_pong_leds-1))){ + player_two_miss = 1; + } + } else { + btn_two_state = 0; + } + + if(player_two_miss == 1){ + abortRun = 1; + player_one_wins += 1; + if(player_one_wins >= pong_max_wins){ + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); + if (publish_results_at_display == 1){ + publish_results(); + } + toggle_leds(0); + } else { + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } + reset_pong_vars(true, player_one_hit_first); + } + } + + + if (abortRun == 0){ + if (reverseMode == 1){ + cur_pixel -= 1; + if (cur_pixel < pong_start_led){ + reverseMode = 0; + player_successfull_one_press = 0; + cur_pixel = pong_start_led + 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } else { + cur_pixel += 1; + if (cur_pixel > (num_pong_leds-1)){ + player_successfull_two_press = 0; + cur_pixel = num_pong_leds-2; + reverseMode = 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } + } + } +} diff --git a/examples/ESP32LedStripOTAWithPongAndMqtt/settings.example.h b/examples/ESP32LedStripOTAWithPongAndMqtt/settings.example.h new file mode 100644 index 0000000..aaa68b1 --- /dev/null +++ b/examples/ESP32LedStripOTAWithPongAndMqtt/settings.example.h @@ -0,0 +1,29 @@ +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. +#define NUM_LEDS 300 +#define NUM_PONG_LEDS 10 +#define DATA_PIN 14 +#define BTN_1_GPIO 23 +#define BTN_2_GPIO 22 +#define BTN_DEBOUNCE_DELAY 500 +#define BTN_LONG_PRESS_DELAY 1000 +#define BRIGHTNESS_CHANGE_INTERVAL 50 +#define BRIGHTNESS_CHANGE_VALUE 5 +#define PONG_START_LED 0 +#define PONG_BTN_DELAY 2.000 +#define PONG_MAX_WINS 2 +#define PONG_TOLERANCE 2 +#define PONG_INIT_LED_DELAY 0.500 +#define PONG_DEC_PER_RUN 0.05 +#define PONG_MIN_LED_DELAY 0.02 +#define PONG_RESULT_DELAY_DURING 2.0 +#define PONG_RESULT_DELAY_AFTER 5.0 +#define REFRESH_INTERVAL 10000 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* host_name = "ESP_LED"; +const String client_name = "ESP_LED"; +const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripWithPongAndMqtt/.gitignore b/examples/ESP32LedStripWithPongAndMqtt/.gitignore index ec75a8e..0e95883 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/.gitignore +++ b/examples/ESP32LedStripWithPongAndMqtt/.gitignore @@ -1 +1,2 @@ settings.h +*.bin diff --git a/examples/ESP32LedStripWithPongAndMqtt/settings.example.h b/examples/ESP32LedStripWithPongAndMqtt/settings.example.h index f73d893..aaa68b1 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/settings.example.h +++ b/examples/ESP32LedStripWithPongAndMqtt/settings.example.h @@ -24,5 +24,6 @@ const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* host_name = "ESP_LED"; const String client_name = "ESP_LED"; const String topic_id = "esp_led"; From f9c3ddf35260e8981de3804d507483ae62aeadf6 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sun, 20 Jun 2021 17:55:52 +0200 Subject: [PATCH 31/40] renamed esp32 ota example ino file to fit the Arduino IDE naming schema --- ...ripWithPongAndMqtt.ino => ESP32LedStripOTAWithPongAndMqtt.ino} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/ESP32LedStripOTAWithPongAndMqtt/{ESP32LedStripWithPongAndMqtt.ino => ESP32LedStripOTAWithPongAndMqtt.ino} (100%) diff --git a/examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripOTAWithPongAndMqtt.ino similarity index 100% rename from examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino rename to examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripOTAWithPongAndMqtt.ino From 2f6294b1086b9303b0b302d6aeaa08105187b5b0 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Mon, 28 Feb 2022 17:18:32 +0100 Subject: [PATCH 32/40] added an example which uses a ESP32 board and an WS2801 LED-Strip; the on/off state is triggered by an external gpio connected source --- .../.gitignore | 2 + .../ESP32LedStripWithMqttAndExternalInput.ino | 309 ++++++++++++++++++ .../settings.example.h | 16 + 3 files changed, 327 insertions(+) create mode 100644 examples/ESP32LedStripWithMqttAndExternalInput/.gitignore create mode 100644 examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino create mode 100644 examples/ESP32LedStripWithMqttAndExternalInput/settings.example.h diff --git a/examples/ESP32LedStripWithMqttAndExternalInput/.gitignore b/examples/ESP32LedStripWithMqttAndExternalInput/.gitignore new file mode 100644 index 0000000..0e95883 --- /dev/null +++ b/examples/ESP32LedStripWithMqttAndExternalInput/.gitignore @@ -0,0 +1,2 @@ +settings.h +*.bin diff --git a/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino b/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino new file mode 100644 index 0000000..c1163b1 --- /dev/null +++ b/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino @@ -0,0 +1,309 @@ +//LED Strip: BTF-LIGHTING WS2801 +//Power Supply: HuaTec LED Trafo 15V +//Step-Down-Module +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//1 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 +//Libs: +// FastLED by Daniel Garcia Version 3.5.0 +// PubSubClient by Nick O'Leary Version 2.8.0 +// ArduinoJson by Benoit Blanchon Version 6.19.2 +#include +#include +#include +#include +#include "settings.h" + +CRGB leds[MAX_LEDS]; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +long last_refresh = 0; + +int brightness = 255; +int color_r = 255; +int color_g = 255; +int color_b = 255; +boolean stripe_on = false; +boolean input_active = false; + +int publish_status_after_every_config_change = 1; +int publish_status_if_toggled = 1; +int publish_status_at_start = 1; + +void show(){ + FastLED.setBrightness(brightness); + FastLED.show(); + FastLED.show(); +} + +void toggle_leds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i].r = color_r; + leds[i].g = color_g; + leds[i].b = color_b; + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + stripe_on = false; + } + + show(); + if (publish_status_if_toggled == 1){ + publish_current_status(); + } +} + +void publish_current_status(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (client.connected()){ + doc["output"] = stripe_on; + doc["brightness"] = brightness; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/status").c_str(), buffer, n); + } +} + +void fixConfigValues(){ + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.print(topic); + Serial.print(". Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + if (!err){ + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + + brightness = doc["brightness"] | brightness; + Serial.print("brightness: "); + Serial.println(brightness); + Serial.print("Doc brightness: "); + Serial.println(doc["brightness"].as()); + Serial.print("Doc color_r: "); + Serial.println(doc["color_r"].as()); + Serial.print("Doc color_g: "); + Serial.println(doc["color_g"].as()); + Serial.print("Doc color_b: "); + Serial.println(doc["color_b"].as()); + + } + } else if (String(topic) == topic_id+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publish_current_status(); + } + + fixConfigValues(); + + if (String(topic) != topic_id+"/get_status") { + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } +} + +void setup() { + client.setBufferSize(512); + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_broker, 1883); + reconnect(); + client.setCallback(callback); + + if (publish_status_at_start){ + publish_current_status(); + } + + FastLED.addLeds(leds, MAX_LEDS); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + leds[i] = CRGB::White; + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + + pinMode(CLOCK_PIN, OUTPUT); + pinMode(DATA_PIN, OUTPUT); + + attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); + delay(500); + input_changed(); +} + +void setup_wifi() { + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void input_changed(){ + if (digitalRead(INPUT_GPIO) == LOW){ + input_active = false; + } else { + input_active = true; + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { + Serial.println("connected"); + // Subscribe + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + client.subscribe((topic_id+"/get_status").c_str()); + client.subscribe((topic_id+"/config").c_str()); + client.subscribe((topic_id+"/output").c_str()); + client.subscribe((topic_id+"/color/r").c_str()); + client.subscribe((topic_id+"/color/g").c_str()); + client.subscribe((topic_id+"/color/b").c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (input_active != stripe_on){ + if (input_active){ + toggle_leds(1); + } else { + toggle_leds(0); + } + + last_refresh = millis(); + } else { + + if ((millis() - last_refresh) > REFRESH_INTERVAL){ + last_refresh = millis(); + show(); + } + } + delay(10); +} diff --git a/examples/ESP32LedStripWithMqttAndExternalInput/settings.example.h b/examples/ESP32LedStripWithMqttAndExternalInput/settings.example.h new file mode 100644 index 0000000..ce8e8c7 --- /dev/null +++ b/examples/ESP32LedStripWithMqttAndExternalInput/settings.example.h @@ -0,0 +1,16 @@ +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. +#define NUM_LEDS 300 +#define NUM_PONG_LEDS 10 +#define DATA_PIN 14 +#define CLOCK_PIN 13 +#define INPUT_GPIO 16 +#define REFRESH_INTERVAL 10000 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* host_name = "ESP_LED"; +const String client_name = "ESP_LED"; +const String topic_id = "esp_led"; From 152a14ef0a93173b41b58d45af72daf89e033116 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 1 Mar 2022 00:10:13 +0100 Subject: [PATCH 33/40] added another ESP32 example which uses an external input signal to trigger the leds, supports MQTT settings and Over-the-air updates via webbrowser (HOSTNAME:80/update); --- .../.gitignore | 2 + .../ESP32LedStripWithMqttAndExternalInput.ino | 326 ++++++++++++++++++ .../settings.example.h | 18 + 3 files changed, 346 insertions(+) create mode 100644 examples/ESP32LedStripWithMqttAndExternalInputOTA/.gitignore create mode 100644 examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInput.ino create mode 100644 examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/.gitignore b/examples/ESP32LedStripWithMqttAndExternalInputOTA/.gitignore new file mode 100644 index 0000000..0e95883 --- /dev/null +++ b/examples/ESP32LedStripWithMqttAndExternalInputOTA/.gitignore @@ -0,0 +1,2 @@ +settings.h +*.bin diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInput.ino b/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInput.ino new file mode 100644 index 0000000..a403002 --- /dev/null +++ b/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInput.ino @@ -0,0 +1,326 @@ +//LED Strip: BTF-LIGHTING WS2801 +//Power Supply: HuaTec LED Trafo 15V +//Step-Down-Module +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//1 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 +//Libs: +// FastLED by Daniel Garcia Version 3.5.0 +// PubSubClient by Nick O'Leary Version 2.8.0 +// ArduinoJson by Benoit Blanchon Version 6.19.2 +// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 +// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP +// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer +#include +#include +#include +#include +#include +#include +#include +#include "settings.h" + +AsyncWebServer server(80); + +CRGB leds[MAX_LEDS]; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +long last_refresh = 0; + +int brightness = 255; +int color_r = 255; +int color_g = 255; +int color_b = 255; +boolean stripe_on = false; +boolean input_active = false; + +int publish_status_after_every_config_change = 1; +int publish_status_if_toggled = 1; +int publish_status_at_start = 1; + +void show(){ + FastLED.setBrightness(brightness); + FastLED.show(); + FastLED.show(); +} + +void toggle_leds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i].r = color_r; + leds[i].g = color_g; + leds[i].b = color_b; + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + stripe_on = false; + } + + show(); + if (publish_status_if_toggled == 1){ + publish_current_status(); + } +} + +void publish_current_status(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (client.connected()){ + doc["output"] = stripe_on; + doc["brightness"] = brightness; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/status").c_str(), buffer, n); + } +} + +void fixConfigValues(){ + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.print(topic); + Serial.print(". Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + if (!err){ + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + + brightness = doc["brightness"] | brightness; + Serial.print("brightness: "); + Serial.println(brightness); + Serial.print("Doc brightness: "); + Serial.println(doc["brightness"].as()); + Serial.print("Doc color_r: "); + Serial.println(doc["color_r"].as()); + Serial.print("Doc color_g: "); + Serial.println(doc["color_g"].as()); + Serial.print("Doc color_b: "); + Serial.println(doc["color_b"].as()); + + } + } else if (String(topic) == topic_id+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publish_current_status(); + } + + fixConfigValues(); + + if (String(topic) != topic_id+"/get_status") { + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } +} + +void setup() { + client.setBufferSize(512); + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_broker, 1883); + reconnect(); + client.setCallback(callback); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hi! I am ESP32."); + }); + + AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA + server.begin(); + Serial.println("HTTP server started"); + + if (publish_status_at_start){ + publish_current_status(); + } + + FastLED.addLeds(leds, MAX_LEDS); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + leds[i] = CRGB::White; + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + + pinMode(CLOCK_PIN, OUTPUT); + pinMode(DATA_PIN, OUTPUT); + + attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); + delay(500); + input_changed(); +} + +void setup_wifi() { + WiFi.setHostname(host_name); + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void input_changed(){ + if (digitalRead(INPUT_GPIO) == LOW){ + input_active = false; + } else { + input_active = true; + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { + Serial.println("connected"); + // Subscribe + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + client.subscribe((topic_id+"/get_status").c_str()); + client.subscribe((topic_id+"/config").c_str()); + client.subscribe((topic_id+"/output").c_str()); + client.subscribe((topic_id+"/color/r").c_str()); + client.subscribe((topic_id+"/color/g").c_str()); + client.subscribe((topic_id+"/color/b").c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (input_active != stripe_on){ + if (input_active){ + toggle_leds(1); + } else { + toggle_leds(0); + } + + last_refresh = millis(); + } else { + + if ((millis() - last_refresh) > REFRESH_INTERVAL){ + last_refresh = millis(); + show(); + } + } + delay(10); +} diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h b/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h new file mode 100644 index 0000000..0ac6d2b --- /dev/null +++ b/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h @@ -0,0 +1,18 @@ +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. +#define NUM_LEDS 300 +#define NUM_PONG_LEDS 10 +#define DATA_PIN 14 +#define CLOCK_PIN 13 +#define INPUT_GPIO 16 +#define REFRESH_INTERVAL 10000 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* ota_user = "ENTER_OTA_USER_HERE"; +const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; +const char* host_name = "ESP_LED"; +const String client_name = "ESP_LED"; +const String topic_id = "esp_led"; From 17deab1204193a1451f3b9cd4dac0338484e515e Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 1 Mar 2022 00:11:47 +0100 Subject: [PATCH 34/40] Config notification now sends the object without converting it to JSON. The notification is not compatible with MMM-MQTTBroker otherwise --- MMM-LEDStripControl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MMM-LEDStripControl.js b/MMM-LEDStripControl.js index 199d4e1..4307a85 100644 --- a/MMM-LEDStripControl.js +++ b/MMM-LEDStripControl.js @@ -610,7 +610,7 @@ Module.register('MMM-LEDStripControl', { } console.log(self.name+": "+"Sending current config") - self.sendNotification(self.notifications["LED_STRIP_CONTROL_CURRENT_CONFIG"], JSON.stringify(curConfigArray)) + self.sendNotification(self.notifications["LED_STRIP_CONTROL_CURRENT_CONFIG"], curConfigArray) }, updateValuesToNotificationPayload: function(newValues){ From b7186071b60134af79938c3f7364c29617980b3b Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 1 Mar 2022 00:14:38 +0100 Subject: [PATCH 35/40] fixed wrong named ino in ESP32LedStripWithMqttAndExternalInputOTA example --- .../ESP32LedStripWithMqttAndExternalInput.ino | 326 ------------------ 1 file changed, 326 deletions(-) delete mode 100644 examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInput.ino diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInput.ino b/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInput.ino deleted file mode 100644 index a403002..0000000 --- a/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInput.ino +++ /dev/null @@ -1,326 +0,0 @@ -//LED Strip: BTF-LIGHTING WS2801 -//Power Supply: HuaTec LED Trafo 15V -//Step-Down-Module -//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 -//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 -//1 x Resistor: 10 kOhm -//Arduino Version: 1.8.13 -//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 -//Libs: -// FastLED by Daniel Garcia Version 3.5.0 -// PubSubClient by Nick O'Leary Version 2.8.0 -// ArduinoJson by Benoit Blanchon Version 6.19.2 -// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 -// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP -// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer -#include -#include -#include -#include -#include -#include -#include -#include "settings.h" - -AsyncWebServer server(80); - -CRGB leds[MAX_LEDS]; - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -long last_refresh = 0; - -int brightness = 255; -int color_r = 255; -int color_g = 255; -int color_b = 255; -boolean stripe_on = false; -boolean input_active = false; - -int publish_status_after_every_config_change = 1; -int publish_status_if_toggled = 1; -int publish_status_at_start = 1; - -void show(){ - FastLED.setBrightness(brightness); - FastLED.show(); - FastLED.show(); -} - -void toggle_leds(int to_state){ - if (to_state != -1){ - if (to_state == 0){ - stripe_on = true; - } else { - stripe_on = false; - } - } - if (stripe_on == false){ - Serial.print("Switch the rgb on with color: "); - Serial.print(color_r); - Serial.print("/"); - Serial.print(color_g); - Serial.print("/"); - Serial.println(color_b); - for (int i = 0; i< NUM_LEDS; i++){ - leds[i].r = color_r; - leds[i].g = color_g; - leds[i].b = color_b; - } - stripe_on = true; - } else { - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - stripe_on = false; - } - - show(); - if (publish_status_if_toggled == 1){ - publish_current_status(); - } -} - -void publish_current_status(){ - Serial.println("Publishing current status"); - StaticJsonDocument<1024> doc; - if (client.connected()){ - doc["output"] = stripe_on; - doc["brightness"] = brightness; - doc["color_r"] = color_r; - doc["color_g"] = color_g; - doc["color_b"] = color_b; - - char buffer[1024]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/status").c_str(), buffer, n); - } -} - -void fixConfigValues(){ - if (color_r > 255){ - color_r = 255; - } else if (color_r < 0){ - color_r = 0; - } - - if (color_g > 255){ - color_g = 255; - } else if (color_g < 0){ - color_g = 0; - } - - if (color_b > 255){ - color_b = 255; - } else if (color_b < 0){ - color_b = 0; - } - - if (brightness > 255){ - brightness = 255; - } else if (brightness < 0){ - brightness = 0; - } -} - -void callback(char* topic, byte* message, unsigned int length) { - Serial.print("Message arrived on topic: "); - Serial.print(topic); - Serial.print(". Message: "); - String messageTemp; - - for (int i = 0; i < length; i++) { - Serial.print((char)message[i]); - messageTemp += (char)message[i]; - } - Serial.println(); - - if (String(topic) == topic_id+"/config"){ - StaticJsonDocument<1024> doc; - DeserializationError err = deserializeJson(doc, messageTemp); - if (!err){ - color_r = doc["color_r"] | color_r; - color_g = doc["color_g"] | color_g; - color_b = doc["color_b"] | color_b; - - brightness = doc["brightness"] | brightness; - Serial.print("brightness: "); - Serial.println(brightness); - Serial.print("Doc brightness: "); - Serial.println(doc["brightness"].as()); - Serial.print("Doc color_r: "); - Serial.println(doc["color_r"].as()); - Serial.print("Doc color_g: "); - Serial.println(doc["color_g"].as()); - Serial.print("Doc color_b: "); - Serial.println(doc["color_b"].as()); - - } - } else if (String(topic) == topic_id+"/color/r"){ - color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/g"){ - color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/b"){ - color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/brightness"){ - brightness = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/get_status"){ - publish_current_status(); - } - - fixConfigValues(); - - if (String(topic) != topic_id+"/get_status") { - if (stripe_on){ - toggle_leds(1); - } else { - toggle_leds(0); - } - } - - if(publish_status_after_every_config_change){ - publish_current_status(); - } -} - -void setup() { - client.setBufferSize(512); - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_broker, 1883); - reconnect(); - client.setCallback(callback); - - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "text/plain", "Hi! I am ESP32."); - }); - - AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA - server.begin(); - Serial.println("HTTP server started"); - - if (publish_status_at_start){ - publish_current_status(); - } - - FastLED.addLeds(leds, MAX_LEDS); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(50); - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::White; - } - show(); - delay(200); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - - pinMode(CLOCK_PIN, OUTPUT); - pinMode(DATA_PIN, OUTPUT); - - attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); - delay(500); - input_changed(); -} - -void setup_wifi() { - WiFi.setHostname(host_name); - WiFi.disconnect(true, true); - WiFi.mode(WIFI_STA); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() == WL_DISCONNECTED) { - delay(500); - } - - if (WiFi.status() != WL_CONNECTED) { - delay(10); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(SSID); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void input_changed(){ - if (digitalRead(INPUT_GPIO) == LOW){ - input_active = false; - } else { - input_active = true; - } -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { - Serial.println("connected"); - // Subscribe - Serial.print("Subscribing with topic_id: "); - Serial.println(topic_id); - client.subscribe((topic_id+"/get_status").c_str()); - client.subscribe((topic_id+"/config").c_str()); - client.subscribe((topic_id+"/output").c_str()); - client.subscribe((topic_id+"/color/r").c_str()); - client.subscribe((topic_id+"/color/g").c_str()); - client.subscribe((topic_id+"/color/b").c_str()); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void loop() { - if (WiFi.status() != WL_CONNECTED) { - setup_wifi(); - } - - if (!client.connected()) { - reconnect(); - } - client.loop(); - - if (input_active != stripe_on){ - if (input_active){ - toggle_leds(1); - } else { - toggle_leds(0); - } - - last_refresh = millis(); - } else { - - if ((millis() - last_refresh) > REFRESH_INTERVAL){ - last_refresh = millis(); - show(); - } - } - delay(10); -} From 4927b7474e85f6c6852e4c5bf4abeeabed4ed52c Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Sat, 5 Mar 2022 11:39:38 +0100 Subject: [PATCH 36/40] added example with OTA update; added option to configure an WS2812B strip instead of WS2801 to setup of MqttAndExternalInput examples --- .../ESP32LedStripWithMqttAndExternalInput.ino | 1 + ...P32LedStripWithMqttAndExternalInputOTA.ino | 327 ++++++++++++++++++ 2 files changed, 328 insertions(+) create mode 100644 examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino diff --git a/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino b/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino index c1163b1..32738aa 100644 --- a/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino +++ b/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino @@ -193,6 +193,7 @@ void setup() { } FastLED.addLeds(leds, MAX_LEDS); + //FastLED.addLeds(leds, MAX_LEDS); for (int i=0; i < MAX_LEDS; i++){ leds[i] = CRGB::Black; } diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino b/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino new file mode 100644 index 0000000..7063ade --- /dev/null +++ b/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino @@ -0,0 +1,327 @@ +//LED Strip: BTF-LIGHTING WS2801 +//Power Supply: HuaTec LED Trafo 15V +//Step-Down-Module +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//1 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 +//Libs: +// FastLED by Daniel Garcia Version 3.5.0 +// PubSubClient by Nick O'Leary Version 2.8.0 +// ArduinoJson by Benoit Blanchon Version 6.19.2 +// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 +// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP +// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer +#include +#include +#include +#include +#include +#include +#include +#include "settings.h" + +AsyncWebServer server(80); + +CRGB leds[MAX_LEDS]; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +long last_refresh = 0; + +int brightness = 255; +int color_r = 255; +int color_g = 255; +int color_b = 255; +boolean stripe_on = false; +boolean input_active = false; + +int publish_status_after_every_config_change = 1; +int publish_status_if_toggled = 1; +int publish_status_at_start = 1; + +void show(){ + FastLED.setBrightness(brightness); + FastLED.show(); + FastLED.show(); +} + +void toggle_leds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i].r = color_r; + leds[i].g = color_g; + leds[i].b = color_b; + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + stripe_on = false; + } + + show(); + if (publish_status_if_toggled == 1){ + publish_current_status(); + } +} + +void publish_current_status(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (client.connected()){ + doc["output"] = stripe_on; + doc["brightness"] = brightness; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/status").c_str(), buffer, n); + } +} + +void fixConfigValues(){ + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.print(topic); + Serial.print(". Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + if (!err){ + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + + brightness = doc["brightness"] | brightness; + Serial.print("brightness: "); + Serial.println(brightness); + Serial.print("Doc brightness: "); + Serial.println(doc["brightness"].as()); + Serial.print("Doc color_r: "); + Serial.println(doc["color_r"].as()); + Serial.print("Doc color_g: "); + Serial.println(doc["color_g"].as()); + Serial.print("Doc color_b: "); + Serial.println(doc["color_b"].as()); + + } + } else if (String(topic) == topic_id+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publish_current_status(); + } + + fixConfigValues(); + + if (String(topic) != topic_id+"/get_status") { + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } +} + +void setup() { + client.setBufferSize(512); + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_broker, 1883); + reconnect(); + client.setCallback(callback); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hi! I am ESP32."); + }); + + AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA + server.begin(); + Serial.println("HTTP server started"); + + if (publish_status_at_start){ + publish_current_status(); + } + + FastLED.addLeds(leds, MAX_LEDS); + //FastLED.addLeds(leds, MAX_LEDS); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + leds[i] = CRGB::White; + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + + pinMode(CLOCK_PIN, OUTPUT); + pinMode(DATA_PIN, OUTPUT); + + attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); + delay(500); + input_changed(); +} + +void setup_wifi() { + WiFi.setHostname(host_name); + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void input_changed(){ + if (digitalRead(INPUT_GPIO) == LOW){ + input_active = false; + } else { + input_active = true; + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { + Serial.println("connected"); + // Subscribe + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + client.subscribe((topic_id+"/get_status").c_str()); + client.subscribe((topic_id+"/config").c_str()); + client.subscribe((topic_id+"/output").c_str()); + client.subscribe((topic_id+"/color/r").c_str()); + client.subscribe((topic_id+"/color/g").c_str()); + client.subscribe((topic_id+"/color/b").c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (input_active != stripe_on){ + if (input_active){ + toggle_leds(1); + } else { + toggle_leds(0); + } + + last_refresh = millis(); + } else { + + if ((millis() - last_refresh) > REFRESH_INTERVAL){ + last_refresh = millis(); + show(); + } + } + delay(10); +} From 8e9f978dc70d3ed8445bc53986e67e72cfec9737 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Tue, 8 Mar 2022 11:05:53 +0100 Subject: [PATCH 37/40] added WS2815 example with external input, mqtt and ota --- .../settings.example.h | 1 - .../Esp32WS2815MqttExternalInOTA/.gitignore | 2 + .../Esp32WS2815MqttExternalInOTA.ino | 326 ++++++++++++++++++ .../settings.example.h | 16 + 4 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 examples/Esp32WS2815MqttExternalInOTA/.gitignore create mode 100644 examples/Esp32WS2815MqttExternalInOTA/Esp32WS2815MqttExternalInOTA.ino create mode 100644 examples/Esp32WS2815MqttExternalInOTA/settings.example.h diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h b/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h index 0ac6d2b..e2da806 100644 --- a/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h +++ b/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h @@ -1,6 +1,5 @@ #define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. #define NUM_LEDS 300 -#define NUM_PONG_LEDS 10 #define DATA_PIN 14 #define CLOCK_PIN 13 #define INPUT_GPIO 16 diff --git a/examples/Esp32WS2815MqttExternalInOTA/.gitignore b/examples/Esp32WS2815MqttExternalInOTA/.gitignore new file mode 100644 index 0000000..0e95883 --- /dev/null +++ b/examples/Esp32WS2815MqttExternalInOTA/.gitignore @@ -0,0 +1,2 @@ +settings.h +*.bin diff --git a/examples/Esp32WS2815MqttExternalInOTA/Esp32WS2815MqttExternalInOTA.ino b/examples/Esp32WS2815MqttExternalInOTA/Esp32WS2815MqttExternalInOTA.ino new file mode 100644 index 0000000..76f4590 --- /dev/null +++ b/examples/Esp32WS2815MqttExternalInOTA/Esp32WS2815MqttExternalInOTA.ino @@ -0,0 +1,326 @@ +//LED Strip: BTF-LIGHTING WS2801 +//Power Supply: HuaTec LED Trafo 15V +//Step-Down-Module +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//1 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 +//Libs: +// FastLED by Daniel Garcia Version 3.5.0 +// PubSubClient by Nick O'Leary Version 2.8.0 +// ArduinoJson by Benoit Blanchon Version 6.19.2 +// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 +// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP +// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer +#include +#include +#include +#include +#include +#include +#include +#include "settings.h" + +AsyncWebServer server(80); + +CRGB leds[MAX_LEDS]; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +long last_refresh = 0; + +int brightness = 255; +int color_r = 255; +int color_g = 255; +int color_b = 255; +boolean stripe_on = false; +boolean input_active = false; + +int publish_status_after_every_config_change = 1; +int publish_status_if_toggled = 1; +int publish_status_at_start = 1; + +void show(){ + //FastLED.setBrightness(brightness); + FastLED.show(); + //FastLED.show(); +} + +void toggle_leds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i].r = color_r; + leds[i].g = color_g; + leds[i].b = color_b; + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + stripe_on = false; + } + + show(); + if (publish_status_if_toggled == 1){ + publish_current_status(); + } +} + +void publish_current_status(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (client.connected()){ + doc["output"] = stripe_on; + doc["brightness"] = brightness; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/status").c_str(), buffer, n); + } +} + +void fixConfigValues(){ + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.print(topic); + Serial.print(". Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + if (!err){ + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + + brightness = doc["brightness"] | brightness; + Serial.print("brightness: "); + Serial.println(brightness); + Serial.print("Doc brightness: "); + Serial.println(doc["brightness"].as()); + Serial.print("Doc color_r: "); + Serial.println(doc["color_r"].as()); + Serial.print("Doc color_g: "); + Serial.println(doc["color_g"].as()); + Serial.print("Doc color_b: "); + Serial.println(doc["color_b"].as()); + + } + } else if (String(topic) == topic_id+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publish_current_status(); + } + + fixConfigValues(); + + if (String(topic) != topic_id+"/get_status") { + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } +} + +void setup() { + client.setBufferSize(512); + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_broker, 1883); + reconnect(); + client.setCallback(callback); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hi! I am ESP32."); + }); + + AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA + server.begin(); + Serial.println("HTTP server started"); + + if (publish_status_at_start){ + publish_current_status(); + } + + FastLED.addLeds(leds, MAX_LEDS); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + leds[i] = CRGB::White; + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + + pinMode(CLOCK_PIN, OUTPUT); + pinMode(DATA_PIN, OUTPUT); + + attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); + delay(500); + input_changed(); +} + +void setup_wifi() { + WiFi.setHostname(host_name); + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void input_changed(){ + if (digitalRead(INPUT_GPIO) == LOW){ + input_active = false; + } else { + input_active = true; + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { + Serial.println("connected"); + // Subscribe + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + client.subscribe((topic_id+"/get_status").c_str()); + client.subscribe((topic_id+"/config").c_str()); + client.subscribe((topic_id+"/output").c_str()); + client.subscribe((topic_id+"/color/r").c_str()); + client.subscribe((topic_id+"/color/g").c_str()); + client.subscribe((topic_id+"/color/b").c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (input_active != stripe_on){ + if (input_active){ + toggle_leds(1); + } else { + toggle_leds(0); + } + + last_refresh = millis(); + } else { + + if ((millis() - last_refresh) > REFRESH_INTERVAL){ + last_refresh = millis(); + show(); + } + } + delay(10); +} diff --git a/examples/Esp32WS2815MqttExternalInOTA/settings.example.h b/examples/Esp32WS2815MqttExternalInOTA/settings.example.h new file mode 100644 index 0000000..ccfa6b9 --- /dev/null +++ b/examples/Esp32WS2815MqttExternalInOTA/settings.example.h @@ -0,0 +1,16 @@ +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. +#define NUM_LEDS 300 +#define DATA_PIN 14 +#define INPUT_GPIO 16 +#define REFRESH_INTERVAL 10000 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* ota_user = "ENTER_OTA_USER_HERE"; +const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; +const char* host_name = "ESP_LED"; +const String client_name = "ESP_LED"; +const String topic_id = "esp_led"; From 40c9ec2cec2da275f7f80ac68c4f4b0a6e2abe45 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Fri, 11 Mar 2022 11:24:35 +0100 Subject: [PATCH 38/40] cleaned up examples and added ones which use the NeoPixel instead of the FastLED library --- ...P32LedStripWithMqttAndExternalInputOTA.ino | 8 +- .../.gitignore | 0 ...ripWithMqttAndExternalInputOTANeopixel.ino | 313 ++++++ .../settings.example.h | 17 + .../ESP32LedStripWithPongAndMqtt.ino | 2 +- .../.gitignore | 2 + .../ESP32LedStripWithPongAndMqttOTA.ino | 931 ++++++++++++++++++ .../settings.example.h | 31 + .../.gitignore | 2 + ...SP32LedStripWithPongAndMqttOTANeoPixel.ino | 927 +++++++++++++++++ .../settings.example.h | 31 + .../ESP32WS2815MqttExternalInOTA/.gitignore | 2 + .../ESP32WS2815MqttExternalInOTA.ino} | 2 +- .../settings.example.h | 0 14 files changed, 2262 insertions(+), 6 deletions(-) rename examples/{Esp32WS2815MqttExternalInOTA => ESP32LedStripWithMqttAndExternalInputOTANeopixel}/.gitignore (100%) create mode 100755 examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino create mode 100755 examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h create mode 100644 examples/ESP32LedStripWithPongAndMqttOTA/.gitignore create mode 100644 examples/ESP32LedStripWithPongAndMqttOTA/ESP32LedStripWithPongAndMqttOTA.ino create mode 100644 examples/ESP32LedStripWithPongAndMqttOTA/settings.example.h create mode 100644 examples/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore create mode 100644 examples/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino create mode 100644 examples/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h create mode 100644 examples/ESP32WS2815MqttExternalInOTA/.gitignore rename examples/{Esp32WS2815MqttExternalInOTA/Esp32WS2815MqttExternalInOTA.ino => ESP32WS2815MqttExternalInOTA/ESP32WS2815MqttExternalInOTA.ino} (99%) rename examples/{Esp32WS2815MqttExternalInOTA => ESP32WS2815MqttExternalInOTA}/settings.example.h (100%) diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino b/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino index 7063ade..07e5650 100644 --- a/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino +++ b/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino @@ -48,7 +48,7 @@ int publish_status_at_start = 1; void show(){ FastLED.setBrightness(brightness); FastLED.show(); - FastLED.show(); + //FastLED.show(); } void toggle_leds(int to_state){ @@ -87,7 +87,7 @@ void toggle_leds(int to_state){ void publish_current_status(){ Serial.println("Publishing current status"); - StaticJsonDocument<1024> doc; + StaticJsonDocument<512> doc; if (client.connected()){ doc["output"] = stripe_on; doc["brightness"] = brightness; @@ -95,7 +95,7 @@ void publish_current_status(){ doc["color_g"] = color_g; doc["color_b"] = color_b; - char buffer[1024]; + char buffer[512]; size_t n = serializeJson(doc, buffer); client.publish((topic_id+"/status").c_str(), buffer, n); @@ -141,7 +141,7 @@ void callback(char* topic, byte* message, unsigned int length) { Serial.println(); if (String(topic) == topic_id+"/config"){ - StaticJsonDocument<1024> doc; + StaticJsonDocument<512> doc; DeserializationError err = deserializeJson(doc, messageTemp); if (!err){ color_r = doc["color_r"] | color_r; diff --git a/examples/Esp32WS2815MqttExternalInOTA/.gitignore b/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/.gitignore similarity index 100% rename from examples/Esp32WS2815MqttExternalInOTA/.gitignore rename to examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/.gitignore diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino b/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino new file mode 100755 index 0000000..9bfd885 --- /dev/null +++ b/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino @@ -0,0 +1,313 @@ +//LED Strip: BTF-LIGHTING WS2801 +//Power Supply: HuaTec LED Trafo 15V +//Step-Down-Module +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//1 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 +//Libs: +// Adafruit_NeoPixel by Adafruit Version 1.10.4 +// PubSubClient by Nick O'Leary Version 2.8.0 +// ArduinoJson by Benoit Blanchon Version 6.19.3 +// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 +// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP +// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer +#include +#include +#include +#include +#include +#include +#include +#include "settings.h" + +AsyncWebServer server(80); + +Adafruit_NeoPixel pixels(MAX_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800); + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +long last_refresh = 0; + +int brightness = 255; +int color_r = 255; +int color_g = 255; +int color_b = 255; +boolean stripe_on = false; +boolean input_active = false; + +int publish_status_after_every_config_change = 1; +int publish_status_if_toggled = 1; +int publish_status_at_start = 1; + +void show(){ + pixels.setBrightness(brightness); + pixels.show(); +} + +void toggle_leds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(color_r,color_g,color_b)); + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + stripe_on = false; + } + + show(); + if (publish_status_if_toggled == 1){ + publish_current_status(); + } +} + +void publish_current_status(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (client.connected()){ + doc["output"] = stripe_on; + doc["brightness"] = brightness; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/status").c_str(), buffer, n); + } +} + +void fixConfigValues(){ + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.print(topic); + Serial.print(". Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + if (!err){ + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + brightness = doc["brightness"] | brightness; + } + } else if (String(topic) == topic_id+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publish_current_status(); + } + + fixConfigValues(); + + if (String(topic) != topic_id+"/get_status") { + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } +} + +void setup() { + client.setBufferSize(512); + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_broker, 1883); + reconnect(); + client.setCallback(callback); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hi! I am "+host_name); + }); + + AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA + server.begin(); + Serial.println("HTTP server started"); + + if (publish_status_at_start){ + publish_current_status(); + } + + pinMode(CLOCK_PIN, OUTPUT); + pinMode(DATA_PIN, OUTPUT); + + pixels.begin(); + pixels.clear(); + + for (int i=0; i < MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0, 0, 0)); + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(255, 255, 255)); + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0, 0, 0)); + } + show(); + + attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); + delay(500); + input_changed(); +} + +void setup_wifi() { + WiFi.setHostname(host_name.c_str()); + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void input_changed(){ + if (digitalRead(INPUT_GPIO) == LOW){ + input_active = false; + } else { + input_active = true; + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { + Serial.println("connected"); + // Subscribe + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + client.subscribe((topic_id+"/get_status").c_str()); + client.subscribe((topic_id+"/config").c_str()); + client.subscribe((topic_id+"/output").c_str()); + client.subscribe((topic_id+"/color/r").c_str()); + client.subscribe((topic_id+"/color/g").c_str()); + client.subscribe((topic_id+"/color/b").c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (input_active != stripe_on){ + if (input_active){ + toggle_leds(1); + } else { + toggle_leds(0); + } + + last_refresh = millis(); + } else { + + if ((millis() - last_refresh) > REFRESH_INTERVAL){ + last_refresh = millis(); + show(); + } + } + delay(10); +} diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h b/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h new file mode 100755 index 0000000..539de4b --- /dev/null +++ b/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h @@ -0,0 +1,17 @@ +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. +#define NUM_LEDS 300 +#define DATA_PIN 14 +#define CLOCK_PIN 13 +#define INPUT_GPIO 16 +#define REFRESH_INTERVAL 10000 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* ota_user = "ENTER_OTA_USER_HERE"; +const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; +const String host_name = "ESP_LED"; +const String client_name = "ESP_LED"; +const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino index f68d0de..8e5370f 100644 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino @@ -416,7 +416,7 @@ void callback(char* topic, byte* message, unsigned int length) { void show(){ FastLED.setBrightness(brightness); FastLED.show(); - FastLED.show(); + //FastLED.show(); } void setup() { diff --git a/examples/ESP32LedStripWithPongAndMqttOTA/.gitignore b/examples/ESP32LedStripWithPongAndMqttOTA/.gitignore new file mode 100644 index 0000000..0e95883 --- /dev/null +++ b/examples/ESP32LedStripWithPongAndMqttOTA/.gitignore @@ -0,0 +1,2 @@ +settings.h +*.bin diff --git a/examples/ESP32LedStripWithPongAndMqttOTA/ESP32LedStripWithPongAndMqttOTA.ino b/examples/ESP32LedStripWithPongAndMqttOTA/ESP32LedStripWithPongAndMqttOTA.ino new file mode 100644 index 0000000..8f8a532 --- /dev/null +++ b/examples/ESP32LedStripWithPongAndMqttOTA/ESP32LedStripWithPongAndMqttOTA.ino @@ -0,0 +1,931 @@ +//LED Strip: BTF-LIGHTING WS2815 -> https://www.amazon.de/gp/product/B07LG5ZT9C/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1 +//Power Supply: HuaTec LED Trafo 12V 120W -> https://www.amazon.de/gp/product/B0829817YM/ref=ppx_yo_dt_b_asin_image_o09_s00?ie=UTF8&psc=1 +//Step-Down-Module: AZDelivery XL4015 -> https://www.amazon.de/gp/product/B07SRXR1VT/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1 +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//2 x Tactile Push Button (Something like https://www.amazon.de/gp/product/B078ZDK6KZ/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) +//2 x Capacitor 0.1 Mikrofarad +//2 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 1.0.6 +//Libs: +// FastLED by Daniel Garcia Version 3.4.0 +// PubSubClient by Nick O'Leary Version 2.8.0 +// ArduinoJson by Benoit Blanchon Version 6.17.3 +#include +#include +#include +#include +#include +#include +#include +#include "settings.h" + +AsyncWebServer server(80); + +CRGB leds[MAX_LEDS]; + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +long last_refresh = 0; + +int reverseMode=0; +int cur_pixel=0; +int btn_one_state = 0; +int btn_one_long_state = 0; +long btn_one_last_pressed = 0; +long btn_one_last_released = -1; +int btn_two_state = 0; +int btn_two_long_state = 0; +long btn_two_last_pressed = 0; +long btn_two_last_released = -1; +bool enable_hardware_btns = true; + + +int brightness = 255; +int brightness_decrease = true; +int color_r = 255; +int color_g = 255; +int color_b = 255; +int stripe_mode = 0; +boolean stripe_on = false; + +float pong_init_delay = PONG_INIT_LED_DELAY; +float cur_pong_delay = pong_init_delay; +int num_pong_leds = NUM_PONG_LEDS; +int pong_start_led = PONG_START_LED; +int pong_max_wins = PONG_MAX_WINS; +float pong_wins_delay_during = PONG_RESULT_DELAY_DURING; +float pong_wins_delay_after = PONG_RESULT_DELAY_AFTER; +float pong_min_delay = PONG_MIN_LED_DELAY; +float pong_dec_per_run = PONG_DEC_PER_RUN; +float pong_btn_delay = PONG_BTN_DELAY; +int pong_tolerance = PONG_TOLERANCE; +int pong_color_r = 0; +int pong_color_g = 0; +int pong_color_b = 255; +int pong_result_color_r = 0; +int pong_result_color_g = 255; +int pong_result_color_b = 0; +int player_one_wins = 0; +int player_successfull_one_press = 0; +int player_two_wins = 0; +int player_successfull_two_press = 0; +int player_one_miss = 0; +int player_two_miss = 0; +int abortRun = 0; +bool player_one_hit_first = true; +bool change_start_led_during_match = true; + +int publish_status_after_every_config_change = 1; +int publish_status_if_toggled = 1; +int publish_status_at_start = 1; +int publish_results_at_display = 1; + + +void publish_current_status(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (client.connected()){ + doc["pong"]["btn_delay"] = pong_btn_delay; + doc["pong"]["init_delay"] = pong_init_delay; + doc["pong"]["min_delay"] = pong_min_delay; + doc["pong"]["dec_per_run"] = pong_dec_per_run; + doc["pong"]["num_leds"] = num_pong_leds; + doc["pong"]["max_wins"] = pong_max_wins; + doc["pong"]["tolerance"] = pong_tolerance; + doc["pong"]["result_delay_during"] = pong_wins_delay_during; + doc["pong"]["result_delay_after"] = pong_wins_delay_after; + doc["pong"]["color_r"] = pong_color_r; + doc["pong"]["color_g"] = pong_color_g; + doc["pong"]["color_b"] = pong_color_b; + doc["pong"]["result_color_r"] = pong_result_color_r; + doc["pong"]["result_color_g"] = pong_result_color_g; + doc["pong"]["result_color_b"] = pong_result_color_b; + doc["output"] = stripe_on; + doc["mode"] = stripe_mode; + doc["brightness"] = brightness; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + doc["hardware_buttons_enabled"] = enable_hardware_btns; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/status").c_str(), buffer, n); + } +} + +void publish_results(){ + StaticJsonDocument<100> doc; + if (client.connected()){ + doc["result_player_one"] = player_one_wins; + doc["result_player_two"] = player_two_wins; + } + char buffer[100]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/results").c_str(), buffer, n); +} + +void fixConfigValues(){ + if (pong_btn_delay < 0){ + pong_btn_delay = 0; + } + + if (pong_init_delay < pong_min_delay){ + pong_init_delay = pong_min_delay; + } + + if (pong_min_delay < 0){ + pong_min_delay = 0; + } + + if (pong_dec_per_run < 0){ + pong_dec_per_run = 0; + } + + if (num_pong_leds > NUM_LEDS){ + num_pong_leds = NUM_LEDS; + } + + if (pong_max_wins > num_pong_leds){ + pong_max_wins = num_pong_leds; + } + + if (pong_wins_delay_during < 0){ + pong_wins_delay_during = 0; + } + + if (pong_wins_delay_after < 0){ + pong_wins_delay_after = 0; + } + + if (pong_result_color_r > 255){ + pong_result_color_r = 255; + } else if (pong_result_color_r < 0){ + pong_result_color_r = 0; + } + + if (pong_result_color_g > 255){ + pong_result_color_g = 255; + } else if (pong_result_color_g < 0){ + pong_result_color_g = 0; + } + + if (pong_result_color_b > 255){ + pong_result_color_b = 255; + } else if (pong_result_color_b < 0){ + pong_result_color_b = 0; + } + + if (pong_tolerance < 0){ + pong_tolerance = 0; + } + + if (pong_tolerance > (num_pong_leds -1)){ + pong_tolerance = num_pong_leds -1; + } + + if (pong_color_r > 255){ + pong_color_r = 255; + } else if (pong_color_r < 0){ + pong_color_r = 0; + } + + if (pong_color_g > 255){ + pong_color_g = 255; + } else if (pong_color_g < 0){ + pong_color_g = 0; + } + + if (pong_color_b > 255){ + pong_color_b = 255; + } else if (pong_color_b < 0){ + pong_color_b = 0; + } + + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.print(topic); + Serial.print(". Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (! (String(topic) == topic_id+"/btn") ) { + // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". + // Changes the output state according to the message + if (String(topic) == topic_id+"/output") { + Serial.print("Changing output to "); + if(messageTemp == "on"){ + Serial.println("on"); + toggle_leds(1); + } + else if(messageTemp == "off"){ + Serial.println("off"); + toggle_leds(0); + } else { + Serial.println("toggle"); + toggle_leds(-1); + } + } else if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + if (!err){ + + if(doc["pong"]["btn_delay"]){ + pong_btn_delay = doc["pong"]["btn_delay"].as(); + } + + if(doc["pong"]["init_delay"]){ + pong_init_delay = doc["pong"]["init_delay"].as(); + } + + if(doc["pong"]["min_delay"]){ + pong_min_delay = doc["pong"]["min_delay"].as(); + } + + if(doc["pong"]["dec_per_run"]){ + pong_dec_per_run = doc["pong"]["dec_per_run"].as(); + } + + num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; + pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; + pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; + + if(doc["pong"]["result_delay_during"]){ + pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); + } + + if(doc["pong"]["result_delay_after"]){ + pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); + } + + pong_color_r = doc["pong"]["color_r"] | pong_color_r; + pong_color_g = doc["pong"]["color_g"] | pong_color_g; + pong_color_b = doc["pong"]["color_b"] | pong_color_b; + + pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; + pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; + pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; + + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + + brightness = doc["brightness"] | brightness; + + if (doc.containsKey("hardware_buttons_enabled")){ + if (!doc["hardware_buttons_enabled"]){ + if (enable_hardware_btns){ + enable_hardware_btns = false; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (!enable_hardware_btns){ + enable_hardware_btns = true; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); + Serial.println("Enable Hardware Buttons"); + } + } + } + + } + + } else if (String(topic) == topic_id+"/pong/btn_delay"){ + pong_btn_delay = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/init_delay"){ + pong_init_delay = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/min_delay"){ + pong_min_delay = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/dec_per_run"){ + pong_dec_per_run = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/num_leds"){ + num_pong_leds = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/max_wins"){ + pong_max_wins = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/result/delay/during"){ + pong_wins_delay_during = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/result/delay/after"){ + pong_wins_delay_after = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/result/color/r"){ + pong_result_color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/result/color/g"){ + pong_result_color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/result/color/b"){ + pong_result_color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/tolerance"){ + pong_tolerance = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/color/r"){ + pong_color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/color/g"){ + pong_color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/color/b"){ + pong_color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publish_current_status(); + } else if (String(topic) == topic_id+"/hardware_buttons_enabled"){ + if (messageTemp.toInt() == 1){ + if (enable_hardware_btns){ + enable_hardware_btns = false; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (!enable_hardware_btns){ + enable_hardware_btns = true; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); + Serial.println("Enable Hardware Buttons"); + } + } + } + + fixConfigValues(); + + if ((String(topic) != topic_id+"/output") && + (String(topic) != topic_id+"/get_status") && + (stripe_mode == 0)){ + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } + } else { + Serial.println("Button press via mqtt"); + Serial.println(messageTemp); + if (messageTemp.toInt() == 2 ){ + btn_two_last_pressed = millis(); + btn_two_last_released = btn_two_last_pressed; + btn_two_state = 1; + } else { + btn_one_last_pressed = millis(); + btn_one_last_released = btn_one_last_pressed; + btn_one_state = 1; + } + } +} + +void show(){ + FastLED.setBrightness(brightness); + FastLED.show(); + //FastLED.show(); +} + +void setup() { + client.setBufferSize(512); + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_broker, 1883); + reconnect(); + client.setCallback(callback); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hi! I am "+host_name); + }); + + AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA + server.begin(); + Serial.println("HTTP server started"); + + if (publish_status_at_start){ + publish_current_status(); + } + + FastLED.addLeds(leds, MAX_LEDS); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + leds[i] = CRGB::White; + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + + pinMode(BTN_1_GPIO, INPUT); + pinMode(BTN_2_GPIO, INPUT); + pinMode(DATA_PIN, OUTPUT); + + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); + delay(500); +} + +void setup_wifi() { + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void btn_one_changed(){ + long cur_time = millis(); + if((cur_time - btn_one_last_pressed) > BTN_DEBOUNCE_DELAY){ + if (digitalRead(BTN_1_GPIO) == LOW){ + btn_one_last_pressed = cur_time; + btn_one_state = 1; + } else{ + btn_one_last_released = cur_time; + } + } else{ + if (digitalRead(BTN_1_GPIO) == HIGH){ + btn_one_last_released = cur_time; + } + } +} + +void btn_two_changed(){ + long cur_time = millis(); + if((cur_time - btn_two_last_pressed) > BTN_DEBOUNCE_DELAY){ + if (digitalRead(BTN_2_GPIO) == LOW){ + btn_two_last_pressed = cur_time; + btn_two_state = 1; + } else{ + btn_two_last_released = cur_time; + } + } else { + if (digitalRead(BTN_2_GPIO) == HIGH){ + btn_two_last_released = cur_time; + } + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { + Serial.println("connected"); + // Subscribe + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + client.subscribe((topic_id+"/get_status").c_str()); + client.subscribe((topic_id+"/config").c_str()); + client.subscribe((topic_id+"/output").c_str()); + client.subscribe((topic_id+"/pong/btn_delay").c_str()); + client.subscribe((topic_id+"/pong/init_delay").c_str()); + client.subscribe((topic_id+"/pong/min_delay").c_str()); + client.subscribe((topic_id+"/pong/dec_per_run").c_str()); + client.subscribe((topic_id+"/pong/num_leds").c_str()); + client.subscribe((topic_id+"/pong/max_wins").c_str()); + client.subscribe((topic_id+"/pong/result/delay/during").c_str()); + client.subscribe((topic_id+"/pong/result/delay/after").c_str()); + client.subscribe((topic_id+"/pong/result/color/r").c_str()); + client.subscribe((topic_id+"/pong/result/color/g").c_str()); + client.subscribe((topic_id+"/pong/result/color/b").c_str()); + client.subscribe((topic_id+"/pong/tolerance").c_str()); + client.subscribe((topic_id+"/pong/color/r").c_str()); + client.subscribe((topic_id+"/pong/color/g").c_str()); + client.subscribe((topic_id+"/pong/color/b").c_str()); + client.subscribe((topic_id+"/color/r").c_str()); + client.subscribe((topic_id+"/color/g").c_str()); + client.subscribe((topic_id+"/color/b").c_str()); + client.subscribe((topic_id+"/btn").c_str()); + client.subscribe((topic_id+"/disable_btns").c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void toggle_leds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i].r = color_r; + leds[i].g = color_g; + leds[i].b = color_b; + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + stripe_on = false; + } + + show(); + if (publish_status_if_toggled == 1){ + publish_current_status(); + } +} + +void reset_pong_vars(bool during, bool oneHitFirst){ + Serial.print("Resetting pong vars ("); + Serial.print(during); + Serial.print("/"); + Serial.print(oneHitFirst); + Serial.println(")"); + client.loop(); + player_one_miss = 0; + player_two_miss = 0; + btn_one_state = 0; + btn_two_state = 0; + player_successfull_one_press = 0; + player_successfull_two_press = 0; + cur_pong_delay = pong_init_delay; + + if (!during){ + player_one_wins = 0; + player_two_wins = 0; + btn_one_last_pressed = 0; + btn_two_last_pressed = 0; + stripe_mode = 0; + } + + if (oneHitFirst){ + cur_pixel = pong_start_led; + reverseMode = 0; + } else { + cur_pixel = num_pong_leds-1; + reverseMode = 1; + } +} + +void switch_to_pong_mode(bool oneHitFirst){ + Serial.println("Switching to pong mode"); + delay(500); + reset_pong_vars(false, oneHitFirst); + + stripe_mode = 1; + + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(1000); + for (int i = pong_start_led; i< num_pong_leds; i++){ + leds[i].r = pong_color_r; + leds[i].g = pong_color_g; + leds[i].b = pong_color_b; + } + show(); + delay(1000); + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + show(); + delay(1000); +} + +void display_result(float cur_delay){ + Serial.println("Displaying results"); + delay(500); + for (int i = 0; i< MAX_LEDS; i++){ + leds[i] = CRGB::Black; + } + + for (int i = pong_start_led; i < player_one_wins+pong_start_led; i++){ + leds[i].r = pong_result_color_r; + leds[i].g = pong_result_color_g; + leds[i].b = pong_result_color_b; + } + + for (int i = (num_pong_leds - 1); i > ((num_pong_leds-1)-player_two_wins); i--){ + leds[i].r = pong_result_color_r; + leds[i].g = pong_result_color_g; + leds[i].b = pong_result_color_b; + } + show(); + delay(cur_delay*1000); +} + +void changeBrightness(){ + if (brightness_decrease){ + //Serial.println("Decrease brightness"); + brightness = brightness - BRIGHTNESS_CHANGE_VALUE; + if (brightness <= 0){ + brightness = 0; + //Serial.println("Smallest value reached"); + brightness_decrease = !brightness_decrease; + } + } else { + //Serial.println("Increase brightness"); + brightness = brightness + BRIGHTNESS_CHANGE_VALUE; + if (brightness >= 255){ + brightness = 255; + //Serial.println("Max value reached"); + brightness_decrease = !brightness_decrease; + } + } + + show(); +} + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (stripe_mode == 0){ + if ((btn_one_state == 1) or (btn_two_state == 1)){ + //Serial.println("btn one or two pressed"); + if (btn_two_state == 1){ + //Serial.println("btn_two_state == 1"); + //Serial.println(btn_two_last_released); + //Serial.println(btn_two_last_pressed); + if ((btn_two_last_released >= btn_two_last_pressed) or (!stripe_on)){ + //Serial.println("btn_two currently is not pressed"); + if (btn_two_long_state == 0){ + //Serial.println("btn_two had no long press"); + player_one_hit_first = true; + btn_two_state = 0; + //Serial.println("Button two pressed."); + if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Toggling led stripe."); + toggle_leds(-1); + } + } else { + //Serial.println("btn_two had long press"); + btn_two_long_state = 0; + btn_two_state = 0; + } + } else { + //button still pressed. Maybe a long press? + if ((millis() - btn_two_last_pressed) > BTN_LONG_PRESS_DELAY){ + //Serial.println("btn_two long press detected"); + btn_two_long_state = 1; + changeBrightness(); + publish_current_status(); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } else { + //Serial.println("btn_two still pressed"); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } + } + } + + if (btn_one_state == 1){ + //Serial.println("btn_one_state == 1"); + //Serial.println(btn_one_last_released); + //Serial.println(btn_one_last_pressed); + if ((btn_one_last_released >= btn_one_last_pressed) or (!stripe_on)){ + //Serial.println("btn_one currently is not pressed"); + if (btn_one_long_state == 0){ + //Serial.println("btn_one had no long press"); + player_one_hit_first = false; + btn_one_state = 0; + if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Button one pressed. Toggling led stripe."); + toggle_leds(-1); + } + } else { + //Serial.println("btn_one had long press"); + btn_one_long_state = 0; + btn_one_state = 0; + } + } else { + //button still pressed. Maybe a long press? + if ((millis() - btn_one_last_pressed) > BTN_LONG_PRESS_DELAY){ + //Serial.println("btn_one long press detected"); + btn_one_long_state = 1; + changeBrightness(); + publish_current_status(); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } else { + //Serial.println("btn_one still pressed"); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } + } + } + } else { + if((millis() - last_refresh) > REFRESH_INTERVAL){ + show(); + } + } + } else if (stripe_mode == 1){ + for (int i=0; i < NUM_LEDS; i++){ + leds[i] = CRGB::Black; + } + + leds[cur_pixel].r = pong_color_r; + leds[cur_pixel].g = pong_color_g; + leds[cur_pixel].b = pong_color_b; + show(); + + delay(cur_pong_delay*1000); + + abortRun = 0; + player_one_miss = 0; + + if (player_successfull_one_press == 0){ + if(btn_one_state == 1){ + btn_one_state = 0; + if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= pong_start_led)){ + player_one_miss = 1; + } else { + player_successfull_one_press = 1; + } + } else if ((reverseMode == 1) && (cur_pixel == pong_start_led)){ + player_one_miss = 1; + } + } else { + btn_one_state = 0; + } + + if(player_one_miss == 1){ + abortRun = 1; + player_two_wins += 1; + if(player_two_wins >= pong_max_wins){ + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); + if (publish_results_at_display == 1){ + publish_results(); + } + toggle_leds(0); + } else { + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); + cur_pixel = pong_start_led; + reverseMode = 0; + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } + reset_pong_vars(true, player_one_hit_first); + } + } + + player_two_miss = 0; + + if (player_successfull_two_press == 0){ + if(btn_two_state == 1){ + btn_two_state = 0; + if ((reverseMode == 1) or ((cur_pixel + pong_tolerance) <= (num_pong_leds-1))){ + player_two_miss = 1; + } else { + player_successfull_two_press = 1; + } + } else if ((reverseMode == 0) && (cur_pixel == (num_pong_leds-1))){ + player_two_miss = 1; + } + } else { + btn_two_state = 0; + } + + if(player_two_miss == 1){ + abortRun = 1; + player_one_wins += 1; + if(player_one_wins >= pong_max_wins){ + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); + if (publish_results_at_display == 1){ + publish_results(); + } + toggle_leds(0); + } else { + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } + reset_pong_vars(true, player_one_hit_first); + } + } + + + if (abortRun == 0){ + if (reverseMode == 1){ + cur_pixel -= 1; + if (cur_pixel < pong_start_led){ + reverseMode = 0; + player_successfull_one_press = 0; + cur_pixel = pong_start_led + 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } else { + cur_pixel += 1; + if (cur_pixel > (num_pong_leds-1)){ + player_successfull_two_press = 0; + cur_pixel = num_pong_leds-2; + reverseMode = 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } + } + } +} diff --git a/examples/ESP32LedStripWithPongAndMqttOTA/settings.example.h b/examples/ESP32LedStripWithPongAndMqttOTA/settings.example.h new file mode 100644 index 0000000..27e5633 --- /dev/null +++ b/examples/ESP32LedStripWithPongAndMqttOTA/settings.example.h @@ -0,0 +1,31 @@ +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. +#define NUM_LEDS 300 +#define NUM_PONG_LEDS 10 +#define DATA_PIN 14 +#define BTN_1_GPIO 23 +#define BTN_2_GPIO 22 +#define BTN_DEBOUNCE_DELAY 500 +#define BTN_LONG_PRESS_DELAY 1000 +#define BRIGHTNESS_CHANGE_INTERVAL 50 +#define BRIGHTNESS_CHANGE_VALUE 5 +#define PONG_START_LED 0 +#define PONG_BTN_DELAY 2.000 +#define PONG_MAX_WINS 2 +#define PONG_TOLERANCE 2 +#define PONG_INIT_LED_DELAY 0.500 +#define PONG_DEC_PER_RUN 0.05 +#define PONG_MIN_LED_DELAY 0.02 +#define PONG_RESULT_DELAY_DURING 2.0 +#define PONG_RESULT_DELAY_AFTER 5.0 +#define REFRESH_INTERVAL 10000 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* ota_user = "ENTER_OTA_USER_HERE"; +const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; +const String host_name = "ESPLED"; +const String client_name = "ESPLED"; +const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore b/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore new file mode 100644 index 0000000..0e95883 --- /dev/null +++ b/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore @@ -0,0 +1,2 @@ +settings.h +*.bin diff --git a/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino b/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino new file mode 100644 index 0000000..761a8c7 --- /dev/null +++ b/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino @@ -0,0 +1,927 @@ +//LED Strip: BTF-LIGHTING WS2815 -> https://www.amazon.de/gp/product/B07LG5ZT9C/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1 +//Power Supply: HuaTec LED Trafo 12V 120W -> https://www.amazon.de/gp/product/B0829817YM/ref=ppx_yo_dt_b_asin_image_o09_s00?ie=UTF8&psc=1 +//Step-Down-Module: AZDelivery XL4015 -> https://www.amazon.de/gp/product/B07SRXR1VT/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1 +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//2 x Tactile Push Button (Something like https://www.amazon.de/gp/product/B078ZDK6KZ/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) +//2 x Capacitor 0.1 Mikrofarad +//2 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 1.0.6 +//Libs: +// Adafruit_Neopixel by Adafruit 1.10.4 +// PubSubClient by Nick O'Leary Version 2.8.0 +// ArduinoJson by Benoit Blanchon Version 6.19.3 +// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 +// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP +// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer +#include +#include +#include +#include +#include +#include +#include +#include "settings.h" + +AsyncWebServer server(80); + +Adafruit_NeoPixel pixels(MAX_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800); + +WiFiClient espClient; +PubSubClient client(espClient); +long lastMsg = 0; +char msg[50]; +int value = 0; + +long last_refresh = 0; + +int reverseMode=0; +int cur_pixel=0; +int btn_one_state = 0; +int btn_one_long_state = 0; +long btn_one_last_pressed = 0; +long btn_one_last_released = -1; +int btn_two_state = 0; +int btn_two_long_state = 0; +long btn_two_last_pressed = 0; +long btn_two_last_released = -1; +bool enable_hardware_btns = true; + + +int brightness = 255; +int brightness_decrease = true; +int color_r = 255; +int color_g = 255; +int color_b = 255; +int stripe_mode = 0; +boolean stripe_on = false; + +float pong_init_delay = PONG_INIT_LED_DELAY; +float cur_pong_delay = pong_init_delay; +int num_pong_leds = NUM_PONG_LEDS; +int pong_start_led = PONG_START_LED; +int pong_max_wins = PONG_MAX_WINS; +float pong_wins_delay_during = PONG_RESULT_DELAY_DURING; +float pong_wins_delay_after = PONG_RESULT_DELAY_AFTER; +float pong_min_delay = PONG_MIN_LED_DELAY; +float pong_dec_per_run = PONG_DEC_PER_RUN; +float pong_btn_delay = PONG_BTN_DELAY; +int pong_tolerance = PONG_TOLERANCE; +int pong_color_r = 0; +int pong_color_g = 0; +int pong_color_b = 255; +int pong_result_color_r = 0; +int pong_result_color_g = 255; +int pong_result_color_b = 0; +int player_one_wins = 0; +int player_successfull_one_press = 0; +int player_two_wins = 0; +int player_successfull_two_press = 0; +int player_one_miss = 0; +int player_two_miss = 0; +int abortRun = 0; +bool player_one_hit_first = true; +bool change_start_led_during_match = true; + +int publish_status_after_every_config_change = 1; +int publish_status_if_toggled = 1; +int publish_status_at_start = 1; +int publish_results_at_display = 1; + + +void publish_current_status(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (client.connected()){ + doc["pong"]["btn_delay"] = pong_btn_delay; + doc["pong"]["init_delay"] = pong_init_delay; + doc["pong"]["min_delay"] = pong_min_delay; + doc["pong"]["dec_per_run"] = pong_dec_per_run; + doc["pong"]["num_leds"] = num_pong_leds; + doc["pong"]["max_wins"] = pong_max_wins; + doc["pong"]["tolerance"] = pong_tolerance; + doc["pong"]["result_delay_during"] = pong_wins_delay_during; + doc["pong"]["result_delay_after"] = pong_wins_delay_after; + doc["pong"]["color_r"] = pong_color_r; + doc["pong"]["color_g"] = pong_color_g; + doc["pong"]["color_b"] = pong_color_b; + doc["pong"]["result_color_r"] = pong_result_color_r; + doc["pong"]["result_color_g"] = pong_result_color_g; + doc["pong"]["result_color_b"] = pong_result_color_b; + doc["output"] = stripe_on; + doc["mode"] = stripe_mode; + doc["brightness"] = brightness; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + doc["hardware_buttons_enabled"] = enable_hardware_btns; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/status").c_str(), buffer, n); + } +} + +void publish_results(){ + StaticJsonDocument<100> doc; + if (client.connected()){ + doc["result_player_one"] = player_one_wins; + doc["result_player_two"] = player_two_wins; + } + char buffer[100]; + + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/results").c_str(), buffer, n); +} + +void fixConfigValues(){ + if (pong_btn_delay < 0){ + pong_btn_delay = 0; + } + + if (pong_init_delay < pong_min_delay){ + pong_init_delay = pong_min_delay; + } + + if (pong_min_delay < 0){ + pong_min_delay = 0; + } + + if (pong_dec_per_run < 0){ + pong_dec_per_run = 0; + } + + if (num_pong_leds > NUM_LEDS){ + num_pong_leds = NUM_LEDS; + } + + if (pong_max_wins > num_pong_leds){ + pong_max_wins = num_pong_leds; + } + + if (pong_wins_delay_during < 0){ + pong_wins_delay_during = 0; + } + + if (pong_wins_delay_after < 0){ + pong_wins_delay_after = 0; + } + + if (pong_result_color_r > 255){ + pong_result_color_r = 255; + } else if (pong_result_color_r < 0){ + pong_result_color_r = 0; + } + + if (pong_result_color_g > 255){ + pong_result_color_g = 255; + } else if (pong_result_color_g < 0){ + pong_result_color_g = 0; + } + + if (pong_result_color_b > 255){ + pong_result_color_b = 255; + } else if (pong_result_color_b < 0){ + pong_result_color_b = 0; + } + + if (pong_tolerance < 0){ + pong_tolerance = 0; + } + + if (pong_tolerance > (num_pong_leds -1)){ + pong_tolerance = num_pong_leds -1; + } + + if (pong_color_r > 255){ + pong_color_r = 255; + } else if (pong_color_r < 0){ + pong_color_r = 0; + } + + if (pong_color_g > 255){ + pong_color_g = 255; + } else if (pong_color_g < 0){ + pong_color_g = 0; + } + + if (pong_color_b > 255){ + pong_color_b = 255; + } else if (pong_color_b < 0){ + pong_color_b = 0; + } + + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } +} + +void callback(char* topic, byte* message, unsigned int length) { + Serial.print("Message arrived on topic: "); + Serial.print(topic); + Serial.print(". Message: "); + String messageTemp; + + for (int i = 0; i < length; i++) { + Serial.print((char)message[i]); + messageTemp += (char)message[i]; + } + Serial.println(); + + if (! (String(topic) == topic_id+"/btn") ) { + // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". + // Changes the output state according to the message + if (String(topic) == topic_id+"/output") { + Serial.print("Changing output to "); + if(messageTemp == "on"){ + Serial.println("on"); + toggle_leds(1); + } + else if(messageTemp == "off"){ + Serial.println("off"); + toggle_leds(0); + } else { + Serial.println("toggle"); + toggle_leds(-1); + } + } else if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, messageTemp); + if (!err){ + + if(doc["pong"]["btn_delay"]){ + pong_btn_delay = doc["pong"]["btn_delay"].as(); + } + + if(doc["pong"]["init_delay"]){ + pong_init_delay = doc["pong"]["init_delay"].as(); + } + + if(doc["pong"]["min_delay"]){ + pong_min_delay = doc["pong"]["min_delay"].as(); + } + + if(doc["pong"]["dec_per_run"]){ + pong_dec_per_run = doc["pong"]["dec_per_run"].as(); + } + + num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; + pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; + pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; + + if(doc["pong"]["result_delay_during"]){ + pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); + } + + if(doc["pong"]["result_delay_after"]){ + pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); + } + + pong_color_r = doc["pong"]["color_r"] | pong_color_r; + pong_color_g = doc["pong"]["color_g"] | pong_color_g; + pong_color_b = doc["pong"]["color_b"] | pong_color_b; + + pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; + pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; + pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; + + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + + brightness = doc["brightness"] | brightness; + + if (doc.containsKey("hardware_buttons_enabled")){ + if (!doc["hardware_buttons_enabled"]){ + if (enable_hardware_btns){ + enable_hardware_btns = false; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (!enable_hardware_btns){ + enable_hardware_btns = true; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); + Serial.println("Enable Hardware Buttons"); + } + } + } + + } + + } else if (String(topic) == topic_id+"/pong/btn_delay"){ + pong_btn_delay = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/init_delay"){ + pong_init_delay = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/min_delay"){ + pong_min_delay = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/dec_per_run"){ + pong_dec_per_run = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/num_leds"){ + num_pong_leds = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/max_wins"){ + pong_max_wins = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/result/delay/during"){ + pong_wins_delay_during = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/result/delay/after"){ + pong_wins_delay_after = messageTemp.toFloat(); + } else if (String(topic) == topic_id+"/pong/result/color/r"){ + pong_result_color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/result/color/g"){ + pong_result_color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/result/color/b"){ + pong_result_color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/tolerance"){ + pong_tolerance = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/color/r"){ + pong_color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/color/g"){ + pong_color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/pong/color/b"){ + pong_color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/r"){ + color_r = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/g"){ + color_g = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/color/b"){ + color_b = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = messageTemp.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publish_current_status(); + } else if (String(topic) == topic_id+"/hardware_buttons_enabled"){ + if (messageTemp.toInt() == 1){ + if (enable_hardware_btns){ + enable_hardware_btns = false; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (!enable_hardware_btns){ + enable_hardware_btns = true; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); + Serial.println("Enable Hardware Buttons"); + } + } + } + + fixConfigValues(); + + if ((String(topic) != topic_id+"/output") && + (String(topic) != topic_id+"/get_status") && + (stripe_mode == 0)){ + if (stripe_on){ + toggle_leds(1); + } else { + toggle_leds(0); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } + } else { + Serial.println("Button press via mqtt"); + Serial.println(messageTemp); + if (messageTemp.toInt() == 2 ){ + btn_two_last_pressed = millis(); + btn_two_last_released = btn_two_last_pressed; + btn_two_state = 1; + } else { + btn_one_last_pressed = millis(); + btn_one_last_released = btn_one_last_pressed; + btn_one_state = 1; + } + } +} + +void show(){ + pixels.setBrightness(brightness); + pixels.show(); +} + +void setup() { + client.setBufferSize(512); + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_broker, 1883); + reconnect(); + client.setCallback(callback); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hi! I am "+host_name); + }); + + AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA + server.begin(); + Serial.println("HTTP server started"); + + if (publish_status_at_start){ + publish_current_status(); + } + + pinMode(DATA_PIN, OUTPUT); + + pixels.begin(); + pixels.clear(); + + for (int i=0; i < MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0, 0, 0)); + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(255, 255, 255)); + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0, 0, 0)); + } + show(); + + pinMode(BTN_1_GPIO, INPUT); + pinMode(BTN_2_GPIO, INPUT); + + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); + delay(500); +} + +void setup_wifi() { + WiFi.disconnect(true, true); + WiFi.mode(WIFI_STA); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() == WL_DISCONNECTED) { + delay(500); + } + + if (WiFi.status() != WL_CONNECTED) { + delay(10); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(SSID); + + WiFi.begin(SSID, PSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +void btn_one_changed(){ + long cur_time = millis(); + if((cur_time - btn_one_last_pressed) > BTN_DEBOUNCE_DELAY){ + if (digitalRead(BTN_1_GPIO) == LOW){ + btn_one_last_pressed = cur_time; + btn_one_state = 1; + } else{ + btn_one_last_released = cur_time; + } + } else{ + if (digitalRead(BTN_1_GPIO) == HIGH){ + btn_one_last_released = cur_time; + } + } +} + +void btn_two_changed(){ + long cur_time = millis(); + if((cur_time - btn_two_last_pressed) > BTN_DEBOUNCE_DELAY){ + if (digitalRead(BTN_2_GPIO) == LOW){ + btn_two_last_pressed = cur_time; + btn_two_state = 1; + } else{ + btn_two_last_released = cur_time; + } + } else { + if (digitalRead(BTN_2_GPIO) == HIGH){ + btn_two_last_released = cur_time; + } + } +} + +void reconnect() { + // Loop until we're reconnected + while (!client.connected()) { + Serial.print("Attempting MQTT connection..."); + // Attempt to connect + if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { + Serial.println("connected"); + // Subscribe + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + client.subscribe((topic_id+"/get_status").c_str()); + client.subscribe((topic_id+"/config").c_str()); + client.subscribe((topic_id+"/output").c_str()); + client.subscribe((topic_id+"/pong/btn_delay").c_str()); + client.subscribe((topic_id+"/pong/init_delay").c_str()); + client.subscribe((topic_id+"/pong/min_delay").c_str()); + client.subscribe((topic_id+"/pong/dec_per_run").c_str()); + client.subscribe((topic_id+"/pong/num_leds").c_str()); + client.subscribe((topic_id+"/pong/max_wins").c_str()); + client.subscribe((topic_id+"/pong/result/delay/during").c_str()); + client.subscribe((topic_id+"/pong/result/delay/after").c_str()); + client.subscribe((topic_id+"/pong/result/color/r").c_str()); + client.subscribe((topic_id+"/pong/result/color/g").c_str()); + client.subscribe((topic_id+"/pong/result/color/b").c_str()); + client.subscribe((topic_id+"/pong/tolerance").c_str()); + client.subscribe((topic_id+"/pong/color/r").c_str()); + client.subscribe((topic_id+"/pong/color/g").c_str()); + client.subscribe((topic_id+"/pong/color/b").c_str()); + client.subscribe((topic_id+"/color/r").c_str()); + client.subscribe((topic_id+"/color/g").c_str()); + client.subscribe((topic_id+"/color/b").c_str()); + client.subscribe((topic_id+"/btn").c_str()); + client.subscribe((topic_id+"/disable_btns").c_str()); + } else { + Serial.print("failed, rc="); + Serial.print(client.state()); + Serial.println(" try again in 5 seconds"); + // Wait 5 seconds before retrying + delay(5000); + } + } +} + +void toggle_leds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(color_r,color_g,color_b)); + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + stripe_on = false; + } + + show(); + if (publish_status_if_toggled == 1){ + publish_current_status(); + } +} + +void reset_pong_vars(bool during, bool oneHitFirst){ + Serial.print("Resetting pong vars ("); + Serial.print(during); + Serial.print("/"); + Serial.print(oneHitFirst); + Serial.println(")"); + client.loop(); + player_one_miss = 0; + player_two_miss = 0; + btn_one_state = 0; + btn_two_state = 0; + player_successfull_one_press = 0; + player_successfull_two_press = 0; + cur_pong_delay = pong_init_delay; + + if (!during){ + player_one_wins = 0; + player_two_wins = 0; + btn_one_last_pressed = 0; + btn_two_last_pressed = 0; + stripe_mode = 0; + } + + if (oneHitFirst){ + cur_pixel = pong_start_led; + reverseMode = 0; + } else { + cur_pixel = num_pong_leds-1; + reverseMode = 1; + } +} + +void switch_to_pong_mode(bool oneHitFirst){ + Serial.println("Switching to pong mode"); + delay(500); + reset_pong_vars(false, oneHitFirst); + + stripe_mode = 1; + + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + show(); + delay(1000); + for (int i = pong_start_led; i< num_pong_leds; i++){ + pixels.setPixelColor(i, pixels.Color(pong_color_r,pong_color_g,pong_color_b)); + } + show(); + delay(1000); + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + show(); + delay(1000); +} + +void display_result(float cur_delay){ + Serial.println("Displaying results"); + delay(500); + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + + for (int i = pong_start_led; i < player_one_wins+pong_start_led; i++){ + pixels.setPixelColor(i, pixels.Color(pong_result_color_r,pong_result_color_g,pong_result_color_b)); + } + + for (int i = (num_pong_leds - 1); i > ((num_pong_leds-1)-player_two_wins); i--){ + pixels.setPixelColor(i, pixels.Color(pong_result_color_r,pong_result_color_g,pong_result_color_b)); + } + show(); + delay(cur_delay*1000); +} + +void changeBrightness(){ + if (brightness_decrease){ + //Serial.println("Decrease brightness"); + brightness = brightness - BRIGHTNESS_CHANGE_VALUE; + if (brightness <= 0){ + brightness = 0; + //Serial.println("Smallest value reached"); + brightness_decrease = !brightness_decrease; + } + } else { + //Serial.println("Increase brightness"); + brightness = brightness + BRIGHTNESS_CHANGE_VALUE; + if (brightness >= 255){ + brightness = 255; + //Serial.println("Max value reached"); + brightness_decrease = !brightness_decrease; + } + } + + show(); +} + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + setup_wifi(); + } + + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if (stripe_mode == 0){ + if ((btn_one_state == 1) or (btn_two_state == 1)){ + //Serial.println("btn one or two pressed"); + if (btn_two_state == 1){ + //Serial.println("btn_two_state == 1"); + //Serial.println(btn_two_last_released); + //Serial.println(btn_two_last_pressed); + if ((btn_two_last_released >= btn_two_last_pressed) or (!stripe_on)){ + //Serial.println("btn_two currently is not pressed"); + if (btn_two_long_state == 0){ + //Serial.println("btn_two had no long press"); + player_one_hit_first = true; + btn_two_state = 0; + //Serial.println("Button two pressed."); + if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Toggling led stripe."); + toggle_leds(-1); + } + } else { + //Serial.println("btn_two had long press"); + btn_two_long_state = 0; + btn_two_state = 0; + } + } else { + //button still pressed. Maybe a long press? + if ((millis() - btn_two_last_pressed) > BTN_LONG_PRESS_DELAY){ + //Serial.println("btn_two long press detected"); + btn_two_long_state = 1; + changeBrightness(); + publish_current_status(); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } else { + //Serial.println("btn_two still pressed"); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } + } + } + + if (btn_one_state == 1){ + //Serial.println("btn_one_state == 1"); + //Serial.println(btn_one_last_released); + //Serial.println(btn_one_last_pressed); + if ((btn_one_last_released >= btn_one_last_pressed) or (!stripe_on)){ + //Serial.println("btn_one currently is not pressed"); + if (btn_one_long_state == 0){ + //Serial.println("btn_one had no long press"); + player_one_hit_first = false; + btn_one_state = 0; + if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Switching to pong mode."); + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Button one pressed. Toggling led stripe."); + toggle_leds(-1); + } + } else { + //Serial.println("btn_one had long press"); + btn_one_long_state = 0; + btn_one_state = 0; + } + } else { + //button still pressed. Maybe a long press? + if ((millis() - btn_one_last_pressed) > BTN_LONG_PRESS_DELAY){ + //Serial.println("btn_one long press detected"); + btn_one_long_state = 1; + changeBrightness(); + publish_current_status(); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } else { + //Serial.println("btn_one still pressed"); + delay(BRIGHTNESS_CHANGE_INTERVAL); + } + } + } + } else { + if((millis() - last_refresh) > REFRESH_INTERVAL){ + show(); + } + } + } else if (stripe_mode == 1){ + for (int i=0; i < NUM_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + + pixels.setPixelColor(cur_pixel, pixels.Color(pong_color_r,pong_color_g,pong_color_b)); + + show(); + + delay(cur_pong_delay*1000); + + abortRun = 0; + player_one_miss = 0; + + if (player_successfull_one_press == 0){ + if(btn_one_state == 1){ + btn_one_state = 0; + if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= pong_start_led)){ + player_one_miss = 1; + } else { + player_successfull_one_press = 1; + } + } else if ((reverseMode == 1) && (cur_pixel == pong_start_led)){ + player_one_miss = 1; + } + } else { + btn_one_state = 0; + } + + if(player_one_miss == 1){ + abortRun = 1; + player_two_wins += 1; + if(player_two_wins >= pong_max_wins){ + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); + if (publish_results_at_display == 1){ + publish_results(); + } + toggle_leds(0); + } else { + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); + cur_pixel = pong_start_led; + reverseMode = 0; + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } + reset_pong_vars(true, player_one_hit_first); + } + } + + player_two_miss = 0; + + if (player_successfull_two_press == 0){ + if(btn_two_state == 1){ + btn_two_state = 0; + if ((reverseMode == 1) or ((cur_pixel + pong_tolerance) <= (num_pong_leds-1))){ + player_two_miss = 1; + } else { + player_successfull_two_press = 1; + } + } else if ((reverseMode == 0) && (cur_pixel == (num_pong_leds-1))){ + player_two_miss = 1; + } + } else { + btn_two_state = 0; + } + + if(player_two_miss == 1){ + abortRun = 1; + player_one_wins += 1; + if(player_one_wins >= pong_max_wins){ + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); + if (publish_results_at_display == 1){ + publish_results(); + } + toggle_leds(0); + } else { + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } + reset_pong_vars(true, player_one_hit_first); + } + } + + + if (abortRun == 0){ + if (reverseMode == 1){ + cur_pixel -= 1; + if (cur_pixel < pong_start_led){ + reverseMode = 0; + player_successfull_one_press = 0; + cur_pixel = pong_start_led + 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } else { + cur_pixel += 1; + if (cur_pixel > (num_pong_leds-1)){ + player_successfull_two_press = 0; + cur_pixel = num_pong_leds-2; + reverseMode = 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } + } + } +} diff --git a/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h b/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h new file mode 100644 index 0000000..27e5633 --- /dev/null +++ b/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h @@ -0,0 +1,31 @@ +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. +#define NUM_LEDS 300 +#define NUM_PONG_LEDS 10 +#define DATA_PIN 14 +#define BTN_1_GPIO 23 +#define BTN_2_GPIO 22 +#define BTN_DEBOUNCE_DELAY 500 +#define BTN_LONG_PRESS_DELAY 1000 +#define BRIGHTNESS_CHANGE_INTERVAL 50 +#define BRIGHTNESS_CHANGE_VALUE 5 +#define PONG_START_LED 0 +#define PONG_BTN_DELAY 2.000 +#define PONG_MAX_WINS 2 +#define PONG_TOLERANCE 2 +#define PONG_INIT_LED_DELAY 0.500 +#define PONG_DEC_PER_RUN 0.05 +#define PONG_MIN_LED_DELAY 0.02 +#define PONG_RESULT_DELAY_DURING 2.0 +#define PONG_RESULT_DELAY_AFTER 5.0 +#define REFRESH_INTERVAL 10000 + +const char* SSID = "ENTER_WIFI_SSID_HERE"; +const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; +const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* ota_user = "ENTER_OTA_USER_HERE"; +const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; +const String host_name = "ESPLED"; +const String client_name = "ESPLED"; +const String topic_id = "esp_led"; diff --git a/examples/ESP32WS2815MqttExternalInOTA/.gitignore b/examples/ESP32WS2815MqttExternalInOTA/.gitignore new file mode 100644 index 0000000..0e95883 --- /dev/null +++ b/examples/ESP32WS2815MqttExternalInOTA/.gitignore @@ -0,0 +1,2 @@ +settings.h +*.bin diff --git a/examples/Esp32WS2815MqttExternalInOTA/Esp32WS2815MqttExternalInOTA.ino b/examples/ESP32WS2815MqttExternalInOTA/ESP32WS2815MqttExternalInOTA.ino similarity index 99% rename from examples/Esp32WS2815MqttExternalInOTA/Esp32WS2815MqttExternalInOTA.ino rename to examples/ESP32WS2815MqttExternalInOTA/ESP32WS2815MqttExternalInOTA.ino index 76f4590..8805b33 100644 --- a/examples/Esp32WS2815MqttExternalInOTA/Esp32WS2815MqttExternalInOTA.ino +++ b/examples/ESP32WS2815MqttExternalInOTA/ESP32WS2815MqttExternalInOTA.ino @@ -208,7 +208,7 @@ void setup() { publish_current_status(); } - FastLED.addLeds(leds, MAX_LEDS); + FastLED.addLeds(leds, MAX_LEDS); for (int i=0; i < MAX_LEDS; i++){ leds[i] = CRGB::Black; } diff --git a/examples/Esp32WS2815MqttExternalInOTA/settings.example.h b/examples/ESP32WS2815MqttExternalInOTA/settings.example.h similarity index 100% rename from examples/Esp32WS2815MqttExternalInOTA/settings.example.h rename to examples/ESP32WS2815MqttExternalInOTA/settings.example.h From 84bf772d0bff6f4c79f36004040e20c97581ae7d Mon Sep 17 00:00:00 2001 From: Thomas Hirschberger Date: Sun, 9 Oct 2022 14:45:54 +0200 Subject: [PATCH 39/40] added more and restructured the examples --- .../ESP32LedStripOTAWithPongAndMqtt.ino | 1005 ---------------- .../settings.example.h | 29 - .../ESP32LedStripWithMqttAndExternalInput.ino | 310 ----- .../settings.example.h | 16 - ...P32LedStripWithMqttAndExternalInputOTA.ino | 327 ----- .../settings.example.h | 17 - ...ripWithMqttAndExternalInputOTANeopixel.ino | 313 ----- .../settings.example.h | 17 - .../ESP32LedStripWithPongAndMqtt/.gitignore | 2 - .../ESP32LedStripWithPongAndMqtt.ino | 918 -------------- .../settings.example.h | 29 - .../.gitignore | 2 - .../ESP32LedStripWithPongAndMqttOTA.ino | 931 --------------- .../.gitignore | 2 - .../ESP32WS2815MqttExternalInOTA/.gitignore | 2 - .../ESP32WS2815MqttExternalInOTA.ino | 326 ----- .../settings.example.h | 16 - .../.gitignore | 0 ...ripWithMqttAndExternalInputOTANeopixel.ino | 418 +++++++ .../README.md | 14 + .../settings.example.h | 29 + .../.gitignore | 0 ...tLedWithMqttAndExternalInputOTAFastLED.ino | 397 +++++++ .../README.md | 14 + .../settings.example.h | 29 + examples/noPong/README.md | 3 + .../{ => util}/MQTTButtonOnEsp8266/.gitignore | 0 .../MQTTButtonOnEsp8266.ino | 0 examples/util/MQTTButtonOnEsp8266/README.md | 12 + .../MQTTButtonOnEsp8266/settings.example.h | 0 .../MQTTButtonOnEsp8266DeepSleep/.gitignore | 0 .../MQTTButtonOnEsp8266DeepSleep.ino | 0 .../MQTTButtonOnEsp8266DeepSleep/README.md | 13 + .../settings.example.h | 0 examples/util/README.md | 3 + .../.gitignore | 0 ...SP32LedStripWithPongAndMqttOTANeoPixel.ino | 91 +- .../README.md | 18 + .../settings.example.h | 3 + .../.gitignore | 0 ...tripWithPongAndMqttOTANeoPixelExtInput.ino | 1055 +++++++++++++++++ .../README.md | 18 + .../settings.example.h | 19 +- examples/withPong/README.md | 3 + 44 files changed, 2088 insertions(+), 4313 deletions(-) delete mode 100644 examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripOTAWithPongAndMqtt.ino delete mode 100644 examples/ESP32LedStripOTAWithPongAndMqtt/settings.example.h delete mode 100644 examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino delete mode 100644 examples/ESP32LedStripWithMqttAndExternalInput/settings.example.h delete mode 100644 examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino delete mode 100644 examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h delete mode 100755 examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino delete mode 100755 examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h delete mode 100644 examples/ESP32LedStripWithPongAndMqtt/.gitignore delete mode 100644 examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino delete mode 100644 examples/ESP32LedStripWithPongAndMqtt/settings.example.h delete mode 100644 examples/ESP32LedStripWithPongAndMqttOTA/.gitignore delete mode 100644 examples/ESP32LedStripWithPongAndMqttOTA/ESP32LedStripWithPongAndMqttOTA.ino delete mode 100644 examples/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore delete mode 100644 examples/ESP32WS2815MqttExternalInOTA/.gitignore delete mode 100644 examples/ESP32WS2815MqttExternalInOTA/ESP32WS2815MqttExternalInOTA.ino delete mode 100644 examples/ESP32WS2815MqttExternalInOTA/settings.example.h rename examples/{ESP32LedStripOTAWithPongAndMqtt => noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel}/.gitignore (100%) mode change 100644 => 100755 create mode 100755 examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino create mode 100644 examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/README.md create mode 100755 examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h rename examples/{ESP32LedStripWithMqttAndExternalInput => noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED}/.gitignore (100%) mode change 100644 => 100755 create mode 100755 examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/ESP8266FastLedWithMqttAndExternalInputOTAFastLED.ino create mode 100644 examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/README.md create mode 100755 examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/settings.example.h create mode 100644 examples/noPong/README.md rename examples/{ => util}/MQTTButtonOnEsp8266/.gitignore (100%) rename examples/{ => util}/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino (100%) create mode 100644 examples/util/MQTTButtonOnEsp8266/README.md rename examples/{ => util}/MQTTButtonOnEsp8266/settings.example.h (100%) rename examples/{ => util}/MQTTButtonOnEsp8266DeepSleep/.gitignore (100%) rename examples/{ => util}/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino (100%) create mode 100644 examples/util/MQTTButtonOnEsp8266DeepSleep/README.md rename examples/{ => util}/MQTTButtonOnEsp8266DeepSleep/settings.example.h (100%) create mode 100644 examples/util/README.md rename examples/{ESP32LedStripWithMqttAndExternalInputOTA => withPong/ESP32LedStripWithPongAndMqttOTANeoPixel}/.gitignore (100%) mode change 100644 => 100755 rename examples/{ => withPong}/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino (96%) mode change 100644 => 100755 create mode 100644 examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/README.md rename examples/{ESP32LedStripWithPongAndMqttOTA => withPong/ESP32LedStripWithPongAndMqttOTANeoPixel}/settings.example.h (93%) mode change 100644 => 100755 rename examples/{ESP32LedStripWithMqttAndExternalInputOTANeopixel => withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput}/.gitignore (100%) mode change 100644 => 100755 create mode 100755 examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput.ino create mode 100644 examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/README.md rename examples/{ESP32LedStripWithPongAndMqttOTANeoPixel => withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput}/settings.example.h (56%) mode change 100644 => 100755 create mode 100644 examples/withPong/README.md diff --git a/examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripOTAWithPongAndMqtt.ino b/examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripOTAWithPongAndMqtt.ino deleted file mode 100644 index 27777c1..0000000 --- a/examples/ESP32LedStripOTAWithPongAndMqtt/ESP32LedStripOTAWithPongAndMqtt.ino +++ /dev/null @@ -1,1005 +0,0 @@ -//LED Strip: BTF-LIGHTING WS2815 -> https://www.amazon.de/gp/product/B07LG5ZT9C/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1 -//Power Supply: HuaTec LED Trafo 12V 120W -> https://www.amazon.de/gp/product/B0829817YM/ref=ppx_yo_dt_b_asin_image_o09_s00?ie=UTF8&psc=1 -//Step-Down-Module: AZDelivery XL4015 -> https://www.amazon.de/gp/product/B07SRXR1VT/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1 -//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 -//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 -//2 x Tactile Push Button (Something like https://www.amazon.de/gp/product/B078ZDK6KZ/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) -//2 x Capacitor 0.1 Mikrofarad -//2 x Resistor: 10 kOhm -//Arduino Version: 1.8.13 -//Board Firmware: ESP32 by Espressif Systems Version 1.0.6 -//Libs: -// FastLED by Daniel Garcia Version 3.4.0 -// PubSubClient by Nick O'Leary Version 2.8.0 -// ArduinoJson by Benoit Blanchon Version 6.17.3 -#include -#include -#include -#include -#include "settings.h" -#include -#include -#include -#include - -CRGB leds[MAX_LEDS]; - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -long last_refresh = 0; - -int reverseMode=0; -int cur_pixel=0; -int btn_one_state = 0; -int btn_one_long_state = 0; -long btn_one_last_pressed = 0; -long btn_one_last_released = -1; -int btn_two_state = 0; -int btn_two_long_state = 0; -long btn_two_last_pressed = 0; -long btn_two_last_released = -1; -bool enable_hardware_btns = true; - - -int brightness = 255; -int brightness_decrease = true; -int color_r = 255; -int color_g = 255; -int color_b = 255; -int stripe_mode = 0; -boolean stripe_on = false; - -float pong_init_delay = PONG_INIT_LED_DELAY; -float cur_pong_delay = pong_init_delay; -int num_pong_leds = NUM_PONG_LEDS; -int pong_start_led = PONG_START_LED; -int pong_max_wins = PONG_MAX_WINS; -float pong_wins_delay_during = PONG_RESULT_DELAY_DURING; -float pong_wins_delay_after = PONG_RESULT_DELAY_AFTER; -float pong_min_delay = PONG_MIN_LED_DELAY; -float pong_dec_per_run = PONG_DEC_PER_RUN; -float pong_btn_delay = PONG_BTN_DELAY; -int pong_tolerance = PONG_TOLERANCE; -int pong_color_r = 0; -int pong_color_g = 0; -int pong_color_b = 255; -int pong_result_color_r = 0; -int pong_result_color_g = 255; -int pong_result_color_b = 0; -int player_one_wins = 0; -int player_successfull_one_press = 0; -int player_two_wins = 0; -int player_successfull_two_press = 0; -int player_one_miss = 0; -int player_two_miss = 0; -int abortRun = 0; -bool player_one_hit_first = true; -bool change_start_led_during_match = true; - -int publish_status_after_every_config_change = 1; -int publish_status_if_toggled = 1; -int publish_status_at_start = 1; -int publish_results_at_display = 1; - -WebServer server(80); - -/* - * Server Index Page - */ - -const char* serverIndex = -"" -"
" - "" - "" - "
" - "
progress: 0%
" - ""; - - -void publish_current_status(){ - Serial.println("Publishing current status"); - StaticJsonDocument<1024> doc; - if (client.connected()){ - doc["pong"]["btn_delay"] = pong_btn_delay; - doc["pong"]["init_delay"] = pong_init_delay; - doc["pong"]["min_delay"] = pong_min_delay; - doc["pong"]["dec_per_run"] = pong_dec_per_run; - doc["pong"]["num_leds"] = num_pong_leds; - doc["pong"]["max_wins"] = pong_max_wins; - doc["pong"]["tolerance"] = pong_tolerance; - doc["pong"]["result_delay_during"] = pong_wins_delay_during; - doc["pong"]["result_delay_after"] = pong_wins_delay_after; - doc["pong"]["color_r"] = pong_color_r; - doc["pong"]["color_g"] = pong_color_g; - doc["pong"]["color_b"] = pong_color_b; - doc["pong"]["result_color_r"] = pong_result_color_r; - doc["pong"]["result_color_g"] = pong_result_color_g; - doc["pong"]["result_color_b"] = pong_result_color_b; - doc["output"] = stripe_on; - doc["mode"] = stripe_mode; - doc["brightness"] = brightness; - doc["color_r"] = color_r; - doc["color_g"] = color_g; - doc["color_b"] = color_b; - doc["hardware_buttons_enabled"] = enable_hardware_btns; - - char buffer[1024]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/status").c_str(), buffer, n); - } -} - -void publish_results(){ - StaticJsonDocument<100> doc; - if (client.connected()){ - doc["result_player_one"] = player_one_wins; - doc["result_player_two"] = player_two_wins; - } - char buffer[100]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/results").c_str(), buffer, n); -} - -void fixConfigValues(){ - if (pong_btn_delay < 0){ - pong_btn_delay = 0; - } - - if (pong_init_delay < pong_min_delay){ - pong_init_delay = pong_min_delay; - } - - if (pong_min_delay < 0){ - pong_min_delay = 0; - } - - if (pong_dec_per_run < 0){ - pong_dec_per_run = 0; - } - - if (num_pong_leds > NUM_LEDS){ - num_pong_leds = NUM_LEDS; - } - - if (pong_max_wins > num_pong_leds){ - pong_max_wins = num_pong_leds; - } - - if (pong_wins_delay_during < 0){ - pong_wins_delay_during = 0; - } - - if (pong_wins_delay_after < 0){ - pong_wins_delay_after = 0; - } - - if (pong_result_color_r > 255){ - pong_result_color_r = 255; - } else if (pong_result_color_r < 0){ - pong_result_color_r = 0; - } - - if (pong_result_color_g > 255){ - pong_result_color_g = 255; - } else if (pong_result_color_g < 0){ - pong_result_color_g = 0; - } - - if (pong_result_color_b > 255){ - pong_result_color_b = 255; - } else if (pong_result_color_b < 0){ - pong_result_color_b = 0; - } - - if (pong_tolerance < 0){ - pong_tolerance = 0; - } - - if (pong_tolerance > (num_pong_leds -1)){ - pong_tolerance = num_pong_leds -1; - } - - if (pong_color_r > 255){ - pong_color_r = 255; - } else if (pong_color_r < 0){ - pong_color_r = 0; - } - - if (pong_color_g > 255){ - pong_color_g = 255; - } else if (pong_color_g < 0){ - pong_color_g = 0; - } - - if (pong_color_b > 255){ - pong_color_b = 255; - } else if (pong_color_b < 0){ - pong_color_b = 0; - } - - if (color_r > 255){ - color_r = 255; - } else if (color_r < 0){ - color_r = 0; - } - - if (color_g > 255){ - color_g = 255; - } else if (color_g < 0){ - color_g = 0; - } - - if (color_b > 255){ - color_b = 255; - } else if (color_b < 0){ - color_b = 0; - } - - if (brightness > 255){ - brightness = 255; - } else if (brightness < 0){ - brightness = 0; - } -} - -void callback(char* topic, byte* message, unsigned int length) { - Serial.print("Message arrived on topic: "); - Serial.print(topic); - Serial.print(". Message: "); - String messageTemp; - - for (int i = 0; i < length; i++) { - Serial.print((char)message[i]); - messageTemp += (char)message[i]; - } - Serial.println(); - - if (! (String(topic) == topic_id+"/btn") ) { - // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". - // Changes the output state according to the message - if (String(topic) == topic_id+"/output") { - Serial.print("Changing output to "); - if(messageTemp == "on"){ - Serial.println("on"); - toggle_leds(1); - } - else if(messageTemp == "off"){ - Serial.println("off"); - toggle_leds(0); - } else { - Serial.println("toggle"); - toggle_leds(-1); - } - } else if (String(topic) == topic_id+"/config"){ - StaticJsonDocument<1024> doc; - DeserializationError err = deserializeJson(doc, messageTemp); - if (!err){ - - if(doc["pong"]["btn_delay"]){ - pong_btn_delay = doc["pong"]["btn_delay"].as(); - } - - if(doc["pong"]["init_delay"]){ - pong_init_delay = doc["pong"]["init_delay"].as(); - } - - if(doc["pong"]["min_delay"]){ - pong_min_delay = doc["pong"]["min_delay"].as(); - } - - if(doc["pong"]["dec_per_run"]){ - pong_dec_per_run = doc["pong"]["dec_per_run"].as(); - } - - num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; - pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; - pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; - - if(doc["pong"]["result_delay_during"]){ - pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); - } - - if(doc["pong"]["result_delay_after"]){ - pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); - } - - pong_color_r = doc["pong"]["color_r"] | pong_color_r; - pong_color_g = doc["pong"]["color_g"] | pong_color_g; - pong_color_b = doc["pong"]["color_b"] | pong_color_b; - - pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; - pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; - pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; - - color_r = doc["color_r"] | color_r; - color_g = doc["color_g"] | color_g; - color_b = doc["color_b"] | color_b; - - brightness = doc["brightness"] | brightness; - - if (doc.containsKey("hardware_buttons_enabled")){ - if (!doc["hardware_buttons_enabled"]){ - if (enable_hardware_btns){ - enable_hardware_btns = false; - detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); - detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); - Serial.println("Disable Hardware Buttons"); - } - } else { - if (!enable_hardware_btns){ - enable_hardware_btns = true; - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); - Serial.println("Enable Hardware Buttons"); - } - } - } - - } - - } else if (String(topic) == topic_id+"/pong/btn_delay"){ - pong_btn_delay = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/init_delay"){ - pong_init_delay = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/min_delay"){ - pong_min_delay = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/dec_per_run"){ - pong_dec_per_run = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/num_leds"){ - num_pong_leds = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/max_wins"){ - pong_max_wins = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/result/delay/during"){ - pong_wins_delay_during = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/result/delay/after"){ - pong_wins_delay_after = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/result/color/r"){ - pong_result_color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/result/color/g"){ - pong_result_color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/result/color/b"){ - pong_result_color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/tolerance"){ - pong_tolerance = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/color/r"){ - pong_color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/color/g"){ - pong_color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/color/b"){ - pong_color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/r"){ - color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/g"){ - color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/b"){ - color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/brightness"){ - brightness = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/get_status"){ - publish_current_status(); - } else if (String(topic) == topic_id+"/hardware_buttons_enabled"){ - if (messageTemp.toInt() == 1){ - if (enable_hardware_btns){ - enable_hardware_btns = false; - detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); - detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); - Serial.println("Disable Hardware Buttons"); - } - } else { - if (!enable_hardware_btns){ - enable_hardware_btns = true; - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); - Serial.println("Enable Hardware Buttons"); - } - } - } - - fixConfigValues(); - - if ((String(topic) != topic_id+"/output") && - (String(topic) != topic_id+"/get_status") && - (stripe_mode == 0)){ - if (stripe_on){ - toggle_leds(1); - } else { - toggle_leds(0); - } - } - - if(publish_status_after_every_config_change){ - publish_current_status(); - } - } else { - Serial.println("Button press via mqtt"); - Serial.println(messageTemp); - if (messageTemp.toInt() == 2 ){ - btn_two_last_pressed = millis(); - btn_two_last_released = btn_two_last_pressed; - btn_two_state = 1; - } else { - btn_one_last_pressed = millis(); - btn_one_last_released = btn_one_last_pressed; - btn_one_state = 1; - } - } -} - -void show(){ - FastLED.setBrightness(brightness); - FastLED.show(); - FastLED.show(); -} - -void setup() { - client.setBufferSize(512); - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_broker, 1883); - reconnect(); - client.setCallback(callback); - - if (publish_status_at_start){ - publish_current_status(); - } - - FastLED.addLeds(leds, MAX_LEDS); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(50); - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::White; - } - show(); - delay(200); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - - pinMode(BTN_1_GPIO, INPUT); - pinMode(BTN_2_GPIO, INPUT); - pinMode(DATA_PIN, OUTPUT); - - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); - delay(500); - - /*use mdns for host_name name resolution*/ - if (!MDNS.begin(host_name)) { //http://ESP_LED - Serial.println("Error setting up MDNS responder!"); - while (1) { - delay(1000); - } - } - Serial.println("mDNS responder started"); - server.on("/", HTTP_GET, []() { - server.sendHeader("Connection", "close"); - server.send(200, "text/html", serverIndex); - }); - /*handling uploading firmware file */ - server.on("/update", HTTP_POST, []() { - server.sendHeader("Connection", "close"); - server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); - ESP.restart(); - }, []() { - HTTPUpload& upload = server.upload(); - if (upload.status == UPLOAD_FILE_START) { - Serial.printf("Update: %s\n", upload.filename.c_str()); - if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size - Update.printError(Serial); - } - } else if (upload.status == UPLOAD_FILE_WRITE) { - /* flashing firmware to ESP*/ - if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { - Update.printError(Serial); - } - } else if (upload.status == UPLOAD_FILE_END) { - if (Update.end(true)) { //true to set the size to the current progress - Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); - } else { - Update.printError(Serial); - } - } - }); - server.begin(); -} - -void setup_wifi() { - WiFi.disconnect(true, true); - WiFi.mode(WIFI_STA); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() == WL_DISCONNECTED) { - delay(500); - } - - if (WiFi.status() != WL_CONNECTED) { - delay(10); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(SSID); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void btn_one_changed(){ - long cur_time = millis(); - if((cur_time - btn_one_last_pressed) > BTN_DEBOUNCE_DELAY){ - if (digitalRead(BTN_1_GPIO) == LOW){ - btn_one_last_pressed = cur_time; - btn_one_state = 1; - } else{ - btn_one_last_released = cur_time; - } - } else{ - if (digitalRead(BTN_1_GPIO) == HIGH){ - btn_one_last_released = cur_time; - } - } -} - -void btn_two_changed(){ - long cur_time = millis(); - if((cur_time - btn_two_last_pressed) > BTN_DEBOUNCE_DELAY){ - if (digitalRead(BTN_2_GPIO) == LOW){ - btn_two_last_pressed = cur_time; - btn_two_state = 1; - } else{ - btn_two_last_released = cur_time; - } - } else { - if (digitalRead(BTN_2_GPIO) == HIGH){ - btn_two_last_released = cur_time; - } - } -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { - Serial.println("connected"); - // Subscribe - Serial.print("Subscribing with topic_id: "); - Serial.println(topic_id); - client.subscribe((topic_id+"/get_status").c_str()); - client.subscribe((topic_id+"/config").c_str()); - client.subscribe((topic_id+"/output").c_str()); - client.subscribe((topic_id+"/pong/btn_delay").c_str()); - client.subscribe((topic_id+"/pong/init_delay").c_str()); - client.subscribe((topic_id+"/pong/min_delay").c_str()); - client.subscribe((topic_id+"/pong/dec_per_run").c_str()); - client.subscribe((topic_id+"/pong/num_leds").c_str()); - client.subscribe((topic_id+"/pong/max_wins").c_str()); - client.subscribe((topic_id+"/pong/result/delay/during").c_str()); - client.subscribe((topic_id+"/pong/result/delay/after").c_str()); - client.subscribe((topic_id+"/pong/result/color/r").c_str()); - client.subscribe((topic_id+"/pong/result/color/g").c_str()); - client.subscribe((topic_id+"/pong/result/color/b").c_str()); - client.subscribe((topic_id+"/pong/tolerance").c_str()); - client.subscribe((topic_id+"/pong/color/r").c_str()); - client.subscribe((topic_id+"/pong/color/g").c_str()); - client.subscribe((topic_id+"/pong/color/b").c_str()); - client.subscribe((topic_id+"/color/r").c_str()); - client.subscribe((topic_id+"/color/g").c_str()); - client.subscribe((topic_id+"/color/b").c_str()); - client.subscribe((topic_id+"/btn").c_str()); - client.subscribe((topic_id+"/disable_btns").c_str()); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void toggle_leds(int to_state){ - if (to_state != -1){ - if (to_state == 0){ - stripe_on = true; - } else { - stripe_on = false; - } - } - if (stripe_on == false){ - Serial.print("Switch the rgb on with color: "); - Serial.print(color_r); - Serial.print("/"); - Serial.print(color_g); - Serial.print("/"); - Serial.println(color_b); - for (int i = 0; i< NUM_LEDS; i++){ - leds[i].r = color_r; - leds[i].g = color_g; - leds[i].b = color_b; - } - stripe_on = true; - } else { - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - stripe_on = false; - } - - show(); - if (publish_status_if_toggled == 1){ - publish_current_status(); - } -} - -void reset_pong_vars(bool during, bool oneHitFirst){ - Serial.print("Resetting pong vars ("); - Serial.print(during); - Serial.print("/"); - Serial.print(oneHitFirst); - Serial.println(")"); - client.loop(); - player_one_miss = 0; - player_two_miss = 0; - btn_one_state = 0; - btn_two_state = 0; - player_successfull_one_press = 0; - player_successfull_two_press = 0; - cur_pong_delay = pong_init_delay; - - if (!during){ - player_one_wins = 0; - player_two_wins = 0; - btn_one_last_pressed = 0; - btn_two_last_pressed = 0; - stripe_mode = 0; - } - - if (oneHitFirst){ - cur_pixel = pong_start_led; - reverseMode = 0; - } else { - cur_pixel = num_pong_leds-1; - reverseMode = 1; - } -} - -void switch_to_pong_mode(bool oneHitFirst){ - Serial.println("Switching to pong mode"); - delay(500); - reset_pong_vars(false, oneHitFirst); - - stripe_mode = 1; - - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(1000); - for (int i = pong_start_led; i< num_pong_leds; i++){ - leds[i].r = pong_color_r; - leds[i].g = pong_color_g; - leds[i].b = pong_color_b; - } - show(); - delay(1000); - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(1000); -} - -void display_result(float cur_delay){ - Serial.println("Displaying results"); - delay(500); - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - - for (int i = pong_start_led; i < player_one_wins+pong_start_led; i++){ - leds[i].r = pong_result_color_r; - leds[i].g = pong_result_color_g; - leds[i].b = pong_result_color_b; - } - - for (int i = (num_pong_leds - 1); i > ((num_pong_leds-1)-player_two_wins); i--){ - leds[i].r = pong_result_color_r; - leds[i].g = pong_result_color_g; - leds[i].b = pong_result_color_b; - } - show(); - delay(cur_delay*1000); -} - -void changeBrightness(){ - if (brightness_decrease){ - //Serial.println("Decrease brightness"); - brightness = brightness - BRIGHTNESS_CHANGE_VALUE; - if (brightness <= 0){ - brightness = 0; - //Serial.println("Smallest value reached"); - brightness_decrease = !brightness_decrease; - } - } else { - //Serial.println("Increase brightness"); - brightness = brightness + BRIGHTNESS_CHANGE_VALUE; - if (brightness >= 255){ - brightness = 255; - //Serial.println("Max value reached"); - brightness_decrease = !brightness_decrease; - } - } - - show(); -} - -void loop() { - if (WiFi.status() != WL_CONNECTED) { - setup_wifi(); - } - - if (!client.connected()) { - reconnect(); - } - client.loop(); - - if (stripe_mode == 0){ - server.handleClient(); - if ((btn_one_state == 1) or (btn_two_state == 1)){ - //Serial.println("btn one or two pressed"); - if (btn_two_state == 1){ - //Serial.println("btn_two_state == 1"); - //Serial.println(btn_two_last_released); - //Serial.println(btn_two_last_pressed); - if ((btn_two_last_released >= btn_two_last_pressed) or (!stripe_on)){ - //Serial.println("btn_two currently is not pressed"); - if (btn_two_long_state == 0){ - //Serial.println("btn_two had no long press"); - player_one_hit_first = true; - btn_two_state = 0; - //Serial.println("Button two pressed."); - if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ - Serial.println("Switching to pong mode."); - switch_to_pong_mode(player_one_hit_first); - } else { - Serial.println("Toggling led stripe."); - toggle_leds(-1); - } - } else { - //Serial.println("btn_two had long press"); - btn_two_long_state = 0; - btn_two_state = 0; - } - } else { - //button still pressed. Maybe a long press? - if ((millis() - btn_two_last_pressed) > BTN_LONG_PRESS_DELAY){ - //Serial.println("btn_two long press detected"); - btn_two_long_state = 1; - changeBrightness(); - publish_current_status(); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } else { - //Serial.println("btn_two still pressed"); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } - } - } - - if (btn_one_state == 1){ - //Serial.println("btn_one_state == 1"); - //Serial.println(btn_one_last_released); - //Serial.println(btn_one_last_pressed); - if ((btn_one_last_released >= btn_one_last_pressed) or (!stripe_on)){ - //Serial.println("btn_one currently is not pressed"); - if (btn_one_long_state == 0){ - //Serial.println("btn_one had no long press"); - player_one_hit_first = false; - btn_one_state = 0; - if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ - Serial.println("Switching to pong mode."); - switch_to_pong_mode(player_one_hit_first); - } else { - Serial.println("Button one pressed. Toggling led stripe."); - toggle_leds(-1); - } - } else { - //Serial.println("btn_one had long press"); - btn_one_long_state = 0; - btn_one_state = 0; - } - } else { - //button still pressed. Maybe a long press? - if ((millis() - btn_one_last_pressed) > BTN_LONG_PRESS_DELAY){ - //Serial.println("btn_one long press detected"); - btn_one_long_state = 1; - changeBrightness(); - publish_current_status(); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } else { - //Serial.println("btn_one still pressed"); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } - } - } - } else { - if((millis() - last_refresh) > REFRESH_INTERVAL){ - show(); - } - } - } else if (stripe_mode == 1){ - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::Black; - } - - leds[cur_pixel].r = pong_color_r; - leds[cur_pixel].g = pong_color_g; - leds[cur_pixel].b = pong_color_b; - show(); - - delay(cur_pong_delay*1000); - - abortRun = 0; - player_one_miss = 0; - - if (player_successfull_one_press == 0){ - if(btn_one_state == 1){ - btn_one_state = 0; - if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= pong_start_led)){ - player_one_miss = 1; - } else { - player_successfull_one_press = 1; - } - } else if ((reverseMode == 1) && (cur_pixel == pong_start_led)){ - player_one_miss = 1; - } - } else { - btn_one_state = 0; - } - - if(player_one_miss == 1){ - abortRun = 1; - player_two_wins += 1; - if(player_two_wins >= pong_max_wins){ - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_after); - reset_pong_vars(false, player_one_hit_first); - if (publish_results_at_display == 1){ - publish_results(); - } - toggle_leds(0); - } else { - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_during); - cur_pixel = pong_start_led; - reverseMode = 0; - if (change_start_led_during_match){ - player_one_hit_first = !player_one_hit_first; - } - reset_pong_vars(true, player_one_hit_first); - } - } - - player_two_miss = 0; - - if (player_successfull_two_press == 0){ - if(btn_two_state == 1){ - btn_two_state = 0; - if ((reverseMode == 1) or ((cur_pixel + pong_tolerance) <= (num_pong_leds-1))){ - player_two_miss = 1; - } else { - player_successfull_two_press = 1; - } - } else if ((reverseMode == 0) && (cur_pixel == (num_pong_leds-1))){ - player_two_miss = 1; - } - } else { - btn_two_state = 0; - } - - if(player_two_miss == 1){ - abortRun = 1; - player_one_wins += 1; - if(player_one_wins >= pong_max_wins){ - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_after); - reset_pong_vars(false, player_one_hit_first); - if (publish_results_at_display == 1){ - publish_results(); - } - toggle_leds(0); - } else { - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_during); - if (change_start_led_during_match){ - player_one_hit_first = !player_one_hit_first; - } - reset_pong_vars(true, player_one_hit_first); - } - } - - - if (abortRun == 0){ - if (reverseMode == 1){ - cur_pixel -= 1; - if (cur_pixel < pong_start_led){ - reverseMode = 0; - player_successfull_one_press = 0; - cur_pixel = pong_start_led + 1; - cur_pong_delay = cur_pong_delay - pong_dec_per_run; - if (cur_pong_delay < pong_min_delay){ - cur_pong_delay = pong_min_delay; - } - } - } else { - cur_pixel += 1; - if (cur_pixel > (num_pong_leds-1)){ - player_successfull_two_press = 0; - cur_pixel = num_pong_leds-2; - reverseMode = 1; - cur_pong_delay = cur_pong_delay - pong_dec_per_run; - if (cur_pong_delay < pong_min_delay){ - cur_pong_delay = pong_min_delay; - } - } - } - } - } -} diff --git a/examples/ESP32LedStripOTAWithPongAndMqtt/settings.example.h b/examples/ESP32LedStripOTAWithPongAndMqtt/settings.example.h deleted file mode 100644 index aaa68b1..0000000 --- a/examples/ESP32LedStripOTAWithPongAndMqtt/settings.example.h +++ /dev/null @@ -1,29 +0,0 @@ -#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. -#define NUM_LEDS 300 -#define NUM_PONG_LEDS 10 -#define DATA_PIN 14 -#define BTN_1_GPIO 23 -#define BTN_2_GPIO 22 -#define BTN_DEBOUNCE_DELAY 500 -#define BTN_LONG_PRESS_DELAY 1000 -#define BRIGHTNESS_CHANGE_INTERVAL 50 -#define BRIGHTNESS_CHANGE_VALUE 5 -#define PONG_START_LED 0 -#define PONG_BTN_DELAY 2.000 -#define PONG_MAX_WINS 2 -#define PONG_TOLERANCE 2 -#define PONG_INIT_LED_DELAY 0.500 -#define PONG_DEC_PER_RUN 0.05 -#define PONG_MIN_LED_DELAY 0.02 -#define PONG_RESULT_DELAY_DURING 2.0 -#define PONG_RESULT_DELAY_AFTER 5.0 -#define REFRESH_INTERVAL 10000 - -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; -const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; -const char* host_name = "ESP_LED"; -const String client_name = "ESP_LED"; -const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino b/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino deleted file mode 100644 index 32738aa..0000000 --- a/examples/ESP32LedStripWithMqttAndExternalInput/ESP32LedStripWithMqttAndExternalInput.ino +++ /dev/null @@ -1,310 +0,0 @@ -//LED Strip: BTF-LIGHTING WS2801 -//Power Supply: HuaTec LED Trafo 15V -//Step-Down-Module -//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 -//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 -//1 x Resistor: 10 kOhm -//Arduino Version: 1.8.13 -//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 -//Libs: -// FastLED by Daniel Garcia Version 3.5.0 -// PubSubClient by Nick O'Leary Version 2.8.0 -// ArduinoJson by Benoit Blanchon Version 6.19.2 -#include -#include -#include -#include -#include "settings.h" - -CRGB leds[MAX_LEDS]; - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -long last_refresh = 0; - -int brightness = 255; -int color_r = 255; -int color_g = 255; -int color_b = 255; -boolean stripe_on = false; -boolean input_active = false; - -int publish_status_after_every_config_change = 1; -int publish_status_if_toggled = 1; -int publish_status_at_start = 1; - -void show(){ - FastLED.setBrightness(brightness); - FastLED.show(); - FastLED.show(); -} - -void toggle_leds(int to_state){ - if (to_state != -1){ - if (to_state == 0){ - stripe_on = true; - } else { - stripe_on = false; - } - } - if (stripe_on == false){ - Serial.print("Switch the rgb on with color: "); - Serial.print(color_r); - Serial.print("/"); - Serial.print(color_g); - Serial.print("/"); - Serial.println(color_b); - for (int i = 0; i< NUM_LEDS; i++){ - leds[i].r = color_r; - leds[i].g = color_g; - leds[i].b = color_b; - } - stripe_on = true; - } else { - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - stripe_on = false; - } - - show(); - if (publish_status_if_toggled == 1){ - publish_current_status(); - } -} - -void publish_current_status(){ - Serial.println("Publishing current status"); - StaticJsonDocument<1024> doc; - if (client.connected()){ - doc["output"] = stripe_on; - doc["brightness"] = brightness; - doc["color_r"] = color_r; - doc["color_g"] = color_g; - doc["color_b"] = color_b; - - char buffer[1024]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/status").c_str(), buffer, n); - } -} - -void fixConfigValues(){ - if (color_r > 255){ - color_r = 255; - } else if (color_r < 0){ - color_r = 0; - } - - if (color_g > 255){ - color_g = 255; - } else if (color_g < 0){ - color_g = 0; - } - - if (color_b > 255){ - color_b = 255; - } else if (color_b < 0){ - color_b = 0; - } - - if (brightness > 255){ - brightness = 255; - } else if (brightness < 0){ - brightness = 0; - } -} - -void callback(char* topic, byte* message, unsigned int length) { - Serial.print("Message arrived on topic: "); - Serial.print(topic); - Serial.print(". Message: "); - String messageTemp; - - for (int i = 0; i < length; i++) { - Serial.print((char)message[i]); - messageTemp += (char)message[i]; - } - Serial.println(); - - if (String(topic) == topic_id+"/config"){ - StaticJsonDocument<1024> doc; - DeserializationError err = deserializeJson(doc, messageTemp); - if (!err){ - color_r = doc["color_r"] | color_r; - color_g = doc["color_g"] | color_g; - color_b = doc["color_b"] | color_b; - - brightness = doc["brightness"] | brightness; - Serial.print("brightness: "); - Serial.println(brightness); - Serial.print("Doc brightness: "); - Serial.println(doc["brightness"].as()); - Serial.print("Doc color_r: "); - Serial.println(doc["color_r"].as()); - Serial.print("Doc color_g: "); - Serial.println(doc["color_g"].as()); - Serial.print("Doc color_b: "); - Serial.println(doc["color_b"].as()); - - } - } else if (String(topic) == topic_id+"/color/r"){ - color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/g"){ - color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/b"){ - color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/brightness"){ - brightness = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/get_status"){ - publish_current_status(); - } - - fixConfigValues(); - - if (String(topic) != topic_id+"/get_status") { - if (stripe_on){ - toggle_leds(1); - } else { - toggle_leds(0); - } - } - - if(publish_status_after_every_config_change){ - publish_current_status(); - } -} - -void setup() { - client.setBufferSize(512); - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_broker, 1883); - reconnect(); - client.setCallback(callback); - - if (publish_status_at_start){ - publish_current_status(); - } - - FastLED.addLeds(leds, MAX_LEDS); - //FastLED.addLeds(leds, MAX_LEDS); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(50); - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::White; - } - show(); - delay(200); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - - pinMode(CLOCK_PIN, OUTPUT); - pinMode(DATA_PIN, OUTPUT); - - attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); - delay(500); - input_changed(); -} - -void setup_wifi() { - WiFi.disconnect(true, true); - WiFi.mode(WIFI_STA); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() == WL_DISCONNECTED) { - delay(500); - } - - if (WiFi.status() != WL_CONNECTED) { - delay(10); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(SSID); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void input_changed(){ - if (digitalRead(INPUT_GPIO) == LOW){ - input_active = false; - } else { - input_active = true; - } -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { - Serial.println("connected"); - // Subscribe - Serial.print("Subscribing with topic_id: "); - Serial.println(topic_id); - client.subscribe((topic_id+"/get_status").c_str()); - client.subscribe((topic_id+"/config").c_str()); - client.subscribe((topic_id+"/output").c_str()); - client.subscribe((topic_id+"/color/r").c_str()); - client.subscribe((topic_id+"/color/g").c_str()); - client.subscribe((topic_id+"/color/b").c_str()); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void loop() { - if (WiFi.status() != WL_CONNECTED) { - setup_wifi(); - } - - if (!client.connected()) { - reconnect(); - } - client.loop(); - - if (input_active != stripe_on){ - if (input_active){ - toggle_leds(1); - } else { - toggle_leds(0); - } - - last_refresh = millis(); - } else { - - if ((millis() - last_refresh) > REFRESH_INTERVAL){ - last_refresh = millis(); - show(); - } - } - delay(10); -} diff --git a/examples/ESP32LedStripWithMqttAndExternalInput/settings.example.h b/examples/ESP32LedStripWithMqttAndExternalInput/settings.example.h deleted file mode 100644 index ce8e8c7..0000000 --- a/examples/ESP32LedStripWithMqttAndExternalInput/settings.example.h +++ /dev/null @@ -1,16 +0,0 @@ -#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. -#define NUM_LEDS 300 -#define NUM_PONG_LEDS 10 -#define DATA_PIN 14 -#define CLOCK_PIN 13 -#define INPUT_GPIO 16 -#define REFRESH_INTERVAL 10000 - -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; -const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; -const char* host_name = "ESP_LED"; -const String client_name = "ESP_LED"; -const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino b/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino deleted file mode 100644 index 07e5650..0000000 --- a/examples/ESP32LedStripWithMqttAndExternalInputOTA/ESP32LedStripWithMqttAndExternalInputOTA.ino +++ /dev/null @@ -1,327 +0,0 @@ -//LED Strip: BTF-LIGHTING WS2801 -//Power Supply: HuaTec LED Trafo 15V -//Step-Down-Module -//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 -//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 -//1 x Resistor: 10 kOhm -//Arduino Version: 1.8.13 -//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 -//Libs: -// FastLED by Daniel Garcia Version 3.5.0 -// PubSubClient by Nick O'Leary Version 2.8.0 -// ArduinoJson by Benoit Blanchon Version 6.19.2 -// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 -// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP -// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer -#include -#include -#include -#include -#include -#include -#include -#include "settings.h" - -AsyncWebServer server(80); - -CRGB leds[MAX_LEDS]; - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -long last_refresh = 0; - -int brightness = 255; -int color_r = 255; -int color_g = 255; -int color_b = 255; -boolean stripe_on = false; -boolean input_active = false; - -int publish_status_after_every_config_change = 1; -int publish_status_if_toggled = 1; -int publish_status_at_start = 1; - -void show(){ - FastLED.setBrightness(brightness); - FastLED.show(); - //FastLED.show(); -} - -void toggle_leds(int to_state){ - if (to_state != -1){ - if (to_state == 0){ - stripe_on = true; - } else { - stripe_on = false; - } - } - if (stripe_on == false){ - Serial.print("Switch the rgb on with color: "); - Serial.print(color_r); - Serial.print("/"); - Serial.print(color_g); - Serial.print("/"); - Serial.println(color_b); - for (int i = 0; i< NUM_LEDS; i++){ - leds[i].r = color_r; - leds[i].g = color_g; - leds[i].b = color_b; - } - stripe_on = true; - } else { - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - stripe_on = false; - } - - show(); - if (publish_status_if_toggled == 1){ - publish_current_status(); - } -} - -void publish_current_status(){ - Serial.println("Publishing current status"); - StaticJsonDocument<512> doc; - if (client.connected()){ - doc["output"] = stripe_on; - doc["brightness"] = brightness; - doc["color_r"] = color_r; - doc["color_g"] = color_g; - doc["color_b"] = color_b; - - char buffer[512]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/status").c_str(), buffer, n); - } -} - -void fixConfigValues(){ - if (color_r > 255){ - color_r = 255; - } else if (color_r < 0){ - color_r = 0; - } - - if (color_g > 255){ - color_g = 255; - } else if (color_g < 0){ - color_g = 0; - } - - if (color_b > 255){ - color_b = 255; - } else if (color_b < 0){ - color_b = 0; - } - - if (brightness > 255){ - brightness = 255; - } else if (brightness < 0){ - brightness = 0; - } -} - -void callback(char* topic, byte* message, unsigned int length) { - Serial.print("Message arrived on topic: "); - Serial.print(topic); - Serial.print(". Message: "); - String messageTemp; - - for (int i = 0; i < length; i++) { - Serial.print((char)message[i]); - messageTemp += (char)message[i]; - } - Serial.println(); - - if (String(topic) == topic_id+"/config"){ - StaticJsonDocument<512> doc; - DeserializationError err = deserializeJson(doc, messageTemp); - if (!err){ - color_r = doc["color_r"] | color_r; - color_g = doc["color_g"] | color_g; - color_b = doc["color_b"] | color_b; - - brightness = doc["brightness"] | brightness; - Serial.print("brightness: "); - Serial.println(brightness); - Serial.print("Doc brightness: "); - Serial.println(doc["brightness"].as()); - Serial.print("Doc color_r: "); - Serial.println(doc["color_r"].as()); - Serial.print("Doc color_g: "); - Serial.println(doc["color_g"].as()); - Serial.print("Doc color_b: "); - Serial.println(doc["color_b"].as()); - - } - } else if (String(topic) == topic_id+"/color/r"){ - color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/g"){ - color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/b"){ - color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/brightness"){ - brightness = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/get_status"){ - publish_current_status(); - } - - fixConfigValues(); - - if (String(topic) != topic_id+"/get_status") { - if (stripe_on){ - toggle_leds(1); - } else { - toggle_leds(0); - } - } - - if(publish_status_after_every_config_change){ - publish_current_status(); - } -} - -void setup() { - client.setBufferSize(512); - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_broker, 1883); - reconnect(); - client.setCallback(callback); - - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "text/plain", "Hi! I am ESP32."); - }); - - AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA - server.begin(); - Serial.println("HTTP server started"); - - if (publish_status_at_start){ - publish_current_status(); - } - - FastLED.addLeds(leds, MAX_LEDS); - //FastLED.addLeds(leds, MAX_LEDS); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(50); - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::White; - } - show(); - delay(200); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - - pinMode(CLOCK_PIN, OUTPUT); - pinMode(DATA_PIN, OUTPUT); - - attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); - delay(500); - input_changed(); -} - -void setup_wifi() { - WiFi.setHostname(host_name); - WiFi.disconnect(true, true); - WiFi.mode(WIFI_STA); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() == WL_DISCONNECTED) { - delay(500); - } - - if (WiFi.status() != WL_CONNECTED) { - delay(10); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(SSID); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void input_changed(){ - if (digitalRead(INPUT_GPIO) == LOW){ - input_active = false; - } else { - input_active = true; - } -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { - Serial.println("connected"); - // Subscribe - Serial.print("Subscribing with topic_id: "); - Serial.println(topic_id); - client.subscribe((topic_id+"/get_status").c_str()); - client.subscribe((topic_id+"/config").c_str()); - client.subscribe((topic_id+"/output").c_str()); - client.subscribe((topic_id+"/color/r").c_str()); - client.subscribe((topic_id+"/color/g").c_str()); - client.subscribe((topic_id+"/color/b").c_str()); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void loop() { - if (WiFi.status() != WL_CONNECTED) { - setup_wifi(); - } - - if (!client.connected()) { - reconnect(); - } - client.loop(); - - if (input_active != stripe_on){ - if (input_active){ - toggle_leds(1); - } else { - toggle_leds(0); - } - - last_refresh = millis(); - } else { - - if ((millis() - last_refresh) > REFRESH_INTERVAL){ - last_refresh = millis(); - show(); - } - } - delay(10); -} diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h b/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h deleted file mode 100644 index e2da806..0000000 --- a/examples/ESP32LedStripWithMqttAndExternalInputOTA/settings.example.h +++ /dev/null @@ -1,17 +0,0 @@ -#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. -#define NUM_LEDS 300 -#define DATA_PIN 14 -#define CLOCK_PIN 13 -#define INPUT_GPIO 16 -#define REFRESH_INTERVAL 10000 - -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; -const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; -const char* ota_user = "ENTER_OTA_USER_HERE"; -const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; -const char* host_name = "ESP_LED"; -const String client_name = "ESP_LED"; -const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino b/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino deleted file mode 100755 index 9bfd885..0000000 --- a/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino +++ /dev/null @@ -1,313 +0,0 @@ -//LED Strip: BTF-LIGHTING WS2801 -//Power Supply: HuaTec LED Trafo 15V -//Step-Down-Module -//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 -//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 -//1 x Resistor: 10 kOhm -//Arduino Version: 1.8.13 -//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 -//Libs: -// Adafruit_NeoPixel by Adafruit Version 1.10.4 -// PubSubClient by Nick O'Leary Version 2.8.0 -// ArduinoJson by Benoit Blanchon Version 6.19.3 -// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 -// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP -// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer -#include -#include -#include -#include -#include -#include -#include -#include "settings.h" - -AsyncWebServer server(80); - -Adafruit_NeoPixel pixels(MAX_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800); - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -long last_refresh = 0; - -int brightness = 255; -int color_r = 255; -int color_g = 255; -int color_b = 255; -boolean stripe_on = false; -boolean input_active = false; - -int publish_status_after_every_config_change = 1; -int publish_status_if_toggled = 1; -int publish_status_at_start = 1; - -void show(){ - pixels.setBrightness(brightness); - pixels.show(); -} - -void toggle_leds(int to_state){ - if (to_state != -1){ - if (to_state == 0){ - stripe_on = true; - } else { - stripe_on = false; - } - } - if (stripe_on == false){ - Serial.print("Switch the rgb on with color: "); - Serial.print(color_r); - Serial.print("/"); - Serial.print(color_g); - Serial.print("/"); - Serial.println(color_b); - for (int i = 0; i< NUM_LEDS; i++){ - pixels.setPixelColor(i, pixels.Color(color_r,color_g,color_b)); - } - stripe_on = true; - } else { - for (int i = 0; i< MAX_LEDS; i++){ - pixels.setPixelColor(i, pixels.Color(0,0,0)); - } - stripe_on = false; - } - - show(); - if (publish_status_if_toggled == 1){ - publish_current_status(); - } -} - -void publish_current_status(){ - Serial.println("Publishing current status"); - StaticJsonDocument<1024> doc; - if (client.connected()){ - doc["output"] = stripe_on; - doc["brightness"] = brightness; - doc["color_r"] = color_r; - doc["color_g"] = color_g; - doc["color_b"] = color_b; - - char buffer[1024]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/status").c_str(), buffer, n); - } -} - -void fixConfigValues(){ - if (color_r > 255){ - color_r = 255; - } else if (color_r < 0){ - color_r = 0; - } - - if (color_g > 255){ - color_g = 255; - } else if (color_g < 0){ - color_g = 0; - } - - if (color_b > 255){ - color_b = 255; - } else if (color_b < 0){ - color_b = 0; - } - - if (brightness > 255){ - brightness = 255; - } else if (brightness < 0){ - brightness = 0; - } -} - -void callback(char* topic, byte* message, unsigned int length) { - Serial.print("Message arrived on topic: "); - Serial.print(topic); - Serial.print(". Message: "); - String messageTemp; - - for (int i = 0; i < length; i++) { - Serial.print((char)message[i]); - messageTemp += (char)message[i]; - } - Serial.println(); - - if (String(topic) == topic_id+"/config"){ - StaticJsonDocument<1024> doc; - DeserializationError err = deserializeJson(doc, messageTemp); - if (!err){ - color_r = doc["color_r"] | color_r; - color_g = doc["color_g"] | color_g; - color_b = doc["color_b"] | color_b; - brightness = doc["brightness"] | brightness; - } - } else if (String(topic) == topic_id+"/color/r"){ - color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/g"){ - color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/b"){ - color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/brightness"){ - brightness = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/get_status"){ - publish_current_status(); - } - - fixConfigValues(); - - if (String(topic) != topic_id+"/get_status") { - if (stripe_on){ - toggle_leds(1); - } else { - toggle_leds(0); - } - } - - if(publish_status_after_every_config_change){ - publish_current_status(); - } -} - -void setup() { - client.setBufferSize(512); - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_broker, 1883); - reconnect(); - client.setCallback(callback); - - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "text/plain", "Hi! I am "+host_name); - }); - - AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA - server.begin(); - Serial.println("HTTP server started"); - - if (publish_status_at_start){ - publish_current_status(); - } - - pinMode(CLOCK_PIN, OUTPUT); - pinMode(DATA_PIN, OUTPUT); - - pixels.begin(); - pixels.clear(); - - for (int i=0; i < MAX_LEDS; i++){ - pixels.setPixelColor(i, pixels.Color(0, 0, 0)); - } - show(); - delay(50); - for (int i=0; i < NUM_LEDS; i++){ - pixels.setPixelColor(i, pixels.Color(255, 255, 255)); - } - show(); - delay(200); - for (int i=0; i < MAX_LEDS; i++){ - pixels.setPixelColor(i, pixels.Color(0, 0, 0)); - } - show(); - - attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); - delay(500); - input_changed(); -} - -void setup_wifi() { - WiFi.setHostname(host_name.c_str()); - WiFi.disconnect(true, true); - WiFi.mode(WIFI_STA); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() == WL_DISCONNECTED) { - delay(500); - } - - if (WiFi.status() != WL_CONNECTED) { - delay(10); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(SSID); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void input_changed(){ - if (digitalRead(INPUT_GPIO) == LOW){ - input_active = false; - } else { - input_active = true; - } -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { - Serial.println("connected"); - // Subscribe - Serial.print("Subscribing with topic_id: "); - Serial.println(topic_id); - client.subscribe((topic_id+"/get_status").c_str()); - client.subscribe((topic_id+"/config").c_str()); - client.subscribe((topic_id+"/output").c_str()); - client.subscribe((topic_id+"/color/r").c_str()); - client.subscribe((topic_id+"/color/g").c_str()); - client.subscribe((topic_id+"/color/b").c_str()); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void loop() { - if (WiFi.status() != WL_CONNECTED) { - setup_wifi(); - } - - if (!client.connected()) { - reconnect(); - } - client.loop(); - - if (input_active != stripe_on){ - if (input_active){ - toggle_leds(1); - } else { - toggle_leds(0); - } - - last_refresh = millis(); - } else { - - if ((millis() - last_refresh) > REFRESH_INTERVAL){ - last_refresh = millis(); - show(); - } - } - delay(10); -} diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h b/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h deleted file mode 100755 index 539de4b..0000000 --- a/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h +++ /dev/null @@ -1,17 +0,0 @@ -#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. -#define NUM_LEDS 300 -#define DATA_PIN 14 -#define CLOCK_PIN 13 -#define INPUT_GPIO 16 -#define REFRESH_INTERVAL 10000 - -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; -const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; -const char* ota_user = "ENTER_OTA_USER_HERE"; -const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; -const String host_name = "ESP_LED"; -const String client_name = "ESP_LED"; -const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripWithPongAndMqtt/.gitignore b/examples/ESP32LedStripWithPongAndMqtt/.gitignore deleted file mode 100644 index 0e95883..0000000 --- a/examples/ESP32LedStripWithPongAndMqtt/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -settings.h -*.bin diff --git a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino b/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino deleted file mode 100644 index 8e5370f..0000000 --- a/examples/ESP32LedStripWithPongAndMqtt/ESP32LedStripWithPongAndMqtt.ino +++ /dev/null @@ -1,918 +0,0 @@ -//LED Strip: BTF-LIGHTING WS2815 -> https://www.amazon.de/gp/product/B07LG5ZT9C/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1 -//Power Supply: HuaTec LED Trafo 12V 120W -> https://www.amazon.de/gp/product/B0829817YM/ref=ppx_yo_dt_b_asin_image_o09_s00?ie=UTF8&psc=1 -//Step-Down-Module: AZDelivery XL4015 -> https://www.amazon.de/gp/product/B07SRXR1VT/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1 -//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 -//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 -//2 x Tactile Push Button (Something like https://www.amazon.de/gp/product/B078ZDK6KZ/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) -//2 x Capacitor 0.1 Mikrofarad -//2 x Resistor: 10 kOhm -//Arduino Version: 1.8.13 -//Board Firmware: ESP32 by Espressif Systems Version 1.0.6 -//Libs: -// FastLED by Daniel Garcia Version 3.4.0 -// PubSubClient by Nick O'Leary Version 2.8.0 -// ArduinoJson by Benoit Blanchon Version 6.17.3 -#include -#include -#include -#include -#include "settings.h" - -CRGB leds[MAX_LEDS]; - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -long last_refresh = 0; - -int reverseMode=0; -int cur_pixel=0; -int btn_one_state = 0; -int btn_one_long_state = 0; -long btn_one_last_pressed = 0; -long btn_one_last_released = -1; -int btn_two_state = 0; -int btn_two_long_state = 0; -long btn_two_last_pressed = 0; -long btn_two_last_released = -1; -bool enable_hardware_btns = true; - - -int brightness = 255; -int brightness_decrease = true; -int color_r = 255; -int color_g = 255; -int color_b = 255; -int stripe_mode = 0; -boolean stripe_on = false; - -float pong_init_delay = PONG_INIT_LED_DELAY; -float cur_pong_delay = pong_init_delay; -int num_pong_leds = NUM_PONG_LEDS; -int pong_start_led = PONG_START_LED; -int pong_max_wins = PONG_MAX_WINS; -float pong_wins_delay_during = PONG_RESULT_DELAY_DURING; -float pong_wins_delay_after = PONG_RESULT_DELAY_AFTER; -float pong_min_delay = PONG_MIN_LED_DELAY; -float pong_dec_per_run = PONG_DEC_PER_RUN; -float pong_btn_delay = PONG_BTN_DELAY; -int pong_tolerance = PONG_TOLERANCE; -int pong_color_r = 0; -int pong_color_g = 0; -int pong_color_b = 255; -int pong_result_color_r = 0; -int pong_result_color_g = 255; -int pong_result_color_b = 0; -int player_one_wins = 0; -int player_successfull_one_press = 0; -int player_two_wins = 0; -int player_successfull_two_press = 0; -int player_one_miss = 0; -int player_two_miss = 0; -int abortRun = 0; -bool player_one_hit_first = true; -bool change_start_led_during_match = true; - -int publish_status_after_every_config_change = 1; -int publish_status_if_toggled = 1; -int publish_status_at_start = 1; -int publish_results_at_display = 1; - - -void publish_current_status(){ - Serial.println("Publishing current status"); - StaticJsonDocument<1024> doc; - if (client.connected()){ - doc["pong"]["btn_delay"] = pong_btn_delay; - doc["pong"]["init_delay"] = pong_init_delay; - doc["pong"]["min_delay"] = pong_min_delay; - doc["pong"]["dec_per_run"] = pong_dec_per_run; - doc["pong"]["num_leds"] = num_pong_leds; - doc["pong"]["max_wins"] = pong_max_wins; - doc["pong"]["tolerance"] = pong_tolerance; - doc["pong"]["result_delay_during"] = pong_wins_delay_during; - doc["pong"]["result_delay_after"] = pong_wins_delay_after; - doc["pong"]["color_r"] = pong_color_r; - doc["pong"]["color_g"] = pong_color_g; - doc["pong"]["color_b"] = pong_color_b; - doc["pong"]["result_color_r"] = pong_result_color_r; - doc["pong"]["result_color_g"] = pong_result_color_g; - doc["pong"]["result_color_b"] = pong_result_color_b; - doc["output"] = stripe_on; - doc["mode"] = stripe_mode; - doc["brightness"] = brightness; - doc["color_r"] = color_r; - doc["color_g"] = color_g; - doc["color_b"] = color_b; - doc["hardware_buttons_enabled"] = enable_hardware_btns; - - char buffer[1024]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/status").c_str(), buffer, n); - } -} - -void publish_results(){ - StaticJsonDocument<100> doc; - if (client.connected()){ - doc["result_player_one"] = player_one_wins; - doc["result_player_two"] = player_two_wins; - } - char buffer[100]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/results").c_str(), buffer, n); -} - -void fixConfigValues(){ - if (pong_btn_delay < 0){ - pong_btn_delay = 0; - } - - if (pong_init_delay < pong_min_delay){ - pong_init_delay = pong_min_delay; - } - - if (pong_min_delay < 0){ - pong_min_delay = 0; - } - - if (pong_dec_per_run < 0){ - pong_dec_per_run = 0; - } - - if (num_pong_leds > NUM_LEDS){ - num_pong_leds = NUM_LEDS; - } - - if (pong_max_wins > num_pong_leds){ - pong_max_wins = num_pong_leds; - } - - if (pong_wins_delay_during < 0){ - pong_wins_delay_during = 0; - } - - if (pong_wins_delay_after < 0){ - pong_wins_delay_after = 0; - } - - if (pong_result_color_r > 255){ - pong_result_color_r = 255; - } else if (pong_result_color_r < 0){ - pong_result_color_r = 0; - } - - if (pong_result_color_g > 255){ - pong_result_color_g = 255; - } else if (pong_result_color_g < 0){ - pong_result_color_g = 0; - } - - if (pong_result_color_b > 255){ - pong_result_color_b = 255; - } else if (pong_result_color_b < 0){ - pong_result_color_b = 0; - } - - if (pong_tolerance < 0){ - pong_tolerance = 0; - } - - if (pong_tolerance > (num_pong_leds -1)){ - pong_tolerance = num_pong_leds -1; - } - - if (pong_color_r > 255){ - pong_color_r = 255; - } else if (pong_color_r < 0){ - pong_color_r = 0; - } - - if (pong_color_g > 255){ - pong_color_g = 255; - } else if (pong_color_g < 0){ - pong_color_g = 0; - } - - if (pong_color_b > 255){ - pong_color_b = 255; - } else if (pong_color_b < 0){ - pong_color_b = 0; - } - - if (color_r > 255){ - color_r = 255; - } else if (color_r < 0){ - color_r = 0; - } - - if (color_g > 255){ - color_g = 255; - } else if (color_g < 0){ - color_g = 0; - } - - if (color_b > 255){ - color_b = 255; - } else if (color_b < 0){ - color_b = 0; - } - - if (brightness > 255){ - brightness = 255; - } else if (brightness < 0){ - brightness = 0; - } -} - -void callback(char* topic, byte* message, unsigned int length) { - Serial.print("Message arrived on topic: "); - Serial.print(topic); - Serial.print(". Message: "); - String messageTemp; - - for (int i = 0; i < length; i++) { - Serial.print((char)message[i]); - messageTemp += (char)message[i]; - } - Serial.println(); - - if (! (String(topic) == topic_id+"/btn") ) { - // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". - // Changes the output state according to the message - if (String(topic) == topic_id+"/output") { - Serial.print("Changing output to "); - if(messageTemp == "on"){ - Serial.println("on"); - toggle_leds(1); - } - else if(messageTemp == "off"){ - Serial.println("off"); - toggle_leds(0); - } else { - Serial.println("toggle"); - toggle_leds(-1); - } - } else if (String(topic) == topic_id+"/config"){ - StaticJsonDocument<1024> doc; - DeserializationError err = deserializeJson(doc, messageTemp); - if (!err){ - - if(doc["pong"]["btn_delay"]){ - pong_btn_delay = doc["pong"]["btn_delay"].as(); - } - - if(doc["pong"]["init_delay"]){ - pong_init_delay = doc["pong"]["init_delay"].as(); - } - - if(doc["pong"]["min_delay"]){ - pong_min_delay = doc["pong"]["min_delay"].as(); - } - - if(doc["pong"]["dec_per_run"]){ - pong_dec_per_run = doc["pong"]["dec_per_run"].as(); - } - - num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; - pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; - pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; - - if(doc["pong"]["result_delay_during"]){ - pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); - } - - if(doc["pong"]["result_delay_after"]){ - pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); - } - - pong_color_r = doc["pong"]["color_r"] | pong_color_r; - pong_color_g = doc["pong"]["color_g"] | pong_color_g; - pong_color_b = doc["pong"]["color_b"] | pong_color_b; - - pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; - pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; - pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; - - color_r = doc["color_r"] | color_r; - color_g = doc["color_g"] | color_g; - color_b = doc["color_b"] | color_b; - - brightness = doc["brightness"] | brightness; - - if (doc.containsKey("hardware_buttons_enabled")){ - if (!doc["hardware_buttons_enabled"]){ - if (enable_hardware_btns){ - enable_hardware_btns = false; - detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); - detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); - Serial.println("Disable Hardware Buttons"); - } - } else { - if (!enable_hardware_btns){ - enable_hardware_btns = true; - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); - Serial.println("Enable Hardware Buttons"); - } - } - } - - } - - } else if (String(topic) == topic_id+"/pong/btn_delay"){ - pong_btn_delay = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/init_delay"){ - pong_init_delay = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/min_delay"){ - pong_min_delay = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/dec_per_run"){ - pong_dec_per_run = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/num_leds"){ - num_pong_leds = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/max_wins"){ - pong_max_wins = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/result/delay/during"){ - pong_wins_delay_during = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/result/delay/after"){ - pong_wins_delay_after = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/result/color/r"){ - pong_result_color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/result/color/g"){ - pong_result_color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/result/color/b"){ - pong_result_color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/tolerance"){ - pong_tolerance = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/color/r"){ - pong_color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/color/g"){ - pong_color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/color/b"){ - pong_color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/r"){ - color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/g"){ - color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/b"){ - color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/brightness"){ - brightness = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/get_status"){ - publish_current_status(); - } else if (String(topic) == topic_id+"/hardware_buttons_enabled"){ - if (messageTemp.toInt() == 1){ - if (enable_hardware_btns){ - enable_hardware_btns = false; - detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); - detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); - Serial.println("Disable Hardware Buttons"); - } - } else { - if (!enable_hardware_btns){ - enable_hardware_btns = true; - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); - Serial.println("Enable Hardware Buttons"); - } - } - } - - fixConfigValues(); - - if ((String(topic) != topic_id+"/output") && - (String(topic) != topic_id+"/get_status") && - (stripe_mode == 0)){ - if (stripe_on){ - toggle_leds(1); - } else { - toggle_leds(0); - } - } - - if(publish_status_after_every_config_change){ - publish_current_status(); - } - } else { - Serial.println("Button press via mqtt"); - Serial.println(messageTemp); - if (messageTemp.toInt() == 2 ){ - btn_two_last_pressed = millis(); - btn_two_last_released = btn_two_last_pressed; - btn_two_state = 1; - } else { - btn_one_last_pressed = millis(); - btn_one_last_released = btn_one_last_pressed; - btn_one_state = 1; - } - } -} - -void show(){ - FastLED.setBrightness(brightness); - FastLED.show(); - //FastLED.show(); -} - -void setup() { - client.setBufferSize(512); - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_broker, 1883); - reconnect(); - client.setCallback(callback); - - if (publish_status_at_start){ - publish_current_status(); - } - - FastLED.addLeds(leds, MAX_LEDS); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(50); - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::White; - } - show(); - delay(200); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - - pinMode(BTN_1_GPIO, INPUT); - pinMode(BTN_2_GPIO, INPUT); - pinMode(DATA_PIN, OUTPUT); - - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); - delay(500); -} - -void setup_wifi() { - WiFi.disconnect(true, true); - WiFi.mode(WIFI_STA); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() == WL_DISCONNECTED) { - delay(500); - } - - if (WiFi.status() != WL_CONNECTED) { - delay(10); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(SSID); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void btn_one_changed(){ - long cur_time = millis(); - if((cur_time - btn_one_last_pressed) > BTN_DEBOUNCE_DELAY){ - if (digitalRead(BTN_1_GPIO) == LOW){ - btn_one_last_pressed = cur_time; - btn_one_state = 1; - } else{ - btn_one_last_released = cur_time; - } - } else{ - if (digitalRead(BTN_1_GPIO) == HIGH){ - btn_one_last_released = cur_time; - } - } -} - -void btn_two_changed(){ - long cur_time = millis(); - if((cur_time - btn_two_last_pressed) > BTN_DEBOUNCE_DELAY){ - if (digitalRead(BTN_2_GPIO) == LOW){ - btn_two_last_pressed = cur_time; - btn_two_state = 1; - } else{ - btn_two_last_released = cur_time; - } - } else { - if (digitalRead(BTN_2_GPIO) == HIGH){ - btn_two_last_released = cur_time; - } - } -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { - Serial.println("connected"); - // Subscribe - Serial.print("Subscribing with topic_id: "); - Serial.println(topic_id); - client.subscribe((topic_id+"/get_status").c_str()); - client.subscribe((topic_id+"/config").c_str()); - client.subscribe((topic_id+"/output").c_str()); - client.subscribe((topic_id+"/pong/btn_delay").c_str()); - client.subscribe((topic_id+"/pong/init_delay").c_str()); - client.subscribe((topic_id+"/pong/min_delay").c_str()); - client.subscribe((topic_id+"/pong/dec_per_run").c_str()); - client.subscribe((topic_id+"/pong/num_leds").c_str()); - client.subscribe((topic_id+"/pong/max_wins").c_str()); - client.subscribe((topic_id+"/pong/result/delay/during").c_str()); - client.subscribe((topic_id+"/pong/result/delay/after").c_str()); - client.subscribe((topic_id+"/pong/result/color/r").c_str()); - client.subscribe((topic_id+"/pong/result/color/g").c_str()); - client.subscribe((topic_id+"/pong/result/color/b").c_str()); - client.subscribe((topic_id+"/pong/tolerance").c_str()); - client.subscribe((topic_id+"/pong/color/r").c_str()); - client.subscribe((topic_id+"/pong/color/g").c_str()); - client.subscribe((topic_id+"/pong/color/b").c_str()); - client.subscribe((topic_id+"/color/r").c_str()); - client.subscribe((topic_id+"/color/g").c_str()); - client.subscribe((topic_id+"/color/b").c_str()); - client.subscribe((topic_id+"/btn").c_str()); - client.subscribe((topic_id+"/disable_btns").c_str()); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void toggle_leds(int to_state){ - if (to_state != -1){ - if (to_state == 0){ - stripe_on = true; - } else { - stripe_on = false; - } - } - if (stripe_on == false){ - Serial.print("Switch the rgb on with color: "); - Serial.print(color_r); - Serial.print("/"); - Serial.print(color_g); - Serial.print("/"); - Serial.println(color_b); - for (int i = 0; i< NUM_LEDS; i++){ - leds[i].r = color_r; - leds[i].g = color_g; - leds[i].b = color_b; - } - stripe_on = true; - } else { - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - stripe_on = false; - } - - show(); - if (publish_status_if_toggled == 1){ - publish_current_status(); - } -} - -void reset_pong_vars(bool during, bool oneHitFirst){ - Serial.print("Resetting pong vars ("); - Serial.print(during); - Serial.print("/"); - Serial.print(oneHitFirst); - Serial.println(")"); - client.loop(); - player_one_miss = 0; - player_two_miss = 0; - btn_one_state = 0; - btn_two_state = 0; - player_successfull_one_press = 0; - player_successfull_two_press = 0; - cur_pong_delay = pong_init_delay; - - if (!during){ - player_one_wins = 0; - player_two_wins = 0; - btn_one_last_pressed = 0; - btn_two_last_pressed = 0; - stripe_mode = 0; - } - - if (oneHitFirst){ - cur_pixel = pong_start_led; - reverseMode = 0; - } else { - cur_pixel = num_pong_leds-1; - reverseMode = 1; - } -} - -void switch_to_pong_mode(bool oneHitFirst){ - Serial.println("Switching to pong mode"); - delay(500); - reset_pong_vars(false, oneHitFirst); - - stripe_mode = 1; - - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(1000); - for (int i = pong_start_led; i< num_pong_leds; i++){ - leds[i].r = pong_color_r; - leds[i].g = pong_color_g; - leds[i].b = pong_color_b; - } - show(); - delay(1000); - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(1000); -} - -void display_result(float cur_delay){ - Serial.println("Displaying results"); - delay(500); - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - - for (int i = pong_start_led; i < player_one_wins+pong_start_led; i++){ - leds[i].r = pong_result_color_r; - leds[i].g = pong_result_color_g; - leds[i].b = pong_result_color_b; - } - - for (int i = (num_pong_leds - 1); i > ((num_pong_leds-1)-player_two_wins); i--){ - leds[i].r = pong_result_color_r; - leds[i].g = pong_result_color_g; - leds[i].b = pong_result_color_b; - } - show(); - delay(cur_delay*1000); -} - -void changeBrightness(){ - if (brightness_decrease){ - //Serial.println("Decrease brightness"); - brightness = brightness - BRIGHTNESS_CHANGE_VALUE; - if (brightness <= 0){ - brightness = 0; - //Serial.println("Smallest value reached"); - brightness_decrease = !brightness_decrease; - } - } else { - //Serial.println("Increase brightness"); - brightness = brightness + BRIGHTNESS_CHANGE_VALUE; - if (brightness >= 255){ - brightness = 255; - //Serial.println("Max value reached"); - brightness_decrease = !brightness_decrease; - } - } - - show(); -} - -void loop() { - if (WiFi.status() != WL_CONNECTED) { - setup_wifi(); - } - - if (!client.connected()) { - reconnect(); - } - client.loop(); - - if (stripe_mode == 0){ - if ((btn_one_state == 1) or (btn_two_state == 1)){ - //Serial.println("btn one or two pressed"); - if (btn_two_state == 1){ - //Serial.println("btn_two_state == 1"); - //Serial.println(btn_two_last_released); - //Serial.println(btn_two_last_pressed); - if ((btn_two_last_released >= btn_two_last_pressed) or (!stripe_on)){ - //Serial.println("btn_two currently is not pressed"); - if (btn_two_long_state == 0){ - //Serial.println("btn_two had no long press"); - player_one_hit_first = true; - btn_two_state = 0; - //Serial.println("Button two pressed."); - if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ - Serial.println("Switching to pong mode."); - switch_to_pong_mode(player_one_hit_first); - } else { - Serial.println("Toggling led stripe."); - toggle_leds(-1); - } - } else { - //Serial.println("btn_two had long press"); - btn_two_long_state = 0; - btn_two_state = 0; - } - } else { - //button still pressed. Maybe a long press? - if ((millis() - btn_two_last_pressed) > BTN_LONG_PRESS_DELAY){ - //Serial.println("btn_two long press detected"); - btn_two_long_state = 1; - changeBrightness(); - publish_current_status(); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } else { - //Serial.println("btn_two still pressed"); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } - } - } - - if (btn_one_state == 1){ - //Serial.println("btn_one_state == 1"); - //Serial.println(btn_one_last_released); - //Serial.println(btn_one_last_pressed); - if ((btn_one_last_released >= btn_one_last_pressed) or (!stripe_on)){ - //Serial.println("btn_one currently is not pressed"); - if (btn_one_long_state == 0){ - //Serial.println("btn_one had no long press"); - player_one_hit_first = false; - btn_one_state = 0; - if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ - Serial.println("Switching to pong mode."); - switch_to_pong_mode(player_one_hit_first); - } else { - Serial.println("Button one pressed. Toggling led stripe."); - toggle_leds(-1); - } - } else { - //Serial.println("btn_one had long press"); - btn_one_long_state = 0; - btn_one_state = 0; - } - } else { - //button still pressed. Maybe a long press? - if ((millis() - btn_one_last_pressed) > BTN_LONG_PRESS_DELAY){ - //Serial.println("btn_one long press detected"); - btn_one_long_state = 1; - changeBrightness(); - publish_current_status(); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } else { - //Serial.println("btn_one still pressed"); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } - } - } - } else { - if((millis() - last_refresh) > REFRESH_INTERVAL){ - show(); - } - } - } else if (stripe_mode == 1){ - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::Black; - } - - leds[cur_pixel].r = pong_color_r; - leds[cur_pixel].g = pong_color_g; - leds[cur_pixel].b = pong_color_b; - show(); - - delay(cur_pong_delay*1000); - - abortRun = 0; - player_one_miss = 0; - - if (player_successfull_one_press == 0){ - if(btn_one_state == 1){ - btn_one_state = 0; - if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= pong_start_led)){ - player_one_miss = 1; - } else { - player_successfull_one_press = 1; - } - } else if ((reverseMode == 1) && (cur_pixel == pong_start_led)){ - player_one_miss = 1; - } - } else { - btn_one_state = 0; - } - - if(player_one_miss == 1){ - abortRun = 1; - player_two_wins += 1; - if(player_two_wins >= pong_max_wins){ - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_after); - reset_pong_vars(false, player_one_hit_first); - if (publish_results_at_display == 1){ - publish_results(); - } - toggle_leds(0); - } else { - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_during); - cur_pixel = pong_start_led; - reverseMode = 0; - if (change_start_led_during_match){ - player_one_hit_first = !player_one_hit_first; - } - reset_pong_vars(true, player_one_hit_first); - } - } - - player_two_miss = 0; - - if (player_successfull_two_press == 0){ - if(btn_two_state == 1){ - btn_two_state = 0; - if ((reverseMode == 1) or ((cur_pixel + pong_tolerance) <= (num_pong_leds-1))){ - player_two_miss = 1; - } else { - player_successfull_two_press = 1; - } - } else if ((reverseMode == 0) && (cur_pixel == (num_pong_leds-1))){ - player_two_miss = 1; - } - } else { - btn_two_state = 0; - } - - if(player_two_miss == 1){ - abortRun = 1; - player_one_wins += 1; - if(player_one_wins >= pong_max_wins){ - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_after); - reset_pong_vars(false, player_one_hit_first); - if (publish_results_at_display == 1){ - publish_results(); - } - toggle_leds(0); - } else { - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_during); - if (change_start_led_during_match){ - player_one_hit_first = !player_one_hit_first; - } - reset_pong_vars(true, player_one_hit_first); - } - } - - - if (abortRun == 0){ - if (reverseMode == 1){ - cur_pixel -= 1; - if (cur_pixel < pong_start_led){ - reverseMode = 0; - player_successfull_one_press = 0; - cur_pixel = pong_start_led + 1; - cur_pong_delay = cur_pong_delay - pong_dec_per_run; - if (cur_pong_delay < pong_min_delay){ - cur_pong_delay = pong_min_delay; - } - } - } else { - cur_pixel += 1; - if (cur_pixel > (num_pong_leds-1)){ - player_successfull_two_press = 0; - cur_pixel = num_pong_leds-2; - reverseMode = 1; - cur_pong_delay = cur_pong_delay - pong_dec_per_run; - if (cur_pong_delay < pong_min_delay){ - cur_pong_delay = pong_min_delay; - } - } - } - } - } -} diff --git a/examples/ESP32LedStripWithPongAndMqtt/settings.example.h b/examples/ESP32LedStripWithPongAndMqtt/settings.example.h deleted file mode 100644 index aaa68b1..0000000 --- a/examples/ESP32LedStripWithPongAndMqtt/settings.example.h +++ /dev/null @@ -1,29 +0,0 @@ -#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. -#define NUM_LEDS 300 -#define NUM_PONG_LEDS 10 -#define DATA_PIN 14 -#define BTN_1_GPIO 23 -#define BTN_2_GPIO 22 -#define BTN_DEBOUNCE_DELAY 500 -#define BTN_LONG_PRESS_DELAY 1000 -#define BRIGHTNESS_CHANGE_INTERVAL 50 -#define BRIGHTNESS_CHANGE_VALUE 5 -#define PONG_START_LED 0 -#define PONG_BTN_DELAY 2.000 -#define PONG_MAX_WINS 2 -#define PONG_TOLERANCE 2 -#define PONG_INIT_LED_DELAY 0.500 -#define PONG_DEC_PER_RUN 0.05 -#define PONG_MIN_LED_DELAY 0.02 -#define PONG_RESULT_DELAY_DURING 2.0 -#define PONG_RESULT_DELAY_AFTER 5.0 -#define REFRESH_INTERVAL 10000 - -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; -const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; -const char* host_name = "ESP_LED"; -const String client_name = "ESP_LED"; -const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripWithPongAndMqttOTA/.gitignore b/examples/ESP32LedStripWithPongAndMqttOTA/.gitignore deleted file mode 100644 index 0e95883..0000000 --- a/examples/ESP32LedStripWithPongAndMqttOTA/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -settings.h -*.bin diff --git a/examples/ESP32LedStripWithPongAndMqttOTA/ESP32LedStripWithPongAndMqttOTA.ino b/examples/ESP32LedStripWithPongAndMqttOTA/ESP32LedStripWithPongAndMqttOTA.ino deleted file mode 100644 index 8f8a532..0000000 --- a/examples/ESP32LedStripWithPongAndMqttOTA/ESP32LedStripWithPongAndMqttOTA.ino +++ /dev/null @@ -1,931 +0,0 @@ -//LED Strip: BTF-LIGHTING WS2815 -> https://www.amazon.de/gp/product/B07LG5ZT9C/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1 -//Power Supply: HuaTec LED Trafo 12V 120W -> https://www.amazon.de/gp/product/B0829817YM/ref=ppx_yo_dt_b_asin_image_o09_s00?ie=UTF8&psc=1 -//Step-Down-Module: AZDelivery XL4015 -> https://www.amazon.de/gp/product/B07SRXR1VT/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1 -//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 -//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 -//2 x Tactile Push Button (Something like https://www.amazon.de/gp/product/B078ZDK6KZ/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) -//2 x Capacitor 0.1 Mikrofarad -//2 x Resistor: 10 kOhm -//Arduino Version: 1.8.13 -//Board Firmware: ESP32 by Espressif Systems Version 1.0.6 -//Libs: -// FastLED by Daniel Garcia Version 3.4.0 -// PubSubClient by Nick O'Leary Version 2.8.0 -// ArduinoJson by Benoit Blanchon Version 6.17.3 -#include -#include -#include -#include -#include -#include -#include -#include "settings.h" - -AsyncWebServer server(80); - -CRGB leds[MAX_LEDS]; - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -long last_refresh = 0; - -int reverseMode=0; -int cur_pixel=0; -int btn_one_state = 0; -int btn_one_long_state = 0; -long btn_one_last_pressed = 0; -long btn_one_last_released = -1; -int btn_two_state = 0; -int btn_two_long_state = 0; -long btn_two_last_pressed = 0; -long btn_two_last_released = -1; -bool enable_hardware_btns = true; - - -int brightness = 255; -int brightness_decrease = true; -int color_r = 255; -int color_g = 255; -int color_b = 255; -int stripe_mode = 0; -boolean stripe_on = false; - -float pong_init_delay = PONG_INIT_LED_DELAY; -float cur_pong_delay = pong_init_delay; -int num_pong_leds = NUM_PONG_LEDS; -int pong_start_led = PONG_START_LED; -int pong_max_wins = PONG_MAX_WINS; -float pong_wins_delay_during = PONG_RESULT_DELAY_DURING; -float pong_wins_delay_after = PONG_RESULT_DELAY_AFTER; -float pong_min_delay = PONG_MIN_LED_DELAY; -float pong_dec_per_run = PONG_DEC_PER_RUN; -float pong_btn_delay = PONG_BTN_DELAY; -int pong_tolerance = PONG_TOLERANCE; -int pong_color_r = 0; -int pong_color_g = 0; -int pong_color_b = 255; -int pong_result_color_r = 0; -int pong_result_color_g = 255; -int pong_result_color_b = 0; -int player_one_wins = 0; -int player_successfull_one_press = 0; -int player_two_wins = 0; -int player_successfull_two_press = 0; -int player_one_miss = 0; -int player_two_miss = 0; -int abortRun = 0; -bool player_one_hit_first = true; -bool change_start_led_during_match = true; - -int publish_status_after_every_config_change = 1; -int publish_status_if_toggled = 1; -int publish_status_at_start = 1; -int publish_results_at_display = 1; - - -void publish_current_status(){ - Serial.println("Publishing current status"); - StaticJsonDocument<1024> doc; - if (client.connected()){ - doc["pong"]["btn_delay"] = pong_btn_delay; - doc["pong"]["init_delay"] = pong_init_delay; - doc["pong"]["min_delay"] = pong_min_delay; - doc["pong"]["dec_per_run"] = pong_dec_per_run; - doc["pong"]["num_leds"] = num_pong_leds; - doc["pong"]["max_wins"] = pong_max_wins; - doc["pong"]["tolerance"] = pong_tolerance; - doc["pong"]["result_delay_during"] = pong_wins_delay_during; - doc["pong"]["result_delay_after"] = pong_wins_delay_after; - doc["pong"]["color_r"] = pong_color_r; - doc["pong"]["color_g"] = pong_color_g; - doc["pong"]["color_b"] = pong_color_b; - doc["pong"]["result_color_r"] = pong_result_color_r; - doc["pong"]["result_color_g"] = pong_result_color_g; - doc["pong"]["result_color_b"] = pong_result_color_b; - doc["output"] = stripe_on; - doc["mode"] = stripe_mode; - doc["brightness"] = brightness; - doc["color_r"] = color_r; - doc["color_g"] = color_g; - doc["color_b"] = color_b; - doc["hardware_buttons_enabled"] = enable_hardware_btns; - - char buffer[1024]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/status").c_str(), buffer, n); - } -} - -void publish_results(){ - StaticJsonDocument<100> doc; - if (client.connected()){ - doc["result_player_one"] = player_one_wins; - doc["result_player_two"] = player_two_wins; - } - char buffer[100]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/results").c_str(), buffer, n); -} - -void fixConfigValues(){ - if (pong_btn_delay < 0){ - pong_btn_delay = 0; - } - - if (pong_init_delay < pong_min_delay){ - pong_init_delay = pong_min_delay; - } - - if (pong_min_delay < 0){ - pong_min_delay = 0; - } - - if (pong_dec_per_run < 0){ - pong_dec_per_run = 0; - } - - if (num_pong_leds > NUM_LEDS){ - num_pong_leds = NUM_LEDS; - } - - if (pong_max_wins > num_pong_leds){ - pong_max_wins = num_pong_leds; - } - - if (pong_wins_delay_during < 0){ - pong_wins_delay_during = 0; - } - - if (pong_wins_delay_after < 0){ - pong_wins_delay_after = 0; - } - - if (pong_result_color_r > 255){ - pong_result_color_r = 255; - } else if (pong_result_color_r < 0){ - pong_result_color_r = 0; - } - - if (pong_result_color_g > 255){ - pong_result_color_g = 255; - } else if (pong_result_color_g < 0){ - pong_result_color_g = 0; - } - - if (pong_result_color_b > 255){ - pong_result_color_b = 255; - } else if (pong_result_color_b < 0){ - pong_result_color_b = 0; - } - - if (pong_tolerance < 0){ - pong_tolerance = 0; - } - - if (pong_tolerance > (num_pong_leds -1)){ - pong_tolerance = num_pong_leds -1; - } - - if (pong_color_r > 255){ - pong_color_r = 255; - } else if (pong_color_r < 0){ - pong_color_r = 0; - } - - if (pong_color_g > 255){ - pong_color_g = 255; - } else if (pong_color_g < 0){ - pong_color_g = 0; - } - - if (pong_color_b > 255){ - pong_color_b = 255; - } else if (pong_color_b < 0){ - pong_color_b = 0; - } - - if (color_r > 255){ - color_r = 255; - } else if (color_r < 0){ - color_r = 0; - } - - if (color_g > 255){ - color_g = 255; - } else if (color_g < 0){ - color_g = 0; - } - - if (color_b > 255){ - color_b = 255; - } else if (color_b < 0){ - color_b = 0; - } - - if (brightness > 255){ - brightness = 255; - } else if (brightness < 0){ - brightness = 0; - } -} - -void callback(char* topic, byte* message, unsigned int length) { - Serial.print("Message arrived on topic: "); - Serial.print(topic); - Serial.print(". Message: "); - String messageTemp; - - for (int i = 0; i < length; i++) { - Serial.print((char)message[i]); - messageTemp += (char)message[i]; - } - Serial.println(); - - if (! (String(topic) == topic_id+"/btn") ) { - // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". - // Changes the output state according to the message - if (String(topic) == topic_id+"/output") { - Serial.print("Changing output to "); - if(messageTemp == "on"){ - Serial.println("on"); - toggle_leds(1); - } - else if(messageTemp == "off"){ - Serial.println("off"); - toggle_leds(0); - } else { - Serial.println("toggle"); - toggle_leds(-1); - } - } else if (String(topic) == topic_id+"/config"){ - StaticJsonDocument<1024> doc; - DeserializationError err = deserializeJson(doc, messageTemp); - if (!err){ - - if(doc["pong"]["btn_delay"]){ - pong_btn_delay = doc["pong"]["btn_delay"].as(); - } - - if(doc["pong"]["init_delay"]){ - pong_init_delay = doc["pong"]["init_delay"].as(); - } - - if(doc["pong"]["min_delay"]){ - pong_min_delay = doc["pong"]["min_delay"].as(); - } - - if(doc["pong"]["dec_per_run"]){ - pong_dec_per_run = doc["pong"]["dec_per_run"].as(); - } - - num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; - pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; - pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; - - if(doc["pong"]["result_delay_during"]){ - pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); - } - - if(doc["pong"]["result_delay_after"]){ - pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); - } - - pong_color_r = doc["pong"]["color_r"] | pong_color_r; - pong_color_g = doc["pong"]["color_g"] | pong_color_g; - pong_color_b = doc["pong"]["color_b"] | pong_color_b; - - pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; - pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; - pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; - - color_r = doc["color_r"] | color_r; - color_g = doc["color_g"] | color_g; - color_b = doc["color_b"] | color_b; - - brightness = doc["brightness"] | brightness; - - if (doc.containsKey("hardware_buttons_enabled")){ - if (!doc["hardware_buttons_enabled"]){ - if (enable_hardware_btns){ - enable_hardware_btns = false; - detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); - detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); - Serial.println("Disable Hardware Buttons"); - } - } else { - if (!enable_hardware_btns){ - enable_hardware_btns = true; - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); - Serial.println("Enable Hardware Buttons"); - } - } - } - - } - - } else if (String(topic) == topic_id+"/pong/btn_delay"){ - pong_btn_delay = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/init_delay"){ - pong_init_delay = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/min_delay"){ - pong_min_delay = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/dec_per_run"){ - pong_dec_per_run = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/num_leds"){ - num_pong_leds = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/max_wins"){ - pong_max_wins = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/result/delay/during"){ - pong_wins_delay_during = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/result/delay/after"){ - pong_wins_delay_after = messageTemp.toFloat(); - } else if (String(topic) == topic_id+"/pong/result/color/r"){ - pong_result_color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/result/color/g"){ - pong_result_color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/result/color/b"){ - pong_result_color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/tolerance"){ - pong_tolerance = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/color/r"){ - pong_color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/color/g"){ - pong_color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/pong/color/b"){ - pong_color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/r"){ - color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/g"){ - color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/b"){ - color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/brightness"){ - brightness = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/get_status"){ - publish_current_status(); - } else if (String(topic) == topic_id+"/hardware_buttons_enabled"){ - if (messageTemp.toInt() == 1){ - if (enable_hardware_btns){ - enable_hardware_btns = false; - detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); - detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); - Serial.println("Disable Hardware Buttons"); - } - } else { - if (!enable_hardware_btns){ - enable_hardware_btns = true; - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); - Serial.println("Enable Hardware Buttons"); - } - } - } - - fixConfigValues(); - - if ((String(topic) != topic_id+"/output") && - (String(topic) != topic_id+"/get_status") && - (stripe_mode == 0)){ - if (stripe_on){ - toggle_leds(1); - } else { - toggle_leds(0); - } - } - - if(publish_status_after_every_config_change){ - publish_current_status(); - } - } else { - Serial.println("Button press via mqtt"); - Serial.println(messageTemp); - if (messageTemp.toInt() == 2 ){ - btn_two_last_pressed = millis(); - btn_two_last_released = btn_two_last_pressed; - btn_two_state = 1; - } else { - btn_one_last_pressed = millis(); - btn_one_last_released = btn_one_last_pressed; - btn_one_state = 1; - } - } -} - -void show(){ - FastLED.setBrightness(brightness); - FastLED.show(); - //FastLED.show(); -} - -void setup() { - client.setBufferSize(512); - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_broker, 1883); - reconnect(); - client.setCallback(callback); - - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "text/plain", "Hi! I am "+host_name); - }); - - AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA - server.begin(); - Serial.println("HTTP server started"); - - if (publish_status_at_start){ - publish_current_status(); - } - - FastLED.addLeds(leds, MAX_LEDS); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(50); - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::White; - } - show(); - delay(200); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - - pinMode(BTN_1_GPIO, INPUT); - pinMode(BTN_2_GPIO, INPUT); - pinMode(DATA_PIN, OUTPUT); - - attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_changed, CHANGE); - attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_changed, CHANGE); - delay(500); -} - -void setup_wifi() { - WiFi.disconnect(true, true); - WiFi.mode(WIFI_STA); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() == WL_DISCONNECTED) { - delay(500); - } - - if (WiFi.status() != WL_CONNECTED) { - delay(10); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(SSID); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void btn_one_changed(){ - long cur_time = millis(); - if((cur_time - btn_one_last_pressed) > BTN_DEBOUNCE_DELAY){ - if (digitalRead(BTN_1_GPIO) == LOW){ - btn_one_last_pressed = cur_time; - btn_one_state = 1; - } else{ - btn_one_last_released = cur_time; - } - } else{ - if (digitalRead(BTN_1_GPIO) == HIGH){ - btn_one_last_released = cur_time; - } - } -} - -void btn_two_changed(){ - long cur_time = millis(); - if((cur_time - btn_two_last_pressed) > BTN_DEBOUNCE_DELAY){ - if (digitalRead(BTN_2_GPIO) == LOW){ - btn_two_last_pressed = cur_time; - btn_two_state = 1; - } else{ - btn_two_last_released = cur_time; - } - } else { - if (digitalRead(BTN_2_GPIO) == HIGH){ - btn_two_last_released = cur_time; - } - } -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { - Serial.println("connected"); - // Subscribe - Serial.print("Subscribing with topic_id: "); - Serial.println(topic_id); - client.subscribe((topic_id+"/get_status").c_str()); - client.subscribe((topic_id+"/config").c_str()); - client.subscribe((topic_id+"/output").c_str()); - client.subscribe((topic_id+"/pong/btn_delay").c_str()); - client.subscribe((topic_id+"/pong/init_delay").c_str()); - client.subscribe((topic_id+"/pong/min_delay").c_str()); - client.subscribe((topic_id+"/pong/dec_per_run").c_str()); - client.subscribe((topic_id+"/pong/num_leds").c_str()); - client.subscribe((topic_id+"/pong/max_wins").c_str()); - client.subscribe((topic_id+"/pong/result/delay/during").c_str()); - client.subscribe((topic_id+"/pong/result/delay/after").c_str()); - client.subscribe((topic_id+"/pong/result/color/r").c_str()); - client.subscribe((topic_id+"/pong/result/color/g").c_str()); - client.subscribe((topic_id+"/pong/result/color/b").c_str()); - client.subscribe((topic_id+"/pong/tolerance").c_str()); - client.subscribe((topic_id+"/pong/color/r").c_str()); - client.subscribe((topic_id+"/pong/color/g").c_str()); - client.subscribe((topic_id+"/pong/color/b").c_str()); - client.subscribe((topic_id+"/color/r").c_str()); - client.subscribe((topic_id+"/color/g").c_str()); - client.subscribe((topic_id+"/color/b").c_str()); - client.subscribe((topic_id+"/btn").c_str()); - client.subscribe((topic_id+"/disable_btns").c_str()); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void toggle_leds(int to_state){ - if (to_state != -1){ - if (to_state == 0){ - stripe_on = true; - } else { - stripe_on = false; - } - } - if (stripe_on == false){ - Serial.print("Switch the rgb on with color: "); - Serial.print(color_r); - Serial.print("/"); - Serial.print(color_g); - Serial.print("/"); - Serial.println(color_b); - for (int i = 0; i< NUM_LEDS; i++){ - leds[i].r = color_r; - leds[i].g = color_g; - leds[i].b = color_b; - } - stripe_on = true; - } else { - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - stripe_on = false; - } - - show(); - if (publish_status_if_toggled == 1){ - publish_current_status(); - } -} - -void reset_pong_vars(bool during, bool oneHitFirst){ - Serial.print("Resetting pong vars ("); - Serial.print(during); - Serial.print("/"); - Serial.print(oneHitFirst); - Serial.println(")"); - client.loop(); - player_one_miss = 0; - player_two_miss = 0; - btn_one_state = 0; - btn_two_state = 0; - player_successfull_one_press = 0; - player_successfull_two_press = 0; - cur_pong_delay = pong_init_delay; - - if (!during){ - player_one_wins = 0; - player_two_wins = 0; - btn_one_last_pressed = 0; - btn_two_last_pressed = 0; - stripe_mode = 0; - } - - if (oneHitFirst){ - cur_pixel = pong_start_led; - reverseMode = 0; - } else { - cur_pixel = num_pong_leds-1; - reverseMode = 1; - } -} - -void switch_to_pong_mode(bool oneHitFirst){ - Serial.println("Switching to pong mode"); - delay(500); - reset_pong_vars(false, oneHitFirst); - - stripe_mode = 1; - - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(1000); - for (int i = pong_start_led; i< num_pong_leds; i++){ - leds[i].r = pong_color_r; - leds[i].g = pong_color_g; - leds[i].b = pong_color_b; - } - show(); - delay(1000); - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(1000); -} - -void display_result(float cur_delay){ - Serial.println("Displaying results"); - delay(500); - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - - for (int i = pong_start_led; i < player_one_wins+pong_start_led; i++){ - leds[i].r = pong_result_color_r; - leds[i].g = pong_result_color_g; - leds[i].b = pong_result_color_b; - } - - for (int i = (num_pong_leds - 1); i > ((num_pong_leds-1)-player_two_wins); i--){ - leds[i].r = pong_result_color_r; - leds[i].g = pong_result_color_g; - leds[i].b = pong_result_color_b; - } - show(); - delay(cur_delay*1000); -} - -void changeBrightness(){ - if (brightness_decrease){ - //Serial.println("Decrease brightness"); - brightness = brightness - BRIGHTNESS_CHANGE_VALUE; - if (brightness <= 0){ - brightness = 0; - //Serial.println("Smallest value reached"); - brightness_decrease = !brightness_decrease; - } - } else { - //Serial.println("Increase brightness"); - brightness = brightness + BRIGHTNESS_CHANGE_VALUE; - if (brightness >= 255){ - brightness = 255; - //Serial.println("Max value reached"); - brightness_decrease = !brightness_decrease; - } - } - - show(); -} - -void loop() { - if (WiFi.status() != WL_CONNECTED) { - setup_wifi(); - } - - if (!client.connected()) { - reconnect(); - } - client.loop(); - - if (stripe_mode == 0){ - if ((btn_one_state == 1) or (btn_two_state == 1)){ - //Serial.println("btn one or two pressed"); - if (btn_two_state == 1){ - //Serial.println("btn_two_state == 1"); - //Serial.println(btn_two_last_released); - //Serial.println(btn_two_last_pressed); - if ((btn_two_last_released >= btn_two_last_pressed) or (!stripe_on)){ - //Serial.println("btn_two currently is not pressed"); - if (btn_two_long_state == 0){ - //Serial.println("btn_two had no long press"); - player_one_hit_first = true; - btn_two_state = 0; - //Serial.println("Button two pressed."); - if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ - Serial.println("Switching to pong mode."); - switch_to_pong_mode(player_one_hit_first); - } else { - Serial.println("Toggling led stripe."); - toggle_leds(-1); - } - } else { - //Serial.println("btn_two had long press"); - btn_two_long_state = 0; - btn_two_state = 0; - } - } else { - //button still pressed. Maybe a long press? - if ((millis() - btn_two_last_pressed) > BTN_LONG_PRESS_DELAY){ - //Serial.println("btn_two long press detected"); - btn_two_long_state = 1; - changeBrightness(); - publish_current_status(); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } else { - //Serial.println("btn_two still pressed"); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } - } - } - - if (btn_one_state == 1){ - //Serial.println("btn_one_state == 1"); - //Serial.println(btn_one_last_released); - //Serial.println(btn_one_last_pressed); - if ((btn_one_last_released >= btn_one_last_pressed) or (!stripe_on)){ - //Serial.println("btn_one currently is not pressed"); - if (btn_one_long_state == 0){ - //Serial.println("btn_one had no long press"); - player_one_hit_first = false; - btn_one_state = 0; - if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ - Serial.println("Switching to pong mode."); - switch_to_pong_mode(player_one_hit_first); - } else { - Serial.println("Button one pressed. Toggling led stripe."); - toggle_leds(-1); - } - } else { - //Serial.println("btn_one had long press"); - btn_one_long_state = 0; - btn_one_state = 0; - } - } else { - //button still pressed. Maybe a long press? - if ((millis() - btn_one_last_pressed) > BTN_LONG_PRESS_DELAY){ - //Serial.println("btn_one long press detected"); - btn_one_long_state = 1; - changeBrightness(); - publish_current_status(); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } else { - //Serial.println("btn_one still pressed"); - delay(BRIGHTNESS_CHANGE_INTERVAL); - } - } - } - } else { - if((millis() - last_refresh) > REFRESH_INTERVAL){ - show(); - } - } - } else if (stripe_mode == 1){ - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::Black; - } - - leds[cur_pixel].r = pong_color_r; - leds[cur_pixel].g = pong_color_g; - leds[cur_pixel].b = pong_color_b; - show(); - - delay(cur_pong_delay*1000); - - abortRun = 0; - player_one_miss = 0; - - if (player_successfull_one_press == 0){ - if(btn_one_state == 1){ - btn_one_state = 0; - if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= pong_start_led)){ - player_one_miss = 1; - } else { - player_successfull_one_press = 1; - } - } else if ((reverseMode == 1) && (cur_pixel == pong_start_led)){ - player_one_miss = 1; - } - } else { - btn_one_state = 0; - } - - if(player_one_miss == 1){ - abortRun = 1; - player_two_wins += 1; - if(player_two_wins >= pong_max_wins){ - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_after); - reset_pong_vars(false, player_one_hit_first); - if (publish_results_at_display == 1){ - publish_results(); - } - toggle_leds(0); - } else { - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_during); - cur_pixel = pong_start_led; - reverseMode = 0; - if (change_start_led_during_match){ - player_one_hit_first = !player_one_hit_first; - } - reset_pong_vars(true, player_one_hit_first); - } - } - - player_two_miss = 0; - - if (player_successfull_two_press == 0){ - if(btn_two_state == 1){ - btn_two_state = 0; - if ((reverseMode == 1) or ((cur_pixel + pong_tolerance) <= (num_pong_leds-1))){ - player_two_miss = 1; - } else { - player_successfull_two_press = 1; - } - } else if ((reverseMode == 0) && (cur_pixel == (num_pong_leds-1))){ - player_two_miss = 1; - } - } else { - btn_two_state = 0; - } - - if(player_two_miss == 1){ - abortRun = 1; - player_one_wins += 1; - if(player_one_wins >= pong_max_wins){ - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_after); - reset_pong_vars(false, player_one_hit_first); - if (publish_results_at_display == 1){ - publish_results(); - } - toggle_leds(0); - } else { - if (publish_results_at_display == 1){ - publish_results(); - } - display_result(pong_wins_delay_during); - if (change_start_led_during_match){ - player_one_hit_first = !player_one_hit_first; - } - reset_pong_vars(true, player_one_hit_first); - } - } - - - if (abortRun == 0){ - if (reverseMode == 1){ - cur_pixel -= 1; - if (cur_pixel < pong_start_led){ - reverseMode = 0; - player_successfull_one_press = 0; - cur_pixel = pong_start_led + 1; - cur_pong_delay = cur_pong_delay - pong_dec_per_run; - if (cur_pong_delay < pong_min_delay){ - cur_pong_delay = pong_min_delay; - } - } - } else { - cur_pixel += 1; - if (cur_pixel > (num_pong_leds-1)){ - player_successfull_two_press = 0; - cur_pixel = num_pong_leds-2; - reverseMode = 1; - cur_pong_delay = cur_pong_delay - pong_dec_per_run; - if (cur_pong_delay < pong_min_delay){ - cur_pong_delay = pong_min_delay; - } - } - } - } - } -} diff --git a/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore b/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore deleted file mode 100644 index 0e95883..0000000 --- a/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -settings.h -*.bin diff --git a/examples/ESP32WS2815MqttExternalInOTA/.gitignore b/examples/ESP32WS2815MqttExternalInOTA/.gitignore deleted file mode 100644 index 0e95883..0000000 --- a/examples/ESP32WS2815MqttExternalInOTA/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -settings.h -*.bin diff --git a/examples/ESP32WS2815MqttExternalInOTA/ESP32WS2815MqttExternalInOTA.ino b/examples/ESP32WS2815MqttExternalInOTA/ESP32WS2815MqttExternalInOTA.ino deleted file mode 100644 index 8805b33..0000000 --- a/examples/ESP32WS2815MqttExternalInOTA/ESP32WS2815MqttExternalInOTA.ino +++ /dev/null @@ -1,326 +0,0 @@ -//LED Strip: BTF-LIGHTING WS2801 -//Power Supply: HuaTec LED Trafo 15V -//Step-Down-Module -//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 -//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 -//1 x Resistor: 10 kOhm -//Arduino Version: 1.8.13 -//Board Firmware: ESP32 by Espressif Systems Version 2.0.1 -//Libs: -// FastLED by Daniel Garcia Version 3.5.0 -// PubSubClient by Nick O'Leary Version 2.8.0 -// ArduinoJson by Benoit Blanchon Version 6.19.2 -// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 -// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP -// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer -#include -#include -#include -#include -#include -#include -#include -#include "settings.h" - -AsyncWebServer server(80); - -CRGB leds[MAX_LEDS]; - -WiFiClient espClient; -PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; -int value = 0; - -long last_refresh = 0; - -int brightness = 255; -int color_r = 255; -int color_g = 255; -int color_b = 255; -boolean stripe_on = false; -boolean input_active = false; - -int publish_status_after_every_config_change = 1; -int publish_status_if_toggled = 1; -int publish_status_at_start = 1; - -void show(){ - //FastLED.setBrightness(brightness); - FastLED.show(); - //FastLED.show(); -} - -void toggle_leds(int to_state){ - if (to_state != -1){ - if (to_state == 0){ - stripe_on = true; - } else { - stripe_on = false; - } - } - if (stripe_on == false){ - Serial.print("Switch the rgb on with color: "); - Serial.print(color_r); - Serial.print("/"); - Serial.print(color_g); - Serial.print("/"); - Serial.println(color_b); - for (int i = 0; i< NUM_LEDS; i++){ - leds[i].r = color_r; - leds[i].g = color_g; - leds[i].b = color_b; - } - stripe_on = true; - } else { - for (int i = 0; i< MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - stripe_on = false; - } - - show(); - if (publish_status_if_toggled == 1){ - publish_current_status(); - } -} - -void publish_current_status(){ - Serial.println("Publishing current status"); - StaticJsonDocument<1024> doc; - if (client.connected()){ - doc["output"] = stripe_on; - doc["brightness"] = brightness; - doc["color_r"] = color_r; - doc["color_g"] = color_g; - doc["color_b"] = color_b; - - char buffer[1024]; - - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/status").c_str(), buffer, n); - } -} - -void fixConfigValues(){ - if (color_r > 255){ - color_r = 255; - } else if (color_r < 0){ - color_r = 0; - } - - if (color_g > 255){ - color_g = 255; - } else if (color_g < 0){ - color_g = 0; - } - - if (color_b > 255){ - color_b = 255; - } else if (color_b < 0){ - color_b = 0; - } - - if (brightness > 255){ - brightness = 255; - } else if (brightness < 0){ - brightness = 0; - } -} - -void callback(char* topic, byte* message, unsigned int length) { - Serial.print("Message arrived on topic: "); - Serial.print(topic); - Serial.print(". Message: "); - String messageTemp; - - for (int i = 0; i < length; i++) { - Serial.print((char)message[i]); - messageTemp += (char)message[i]; - } - Serial.println(); - - if (String(topic) == topic_id+"/config"){ - StaticJsonDocument<1024> doc; - DeserializationError err = deserializeJson(doc, messageTemp); - if (!err){ - color_r = doc["color_r"] | color_r; - color_g = doc["color_g"] | color_g; - color_b = doc["color_b"] | color_b; - - brightness = doc["brightness"] | brightness; - Serial.print("brightness: "); - Serial.println(brightness); - Serial.print("Doc brightness: "); - Serial.println(doc["brightness"].as()); - Serial.print("Doc color_r: "); - Serial.println(doc["color_r"].as()); - Serial.print("Doc color_g: "); - Serial.println(doc["color_g"].as()); - Serial.print("Doc color_b: "); - Serial.println(doc["color_b"].as()); - - } - } else if (String(topic) == topic_id+"/color/r"){ - color_r = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/g"){ - color_g = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/color/b"){ - color_b = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/brightness"){ - brightness = messageTemp.toInt(); - } else if (String(topic) == topic_id+"/get_status"){ - publish_current_status(); - } - - fixConfigValues(); - - if (String(topic) != topic_id+"/get_status") { - if (stripe_on){ - toggle_leds(1); - } else { - toggle_leds(0); - } - } - - if(publish_status_after_every_config_change){ - publish_current_status(); - } -} - -void setup() { - client.setBufferSize(512); - Serial.begin(115200); - setup_wifi(); - client.setServer(mqtt_broker, 1883); - reconnect(); - client.setCallback(callback); - - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "text/plain", "Hi! I am ESP32."); - }); - - AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA - server.begin(); - Serial.println("HTTP server started"); - - if (publish_status_at_start){ - publish_current_status(); - } - - FastLED.addLeds(leds, MAX_LEDS); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - delay(50); - for (int i=0; i < NUM_LEDS; i++){ - leds[i] = CRGB::White; - } - show(); - delay(200); - for (int i=0; i < MAX_LEDS; i++){ - leds[i] = CRGB::Black; - } - show(); - - pinMode(CLOCK_PIN, OUTPUT); - pinMode(DATA_PIN, OUTPUT); - - attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_changed, CHANGE); - delay(500); - input_changed(); -} - -void setup_wifi() { - WiFi.setHostname(host_name); - WiFi.disconnect(true, true); - WiFi.mode(WIFI_STA); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() == WL_DISCONNECTED) { - delay(500); - } - - if (WiFi.status() != WL_CONNECTED) { - delay(10); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(SSID); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); -} - -void input_changed(){ - if (digitalRead(INPUT_GPIO) == LOW){ - input_active = false; - } else { - input_active = true; - } -} - -void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { - Serial.print("Attempting MQTT connection..."); - // Attempt to connect - if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { - Serial.println("connected"); - // Subscribe - Serial.print("Subscribing with topic_id: "); - Serial.println(topic_id); - client.subscribe((topic_id+"/get_status").c_str()); - client.subscribe((topic_id+"/config").c_str()); - client.subscribe((topic_id+"/output").c_str()); - client.subscribe((topic_id+"/color/r").c_str()); - client.subscribe((topic_id+"/color/g").c_str()); - client.subscribe((topic_id+"/color/b").c_str()); - } else { - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); - } - } -} - -void loop() { - if (WiFi.status() != WL_CONNECTED) { - setup_wifi(); - } - - if (!client.connected()) { - reconnect(); - } - client.loop(); - - if (input_active != stripe_on){ - if (input_active){ - toggle_leds(1); - } else { - toggle_leds(0); - } - - last_refresh = millis(); - } else { - - if ((millis() - last_refresh) > REFRESH_INTERVAL){ - last_refresh = millis(); - show(); - } - } - delay(10); -} diff --git a/examples/ESP32WS2815MqttExternalInOTA/settings.example.h b/examples/ESP32WS2815MqttExternalInOTA/settings.example.h deleted file mode 100644 index ccfa6b9..0000000 --- a/examples/ESP32WS2815MqttExternalInOTA/settings.example.h +++ /dev/null @@ -1,16 +0,0 @@ -#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. -#define NUM_LEDS 300 -#define DATA_PIN 14 -#define INPUT_GPIO 16 -#define REFRESH_INTERVAL 10000 - -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; -const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; -const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; -const char* ota_user = "ENTER_OTA_USER_HERE"; -const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; -const char* host_name = "ESP_LED"; -const String client_name = "ESP_LED"; -const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripOTAWithPongAndMqtt/.gitignore b/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/.gitignore old mode 100644 new mode 100755 similarity index 100% rename from examples/ESP32LedStripOTAWithPongAndMqtt/.gitignore rename to examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/.gitignore diff --git a/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino b/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino new file mode 100755 index 0000000..9c88057 --- /dev/null +++ b/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/ESP32LedStripWithMqttAndExternalInputOTANeopixel.ino @@ -0,0 +1,418 @@ +//LED Strip: BTF-LIGHTING WS2801 +//Power Supply: HuaTec LED Trafo 12V +//Step-Down-Module +//Board: AZDelivery D1 mini ESP32 +//Logic Level Converter: ARCELI 4 Channel I2C Converter +//1 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 2.0.4 +//Libs: +// Adafruit_WS2801 by Adafruit Version 1.1.1 +// AsyncMqttClient: https://github.com/marvinroger/async-mqtt-client 0.9.0 +// ArduinoJson by Benoit Blanchon Version 6.19.4 +// AsyncElegantOTA by Ayusha Sharma Version 2.2.7 +// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP 1.1.1 +// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer 1.2.3 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "settings.h" + +uint8_t dataPin = DATA_PIN; +uint8_t clockPin = CLOCK_PIN; + +Preferences preferences; + +AsyncWebServer server(80); + +Adafruit_WS2801 pixels = Adafruit_WS2801(MAX_LEDS, dataPin, clockPin, WS2801_RGB); + +WiFiClient espClient; + +AsyncMqttClient mqttClient; +String payloadBuf; +Ticker mqttReconnectTimer; +Ticker wifiReconnectTimer; + +long lastMillis = 0; +long lastRefresh = 0; +long lastInputChange = 0; + +int color_r = 255; +int color_g = 150; +int color_b = 150; +boolean stripe_on = false; +boolean inputChanged = false; + +boolean publishStatusAfterEveryConfigChange = true; +boolean publishStatusIfToggled = true; +boolean publishStatusAtReconnect = true; + +// Create a 24 bit color value from R,G,B +uint32_t Color(byte r, byte g, byte b) +{ + uint32_t c; + c = r; + c <<= 8; + c |= g; + c <<= 8; + c |= b; + return c; +} + +void connectToWifi() { + Serial.println("Connecting to Wi-Fi..."); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +} + +void connectToMqtt() { + Serial.println("Connecting to MQTT..."); + mqttClient.connect(); +} + +void WiFiEvent(WiFiEvent_t event) { + Serial.printf("[WiFi-event] event: %d\n", event); + switch(event) { + case SYSTEM_EVENT_STA_GOT_IP: + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + connectToMqtt(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + Serial.println("WiFi lost connection"); + mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi + wifiReconnectTimer.once(2, connectToWifi); + break; + } +} + +void onMqttConnect(bool sessionPresent) { + Serial.println("Connected to MQTT."); + Serial.print("Session present: "); + Serial.println(sessionPresent); + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + mqttClient.subscribe((topic_id+"/get_status").c_str(), 0); + mqttClient.subscribe((topic_id+"/get_free_heap").c_str(), 0); + mqttClient.subscribe((topic_id+"/config").c_str(), 0); + mqttClient.subscribe((topic_id+"/output").c_str(), 0); + mqttClient.subscribe((topic_id+"/color_r").c_str(), 0); + mqttClient.subscribe((topic_id+"/color_g").c_str(), 0); + mqttClient.subscribe((topic_id+"/color_b").c_str(), 0); + Serial.println("All topics subscribed!"); + if (publishStatusAtReconnect){ + publishCurrentStatus(); + } +} + +void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { + Serial.println("Disconnected from MQTT."); + + if (reason == AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT) { + Serial.println("Bad server fingerprint."); + } + + if (WiFi.isConnected()) { + mqttReconnectTimer.once(2, connectToMqtt); + } +} + + +void show(){ + pixels.show(); +} + +void toggleLeds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + pixels.setPixelColor(i, Color(color_r,color_g,color_b)); + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, Color(0,0,0)); + } + stripe_on = false; + } + + show(); + if (publishStatusIfToggled == 1){ + publishCurrentStatus(); + } +} + +void publishCurrentStatus(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (mqttClient.connected()){ + doc["output"] = stripe_on; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + mqttClient.publish((topic_id+"/status").c_str(), 0, false, buffer); + } +} + +void fixConfigValues(){ + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } +} + +void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { + Serial.println("Publish received."); + Serial.print(" topic: "); + Serial.println(topic); + Serial.print(" qos: "); + Serial.println(properties.qos); + Serial.print(" dup: "); + Serial.println(properties.dup); + Serial.print(" retain: "); + Serial.println(properties.retain); + Serial.print(" len: "); + Serial.println(len); + Serial.print(" index: "); + Serial.println(index); + Serial.print(" total: "); + Serial.println(total); + + if (index == 0) { + payloadBuf = ""; + } + + auto pl = len; + auto p = payload; + while (pl--) { + payloadBuf += *(p++); + } + + + if (index + len == total) { + Serial.print(" message: "); + Serial.println(payloadBuf); + + if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, payloadBuf); + if (!err){ + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + } + } else if (String(topic) == topic_id+"/output") { + Serial.print("Changing output to "); + if(payloadBuf == "on"){ + Serial.println("on"); + toggleLeds(1); + } + else if(payloadBuf == "off"){ + Serial.println("off"); + toggleLeds(0); + } else { + Serial.println("toggle"); + toggleLeds(-1); + } + } else if (String(topic) == topic_id+"/color_r"){ + color_r = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/color_g"){ + color_g = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/color_b"){ + color_b = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publishCurrentStatus(); + } else if (String(topic) == topic_id+"/get_free_heap"){ + mqttClient.publish((topic_id+"/free_heap").c_str(), 1, false, String(ESP.getFreeHeap()).c_str()); + } + + fixConfigValues(); + savePrefs(); + + if (String(topic) != topic_id+"/get_status") { + if (stripe_on){ + toggleLeds(1); + } else { + toggleLeds(0); + } + } + + if((String(topic) != topic_id+"/get_free_heap") && (publishStatusAfterEveryConfigChange)){ + publishCurrentStatus(); + } + } + + +} + +void IRAM_ATTR inputLow(){ + long cur_time = millis(); + if ((cur_time-lastInputChange) > INPUT_DEBOUNCE){ + if (digitalRead(INPUT_GPIO) == LOW){ + lastInputChange = cur_time; + inputChanged = true; + } + } +} + +void loadPrefs(){ + preferences.begin(topic_id.c_str(), false); + color_r = preferences.getInt("color_r", 255); + color_g = preferences.getInt("color_g", 150); + color_b = preferences.getInt("color_b", 150); + preferences.end(); +} + +void savePrefs(){ + preferences.begin(topic_id.c_str(), false); + preferences.putInt("color_r", color_r); + preferences.putInt("color_g", color_g); + preferences.putInt("color_b", color_b); + preferences.end(); +} + +void setup() { + Serial.begin(115200); + loadPrefs(); + Serial.println(); + Serial.println(); + + mqttClient.setClientId(client_name.c_str()); + + Serial.println("Setup wifi events"); + + WiFi.onEvent(WiFiEvent); + + Serial.println("Setup mqtt events"); + mqttClient.onConnect(onMqttConnect); + mqttClient.onDisconnect(onMqttDisconnect); + mqttClient.onMessage(onMqttMessage); + mqttClient.setServer(MQTT_HOST, MQTT_PORT); + mqttClient.setCredentials(mqtt_user, mqtt_pass); + + Serial.print(" MQTT_HOST: "); + Serial.println(MQTT_HOST); + Serial.print(" MQTT_PORT: "); + Serial.println(MQTT_PORT); + Serial.print(" MQTT_SECURE: "); + Serial.println(MQTT_SECURE); + #if ASYNC_TCP_SSL_ENABLED + mqttClient.setSecure(MQTT_SECURE); + if (MQTT_SECURE) { + Serial.println("Using secure MQTT!"); + mqttClient.addServerFingerprint((const uint8_t[])MQTT_SERVER_FINGERPRINT); + } + #else + Serial.println("Using insecure MQTT cuase AsyncTCP does not support SSL!"); + #endif + + Serial.println("Connect to wifi"); + connectToWifi(); + + + Serial.println("Setup webserver"); + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hi! I am "+host_name); + }); + + Serial.println("Start webserver"); + AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA + server.begin(); + Serial.println("Webserver started"); + + delay(1000); + + Serial.println("Setup LEDs"); + pinMode(CLOCK_PIN, OUTPUT); + pinMode(DATA_PIN, OUTPUT); + + pixels.begin(); + pixels.clear(); + + Serial.println("Flash LEDs"); + for (int i=0; i < MAX_LEDS; i++){ + pixels.setPixelColor(i, Color(0, 0, 0)); + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + pixels.setPixelColor(i, Color(255, 255, 255)); + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + pixels.setPixelColor(i, Color(0, 0, 0)); + } + show(); + + Serial.println("Attach interrupt"); + + attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), inputLow, CHANGE); + delay(500); + + lastMillis = millis(); + + Serial.println("Setup finished"); +} + +void loop() { + if (inputChanged){ + inputChanged = false; + + toggleLeds(-1); + + lastRefresh = millis(); + } else { + + unsigned long currentMillis = millis(); + + if (currentMillis < lastMillis){ + lastMillis = currentMillis; + lastRefresh = 0; + lastInputChange = 0; + } + + if ((currentMillis - lastRefresh) > REFRESH_INTERVAL){ + lastRefresh = currentMillis; + show(); + } + } + delay(10); +} diff --git a/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/README.md b/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/README.md new file mode 100644 index 0000000..beb8d8e --- /dev/null +++ b/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/README.md @@ -0,0 +1,14 @@ +# ESP32LedStripWithMqttAndExternalInputOTANeopixel + +This example provides the following features: + +* Switch LED strip on/off or toggle it via MQTT or via a button connected to a GPIO +* Control the color of the strip via MQTT + +Used Hardware: + +* ESP32 based microcontroller (i.e. D1 mini ESP32) +* WS2801 LED strip +* I2C Level shifter +* Button +* 10kOhm resistor diff --git a/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h b/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h new file mode 100755 index 0000000..e96f915 --- /dev/null +++ b/examples/noPong/ESP32LedStripWithMqttAndExternalInputOTANeopixel/settings.example.h @@ -0,0 +1,29 @@ +#define MAX_LEDS 300 //All leds will be switched off. But only NUM_LEDS will be used. +#define NUM_LEDS 300 +#define DATA_PIN 14 +#define CLOCK_PIN 13 +#define INPUT_GPIO 16 +#define INPUT_DEBOUNCE 300 +#define REFRESH_INTERVAL 10000 + +const char* WIFI_SSID = "ENTER_WIFI_SSID_HERE"; +const char* WIFI_PASSWORD = "ENTER_WIFI_PASSWORD_HER"; + +#if ASYNC_TCP_SSL_ENABLED +#define MQTT_SECURE true +//FINGERPRINT=`openssl x509 -noout -fingerprint -sha1 -inform pem -in /path/to/cert/cert.pem | tr '[:upper:]' '[:lower:]' | sed 's/^[^=]\+=//g' | sed 's/:/, 0x/g'`; echo "#define MQTT_SERVER_FINGERPRINT {0x${FINGERPRINT}}" +#define MQTT_SERVER_FINGERPRINT {0x7e, 0x36, 0x22, 0x01, 0xf9, 0x7e, 0x99, 0x2f, 0xc5, 0xdb, 0x3d, 0xbe, 0xac, 0x48, 0x67, 0x5b, 0x5d, 0x47, 0x94, 0xd2} +#define MQTT_PORT 8883 +#else +#define MQTT_SECURE false +#define MQTT_PORT 1883 +#endif + +#define MQTT_HOST IPAddress(192, 1, 1, 2) +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* ota_user = "ENTER_OTA_USER_HERE"; +const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; +const String host_name = "ESP_LED"; +const String client_name = "ESP_LED"; +const String topic_id = "esp_led"; diff --git a/examples/ESP32LedStripWithMqttAndExternalInput/.gitignore b/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/.gitignore old mode 100644 new mode 100755 similarity index 100% rename from examples/ESP32LedStripWithMqttAndExternalInput/.gitignore rename to examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/.gitignore diff --git a/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/ESP8266FastLedWithMqttAndExternalInputOTAFastLED.ino b/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/ESP8266FastLedWithMqttAndExternalInputOTAFastLED.ino new file mode 100755 index 0000000..1870737 --- /dev/null +++ b/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/ESP8266FastLedWithMqttAndExternalInputOTAFastLED.ino @@ -0,0 +1,397 @@ +//LED Strip: BTF-LIGHTING WS2801 +//Board: AZDelivery D1 mini ESP8266 +//Logic Level Converter: ARCELI 4 Channel I2C Converter +//1 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 2.0.4 +//Libs: +// AsyncMqttClient: https://github.com/marvinroger/async-mqtt-client 0.9.0 +// ArduinoJson by Benoit Blanchon Version 6.19.4 +// AsyncElegantOTA by Ayusha Sharma Version 2.2.7 +// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP 1.1.1 +// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer 1.2.3 +#include +#include +#include +#include +#include +#include +#include +#include +#include "settings.h" +#include + +uint8_t dataPin = DATA_PIN; +uint8_t clockPin = CLOCK_PIN; + +Preferences preferences; + +CRGB leds[MAX_LEDS]; + +AsyncWebServer server(80); + +WiFiClient espClient; +WiFiEventHandler gotIpEventHandler, disconnectedEventHandler; + +AsyncMqttClient mqttClient; +String payloadBuf; +Ticker mqttReconnectTimer; +Ticker wifiReconnectTimer; + +long lastMillis = 0; +long lastRefresh = 0; +long lastInputChange = 0; + +int color_r = 255; +int color_g = 150; +int color_b = 150; +boolean stripe_on = false; +boolean inputChanged = false; + +boolean publishStatusAfterEveryConfigChange = true; +boolean publishStatusIfToggled = true; +boolean publishStatusAtReconnect = true; + +void connectToWifi() { + Serial.println("Connecting to Wi-Fi..."); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +} + +void connectToMqtt() { + Serial.println("Connecting to MQTT..."); + mqttClient.connect(); +} + +void onMqttConnect(bool sessionPresent) { + Serial.println("Connected to MQTT."); + Serial.print("Session present: "); + Serial.println(sessionPresent); + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + mqttClient.subscribe((topic_id+"/get_status").c_str(), 0); + mqttClient.subscribe((topic_id+"/get_free_heap").c_str(), 0); + mqttClient.subscribe((topic_id+"/config").c_str(), 0); + mqttClient.subscribe((topic_id+"/output").c_str(), 0); + mqttClient.subscribe((topic_id+"/color_r").c_str(), 0); + mqttClient.subscribe((topic_id+"/color_g").c_str(), 0); + mqttClient.subscribe((topic_id+"/color_b").c_str(), 0); + Serial.println("All topics subscribed!"); + if (publishStatusAtReconnect){ + publishCurrentStatus(); + } +} + +void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { + Serial.println("Disconnected from MQTT."); + + if (reason == AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT) { + Serial.println("Bad server fingerprint."); + } + + if (WiFi.isConnected()) { + mqttReconnectTimer.once(2, connectToMqtt); + } +} + +void show(){ + FastLED.show(); +} + +void toggleLeds(int to_state){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + if (stripe_on == false){ + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + leds[i].setRGB(color_r, color_g, color_b); + //leds[i].setRGB(255,255,255); + } + stripe_on = true; + } else { + for (int i=0; i < MAX_LEDS; i++){ + leds[i].setRGB(0,0,0); + } + stripe_on = false; + } + + show(); + if (publishStatusIfToggled == true){ + publishCurrentStatus(); + } +} + +void publishCurrentStatus(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (mqttClient.connected()){ + doc["output"] = stripe_on; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + + char buffer[1024]; + + size_t n = serializeJson(doc, buffer); + mqttClient.publish((topic_id+"/status").c_str(), 0, false, buffer); + } +} + +void fixConfigValues(){ + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } +} + +void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { + Serial.println("Publish received."); + Serial.print(" topic: "); + Serial.println(topic); + Serial.print(" qos: "); + Serial.println(properties.qos); + Serial.print(" dup: "); + Serial.println(properties.dup); + Serial.print(" retain: "); + Serial.println(properties.retain); + Serial.print(" len: "); + Serial.println(len); + Serial.print(" index: "); + Serial.println(index); + Serial.print(" total: "); + Serial.println(total); + + if (index == 0) { + payloadBuf = ""; + } + + auto pl = len; + auto p = payload; + while (pl--) { + payloadBuf += *(p++); + } + + + if (index + len == total) { + Serial.print(" message: "); + Serial.println(payloadBuf); + + if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<512> doc; + DeserializationError err = deserializeJson(doc, payloadBuf); + if (!err){ + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + } + } else if (String(topic) == topic_id+"/output") { + Serial.print("Changing output to "); + if(payloadBuf == "on"){ + Serial.println("on"); + toggleLeds(1); + } + else if(payloadBuf == "off"){ + Serial.println("off"); + toggleLeds(0); + } else { + Serial.println("toggle"); + toggleLeds(-1); + } + } else if (String(topic) == topic_id+"/color_r"){ + color_r = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/color_g"){ + color_g = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/color_b"){ + color_b = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publishCurrentStatus(); + } else if (String(topic) == topic_id+"/get_free_heap"){ + mqttClient.publish((topic_id+"/free_heap").c_str(), 1, false, String(ESP.getFreeHeap()).c_str()); + } + + fixConfigValues(); + savePrefs(); + + if (String(topic) != topic_id+"/get_status") { + if (stripe_on){ + toggleLeds(1); + } else { + toggleLeds(0); + } + } + + if((String(topic) != topic_id+"/get_free_heap") && (publishStatusAfterEveryConfigChange)){ + publishCurrentStatus(); + } + } +} + +void IRAM_ATTR inputLow(){ + long cur_time = millis(); + if ((cur_time-lastInputChange) > INPUT_DEBOUNCE){ + if (digitalRead(INPUT_GPIO) == LOW){ + lastInputChange = cur_time; + inputChanged = true; + } + } +} + +void loadPrefs(){ + preferences.begin(topic_id.c_str(), false); + color_r = preferences.getInt("color_r", 255); + color_g = preferences.getInt("color_g", 150); + color_b = preferences.getInt("color_b", 150); + preferences.end(); +} + +void savePrefs(){ + preferences.begin(topic_id.c_str(), false); + preferences.putInt("color_r", color_r); + preferences.putInt("color_g", color_g); + preferences.putInt("color_b", color_b); + preferences.end(); +} + +void setup() { + Serial.begin(115200); + loadPrefs(); + Serial.println(); + Serial.println(); + + mqttClient.setClientId(client_name.c_str()); + + Serial.println("Setup wifi events"); + + gotIpEventHandler = WiFi.onStationModeGotIP([](const WiFiEventStationModeGotIP& event) + { + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + connectToMqtt(); + }); + + disconnectedEventHandler = WiFi.onStationModeDisconnected([](const WiFiEventStationModeDisconnected& event) + { + Serial.println("WiFi lost connection"); + mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi + wifiReconnectTimer.once(2, connectToWifi); + }); + + + Serial.println("Setup mqtt events"); + mqttClient.onConnect(onMqttConnect); + mqttClient.onDisconnect(onMqttDisconnect); + mqttClient.onMessage(onMqttMessage); + mqttClient.setServer(MQTT_HOST, MQTT_PORT); + mqttClient.setCredentials(mqtt_user, mqtt_pass); + + Serial.print(" MQTT_HOST: "); + Serial.println(MQTT_HOST); + Serial.print(" MQTT_PORT: "); + Serial.println(MQTT_PORT); + Serial.print(" MQTT_SECURE: "); + Serial.println(MQTT_SECURE); + #if ASYNC_TCP_SSL_ENABLED + mqttClient.setSecure(MQTT_SECURE); + if (MQTT_SECURE) { + Serial.println("Using secure MQTT!"); + mqttClient.addServerFingerprint((const uint8_t[])MQTT_SERVER_FINGERPRINT); + } + #else + Serial.println("Using insecure MQTT cuase AsyncTCP does not support SSL!"); + #endif + + Serial.println("Connect to wifi"); + connectToWifi(); + + + Serial.println("Setup webserver"); + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hi! I am "+host_name); + }); + + Serial.println("Start webserver"); + AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA + server.begin(); + Serial.println("Webserver started"); + + delay(1000); + + Serial.println("Setup LEDs"); + pinMode(CLOCK_PIN, OUTPUT); + pinMode(DATA_PIN, OUTPUT); + + FastLED.addLeds(leds, MAX_LEDS); + + Serial.println("Flash LEDs"); + for (int i=0; i < MAX_LEDS; i++){ + leds[i].setRGB(0,0,0); + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + leds[i].setRGB(255,255,255); + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + leds[i].setRGB(0,0,0); + } + show(); + + Serial.println("Attach interrupt"); + + attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), inputLow, CHANGE); + delay(500); + + lastMillis = millis(); + + Serial.println("Setup finished"); +} + +void loop() { + if (inputChanged){ + inputChanged = false; + + toggleLeds(-1); + + lastRefresh = millis(); + } else { + + unsigned long currentMillis = millis(); + + if (currentMillis < lastMillis){ + lastMillis = currentMillis; + lastRefresh = 0; + lastInputChange = 0; + } + + if ((currentMillis - lastRefresh) > REFRESH_INTERVAL){ + lastRefresh = currentMillis; + show(); + } + } + delay(10); +} diff --git a/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/README.md b/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/README.md new file mode 100644 index 0000000..91ab903 --- /dev/null +++ b/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/README.md @@ -0,0 +1,14 @@ +# ESP8266FastLedWithMqttAndExternalInputOTAFastLED + +This example provides the following features: + +* Switch LED strip on/off or toggle it via MQTT or via a button connected to a GPIO +* Control the color of the strip via MQTT + +Used Hardware: + +* ESP8266 based microcontroller (i.e. D1 mini ESP8266) +* WS2801 LED strip +* I2C Level shifter +* Button +* 10kOhm resistor diff --git a/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/settings.example.h b/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/settings.example.h new file mode 100755 index 0000000..b5bdc6c --- /dev/null +++ b/examples/noPong/ESP8266FastLedWithMqttAndExternalInputOTAFastLED/settings.example.h @@ -0,0 +1,29 @@ +#define MAX_LEDS 20 +#define NUM_LEDS 20 +#define DATA_PIN 4 +#define CLOCK_PIN 5 +#define INPUT_GPIO 14 +#define INPUT_DEBOUNCE 300 +#define REFRESH_INTERVAL 10000 + +const char* WIFI_SSID = "ENTER_WIFI_SSID_HERE"; +const char* WIFI_PASSWORD = "ENTER_WIFI_PASSWORD_HER"; + +#if ASYNC_TCP_SSL_ENABLED +#define MQTT_SECURE true +//FINGERPRINT=`openssl x509 -noout -fingerprint -sha1 -inform pem -in /path/to/cert/cert.pem | tr '[:upper:]' '[:lower:]' | sed 's/^[^=]\+=//g' | sed 's/:/, 0x/g'`; echo "#define MQTT_SERVER_FINGERPRINT {0x${FINGERPRINT}}" +#define MQTT_SERVER_FINGERPRINT {0x7e, 0x36, 0x22, 0x01, 0xf9, 0x7e, 0x99, 0x2f, 0xc5, 0xdb, 0x3d, 0xbe, 0xac, 0x48, 0x67, 0x5b, 0x5d, 0x47, 0x94, 0xd2} +#define MQTT_PORT 8883 +#else +#define MQTT_SECURE false +#define MQTT_PORT 1883 +#endif + +#define MQTT_HOST IPAddress(192, 1, 1, 2) +const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; +const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; +const char* ota_user = "ENTER_OTA_USER_HERE"; +const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; +const String host_name = "ESP_LED"; +const String client_name = "ESP_LED"; +const String topic_id = "esp_led"; diff --git a/examples/noPong/README.md b/examples/noPong/README.md new file mode 100644 index 0000000..b03035b --- /dev/null +++ b/examples/noPong/README.md @@ -0,0 +1,3 @@ +# noPong + +All examples in this dirctory provide color setting via mqtt but do not implement the pong game. diff --git a/examples/MQTTButtonOnEsp8266/.gitignore b/examples/util/MQTTButtonOnEsp8266/.gitignore similarity index 100% rename from examples/MQTTButtonOnEsp8266/.gitignore rename to examples/util/MQTTButtonOnEsp8266/.gitignore diff --git a/examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino b/examples/util/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino similarity index 100% rename from examples/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino rename to examples/util/MQTTButtonOnEsp8266/MQTTButtonOnEsp8266.ino diff --git a/examples/util/MQTTButtonOnEsp8266/README.md b/examples/util/MQTTButtonOnEsp8266/README.md new file mode 100644 index 0000000..2806d5f --- /dev/null +++ b/examples/util/MQTTButtonOnEsp8266/README.md @@ -0,0 +1,12 @@ +# MQTTButtonOnEsp8266 + +This example provides the following features: + +* Send on/off to a configurable MQTT topic if a connected button is pressed +* Display the pong results on the LCD display + +Used Hardware: + +* Heltec Wifi Kit 8 +* Button +* 10kOhm resistor diff --git a/examples/MQTTButtonOnEsp8266/settings.example.h b/examples/util/MQTTButtonOnEsp8266/settings.example.h similarity index 100% rename from examples/MQTTButtonOnEsp8266/settings.example.h rename to examples/util/MQTTButtonOnEsp8266/settings.example.h diff --git a/examples/MQTTButtonOnEsp8266DeepSleep/.gitignore b/examples/util/MQTTButtonOnEsp8266DeepSleep/.gitignore similarity index 100% rename from examples/MQTTButtonOnEsp8266DeepSleep/.gitignore rename to examples/util/MQTTButtonOnEsp8266DeepSleep/.gitignore diff --git a/examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino b/examples/util/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino similarity index 100% rename from examples/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino rename to examples/util/MQTTButtonOnEsp8266DeepSleep/MQTTButtonOnEsp8266DeepSleep.ino diff --git a/examples/util/MQTTButtonOnEsp8266DeepSleep/README.md b/examples/util/MQTTButtonOnEsp8266DeepSleep/README.md new file mode 100644 index 0000000..d447950 --- /dev/null +++ b/examples/util/MQTTButtonOnEsp8266DeepSleep/README.md @@ -0,0 +1,13 @@ +# MQTTButtonOnEsp8266DeepSleep + +This example provides the following features: + +* Send on/off to a configurable MQTT topic if a connected button is pressed +* Display the pong results on the LCD display +* Set the controller to deep sleep mode is no action is trigger within a configurable time range. RST button needs to be pressed to reconnect/redisplay values + +Used Hardware: + +* Heltec Wifi Kit 8 +* Button +* 10kOhm resistor diff --git a/examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h b/examples/util/MQTTButtonOnEsp8266DeepSleep/settings.example.h similarity index 100% rename from examples/MQTTButtonOnEsp8266DeepSleep/settings.example.h rename to examples/util/MQTTButtonOnEsp8266DeepSleep/settings.example.h diff --git a/examples/util/README.md b/examples/util/README.md new file mode 100644 index 0000000..3ab010a --- /dev/null +++ b/examples/util/README.md @@ -0,0 +1,3 @@ +# util + +All examples in this directory provide util implementations like sending on/off via MQTT (i.e. with a battery powered second micro controller). diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTA/.gitignore b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore old mode 100644 new mode 100755 similarity index 100% rename from examples/ESP32LedStripWithMqttAndExternalInputOTA/.gitignore rename to examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/.gitignore diff --git a/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino old mode 100644 new mode 100755 similarity index 96% rename from examples/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino rename to examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino index 761a8c7..a0907e5 --- a/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino +++ b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/ESP32LedStripWithPongAndMqttOTANeoPixel.ino @@ -10,7 +10,7 @@ //Board Firmware: ESP32 by Espressif Systems Version 1.0.6 //Libs: // Adafruit_Neopixel by Adafruit 1.10.4 -// PubSubClient by Nick O'Leary Version 2.8.0 +// AsyncMqttClient: https://github.com/marvinroger/async-mqtt-client // ArduinoJson by Benoit Blanchon Version 6.19.3 // AsyncElegantOTA by Ayusha Sharma Version 2.2.6 // AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP @@ -89,6 +89,9 @@ int publish_status_if_toggled = 1; int publish_status_at_start = 1; int publish_results_at_display = 1; +long lastMqttReconnect = 0; +long lastWifiReconnect = 0; + void publish_current_status(){ Serial.println("Publishing current status"); @@ -129,11 +132,11 @@ void publish_results(){ if (client.connected()){ doc["result_player_one"] = player_one_wins; doc["result_player_two"] = player_two_wins; - } - char buffer[100]; + char buffer[100]; - size_t n = serializeJson(doc, buffer); - client.publish((topic_id+"/results").c_str(), buffer, n); + size_t n = serializeJson(doc, buffer); + client.publish((topic_id+"/results").c_str(), buffer, n); + } } void fixConfigValues(){ @@ -255,11 +258,10 @@ void callback(char* topic, byte* message, unsigned int length) { // Changes the output state according to the message if (String(topic) == topic_id+"/output") { Serial.print("Changing output to "); - if(messageTemp == "on"){ + if(String(messageTemp) == "on"){ Serial.println("on"); toggle_leds(1); - } - else if(messageTemp == "off"){ + } else if(String(messageTemp) == "off"){ Serial.println("off"); toggle_leds(0); } else { @@ -428,10 +430,9 @@ void show(){ void setup() { client.setBufferSize(512); + client.setServer(mqtt_broker, 1883); Serial.begin(115200); setup_wifi(); - client.setServer(mqtt_broker, 1883); - reconnect(); client.setCallback(callback); server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { @@ -442,9 +443,7 @@ void setup() { server.begin(); Serial.println("HTTP server started"); - if (publish_status_at_start){ - publish_current_status(); - } + delay(1000); pinMode(DATA_PIN, OUTPUT); @@ -475,33 +474,22 @@ void setup() { } void setup_wifi() { + lastWifiReconnect = millis(); + WiFi.setHostname(host_name.c_str()); WiFi.disconnect(true, true); + delay(100); WiFi.mode(WIFI_STA); - + delay(50); WiFi.begin(SSID, PSK); + delay(1000); - while (WiFi.status() == WL_DISCONNECTED) { - delay(500); - } - - if (WiFi.status() != WL_CONNECTED) { - delay(10); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(SSID); - - WiFi.begin(SSID, PSK); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } + if (WiFi.status() == WL_CONNECTED) { + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + reconnect(); } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); } void btn_one_changed(){ @@ -535,10 +523,10 @@ void btn_two_changed(){ } } } - + void reconnect() { - // Loop until we're reconnected - while (!client.connected()) { + if (!client.connected()) { + lastMqttReconnect = millis(); Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect(client_name.c_str(), mqtt_user, mqtt_pass)) { @@ -569,12 +557,13 @@ void reconnect() { client.subscribe((topic_id+"/color/b").c_str()); client.subscribe((topic_id+"/btn").c_str()); client.subscribe((topic_id+"/disable_btns").c_str()); + + if (publish_status_at_start){ + publish_current_status(); + } } else { Serial.print("failed, rc="); Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); } } } @@ -708,14 +697,20 @@ void changeBrightness(){ } void loop() { - if (WiFi.status() != WL_CONNECTED) { - setup_wifi(); - } - - if (!client.connected()) { - reconnect(); + unsigned long curTime = millis(); + if (WiFi.status() != WL_CONNECTED){ + if ((curTime - lastWifiReconnect) > WIFI_RECONNECT_INTERVAL){ + setup_wifi(); + } + } else { + if (client.connected()) { + client.loop(); + } else { + if ((curTime - lastMqttReconnect) > MQTT_RECONNECT_INTERVAL) { + reconnect(); + } + } } - client.loop(); if (stripe_mode == 0){ if ((btn_one_state == 1) or (btn_two_state == 1)){ diff --git a/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/README.md b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/README.md new file mode 100644 index 0000000..b05bb8c --- /dev/null +++ b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/README.md @@ -0,0 +1,18 @@ +# ESP32LedStripWithPongAndMqttOTANeoPixel + +This example provides the following features: + +* Switch LED strip on/off or toggle it via MQTT +* Control the color of the strip via MQTT +* Play pong by pressing the two connected buttons after each other in a specific amount of time +* Control all pong game parameters (color, initial speed, speed increase amount per return, etc. ) via MQTT +* Display the game result at the end of each game/match as lighted LEDs at the ends of the strip +* Send the game/match result via MQTT + +Used Hardware: + +* ESP32 based microcontroller (i.e. ESP32 Dev Kit) +* WS2801 LED strip +* I2C Level shifter +* Buttons +* 10kOhm resistors diff --git a/examples/ESP32LedStripWithPongAndMqttOTA/settings.example.h b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h old mode 100644 new mode 100755 similarity index 93% rename from examples/ESP32LedStripWithPongAndMqttOTA/settings.example.h rename to examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h index 27e5633..337ab74 --- a/examples/ESP32LedStripWithPongAndMqttOTA/settings.example.h +++ b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h @@ -19,6 +19,9 @@ #define PONG_RESULT_DELAY_AFTER 5.0 #define REFRESH_INTERVAL 10000 +#define WIFI_RECONNECT_INTERVAL 30000 +#define MQTT_RECONNECT_INTERVAL 30000 + const char* SSID = "ENTER_WIFI_SSID_HERE"; const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; diff --git a/examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/.gitignore b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/.gitignore old mode 100644 new mode 100755 similarity index 100% rename from examples/ESP32LedStripWithMqttAndExternalInputOTANeopixel/.gitignore rename to examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/.gitignore diff --git a/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput.ino b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput.ino new file mode 100755 index 0000000..e4d5434 --- /dev/null +++ b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput.ino @@ -0,0 +1,1055 @@ +//LED Strip: BTF-LIGHTING WS2815 -> https://www.amazon.de/gp/product/B07LG5ZT9C/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1 +//Power Supply: HuaTec LED Trafo 12V 120W -> https://www.amazon.de/gp/product/B0829817YM/ref=ppx_yo_dt_b_asin_image_o09_s00?ie=UTF8&psc=1 +//Step-Down-Module: AZDelivery XL4015 -> https://www.amazon.de/gp/product/B07SRXR1VT/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1 +//Board: AZDelivery ESP32 Dev Kit C V4 -> https://www.amazon.de/gp/product/B08BTS62L7/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1 +//Logic Level Converter: ARCELI 4 Channel I2C Converter -> https://www.amazon.de/gp/product/B07RDHR315/ref=ppx_yo_dt_b_search_asin_image?ie=UTF8&psc=1 +//2 x Tactile Push Button (Something like https://www.amazon.de/gp/product/B078ZDK6KZ/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) +//2 x Capacitor 0.1 Mikrofarad +//2 x Resistor: 10 kOhm +//Arduino Version: 1.8.13 +//Board Firmware: ESP32 by Espressif Systems Version 1.0.6 +//Libs: +// Adafruit_Neopixel by Adafruit 1.10.4 +// AsyncMqttClient: https://github.com/marvinroger/async-mqtt-client +// ArduinoJson by Benoit Blanchon Version 6.19.3 +// AsyncElegantOTA by Ayusha Sharma Version 2.2.6 +// AsyncTCP by me-no-dev: https://github.com/me-no-dev/AsyncTCP +// ESPAsyncWebserver by me-no-dev: https://github.com/me-no-dev/ESPAsyncWebServer +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "settings.h" + +Preferences preferences; + +AsyncWebServer server(80); + +Adafruit_NeoPixel pixels(MAX_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800); + +WiFiClient espClient; + +AsyncMqttClient mqttClient; +String payloadBuf; +Ticker mqttReconnectTimer; +Ticker wifiReconnectTimer; + +long last_refresh = 0; +long lastMillis = 0; + +int reverseMode=0; +int cur_pixel=0; +bool btn_one_changed = false; +long btn_one_last_pressed = 0; +bool btn_two_changed = false; +long btn_two_last_pressed = 0; +bool enable_hardware_btns = true; + +bool input_changed = false; +bool input_active = false; + + +int brightness = 255; +int brightness_decrease = true; +int color_r = 255; +int color_g = 255; +int color_b = 255; +int stripe_mode = 0; +boolean stripe_on = false; + +float pong_init_delay = PONG_INIT_LED_DELAY; +float cur_pong_delay = pong_init_delay; +int num_pong_leds = NUM_PONG_LEDS; +int pong_start_led = PONG_START_LED; +int pong_max_wins = PONG_MAX_WINS; +float pong_wins_delay_during = PONG_RESULT_DELAY_DURING; +float pong_wins_delay_after = PONG_RESULT_DELAY_AFTER; +float pong_min_delay = PONG_MIN_LED_DELAY; +float pong_dec_per_run = PONG_DEC_PER_RUN; +float pong_btn_delay = PONG_BTN_DELAY; +int pong_tolerance = PONG_TOLERANCE; +int pong_color_r = 0; +int pong_color_g = 0; +int pong_color_b = 255; +int pong_result_color_r = 0; +int pong_result_color_g = 255; +int pong_result_color_b = 0; +int player_one_wins = 0; +int player_successfull_one_press = 0; +int player_two_wins = 0; +int player_successfull_two_press = 0; +int player_one_miss = 0; +int player_two_miss = 0; +int abortRun = 0; +bool player_one_hit_first = true; +bool change_start_led_during_match = true; + +bool publish_status_after_every_config_change = true; +bool publish_status_if_toggled = true; +bool publish_status_at_reconnect = true; +bool publish_results_at_display = true; + + +void connectToWifi() { + Serial.println("Connecting to Wi-Fi..."); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +} + +void connectToMqtt() { + Serial.println("Connecting to MQTT..."); + mqttClient.connect(); +} + +void WiFiEvent(WiFiEvent_t event) { + Serial.printf("[WiFi-event] event: %d\n", event); + switch(event) { + case SYSTEM_EVENT_STA_GOT_IP: + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + connectToMqtt(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + Serial.println("WiFi lost connection"); + mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi + wifiReconnectTimer.once(2, connectToWifi); + break; + } +} + +void onMqttConnect(bool sessionPresent) { + Serial.println("Connected to MQTT."); + Serial.print("Session present: "); + Serial.println(sessionPresent); + Serial.print("Subscribing with topic_id: "); + Serial.println(topic_id); + mqttClient.subscribe((topic_id+"/get_status").c_str(), 0); + mqttClient.subscribe((topic_id+"/config").c_str(), 0); + mqttClient.subscribe((topic_id+"/output").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/btn_delay").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/init_delay").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/min_delay").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/dec_per_run").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/num_leds").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/max_wins").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/result/delay/during").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/result/delay/after").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/result/color/r").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/result/color/g").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/result/color/b").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/tolerance").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/color/r").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/color/g").c_str(), 0); + mqttClient.subscribe((topic_id+"/pong/color/b").c_str(), 0); + mqttClient.subscribe((topic_id+"/color/r").c_str(), 0); + mqttClient.subscribe((topic_id+"/color/g").c_str(), 0); + mqttClient.subscribe((topic_id+"/color/b").c_str(), 0); + mqttClient.subscribe((topic_id+"/btn").c_str(), 0); + mqttClient.subscribe((topic_id+"/disable_btns").c_str(), 0); + + Serial.println("All topics subscribed!"); + if (publish_status_at_reconnect){ + publish_current_status(); + } +} + +void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { + Serial.println("Disconnected from MQTT."); + + if (reason == AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT) { + Serial.println("Bad server fingerprint."); + } + + if (WiFi.isConnected()) { + mqttReconnectTimer.once(2, connectToMqtt); + } +} + +void input_trigger(){ + input_changed = true; +} + +void btn_one_trigger(){ + long cur_time = millis(); + if((cur_time - btn_one_last_pressed) > BTN_DEBOUNCE_DELAY){ + if (digitalRead(BTN_1_GPIO) == LOW){ + btn_one_last_pressed = cur_time; + btn_one_changed = true; + } + } +} + +void btn_two_trigger(){ + long cur_time = millis(); + if((cur_time - btn_two_last_pressed) > BTN_DEBOUNCE_DELAY){ + if (digitalRead(BTN_2_GPIO) == LOW){ + btn_two_last_pressed = cur_time; + btn_two_changed = true; + } + } +} + +void show(){ + pixels.setBrightness(brightness); + pixels.show(); +} + +void toggle_leds(int to_state, boolean power_off){ + if (to_state != -1){ + if (to_state == 0){ + stripe_on = true; + } else { + stripe_on = false; + } + } + + if (stripe_on == false){ + if (!input_active){ + setKNXInput(true); + delay(250); + } + Serial.print("Switch the rgb on with color: "); + Serial.print(color_r); + Serial.print("/"); + Serial.print(color_g); + Serial.print("/"); + Serial.println(color_b); + for (int i = 0; i< NUM_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(color_r,color_g,color_b)); + } + stripe_on = true; + } else { + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + if (power_off){ + setKNXInput(false); + delay(250); + } + stripe_on = false; + } + + if(input_active){ + show(); + delay(100); + show(); + } + if (publish_status_if_toggled){ + publish_current_status(); + } + delay(500); +} + +void publish_current_status(){ + Serial.println("Publishing current status"); + StaticJsonDocument<1024> doc; + if (mqttClient.connected()){ + doc["pong"]["btn_delay"] = pong_btn_delay; + doc["pong"]["init_delay"] = pong_init_delay; + doc["pong"]["min_delay"] = pong_min_delay; + doc["pong"]["dec_per_run"] = pong_dec_per_run; + doc["pong"]["num_leds"] = num_pong_leds; + doc["pong"]["max_wins"] = pong_max_wins; + doc["pong"]["tolerance"] = pong_tolerance; + doc["pong"]["result_delay_during"] = pong_wins_delay_during; + doc["pong"]["result_delay_after"] = pong_wins_delay_after; + doc["pong"]["color_r"] = pong_color_r; + doc["pong"]["color_g"] = pong_color_g; + doc["pong"]["color_b"] = pong_color_b; + doc["pong"]["result_color_r"] = pong_result_color_r; + doc["pong"]["result_color_g"] = pong_result_color_g; + doc["pong"]["result_color_b"] = pong_result_color_b; + doc["output"] = stripe_on; + doc["mode"] = stripe_mode; + doc["brightness"] = brightness; + doc["color_r"] = color_r; + doc["color_g"] = color_g; + doc["color_b"] = color_b; + doc["hardware_buttons_enabled"] = enable_hardware_btns; + + char buffer[1024]; + size_t n = serializeJson(doc, buffer); + mqttClient.publish((topic_id+"/status").c_str(), 0, false, buffer); + } +} + +void publish_results(){ + StaticJsonDocument<100> doc; + if (mqttClient.connected()){ + doc["result_player_one"] = player_one_wins; + doc["result_player_two"] = player_two_wins; + char buffer[100]; + size_t n = serializeJson(doc, buffer); + mqttClient.publish((topic_id+"/results").c_str(), 0, false, buffer); + } +} + +void setKNXInput(bool newState){ + mqttClient.publish((knx_topic).c_str(), 0, false, String(newState).c_str()); +} + +void fixConfigValues(){ + if (pong_btn_delay < 0){ + pong_btn_delay = 0; + } + + if (pong_init_delay < pong_min_delay){ + pong_init_delay = pong_min_delay; + } + + if (pong_min_delay < 0){ + pong_min_delay = 0; + } + + if (pong_dec_per_run < 0){ + pong_dec_per_run = 0; + } + + if (num_pong_leds > NUM_LEDS){ + num_pong_leds = NUM_LEDS; + } + + if (pong_max_wins > num_pong_leds){ + pong_max_wins = num_pong_leds; + } + + if (pong_wins_delay_during < 0){ + pong_wins_delay_during = 0; + } + + if (pong_wins_delay_after < 0){ + pong_wins_delay_after = 0; + } + + if (pong_result_color_r > 255){ + pong_result_color_r = 255; + } else if (pong_result_color_r < 0){ + pong_result_color_r = 0; + } + + if (pong_result_color_g > 255){ + pong_result_color_g = 255; + } else if (pong_result_color_g < 0){ + pong_result_color_g = 0; + } + + if (pong_result_color_b > 255){ + pong_result_color_b = 255; + } else if (pong_result_color_b < 0){ + pong_result_color_b = 0; + } + + if (pong_tolerance < 0){ + pong_tolerance = 0; + } + + if (pong_tolerance > (num_pong_leds -1)){ + pong_tolerance = num_pong_leds -1; + } + + if (pong_color_r > 255){ + pong_color_r = 255; + } else if (pong_color_r < 0){ + pong_color_r = 0; + } + + if (pong_color_g > 255){ + pong_color_g = 255; + } else if (pong_color_g < 0){ + pong_color_g = 0; + } + + if (pong_color_b > 255){ + pong_color_b = 255; + } else if (pong_color_b < 0){ + pong_color_b = 0; + } + + if (color_r > 255){ + color_r = 255; + } else if (color_r < 0){ + color_r = 0; + } + + if (color_g > 255){ + color_g = 255; + } else if (color_g < 0){ + color_g = 0; + } + + if (color_b > 255){ + color_b = 255; + } else if (color_b < 0){ + color_b = 0; + } + + if (brightness > 255){ + brightness = 255; + } else if (brightness < 0){ + brightness = 0; + } +} + +void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { + Serial.println("Publish received."); + Serial.print(" topic: "); + Serial.println(topic); + Serial.print(" qos: "); + Serial.println(properties.qos); + Serial.print(" dup: "); + Serial.println(properties.dup); + Serial.print(" retain: "); + Serial.println(properties.retain); + Serial.print(" len: "); + Serial.println(len); + Serial.print(" index: "); + Serial.println(index); + Serial.print(" total: "); + Serial.println(total); + + if (index == 0) { + payloadBuf = ""; + } + + auto pl = len; + auto p = payload; + while (pl--) { + payloadBuf += *(p++); + } + + + if (index + len == total) { + Serial.print(" message: "); + Serial.println(payloadBuf); + + if (! (String(topic) == topic_id+"/btn") ) { + // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". + // Changes the output state according to the message + if (String(topic) == topic_id+"/output") { + Serial.print("Changing output to "); + if(payloadBuf == "on"){ + Serial.println("on"); + toggle_leds(1, true); + } else if(payloadBuf == "off"){ + Serial.println("off"); + toggle_leds(0, true); + } else { + Serial.println("toggle"); + toggle_leds(-1, true); + } + } else if (String(topic) == topic_id+"/config"){ + StaticJsonDocument<1024> doc; + DeserializationError err = deserializeJson(doc, payloadBuf); + if (!err){ + + if(doc["pong"]["btn_delay"]){ + pong_btn_delay = doc["pong"]["btn_delay"].as(); + } + + if(doc["pong"]["init_delay"]){ + pong_init_delay = doc["pong"]["init_delay"].as(); + } + + if(doc["pong"]["min_delay"]){ + pong_min_delay = doc["pong"]["min_delay"].as(); + } + + if(doc["pong"]["dec_per_run"]){ + pong_dec_per_run = doc["pong"]["dec_per_run"].as(); + } + + num_pong_leds = doc["pong"]["num_leds"] | num_pong_leds; + pong_max_wins = doc["pong"]["max_wins"] | pong_max_wins; + pong_tolerance = doc["pong"]["tolerance"] | pong_tolerance; + + if(doc["pong"]["result_delay_during"]){ + pong_wins_delay_during = doc["pong"]["result_delay_during"].as(); + } + + if(doc["pong"]["result_delay_after"]){ + pong_wins_delay_after = doc["pong"]["result_delay_after"].as(); + } + + pong_color_r = doc["pong"]["color_r"] | pong_color_r; + pong_color_g = doc["pong"]["color_g"] | pong_color_g; + pong_color_b = doc["pong"]["color_b"] | pong_color_b; + + pong_result_color_r = doc["pong"]["result_color_r"] | pong_result_color_r; + pong_result_color_g = doc["pong"]["result_color_g"] | pong_result_color_g; + pong_result_color_b = doc["pong"]["result_color_b"] | pong_result_color_b; + + color_r = doc["color_r"] | color_r; + color_g = doc["color_g"] | color_g; + color_b = doc["color_b"] | color_b; + + brightness = doc["brightness"] | brightness; + + if (doc.containsKey("hardware_buttons_enabled")){ + if (!doc["hardware_buttons_enabled"]){ + if (enable_hardware_btns){ + enable_hardware_btns = false; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (!enable_hardware_btns){ + enable_hardware_btns = true; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_trigger, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_trigger, CHANGE); + Serial.println("Enable Hardware Buttons"); + } + } + } + + } + + } else if (String(topic) == topic_id+"/pong/btn_delay"){ + pong_btn_delay = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/pong/init_delay"){ + pong_init_delay = payloadBuf.toFloat(); + } else if (String(topic) == topic_id+"/pong/min_delay"){ + pong_min_delay = payloadBuf.toFloat(); + } else if (String(topic) == topic_id+"/pong/dec_per_run"){ + pong_dec_per_run = payloadBuf.toFloat(); + } else if (String(topic) == topic_id+"/pong/num_leds"){ + num_pong_leds = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/pong/max_wins"){ + pong_max_wins = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/pong/result/delay/during"){ + pong_wins_delay_during = payloadBuf.toFloat(); + } else if (String(topic) == topic_id+"/pong/result/delay/after"){ + pong_wins_delay_after = payloadBuf.toFloat(); + } else if (String(topic) == topic_id+"/pong/result/color/r"){ + pong_result_color_r = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/pong/result/color/g"){ + pong_result_color_g = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/pong/result/color/b"){ + pong_result_color_b = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/pong/tolerance"){ + pong_tolerance = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/pong/color/r"){ + pong_color_r = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/pong/color/g"){ + pong_color_g = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/pong/color/b"){ + pong_color_b = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/color/r"){ + color_r = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/color/g"){ + color_g = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/color/b"){ + color_b = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/brightness"){ + brightness = payloadBuf.toInt(); + } else if (String(topic) == topic_id+"/get_status"){ + publish_current_status(); + } else if (String(topic) == topic_id+"/hardware_buttons_enabled"){ + if (payloadBuf.toInt() == 1){ + if (enable_hardware_btns){ + enable_hardware_btns = false; + detachInterrupt(digitalPinToInterrupt(BTN_1_GPIO)); + detachInterrupt(digitalPinToInterrupt(BTN_2_GPIO)); + Serial.println("Disable Hardware Buttons"); + } + } else { + if (!enable_hardware_btns){ + enable_hardware_btns = true; + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_trigger, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_trigger, CHANGE); + Serial.println("Enable Hardware Buttons"); + } + } + } + + fixConfigValues(); + + save_prefs(); + + if ((String(topic) != topic_id+"/output") && + (String(topic) != topic_id+"/get_status") && + (stripe_mode == 0)){ + if (stripe_on){ + toggle_leds(1, true); + } else { + toggle_leds(0, true); + } + } + + if(publish_status_after_every_config_change){ + publish_current_status(); + } + + } else { + Serial.println("Button press via mqtt"); + Serial.println(payloadBuf); + if (payloadBuf.toInt() == 2 ){ + btn_two_last_pressed = millis(); + btn_two_changed = true; + } else { + btn_one_last_pressed = millis(); + btn_one_changed = true; + } + } + } +} + +void load_prefs(){ + preferences.begin(topic_id.c_str(), false); + brightness = preferences.getInt("brightness", 255); + color_r = preferences.getInt("color_r", 255); + color_g = preferences.getInt("color_g", 255); + color_b = preferences.getInt("color_b", 255); + + pong_init_delay = preferences.getFloat("pong_init_delay", PONG_INIT_LED_DELAY); + cur_pong_delay = pong_init_delay; + num_pong_leds = preferences.getInt("num_pong_leds", NUM_PONG_LEDS); + pong_start_led = preferences.getInt("pong_start_led", PONG_START_LED); + pong_max_wins = preferences.getInt("pong_max_wins", PONG_MAX_WINS); + pong_wins_delay_during = preferences.getFloat("pong_wins_delay_during", PONG_RESULT_DELAY_DURING); + pong_wins_delay_after = preferences.getFloat("pong_wins_delay_after", PONG_RESULT_DELAY_AFTER); + + pong_min_delay = preferences.getFloat("pong_min_delay", PONG_MIN_LED_DELAY); + pong_dec_per_run = preferences.getFloat("pong_dec_per_run", PONG_DEC_PER_RUN); + pong_btn_delay = preferences.getFloat("pong_btn_delay", PONG_BTN_DELAY); + + pong_tolerance = preferences.getInt("pong_tolerance", PONG_TOLERANCE); + pong_color_r = preferences.getInt("pong_color_r", 0); + pong_color_g = preferences.getInt("pong_color_g", 0); + pong_color_b = preferences.getInt("pong_color_b", 255); + pong_result_color_r = preferences.getInt("pong_result_color_r", 0); + pong_result_color_g = preferences.getInt("pong_result_color_g", 255); + pong_result_color_b = preferences.getInt("pong_result_color_b", 0); + + enable_hardware_btns = preferences.getBool("enable_hardware_btns", true); + preferences.end(); +} + +void save_prefs(){ + preferences.begin(topic_id.c_str(), false); + preferences.putInt("brightness", brightness); + preferences.putInt("color_r", color_r); + preferences.putInt("color_g", color_g); + preferences.putInt("color_b", color_b); + + preferences.putFloat("pong_init_delay", pong_init_delay); + preferences.putInt("num_pong_leds", num_pong_leds); + preferences.putInt("pong_start_led", pong_start_led); + preferences.putInt("pong_max_wins", pong_max_wins); + preferences.putFloat("pong_wins_delay_during", pong_wins_delay_during); + preferences.putFloat("pong_wins_delay_after", pong_wins_delay_after); + + preferences.putFloat("pong_min_delay", pong_min_delay); + preferences.putFloat("pong_dec_per_run", pong_dec_per_run); + preferences.putFloat("pong_btn_delay", pong_btn_delay); + + preferences.putInt("pong_tolerance", pong_tolerance); + preferences.putInt("pong_color_r", pong_color_r); + preferences.putInt("pong_color_g", pong_color_g); + preferences.putInt("pong_color_b", pong_color_b); + preferences.putInt("pong_result_color_r", pong_result_color_r); + preferences.putInt("pong_result_color_g", pong_result_color_g); + preferences.putInt("pong_result_color_b", pong_result_color_b); + + preferences.putBool("enable_hardware_btns", enable_hardware_btns); + preferences.end(); +} + +void setup() { + Serial.begin(115200); + + load_prefs(); + + mqttClient.setClientId(client_name.c_str()); + + WiFi.onEvent(WiFiEvent); + + Serial.println("Setup mqtt events"); + mqttClient.onConnect(onMqttConnect); + mqttClient.onDisconnect(onMqttDisconnect); + mqttClient.onMessage(onMqttMessage); + mqttClient.setServer(MQTT_HOST, MQTT_PORT); + mqttClient.setCredentials(mqtt_user, mqtt_pass); + + Serial.print(" MQTT_HOST: "); + Serial.println(MQTT_HOST); + Serial.print(" MQTT_PORT: "); + Serial.println(MQTT_PORT); + Serial.print(" MQTT_SECURE: "); + Serial.println(MQTT_SECURE); + #if ASYNC_TCP_SSL_ENABLED + mqttClient.setSecure(MQTT_SECURE); + if (MQTT_SECURE) { + Serial.println("Using secure MQTT!"); + mqttClient.addServerFingerprint((const uint8_t[])MQTT_SERVER_FINGERPRINT); + } + #else + Serial.println("Using insecure MQTT cuase AsyncTCP does not support SSL!"); + #endif + + Serial.println("Connect to wifi"); + connectToWifi(); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hi! I am "+host_name); + }); + + AsyncElegantOTA.begin(&server, ota_user, ota_pass); // Start ElegantOTA + server.begin(); + Serial.println("HTTP server started"); + + delay(1000); + + pinMode(BTN_1_GPIO, INPUT); + pinMode(BTN_2_GPIO, INPUT); + pinMode(INPUT_GPIO, INPUT); + pinMode(DATA_PIN, OUTPUT); + + pixels.begin(); + pixels.clear(); + + for (int i=0; i < MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0, 0, 0)); + } + show(); + delay(50); + for (int i=0; i < NUM_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(255, 255, 255)); + } + show(); + delay(200); + for (int i=0; i < MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0, 0, 0)); + } + + input_trigger(); + + if (input_active){ + show(); + } + + delay(500); + + if( enable_hardware_btns ){ + attachInterrupt(digitalPinToInterrupt(BTN_1_GPIO), btn_one_trigger, CHANGE); + attachInterrupt(digitalPinToInterrupt(BTN_2_GPIO), btn_two_trigger, CHANGE); + } + attachInterrupt(digitalPinToInterrupt(INPUT_GPIO), input_trigger, CHANGE); + + lastMillis = millis(); +} + +void reset_pong_vars(bool during, bool oneHitFirst){ + Serial.print("Resetting pong vars ("); + Serial.print(during); + Serial.print("/"); + Serial.print(oneHitFirst); + Serial.println(")"); + player_one_miss = 0; + player_two_miss = 0; + btn_one_changed = false; + btn_two_changed = false; + player_successfull_one_press = 0; + player_successfull_two_press = 0; + cur_pong_delay = pong_init_delay; + + if (!during){ + player_one_wins = 0; + player_two_wins = 0; + btn_one_last_pressed = 0; + btn_two_last_pressed = 0; + } + + if (oneHitFirst){ + cur_pixel = pong_start_led; + reverseMode = 0; + } else { + cur_pixel = num_pong_leds-1; + reverseMode = 1; + } +} + +void switch_to_pong_mode(bool oneHitFirst){ + Serial.println("Switching to pong mode"); + stripe_mode = 1; + if (!input_active){ + setKNXInput(true); + } + delay(500); + if (input_active) { + reset_pong_vars(false, oneHitFirst); + + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + show(); + delay(1000); + for (int i = pong_start_led; i< num_pong_leds; i++){ + pixels.setPixelColor(i, pixels.Color(pong_color_r,pong_color_g,pong_color_b)); + } + show(); + delay(1000); + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + show(); + delay(1000); + } +} + +void display_result(float cur_delay){ + Serial.println("Displaying results"); + delay(500); + for (int i = 0; i< MAX_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + + for (int i = pong_start_led; i < player_one_wins+pong_start_led; i++){ + pixels.setPixelColor(i, pixels.Color(pong_result_color_r,pong_result_color_g,pong_result_color_b)); + } + + for (int i = (num_pong_leds - 1); i > ((num_pong_leds-1)-player_two_wins); i--){ + pixels.setPixelColor(i, pixels.Color(pong_result_color_r,pong_result_color_g,pong_result_color_b)); + } + show(); + delay(cur_delay*1000); +} + + +void handleButtonChangesWhileNotPlaying(){ + Serial.println("Handling button press while not playing"); + if(btn_one_last_pressed > btn_two_last_pressed){ + Serial.println("Button one pressed after two"); + player_one_hit_first = false; + if ((btn_one_last_pressed - btn_two_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Within pong delay. Lets play!"); + //lets play now + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Not within pong delay. Switch led panel"); + toggle_leds(-1, true); + } + } else { + Serial.println("Button two pressed after one"); + player_one_hit_first = true; + if ((btn_two_last_pressed - btn_one_last_pressed) < (pong_btn_delay*1000)){ + Serial.println("Within pong delay. Lets play!"); + //lets play now + switch_to_pong_mode(player_one_hit_first); + } else { + Serial.println("Not within pong delay. Switch led panel"); + toggle_leds(-1, true); + } + } +} + +void loop() { + if (stripe_mode == 0){ + if (input_changed){ + Serial.println("Input changed!"); + input_changed = false; + if (digitalRead(INPUT_GPIO) == LOW){ + input_active = false; + } else { + input_active = true; + } + + if (input_active){ + Serial.println("It is now active!"); + toggle_leds(1, true); + } else { + Serial.println("It is now inactive!"); + toggle_leds(0, true); + } + last_refresh = millis(); + } else if (btn_one_changed or btn_two_changed){ + btn_one_changed = false; + btn_two_changed = false; + handleButtonChangesWhileNotPlaying(); + } else { + unsigned long curMillis = millis(); + + if (curMillis < lastMillis){ + lastMillis = curMillis; + last_refresh = 0; + } + + if((curMillis - last_refresh) > REFRESH_INTERVAL){ + Serial.println("Refresh interval reached. Refreshing!"); + show(); + last_refresh = curMillis; + } + } + } else if (stripe_mode == 1){ + if (input_changed){ + Serial.println("Input changed while playing."); + input_changed = false; + if (digitalRead(INPUT_GPIO) == LOW){ + Serial.println("Input is inactive now. Aborting game!"); + input_active = false; + stripe_mode = 0; + toggle_leds(0, true); + } else { + input_active = true; + } + } else { + Serial.println("Blackout all leds"); + for (int i=0; i < NUM_LEDS; i++){ + pixels.setPixelColor(i, pixels.Color(0,0,0)); + } + + Serial.print("Setting pong color to pixel number: "); + Serial.println(cur_pixel); + pixels.setPixelColor(cur_pixel, pixels.Color(pong_color_r,pong_color_g,pong_color_b)); + + Serial.println("Activating colors on stripe"); + show(); + + Serial.print("Waiting current pong delay of: "); + Serial.println(cur_pong_delay*1000); + delay(cur_pong_delay*1000); + + abortRun = 0; + player_one_miss = 0; + + if (player_successfull_one_press == 0){ + Serial.println("Player one has not press within tolerance currently"); + if(btn_one_changed){ + Serial.println("Button one changed!"); + btn_one_changed = false; + if ((reverseMode == 0) or ((cur_pixel - pong_tolerance) >= pong_start_led)){ + Serial.println("Player one did not hit in tolerance. Miss!"); + player_one_miss = 1; + } else { + Serial.println("Player one pressed in right moment!"); + player_successfull_one_press = 1; + } + } else if ((reverseMode == 1) && (cur_pixel == pong_start_led)){ + Serial.println("Player one missed at the end"); + player_one_miss = 1; + } + } else { + Serial.println("Player one hit within tolerance already!"); + btn_one_changed = false; + } + + if(player_one_miss == 1){ + Serial.println("Handling player one miss!"); + abortRun = 1; + player_two_wins += 1; + if(player_two_wins >= pong_max_wins){ + Serial.println("Player two wins match. Displaying results!"); + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); + stripe_mode = 0; + if (publish_results_at_display == 1){ + publish_results(); + } + toggle_leds(0, true); + } else { + Serial.println("Player two wins game. Displaying results!"); + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); + cur_pixel = pong_start_led; + reverseMode = 0; + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } + reset_pong_vars(true, player_one_hit_first); + } + } + + player_two_miss = 0; + + if (player_successfull_two_press == 0){ + Serial.println("Player two has not press within tolerance currently"); + if(btn_two_changed){ + Serial.println("Button two changed!"); + btn_two_changed = false; + if ((reverseMode == 1) or ((cur_pixel + pong_tolerance) <= (num_pong_leds-1))){ + Serial.println("Player two did not hit in tolerance. Miss!"); + player_two_miss = 1; + } else { + Serial.println("Player two pressed in right moment!"); + player_successfull_two_press = 1; + } + } else if ((reverseMode == 0) && (cur_pixel == (num_pong_leds-1))){ + Serial.println("Player two missed at the end"); + player_two_miss = 1; + } + } else { + Serial.println("Player two hit within tolerance already!"); + btn_two_changed = false; + } + + if(player_two_miss == 1){ + Serial.println("Handling player two miss!"); + abortRun = 1; + player_one_wins += 1; + if(player_one_wins >= pong_max_wins){ + Serial.println("Player one wins match. Displaying results!"); + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_after); + reset_pong_vars(false, player_one_hit_first); + stripe_mode = 0; + if (publish_results_at_display == 1){ + publish_results(); + } + toggle_leds(0, true); + } else { + Serial.println("Player one wins game. Displaying results!"); + if (publish_results_at_display == 1){ + publish_results(); + } + display_result(pong_wins_delay_during); + if (change_start_led_during_match){ + player_one_hit_first = !player_one_hit_first; + } + reset_pong_vars(true, player_one_hit_first); + } + } + + + if (abortRun == 0){ + Serial.println("No abort of run needed!"); + if (reverseMode == 1){ + Serial.println("We are in reverse mode!"); + cur_pixel -= 1; + if (cur_pixel < pong_start_led){ + reverseMode = 0; + player_successfull_one_press = 0; + cur_pixel = pong_start_led + 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } else { + Serial.println("We are not in reverse mode!"); + cur_pixel += 1; + if (cur_pixel > (num_pong_leds-1)){ + player_successfull_two_press = 0; + cur_pixel = num_pong_leds-2; + reverseMode = 1; + cur_pong_delay = cur_pong_delay - pong_dec_per_run; + if (cur_pong_delay < pong_min_delay){ + cur_pong_delay = pong_min_delay; + } + } + } + } + } + } +} diff --git a/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/README.md b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/README.md new file mode 100644 index 0000000..f93c432 --- /dev/null +++ b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/README.md @@ -0,0 +1,18 @@ +# ESP32LedStripWithPongAndMqttOTANeoPixelExtInput + +This example provides the following features: + +* Switch LED strip on/off or toggle it via MQTT or external connected buttons +* Control the color of the strip via MQTT +* Play pong by pressing the two connected buttons after each other in a specific amount of time or via MQTT buttons +* Control all pong game parameters (color, initial speed, speed increase amount per return, etc. ) via MQTT +* Display the game result at the end of each game/match as lighted LEDs at the ends of the strip +* Send the game/match result via MQTT to MQTT buttons + +Used Hardware: + +* ESP32 based microcontroller (i.e. ESP32 Dev Kit) +* WS2801 LED strip +* I2C Level shifter +* Buttons +* 10kOhm resistors diff --git a/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/settings.example.h old mode 100644 new mode 100755 similarity index 56% rename from examples/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h rename to examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/settings.example.h index 27e5633..ad24a52 --- a/examples/ESP32LedStripWithPongAndMqttOTANeoPixel/settings.example.h +++ b/examples/withPong/ESP32LedStripWithPongAndMqttOTANeoPixelExtInput/settings.example.h @@ -2,6 +2,7 @@ #define NUM_LEDS 300 #define NUM_PONG_LEDS 10 #define DATA_PIN 14 +#define INPUT_GPIO 16 #define BTN_1_GPIO 23 #define BTN_2_GPIO 22 #define BTN_DEBOUNCE_DELAY 500 @@ -19,9 +20,20 @@ #define PONG_RESULT_DELAY_AFTER 5.0 #define REFRESH_INTERVAL 10000 -const char* SSID = "ENTER_WIFI_SSID_HERE"; -const char* PSK = "ENTER_WIFI_PASSWORD_HERE"; -const char* mqtt_broker = "ENTER_MQTT_SERVER_ADDRESS_HERE"; +const char* WIFI_SSID = "ENTER_WIFI_SSID_HERE"; +const char* WIFI_PASSWORD = "ENTER_WIFI_PASSWORD_HER"; + +#if ASYNC_TCP_SSL_ENABLED +#define MQTT_SECURE true +//FINGERPRINT=`openssl x509 -noout -fingerprint -sha1 -inform pem -in /path/to/cert/cert.pem | tr '[:upper:]' '[:lower:]' | sed 's/^[^=]\+=//g' | sed 's/:/, 0x/g'`; echo "#define MQTT_SERVER_FINGERPRINT {0x${FINGERPRINT}}" +#define MQTT_SERVER_FINGERPRINT {0x7e, 0x36, 0x22, 0x01, 0xf9, 0x7e, 0x99, 0x2f, 0xc5, 0xdb, 0x3d, 0xbe, 0xac, 0x48, 0x67, 0x5b, 0x5d, 0x47, 0x94, 0xd2} +#define MQTT_PORT 8883 +#else +#define MQTT_SECURE false +#define MQTT_PORT 1883 +#endif + +#define MQTT_HOST IPAddress(192, 1, 1, 2) const char* mqtt_user = "ENTER_MQTT_USERNAME_HERE"; const char* mqtt_pass = "ENTER_MQTT_PASSWORD_HERE"; const char* ota_user = "ENTER_OTA_USER_HERE"; @@ -29,3 +41,4 @@ const char* ota_pass = "ENTER_OTA_PASSWORD_HERE"; const String host_name = "ESPLED"; const String client_name = "ESPLED"; const String topic_id = "esp_led"; +const String knx_topic = "ENTER_KNX_TOPIC_HERE"; diff --git a/examples/withPong/README.md b/examples/withPong/README.md new file mode 100644 index 0000000..820660a --- /dev/null +++ b/examples/withPong/README.md @@ -0,0 +1,3 @@ +# withPong + +All examples in this directory provide the full feature set including setting the color and the pong options via MQTT. \ No newline at end of file From 9ecc7fff1d0faef6333ec62c3e02ec0e11ae51d6 Mon Sep 17 00:00:00 2001 From: Thomas Hirschberger Date: Sun, 9 Oct 2022 14:51:05 +0200 Subject: [PATCH 40/40] added one more README with a reference to PythonLedControl --- examples/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 examples/README.md diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..f4da377 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,5 @@ +# Examples + +All examples in this directory use additional micro controllers (like ESP8266 or ESP32 boards) to control the LED strip. + +If you are looking for a script to control a LED strip that is connected to Raspberry you may want to take a look to [PythonLedControl](https://github.com/Tom-Hirschberger/PythonLedControl).