Initial Commit
This commit is contained in:
		
						commit
						349a62c4c0
					
				
							
								
								
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					.pio
 | 
				
			||||||
 | 
					.vscode/.browse.c_cpp.db*
 | 
				
			||||||
 | 
					.vscode/c_cpp_properties.json
 | 
				
			||||||
 | 
					.vscode/launch.json
 | 
				
			||||||
 | 
					.vscode/ipch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Vim
 | 
				
			||||||
 | 
					*.swp
 | 
				
			||||||
 | 
					*.swo
 | 
				
			||||||
							
								
								
									
										10
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // See http://go.microsoft.com/fwlink/?LinkId=827846
 | 
				
			||||||
 | 
					    // for the documentation about the extensions.json format
 | 
				
			||||||
 | 
					    "recommendations": [
 | 
				
			||||||
 | 
					        "platformio.platformio-ide"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "unwantedRecommendations": [
 | 
				
			||||||
 | 
					        "ms-vscode.cpptools-extension-pack"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "cmake.configureOnOpen": false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					# LEDChooser Hardware LED Controller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This project is designed to run on an ESP-32 microcontroller dev board. It is used in a on-off custom designed hardare device for interfacing with LEDController driven LED strips.
 | 
				
			||||||
							
								
								
									
										39
									
								
								include/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/README
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This directory is intended for project header files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A header file is a file containing C declarations and macro definitions
 | 
				
			||||||
 | 
					to be shared between several project source files. You request the use of a
 | 
				
			||||||
 | 
					header file in your project source file (C, C++, etc) located in `src` folder
 | 
				
			||||||
 | 
					by including it, with the C preprocessing directive `#include'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```src/main.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "header.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main (void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					 ...
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Including a header file produces the same results as copying the header file
 | 
				
			||||||
 | 
					into each source file that needs it. Such copying would be time-consuming
 | 
				
			||||||
 | 
					and error-prone. With a header file, the related declarations appear
 | 
				
			||||||
 | 
					in only one place. If they need to be changed, they can be changed in one
 | 
				
			||||||
 | 
					place, and programs that include the header file will automatically use the
 | 
				
			||||||
 | 
					new version when next recompiled. The header file eliminates the labor of
 | 
				
			||||||
 | 
					finding and changing all the copies as well as the risk that a failure to
 | 
				
			||||||
 | 
					find one copy will result in inconsistencies within a program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In C, the usual convention is to give header files names that end with `.h'.
 | 
				
			||||||
 | 
					It is most portable to use only letters, digits, dashes, and underscores in
 | 
				
			||||||
 | 
					header file names, and at most one dot.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Read more about using header files in official GCC documentation:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Include Syntax
 | 
				
			||||||
 | 
					* Include Operation
 | 
				
			||||||
 | 
					* Once-Only Headers
 | 
				
			||||||
 | 
					* Computed Includes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
 | 
				
			||||||
							
								
								
									
										46
									
								
								lib/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/README
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This directory is intended for project specific (private) libraries.
 | 
				
			||||||
 | 
					PlatformIO will compile them to static libraries and link into executable file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The source code of each library should be placed in a an own separate directory
 | 
				
			||||||
 | 
					("lib/your_library_name/[here are source files]").
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For example, see a structure of the following two libraries `Foo` and `Bar`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|--lib
 | 
				
			||||||
 | 
					|  |
 | 
				
			||||||
 | 
					|  |--Bar
 | 
				
			||||||
 | 
					|  |  |--docs
 | 
				
			||||||
 | 
					|  |  |--examples
 | 
				
			||||||
 | 
					|  |  |--src
 | 
				
			||||||
 | 
					|  |     |- Bar.c
 | 
				
			||||||
 | 
					|  |     |- Bar.h
 | 
				
			||||||
 | 
					|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
 | 
				
			||||||
 | 
					|  |
 | 
				
			||||||
 | 
					|  |--Foo
 | 
				
			||||||
 | 
					|  |  |- Foo.c
 | 
				
			||||||
 | 
					|  |  |- Foo.h
 | 
				
			||||||
 | 
					|  |
 | 
				
			||||||
 | 
					|  |- README --> THIS FILE
 | 
				
			||||||
 | 
					|
 | 
				
			||||||
 | 
					|- platformio.ini
 | 
				
			||||||
 | 
					|--src
 | 
				
			||||||
 | 
					   |- main.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					and a contents of `src/main.c`:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					#include <Foo.h>
 | 
				
			||||||
 | 
					#include <Bar.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main (void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  ...
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PlatformIO Library Dependency Finder will find automatically dependent
 | 
				
			||||||
 | 
					libraries scanning project source files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					More information about PlatformIO Library Dependency Finder
 | 
				
			||||||
 | 
					- https://docs.platformio.org/page/librarymanager/ldf.html
 | 
				
			||||||
							
								
								
									
										24
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					; PlatformIO Project Configuration File
 | 
				
			||||||
 | 
					;
 | 
				
			||||||
 | 
					;   Build options: build flags, source filter
 | 
				
			||||||
 | 
					;   Upload options: custom upload port, speed and extra flags
 | 
				
			||||||
 | 
					;   Library options: dependencies, extra library storages
 | 
				
			||||||
 | 
					;   Advanced options: extra scripting
 | 
				
			||||||
 | 
					;
 | 
				
			||||||
 | 
					; Please visit documentation for the other options and examples
 | 
				
			||||||
 | 
					; https://docs.platformio.org/page/projectconf.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[env:esp32doit-devkit-v1]
 | 
				
			||||||
 | 
					platform = espressif32
 | 
				
			||||||
 | 
					board = esp32doit-devkit-v1
 | 
				
			||||||
 | 
					framework = arduino
 | 
				
			||||||
 | 
					monitor_port = com4
 | 
				
			||||||
 | 
					monitor_speed = 115200
 | 
				
			||||||
 | 
					upload_protocol = espota
 | 
				
			||||||
 | 
					upload_port = 192.168.2.214
 | 
				
			||||||
 | 
					lib_deps = 
 | 
				
			||||||
 | 
						fastled/FastLED@^3.5.0
 | 
				
			||||||
 | 
						https://github.com/tzapu/WiFiManager.git
 | 
				
			||||||
 | 
						adafruit/Adafruit SSD1306@^2.5.3
 | 
				
			||||||
 | 
						adafruit/Adafruit GFX Library@^1.11.1
 | 
				
			||||||
 | 
						madhephaestus/ESP32Encoder@^0.9.2
 | 
				
			||||||
							
								
								
									
										585
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										585
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,585 @@
 | 
				
			||||||
 | 
					#include <Arduino.h>
 | 
				
			||||||
 | 
					#include <FastLED.h>
 | 
				
			||||||
 | 
					#include <WiFiManager.h>
 | 
				
			||||||
 | 
					#include <WiFi.h>
 | 
				
			||||||
 | 
					#include <HTTPClient.h>
 | 
				
			||||||
 | 
					#include <Wire.h>
 | 
				
			||||||
 | 
					#include <Adafruit_I2CDevice.h>
 | 
				
			||||||
 | 
					#include <Adafruit_GFX.h>
 | 
				
			||||||
 | 
					#include <Adafruit_SSD1306.h>
 | 
				
			||||||
 | 
					#include <ESP32Encoder.h>
 | 
				
			||||||
 | 
					#include <ArduinoOTA.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pins Used:
 | 
				
			||||||
 | 
					// 4, 13, 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33, 34, 36, 39
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEBUGMODE true
 | 
				
			||||||
 | 
					#define TRIGGERENABLED false
 | 
				
			||||||
 | 
					#define REDPIN 36
 | 
				
			||||||
 | 
					#define GREENPIN 39
 | 
				
			||||||
 | 
					#define BLUEPIN 34
 | 
				
			||||||
 | 
					#define LEDPIN 32
 | 
				
			||||||
 | 
					#define NUMLEDS 6
 | 
				
			||||||
 | 
					#define LEDUPDATEMS 100
 | 
				
			||||||
 | 
					#define MESSAGERATEMS 250
 | 
				
			||||||
 | 
					#define MESSAGETRIGGERPIN 33
 | 
				
			||||||
 | 
					#define MESSAGETOGGLEPIN 25
 | 
				
			||||||
 | 
					#define ZONEPIN_CABU 15
 | 
				
			||||||
 | 
					#define ZONEPIN_CABD 16
 | 
				
			||||||
 | 
					#define ZONEPIN_WALL 17
 | 
				
			||||||
 | 
					#define ZONEPIN_CLDN 18
 | 
				
			||||||
 | 
					#define ZONEPIN_GZBO 19
 | 
				
			||||||
 | 
					#define ZONEPIN_EXTR 26
 | 
				
			||||||
 | 
					#define NUMZONES 6
 | 
				
			||||||
 | 
					#define DEBOUNCEMS 15
 | 
				
			||||||
 | 
					#define OLED_SCL 22
 | 
				
			||||||
 | 
					#define OLED_SDA 21
 | 
				
			||||||
 | 
					#define SCREEN_WIDTH 128
 | 
				
			||||||
 | 
					#define SCREEN_HEIGHT 64
 | 
				
			||||||
 | 
					#define ROTARYPBPIN 23
 | 
				
			||||||
 | 
					#define ROTARYPIN1 13
 | 
				
			||||||
 | 
					#define ROTARYPIN2 27
 | 
				
			||||||
 | 
					#define COLORMODEPIN 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ZoneStruct {
 | 
				
			||||||
 | 
					  unsigned int pin;
 | 
				
			||||||
 | 
					  unsigned int id;
 | 
				
			||||||
 | 
					  bool active;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ZoneStruct() {
 | 
				
			||||||
 | 
					    pin = 0;
 | 
				
			||||||
 | 
					    id = 0;
 | 
				
			||||||
 | 
					    active = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ZoneStruct(unsigned int p, unsigned int i) {
 | 
				
			||||||
 | 
					    this->pin = p;
 | 
				
			||||||
 | 
					    this->id = i;
 | 
				
			||||||
 | 
					    this->active = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Create OLED display object
 | 
				
			||||||
 | 
					Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Yeah, yeah. The zones and zone IDs are hard coded.
 | 
				
			||||||
 | 
					unsigned int dimmerPins[3] = {REDPIN, GREENPIN, BLUEPIN};
 | 
				
			||||||
 | 
					ZoneStruct zones[NUMZONES] = {
 | 
				
			||||||
 | 
					  ZoneStruct(ZONEPIN_CABU, 1),
 | 
				
			||||||
 | 
					  ZoneStruct(ZONEPIN_CABD, 2),
 | 
				
			||||||
 | 
					  ZoneStruct(ZONEPIN_WALL, 3),
 | 
				
			||||||
 | 
					  ZoneStruct(ZONEPIN_GZBO, 5),
 | 
				
			||||||
 | 
					  ZoneStruct(ZONEPIN_CLDN, 4),
 | 
				
			||||||
 | 
					  ZoneStruct(ZONEPIN_EXTR, 6)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					// Define the array for the addressable LEDs
 | 
				
			||||||
 | 
					CRGB leds[NUMLEDS];
 | 
				
			||||||
 | 
					unsigned int red = 0, green = 0, blue = 0;
 | 
				
			||||||
 | 
					unsigned int lastRed = 0, lastGreen = 0, lastBlue = 0;
 | 
				
			||||||
 | 
					// A couple main loop variables to keep track of timing triggers
 | 
				
			||||||
 | 
					// Only the "trigger" button is debounced since the zone switches
 | 
				
			||||||
 | 
					// and "toggle" switch are not time sensitive
 | 
				
			||||||
 | 
					unsigned long lastDimmerSample, lastDebugMessage, lastTriggerDebounceTime;
 | 
				
			||||||
 | 
					// Variable to track the state of the "trigger" button. Button/switch
 | 
				
			||||||
 | 
					// inputs are pulled HIGH so a LOW state means the button is pressed
 | 
				
			||||||
 | 
					unsigned short triggerButtonState = HIGH, lastTriggerButtonState = HIGH;
 | 
				
			||||||
 | 
					// Triggered messages should only be sent once per press.
 | 
				
			||||||
 | 
					// Same for pattern messages. These variables tracks that
 | 
				
			||||||
 | 
					bool triggerMessageSent = false, patternMessageSent = false;
 | 
				
			||||||
 | 
					// Variable to track the state of the rotary encoder push button
 | 
				
			||||||
 | 
					// inputs are pulled HIGH so a LOW state means the button is pressed
 | 
				
			||||||
 | 
					unsigned short rotaryPBState = HIGH, lastRotaryPBState = HIGH;
 | 
				
			||||||
 | 
					unsigned long lastRPBDebounceTime;
 | 
				
			||||||
 | 
					// The Rotary Encoder for the pattern menu
 | 
				
			||||||
 | 
					ESP32Encoder encoder;
 | 
				
			||||||
 | 
					unsigned int encoderIndex = 0;
 | 
				
			||||||
 | 
					unsigned int maxEncoderIndex = 0;
 | 
				
			||||||
 | 
					// Keep track of color patterns pulled from server
 | 
				
			||||||
 | 
					unsigned int patternCount = 0;
 | 
				
			||||||
 | 
					char patterns[100][11];
 | 
				
			||||||
 | 
					unsigned short colorModeState = HIGH, lastColorModeState = HIGH;
 | 
				
			||||||
 | 
					unsigned long lastColorModeDebounceTime;
 | 
				
			||||||
 | 
					// Variable for pulse-repaint of OLED
 | 
				
			||||||
 | 
					bool needRepopulate = false;
 | 
				
			||||||
 | 
					unsigned long repopulateTime;
 | 
				
			||||||
 | 
					// Variable to monitor if we are in "Demo" mode
 | 
				
			||||||
 | 
					// which means no WiFi connection attempt and no HTTP messages
 | 
				
			||||||
 | 
					bool demoModeEnabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A simple function to get the dimmer/POT values
 | 
				
			||||||
 | 
					// and return them as a mapped value for FastLED colors
 | 
				
			||||||
 | 
					unsigned int getColorValue(unsigned int dimmerPin) {
 | 
				
			||||||
 | 
					  // Take ten samples of the dimmer and average them.
 | 
				
			||||||
 | 
					  // This smooths out the abysmal ADC built into the ESP32
 | 
				
			||||||
 | 
					  unsigned long sum = 0;
 | 
				
			||||||
 | 
					  for ( int i=0; i<10; i++ ) {
 | 
				
			||||||
 | 
					    sum += analogRead(dimmerPin);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  sum = sum/10;
 | 
				
			||||||
 | 
					  // Map the sampled 10bit values to 8bit FastLED colors
 | 
				
			||||||
 | 
					  return map(sum, 0, 1023, 0, 255);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to send messages to the back-end LED controller
 | 
				
			||||||
 | 
					// for setting the current pattern active.
 | 
				
			||||||
 | 
					void sendPatternMessage() {
 | 
				
			||||||
 | 
					  // Build our GET message for seting pattern
 | 
				
			||||||
 | 
					  char webMsg[255] = "";
 | 
				
			||||||
 | 
					  strcat(webMsg, "http://192.168.2.2/l/setpattern.php?");
 | 
				
			||||||
 | 
					  // This varieble will only be set to true
 | 
				
			||||||
 | 
					  // if any of the zone switches are on
 | 
				
			||||||
 | 
					  bool haveTarget = false;
 | 
				
			||||||
 | 
					  // Add all the target IDs
 | 
				
			||||||
 | 
					  // This is done using the "[]" notation
 | 
				
			||||||
 | 
					  // for URL array parameters native to PHP
 | 
				
			||||||
 | 
					  for ( int i=0; i<NUMZONES; i++ ) {
 | 
				
			||||||
 | 
					    if ( zones[i].active == true ) {
 | 
				
			||||||
 | 
					      char target[3] = "";
 | 
				
			||||||
 | 
					      sprintf(target, "%d", zones[i].id);
 | 
				
			||||||
 | 
					      strcat(webMsg, "t[]=");
 | 
				
			||||||
 | 
					      strcat(webMsg, target);
 | 
				
			||||||
 | 
					      strcat(webMsg, "&");
 | 
				
			||||||
 | 
					      haveTarget = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Bail out of all the targets are false
 | 
				
			||||||
 | 
					  if ( !haveTarget ) return;
 | 
				
			||||||
 | 
					  strcat(webMsg, "p=");
 | 
				
			||||||
 | 
					  strcat(webMsg, patterns[encoderIndex]);
 | 
				
			||||||
 | 
					  // Send the message if not in demo mode
 | 
				
			||||||
 | 
					  if ( !demoModeEnabled ) {
 | 
				
			||||||
 | 
					    HTTPClient http;
 | 
				
			||||||
 | 
					    http.begin(webMsg);
 | 
				
			||||||
 | 
					    http.GET();
 | 
				
			||||||
 | 
					    http.end();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Set patternMessageSent to true if it wasn't and the trigger button is pressed
 | 
				
			||||||
 | 
					  if ( !rotaryPBState && !patternMessageSent ) patternMessageSent = true;
 | 
				
			||||||
 | 
					  if ( DEBUGMODE ) Serial.println(webMsg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to send messages to the back-end LED controller
 | 
				
			||||||
 | 
					// We could send UDP messages from here, but it's better to
 | 
				
			||||||
 | 
					// rely on the back end so this code doesn't need to change
 | 
				
			||||||
 | 
					// if the LED control message format changes.
 | 
				
			||||||
 | 
					void sendColorMessage() {
 | 
				
			||||||
 | 
					  // Our variables to hold the nex values
 | 
				
			||||||
 | 
					  char redHex[3] = "", greenHex[3] = "", blueHex[3] = "";
 | 
				
			||||||
 | 
					  // Set the hex values for the three colors from the global variables
 | 
				
			||||||
 | 
					  sprintf(redHex, "%02x", red);
 | 
				
			||||||
 | 
					  sprintf(greenHex, "%02x", green);
 | 
				
			||||||
 | 
					  sprintf(blueHex, "%02x", blue);
 | 
				
			||||||
 | 
					  // Build our GET message for setting colors
 | 
				
			||||||
 | 
					  char webMsg[255] = "";
 | 
				
			||||||
 | 
					  strcat(webMsg, "http://192.168.2.2/l/setcolor.php?");
 | 
				
			||||||
 | 
					  // This varieble will only be set to true
 | 
				
			||||||
 | 
					  // if any of the zone switches are on
 | 
				
			||||||
 | 
					  bool haveTarget = false;
 | 
				
			||||||
 | 
					  // Add all the target IDs
 | 
				
			||||||
 | 
					  // This is done using the "[]" notation
 | 
				
			||||||
 | 
					  // for URL array parameters native to PHP
 | 
				
			||||||
 | 
					  for ( int i=0; i<NUMZONES; i++ ) {
 | 
				
			||||||
 | 
					    if ( zones[i].active == true ) {
 | 
				
			||||||
 | 
					      char target[3] = "";
 | 
				
			||||||
 | 
					      sprintf(target, "%d", zones[i].id);
 | 
				
			||||||
 | 
					      strcat(webMsg, "t[]=");
 | 
				
			||||||
 | 
					      strcat(webMsg, target);
 | 
				
			||||||
 | 
					      strcat(webMsg, "&");
 | 
				
			||||||
 | 
					      haveTarget = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Bail out of all the targets are false
 | 
				
			||||||
 | 
					  if ( !haveTarget ) return;
 | 
				
			||||||
 | 
					  // Add the converted hex color value
 | 
				
			||||||
 | 
					  strcat(webMsg, "c=");
 | 
				
			||||||
 | 
					  strcat(webMsg, redHex);
 | 
				
			||||||
 | 
					  strcat(webMsg, greenHex);
 | 
				
			||||||
 | 
					  strcat(webMsg, blueHex);
 | 
				
			||||||
 | 
					  // Send the message if not in demo mode
 | 
				
			||||||
 | 
					  if ( !demoModeEnabled ) {
 | 
				
			||||||
 | 
					    HTTPClient http;
 | 
				
			||||||
 | 
					    http.begin(webMsg);
 | 
				
			||||||
 | 
					    http.GET();
 | 
				
			||||||
 | 
					    http.end();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Set triggerMessageSent to true if it wasn't and the trigger button is pressed
 | 
				
			||||||
 | 
					  if ( !triggerButtonState && !triggerMessageSent ) triggerMessageSent = true;
 | 
				
			||||||
 | 
					  if ( DEBUGMODE ) Serial.println(webMsg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int getEncoderIndex() {
 | 
				
			||||||
 | 
					  // If we aren't in "pattern" mode then
 | 
				
			||||||
 | 
					  // reset the current encoder count and return
 | 
				
			||||||
 | 
					  if ( colorModeState == HIGH ) {
 | 
				
			||||||
 | 
					    encoder.setCount(encoderIndex);
 | 
				
			||||||
 | 
					    return encoderIndex;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  double currentIndex = encoder.getCount();
 | 
				
			||||||
 | 
					  if ( currentIndex > maxEncoderIndex ) {
 | 
				
			||||||
 | 
					    currentIndex = maxEncoderIndex;
 | 
				
			||||||
 | 
					    encoder.setCount(maxEncoderIndex);
 | 
				
			||||||
 | 
					  } else if ( currentIndex < 0 ) {
 | 
				
			||||||
 | 
					    currentIndex = 0;
 | 
				
			||||||
 | 
					    encoder.setCount(0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return (unsigned int)currentIndex;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void getColorPatterns() {
 | 
				
			||||||
 | 
					  if ( demoModeEnabled ) {
 | 
				
			||||||
 | 
					    // If in demo mode make some dummy patterns
 | 
				
			||||||
 | 
					    strcpy(patterns[0], "Demo Time!");
 | 
				
			||||||
 | 
					    strcpy(patterns[1], "Happyness");
 | 
				
			||||||
 | 
					    strcpy(patterns[2], "Hilarious");
 | 
				
			||||||
 | 
					    strcpy(patterns[3], "California");
 | 
				
			||||||
 | 
					    strcpy(patterns[4], "Tortoise");
 | 
				
			||||||
 | 
					    patternCount = 5;
 | 
				
			||||||
 | 
					    maxEncoderIndex = patternCount - 1;
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Make the web call to get the color patterns
 | 
				
			||||||
 | 
					  HTTPClient http;
 | 
				
			||||||
 | 
					  http.begin("http://192.168.2.2/l/getpatterns.php");
 | 
				
			||||||
 | 
					  int httpCode = http.GET();
 | 
				
			||||||
 | 
					  String payload = http.getString();
 | 
				
			||||||
 | 
					  http.end();
 | 
				
			||||||
 | 
					  // If we don't have a good HTTP return code
 | 
				
			||||||
 | 
					  // or the payload is empty, then bail
 | 
				
			||||||
 | 
					  if ( (httpCode == 0) || (payload.length() == 0) ) return;
 | 
				
			||||||
 | 
					  // Parse the payload delimited by commas
 | 
				
			||||||
 | 
					  char values[payload.length() + 1];
 | 
				
			||||||
 | 
					  memset(values, '\0', sizeof(values));
 | 
				
			||||||
 | 
					  strcpy(values, payload.c_str());
 | 
				
			||||||
 | 
					  char *token = strtok(values, ",");
 | 
				
			||||||
 | 
					  while ( token != NULL ) {
 | 
				
			||||||
 | 
					    //strncpy(patterns[patternCount], token, strlen(token));
 | 
				
			||||||
 | 
					    strcpy(patterns[patternCount], token);
 | 
				
			||||||
 | 
					    patternCount++;
 | 
				
			||||||
 | 
					    token = strtok(NULL, ",");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Update the maximum encoder value
 | 
				
			||||||
 | 
					  maxEncoderIndex = patternCount - 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void paintLEDs() {
 | 
				
			||||||
 | 
					  if ( colorModeState == LOW ) {
 | 
				
			||||||
 | 
					    leds[0] = CRGB(128, 0, 0);
 | 
				
			||||||
 | 
					    leds[1] = CRGB(128, 0, 0);
 | 
				
			||||||
 | 
					    leds[2] = CRGB(0, 128, 0);
 | 
				
			||||||
 | 
					    leds[3] = CRGB(0, 128, 0);
 | 
				
			||||||
 | 
					    leds[4] = CRGB(0, 0, 128);
 | 
				
			||||||
 | 
					    leds[5] = CRGB(0, 0, 128);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // Grab the current color values
 | 
				
			||||||
 | 
					    red = getColorValue(REDPIN);
 | 
				
			||||||
 | 
					    green = getColorValue(GREENPIN);
 | 
				
			||||||
 | 
					    blue = getColorValue(BLUEPIN);
 | 
				
			||||||
 | 
					    // Set all the LEDs to the current color
 | 
				
			||||||
 | 
					    for ( int i=0; i<NUMLEDS; i++ ) {
 | 
				
			||||||
 | 
					      leds[i] = CRGB(red, green, blue);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  FastLED.show();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void populateOLED(bool inverted = false) {
 | 
				
			||||||
 | 
					  unsigned short foreground = WHITE, background = BLACK;
 | 
				
			||||||
 | 
					  if ( inverted ) {
 | 
				
			||||||
 | 
					    foreground = BLACK;
 | 
				
			||||||
 | 
					    background = WHITE;
 | 
				
			||||||
 | 
					    needRepopulate = true;
 | 
				
			||||||
 | 
					    repopulateTime = millis() + 150;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  oled.clearDisplay();
 | 
				
			||||||
 | 
					  oled.setCursor(0, 0);
 | 
				
			||||||
 | 
					  if ( colorModeState == HIGH ) {
 | 
				
			||||||
 | 
					    // State HIGH means in "single color mode"
 | 
				
			||||||
 | 
					    oled.setTextColor(foreground, background);
 | 
				
			||||||
 | 
					    oled.println("TURN DIALS");
 | 
				
			||||||
 | 
					    oled.println("PICK COLOR");
 | 
				
			||||||
 | 
					    oled.println("HIT BUTTON");
 | 
				
			||||||
 | 
					    oled.println("BE AMAZED!");
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // State LOW means in "pattern mode"
 | 
				
			||||||
 | 
					    unsigned int startingIndex = 0;
 | 
				
			||||||
 | 
					    if ( encoderIndex > 2 ) {
 | 
				
			||||||
 | 
					      startingIndex = encoderIndex - 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    unsigned int endingIndex = ((startingIndex + 3) > patternCount) ? patternCount : (startingIndex + 3);
 | 
				
			||||||
 | 
					    for ( unsigned int i=startingIndex; i<=endingIndex; i++ ) {
 | 
				
			||||||
 | 
					      if ( i == encoderIndex ) {
 | 
				
			||||||
 | 
					        oled.setTextColor(background, foreground);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        oled.setTextColor(foreground, background);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      char line[11] = "";
 | 
				
			||||||
 | 
					      // Buffer variable for string padding
 | 
				
			||||||
 | 
					      char spaceBuffer[] = "          ";
 | 
				
			||||||
 | 
					      strcpy(line, patterns[i]);
 | 
				
			||||||
 | 
					      strncat(line, spaceBuffer, (10-strlen(patterns[i])));
 | 
				
			||||||
 | 
					      oled.println(line);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  oled.display();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This function gets called if the board goes into
 | 
				
			||||||
 | 
					// AP Captive Portal mode to provide WiFi configuration
 | 
				
			||||||
 | 
					void configModeCallback (WiFiManager *myWiFiManager) {
 | 
				
			||||||
 | 
					  oled.clearDisplay();
 | 
				
			||||||
 | 
					  oled.setTextSize(2);
 | 
				
			||||||
 | 
					  oled.setTextColor(WHITE);
 | 
				
			||||||
 | 
					  oled.setCursor(0, 0);
 | 
				
			||||||
 | 
					  oled.println("-- SSID --");
 | 
				
			||||||
 | 
					  oled.println("LEDChooser");
 | 
				
			||||||
 | 
					  oled.println("Use Phone");
 | 
				
			||||||
 | 
					  oled.println("Setup WiFi");
 | 
				
			||||||
 | 
					  oled.display();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setup() {
 | 
				
			||||||
 | 
					  // Set COLORMODEPIN to INTPUT_PULLUP
 | 
				
			||||||
 | 
					  pinMode(COLORMODEPIN, INPUT_PULLUP);
 | 
				
			||||||
 | 
					  colorModeState = digitalRead(COLORMODEPIN);
 | 
				
			||||||
 | 
					  lastColorModeState = colorModeState;
 | 
				
			||||||
 | 
					  // Initialize color pattern name array
 | 
				
			||||||
 | 
					  memset(patterns, '\0', sizeof(patterns));
 | 
				
			||||||
 | 
					  // Set up the serial console
 | 
				
			||||||
 | 
					  Serial.begin(115200);
 | 
				
			||||||
 | 
					  // Set up the Rotary Encoder push button input
 | 
				
			||||||
 | 
					  pinMode(ROTARYPBPIN, INPUT_PULLUP);
 | 
				
			||||||
 | 
					  //ESP32Encoder::useInternalWeakPullResistors=UP;
 | 
				
			||||||
 | 
					  encoder.attachSingleEdge(ROTARYPIN1, ROTARYPIN2);
 | 
				
			||||||
 | 
					  encoder.setCount(encoderIndex);
 | 
				
			||||||
 | 
					  // Set up the two pins for initiating a set color message to network
 | 
				
			||||||
 | 
					  pinMode(MESSAGETRIGGERPIN, INPUT_PULLUP);
 | 
				
			||||||
 | 
					  pinMode(MESSAGETOGGLEPIN, INPUT_PULLUP);
 | 
				
			||||||
 | 
					  // Set up the pins for tracking the zone enable/disable switches
 | 
				
			||||||
 | 
					  for ( int i=0; i<NUMZONES; i++ ) {
 | 
				
			||||||
 | 
					    pinMode(zones[i].pin, INPUT_PULLUP);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Set up our in-box addressable LEDs and set them all to off
 | 
				
			||||||
 | 
					  FastLED.addLeds<WS2812B, LEDPIN, GRB>(leds, NUMLEDS);
 | 
				
			||||||
 | 
					  fill_solid(leds, NUMLEDS, CRGB::Black);
 | 
				
			||||||
 | 
					  FastLED.show();
 | 
				
			||||||
 | 
					  // Turn on OLED
 | 
				
			||||||
 | 
					  if ( !oled.begin(SSD1306_SWITCHCAPVCC, 0x3C) ) {
 | 
				
			||||||
 | 
					    Serial.println(F("Failed to start OLED Display!"));
 | 
				
			||||||
 | 
					    while (1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Print the MAC Address
 | 
				
			||||||
 | 
					  Serial.println("MAC Address: " + WiFi.macAddress());
 | 
				
			||||||
 | 
					  // Clear the OLED display
 | 
				
			||||||
 | 
					  oled.clearDisplay();
 | 
				
			||||||
 | 
					  oled.display();
 | 
				
			||||||
 | 
					  // Test if we are in "Demo" mode. If the Rotary Push Button and
 | 
				
			||||||
 | 
					  // the "Trigger" button are held during boot the system will go
 | 
				
			||||||
 | 
					  // into demo mode. In demo mode no WiFi connection will be made
 | 
				
			||||||
 | 
					  // and no HTTP messages will be sent. If demo mode is detected
 | 
				
			||||||
 | 
					  // the system will cycle the addressable LED strip until both
 | 
				
			||||||
 | 
					  // buttons are released before continuing.
 | 
				
			||||||
 | 
					  if ( (digitalRead(ROTARYPBPIN) == LOW) && ((digitalRead(MESSAGETRIGGERPIN) == LOW) || !TRIGGERENABLED) ) {
 | 
				
			||||||
 | 
					    demoModeEnabled = true;
 | 
				
			||||||
 | 
					    short activeLED = 0;
 | 
				
			||||||
 | 
					    bool countingUp = true;
 | 
				
			||||||
 | 
					    oled.clearDisplay();
 | 
				
			||||||
 | 
					    oled.setCursor(0, 0);
 | 
				
			||||||
 | 
					    oled.setTextSize(2);
 | 
				
			||||||
 | 
					    oled.setTextColor(WHITE);
 | 
				
			||||||
 | 
					    oled.println("DEMO  MODE");
 | 
				
			||||||
 | 
					    oled.println(" DETECTED ");
 | 
				
			||||||
 | 
					    oled.println("----------");
 | 
				
			||||||
 | 
					    oled.println(" RELEASE! ");
 | 
				
			||||||
 | 
					    oled.display();
 | 
				
			||||||
 | 
					    // Wait until both buttons have been released before continuing
 | 
				
			||||||
 | 
					    // Cycle the LEDs like KITT while waiting :)
 | 
				
			||||||
 | 
					    while ( (digitalRead(ROTARYPBPIN) == LOW) || (digitalRead(MESSAGETRIGGERPIN) == LOW) ) {
 | 
				
			||||||
 | 
					      leds[activeLED] = CRGB::Red;
 | 
				
			||||||
 | 
					      FastLED.show();
 | 
				
			||||||
 | 
					      delay(200);
 | 
				
			||||||
 | 
					      leds[activeLED] = CRGB::Black;
 | 
				
			||||||
 | 
					      FastLED.show();
 | 
				
			||||||
 | 
					      if ( countingUp ) {
 | 
				
			||||||
 | 
					        activeLED += 1;
 | 
				
			||||||
 | 
					        if ( activeLED == NUMLEDS ) {
 | 
				
			||||||
 | 
					          countingUp = false;
 | 
				
			||||||
 | 
					          activeLED = NUMLEDS - 2;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        activeLED -= 1;
 | 
				
			||||||
 | 
					        if ( activeLED == -1 ) {
 | 
				
			||||||
 | 
					          countingUp = true;
 | 
				
			||||||
 | 
					          activeLED = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fill_solid(leds, NUMLEDS, CRGB::Black);
 | 
				
			||||||
 | 
					    FastLED.show();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Set the analog resolution for color dials to 10 bits (0-1023)
 | 
				
			||||||
 | 
					  analogReadResolution(10);
 | 
				
			||||||
 | 
					  // Join the network or start the captive portal AP for configuration
 | 
				
			||||||
 | 
					  // Turn the first LED blue while configuring WiFi so we know when it's done
 | 
				
			||||||
 | 
					  // Only do this if not in demo mode
 | 
				
			||||||
 | 
					  oled.clearDisplay();
 | 
				
			||||||
 | 
					  oled.setTextSize(2);
 | 
				
			||||||
 | 
					  oled.setTextColor(WHITE);
 | 
				
			||||||
 | 
					  oled.setCursor(0, 0);
 | 
				
			||||||
 | 
					  oled.println("CONNECTING");
 | 
				
			||||||
 | 
					  oled.println("    TO");
 | 
				
			||||||
 | 
					  oled.println("   WiFi");
 | 
				
			||||||
 | 
					  oled.println("..........");
 | 
				
			||||||
 | 
					  oled.display();
 | 
				
			||||||
 | 
					  fill_rainbow(leds, NUMLEDS, 0, 42);
 | 
				
			||||||
 | 
					  FastLED.show();
 | 
				
			||||||
 | 
					  if ( !demoModeEnabled ) {
 | 
				
			||||||
 | 
					    WiFiManager wifiManager;
 | 
				
			||||||
 | 
					    wifiManager.setAPCallback(configModeCallback);
 | 
				
			||||||
 | 
					    wifiManager.autoConnect("LEDChooser");
 | 
				
			||||||
 | 
					    ArduinoOTA
 | 
				
			||||||
 | 
					    .onStart([]() {
 | 
				
			||||||
 | 
					      String type;
 | 
				
			||||||
 | 
					      if (ArduinoOTA.getCommand() == U_FLASH)
 | 
				
			||||||
 | 
					        type = "sketch";
 | 
				
			||||||
 | 
					      else // U_SPIFFS
 | 
				
			||||||
 | 
					        type = "filesystem";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
 | 
				
			||||||
 | 
					      Serial.println("Start OTA updating " + type);
 | 
				
			||||||
 | 
					      oled.clearDisplay();
 | 
				
			||||||
 | 
					      oled.setTextColor(WHITE);
 | 
				
			||||||
 | 
					      oled.setCursor(0, 0);
 | 
				
			||||||
 | 
					      oled.println(" UPDATING ");
 | 
				
			||||||
 | 
					      oled.println(" FIRMWARE ");
 | 
				
			||||||
 | 
					      oled.println("          ");
 | 
				
			||||||
 | 
					      oled.display();
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .onEnd([]() {
 | 
				
			||||||
 | 
					      Serial.println("\nOTA Update Completed");
 | 
				
			||||||
 | 
					      oled.clearDisplay();
 | 
				
			||||||
 | 
					      oled.setTextColor(WHITE);
 | 
				
			||||||
 | 
					      oled.setCursor(0, 0);
 | 
				
			||||||
 | 
					      oled.println(" FIRMWARE ");
 | 
				
			||||||
 | 
					      oled.println("  UPDATE  ");
 | 
				
			||||||
 | 
					      oled.println(" COMPLETE ");
 | 
				
			||||||
 | 
					      oled.display();
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .onProgress([](unsigned int progress, unsigned int total) {
 | 
				
			||||||
 | 
					      Serial.printf("OTA Update Progress: %u%%\r", (progress / (total / 100)));
 | 
				
			||||||
 | 
					      oled.setCursor(40, 48);
 | 
				
			||||||
 | 
					      oled.print("    ");
 | 
				
			||||||
 | 
					      oled.display();
 | 
				
			||||||
 | 
					      oled.setCursor(40, 48);
 | 
				
			||||||
 | 
					      oled.print(progress / (total / 100));
 | 
				
			||||||
 | 
					      oled.print("%");
 | 
				
			||||||
 | 
					      oled.display();
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .onError([](ota_error_t error) {
 | 
				
			||||||
 | 
					      Serial.printf("OTA Update Error[%u]: ", error);
 | 
				
			||||||
 | 
					      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
 | 
				
			||||||
 | 
					      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
 | 
				
			||||||
 | 
					      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
 | 
				
			||||||
 | 
					      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
 | 
				
			||||||
 | 
					      else if (error == OTA_END_ERROR) Serial.println("End Failed");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    ArduinoOTA.begin();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // If in demo mode wait for 3 seconds to show
 | 
				
			||||||
 | 
					    // WiFi connection attempt on OLED and LEDs
 | 
				
			||||||
 | 
					    delay(3000);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  fill_solid(leds, NUMLEDS, CRGB::Black);
 | 
				
			||||||
 | 
					  FastLED.show();
 | 
				
			||||||
 | 
					  getColorPatterns();
 | 
				
			||||||
 | 
					  paintLEDs();
 | 
				
			||||||
 | 
					  populateOLED();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void loop() {
 | 
				
			||||||
 | 
					  // Check the state of the "trigger" button and debounce if needed
 | 
				
			||||||
 | 
					  unsigned short triggerCheck = digitalRead(MESSAGETRIGGERPIN);
 | 
				
			||||||
 | 
					  if ( triggerCheck != lastTriggerButtonState ) lastTriggerDebounceTime = millis();
 | 
				
			||||||
 | 
					  // If the button state has settled/debounced then take action
 | 
				
			||||||
 | 
					  if ( millis() > (lastTriggerDebounceTime + DEBOUNCEMS) ) {
 | 
				
			||||||
 | 
					    if ( triggerCheck != triggerButtonState ) {
 | 
				
			||||||
 | 
					      triggerButtonState = triggerCheck;
 | 
				
			||||||
 | 
					      // If the trigger button was released set the message tracker to false
 | 
				
			||||||
 | 
					      if ( triggerButtonState == HIGH ) triggerMessageSent = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  lastTriggerButtonState = triggerCheck;
 | 
				
			||||||
 | 
					  // Check the state of the "pattern mode" switch
 | 
				
			||||||
 | 
					  unsigned short colorModeCheck = digitalRead(COLORMODEPIN);
 | 
				
			||||||
 | 
					  if ( colorModeCheck != lastColorModeState ) lastColorModeDebounceTime = millis();
 | 
				
			||||||
 | 
					  // If the pattern mode switch state has settled/debounced then take action
 | 
				
			||||||
 | 
					  if ( millis() > (lastColorModeDebounceTime + DEBOUNCEMS) ) {
 | 
				
			||||||
 | 
					    if ( colorModeCheck != colorModeState ) {
 | 
				
			||||||
 | 
					      colorModeState = colorModeCheck;
 | 
				
			||||||
 | 
					      if ( colorModeState == LOW ) {
 | 
				
			||||||
 | 
					        paintLEDs();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      populateOLED();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  lastColorModeState = colorModeCheck;
 | 
				
			||||||
 | 
					  // Check the state of the RotaryPB and debounce if needed
 | 
				
			||||||
 | 
					  unsigned short rotaryPBCheck = digitalRead(ROTARYPBPIN);
 | 
				
			||||||
 | 
					  if ( rotaryPBCheck != lastRotaryPBState ) lastRPBDebounceTime = millis();
 | 
				
			||||||
 | 
					  // If the rotary PB state has settled/debounced then take action
 | 
				
			||||||
 | 
					  if ( millis() > (lastRPBDebounceTime + DEBOUNCEMS) ) {
 | 
				
			||||||
 | 
					    if ( rotaryPBCheck != rotaryPBState ) {
 | 
				
			||||||
 | 
					      rotaryPBState = rotaryPBCheck;
 | 
				
			||||||
 | 
					      if ( ((colorModeState == LOW) || !TRIGGERENABLED) && (rotaryPBState == LOW) ) {
 | 
				
			||||||
 | 
					        // Poll all the zone switches
 | 
				
			||||||
 | 
					        for ( int i=0; i<NUMZONES; i++ ) {
 | 
				
			||||||
 | 
					          zones[i].active = (digitalRead(zones[i].pin) == LOW) ? true : false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        populateOLED(true);
 | 
				
			||||||
 | 
					        if ( colorModeState == LOW ) {
 | 
				
			||||||
 | 
					          sendPatternMessage();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          sendColorMessage();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  lastRotaryPBState = rotaryPBCheck;
 | 
				
			||||||
 | 
					  // Only sample the dimmers and update LED colors every LEDUPDATEMS milliseconds
 | 
				
			||||||
 | 
					  // Or if the trigger button has been pressed and no message sent yet
 | 
				
			||||||
 | 
					  if ( (colorModeState == HIGH) && ((!triggerButtonState && !triggerMessageSent) || (millis() > (lastDimmerSample + LEDUPDATEMS))) ) {
 | 
				
			||||||
 | 
					    paintLEDs();
 | 
				
			||||||
 | 
					    lastDimmerSample = millis();
 | 
				
			||||||
 | 
					    // If the "trigger" button has been pressed, or the "toggle" switch for
 | 
				
			||||||
 | 
					    // continuous message sending is turned on then we should send a set color
 | 
				
			||||||
 | 
					    // messages to the back-end. A triggered message will only be sent once
 | 
				
			||||||
 | 
					    // per press of the button. Continuous messages will only be sent every
 | 
				
			||||||
 | 
					    // LEDUPDATEMS milliseconds (i.e. the same rate as the sampling)
 | 
				
			||||||
 | 
					    if ( !digitalRead(MESSAGETOGGLEPIN) || (!digitalRead(MESSAGETRIGGERPIN) && !triggerButtonState && !triggerMessageSent) ) {
 | 
				
			||||||
 | 
					      for ( int i=0; i<NUMZONES; i++ ) {
 | 
				
			||||||
 | 
					        zones[i].active = (digitalRead(zones[i].pin) == LOW) ? true : false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if ( !triggerButtonState && !triggerMessageSent ) populateOLED(true);
 | 
				
			||||||
 | 
					      sendColorMessage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    lastRed = red;
 | 
				
			||||||
 | 
					    lastGreen = green;
 | 
				
			||||||
 | 
					    lastBlue = blue;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Check if the rotary encoder has been turned and take action
 | 
				
			||||||
 | 
					  unsigned int currentEncoderIndex = getEncoderIndex();
 | 
				
			||||||
 | 
					  if ( (colorModeState == LOW) && (currentEncoderIndex != encoderIndex) ) {
 | 
				
			||||||
 | 
					    encoderIndex = currentEncoderIndex;
 | 
				
			||||||
 | 
					    populateOLED();
 | 
				
			||||||
 | 
					    if ( DEBUGMODE ) Serial.println("Encoder: " + String(encoderIndex));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Send state message to serial monitor port if DEBUGMODE is enabled
 | 
				
			||||||
 | 
					  if ( DEBUGMODE && (millis() > (lastDebugMessage + 1000)) ) {
 | 
				
			||||||
 | 
					    //Serial.println("Colors: " + String(red) + ", " + String(green) + ", " + String(blue) + ", " + String(getColorValue(REDPIN)));
 | 
				
			||||||
 | 
					    lastDebugMessage = millis();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // If we need to repopulate/repaint due to "pulse invert"
 | 
				
			||||||
 | 
					  if ( needRepopulate && (millis() > repopulateTime) ) {
 | 
				
			||||||
 | 
					    populateOLED();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if ( !demoModeEnabled ) ArduinoOTA.handle();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								test/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								test/README
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This directory is intended for PlatformIO Unit Testing and project tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unit Testing is a software testing method by which individual units of
 | 
				
			||||||
 | 
					source code, sets of one or more MCU program modules together with associated
 | 
				
			||||||
 | 
					control data, usage procedures, and operating procedures, are tested to
 | 
				
			||||||
 | 
					determine whether they are fit for use. Unit testing finds problems early
 | 
				
			||||||
 | 
					in the development cycle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					More information about PlatformIO Unit Testing:
 | 
				
			||||||
 | 
					- https://docs.platformio.org/page/plus/unit-testing.html
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user