Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <ESP8266WiFi.h>
- #include <WiFiUdp.h>
- #include <stdlib.h>
- // The GPIO pin numbers for the three colors. Make sure these match your wiring/schematic.
- #define GPIO_RED 13
- #define GPIO_GREEN 12
- #define GPIO_BLUE 15
- // The target ID of this device on the network if ID_SWITCHED is false
- // Commands sent to target ID 0 (zero) will be executed by ALL targets
- #define TARGET_ID_FIXED 1
- // If a 4-position dip switch is present and tied to 4 GPIO pins, set ID_SWITCHED to true and put the pin numbers in the ID_BIT_? settings
- #define ID_SWITCHED true
- #define ID_BIT_0 16
- #define ID_BIT_1 14
- #define ID_BIT_2 4
- #define ID_BIT_3 5
- // Used to turn debug serial output on/off
- #define DEBUG true
- // UDP Command values
- #define CMD_OFF 0x00
- #define CMD_SETLEVELS 0x01
- #define CMD_AUTOPATTERN 0x02
- #define CMD_AUTODISABLE 0x03
- // Auto-cycler state conditions
- #define AUTO_DISABLED 0x00
- #define AUTO_ACTIVE 0x01
- // Our WiFi credentials
- const char* ssid = "yourssid";
- const char* password = "yourpassword";
- // Struct for storing color value sets
- // Colors are obvious. restDuration is how long to rest on this color.
- struct colorTriplet {
- short red;
- short green;
- short blue;
- unsigned long restDuration;
- colorTriplet() {
- red = 0;
- green = 0;
- blue = 0;
- restDuration = 0;
- }
- };
- // This gets dynamically reset in setup() from the DIP switch or the #define at the top of the sketch so make sure this is set to 0 (zero)
- byte myTargetID = 0;
- // Variables for keeping the state of automatic color switching
- byte autoMode = AUTO_DISABLED;
- bool autoActive = false;
- // For storing automatic color values
- #define MAX_AUTO_COLORS 35
- unsigned int rampDuration;
- byte numAutoColors = 0;
- struct colorTriplet autoColors[MAX_AUTO_COLORS];
- byte autoColorTargetIndex = 0;
- short redStatic = 0;
- short greenStatic = 0;
- short blueStatic = 0;
- bool resting = false;
- // We're going to listen on port 6565
- WiFiUDP listener;
- // Variables to track message IDs so we don't process duplicate messages
- unsigned int lastMessageID = 0;
- unsigned int curMessageID = 0;
- void setup() {
- // Set the three color PWM pins to output
- pinMode(GPIO_RED, OUTPUT);
- pinMode(GPIO_GREEN, OUTPUT);
- pinMode(GPIO_BLUE, OUTPUT);
- // If ID_SWITCHED is true then set myTargetID from the dip switch, otherwise set it from TARGET_ID_FIXED
- if ( ID_SWITCHED ) {
- pinMode(ID_BIT_0, INPUT_PULLUP);
- pinMode(ID_BIT_1, INPUT_PULLUP);
- pinMode(ID_BIT_2, INPUT_PULLUP);
- pinMode(ID_BIT_3, INPUT_PULLUP);
- bitWrite(myTargetID, 0, ((digitalRead(ID_BIT_0) == HIGH) ? 1 : 0));
- bitWrite(myTargetID, 1, ((digitalRead(ID_BIT_1) == HIGH) ? 1 : 0));
- bitWrite(myTargetID, 2, ((digitalRead(ID_BIT_2) == HIGH) ? 1 : 0));
- bitWrite(myTargetID, 3, ((digitalRead(ID_BIT_3) == HIGH) ? 1 : 0));
- //pinMode(ID_BIT_1, INPUT);
- } else {
- myTargetID = TARGET_ID_FIXED;
- }
- // Start up the serial console output
- Serial.begin(115200);
- Serial.println("--- Serial Output Started ---");
- delay(10);
- // Show our ID!
- Serial.println();
- Serial.print("My target ID: ");
- Serial.println(myTargetID);
- // We start by connecting to a WiFi network
- Serial.println();
- Serial.println();
- Serial.print("Connecting to ");
- Serial.println(ssid);
- WiFi.begin(ssid, password);
- // Idle here until WiFi is connected. Blink the blue output while waiting
- bool blueState = false;
- while (WiFi.status() != WL_CONNECTED) {
- blueState = !blueState;
- if ( blueState ) {
- analogWrite(GPIO_BLUE, 255);
- } else {
- analogWrite(GPIO_BLUE, 0);
- }
- delay(500);
- Serial.print(".");
- }
- analogWrite(GPIO_BLUE, 0);
- Serial.println("");
- Serial.println("WiFi connected");
- Serial.println("IP address: ");
- Serial.println(WiFi.localIP());
- // Start listening for packets on port 6565 (yes, this should probably be defined at the top)
- listener.begin(6565);
- }
- bool processMessage() {
- struct colorTriplet colorBlank;
- byte command;
- unsigned long long targetBitField;
- Serial.println("Got UDP packet!");
- // Read in the packet data to buff (up to 1024 bytes which is way more than we would ever need)
- char buff[1024];
- listener.read(buff, 1024);
- listener.flush();
- // Parse out the command, target, and messageID fields
- memcpy(&command, (char*)buff, 1);
- memcpy(&targetBitField, (char*)buff + 1, 8);
- memcpy(&curMessageID, (char*)buff + 9, 4);
- // If we've seen the message before, skip it, otherwise update lastMessageID
- if ( curMessageID == lastMessageID ) return false;
- lastMessageID = curMessageID;
- // If this packet isn't destined for ID=0 (all targets) or ID=TARGET_ID (our ID) then stop processing
- if ( (myTargetID != 0 ) && (targetBitField != 0) && (bitRead(targetBitField, myTargetID - 1) != 1) ) return false;
- // Clear out the global autoColors[] array
- memset(autoColors, 0, sizeof(autoColors));
- // If we get a CMD_SETLEVELS then disable autoMode, set the new static values and ramp to that color
- if ( command == CMD_SETLEVELS ) {
- autoMode = AUTO_DISABLED;
- numAutoColors = 1;
- autoColorTargetIndex = 0;
- memcpy(&rampDuration, (char*)buff + 13, 4);
- memcpy(&autoColors[0].red, (char*)buff + 17, 1);
- memcpy(&autoColors[0].green, (char*)buff + 18, 1);
- memcpy(&autoColors[0].blue, (char*)buff + 19, 1);
- autoColors[0].red *= 4;
- autoColors[0].green *= 4;
- autoColors[0].blue *= 4;
- redStatic = autoColors[0].red;
- greenStatic = autoColors[0].green;
- blueStatic = autoColors[0].blue;
- if ( DEBUG ) Serial.print("Setting Levels: "); Serial.print(redStatic); Serial.print(", "); Serial.print(greenStatic); Serial.print(", "); Serial.print(blueStatic); Serial.print(", "); Serial.println(rampDuration);
- return true;
- }
- // If we get a CMD_AUTOPATTERN then build up the autoColors array and set autoMode to AUTO_ACTIVE
- if ( command == CMD_AUTOPATTERN ) {
- autoMode = AUTO_ACTIVE;
- autoColorTargetIndex = 0;
- memcpy(&rampDuration, (char*)buff + 13, 4);
- memcpy(&numAutoColors, (char*)buff + 17, 1);
- if ( numAutoColors > MAX_AUTO_COLORS ) numAutoColors = MAX_AUTO_COLORS;
- for ( int i=0; i<numAutoColors; i++ ) {
- memcpy(&autoColors[i].red, (char*)buff + 18 + (i*7), 1);
- memcpy(&autoColors[i].green, (char*)buff + 19 + (i*7), 1);
- memcpy(&autoColors[i].blue, (char*)buff + 20 + (i*7), 1);
- memcpy(&autoColors[i].restDuration, (char*)buff + 21 + (i*7), 4);
- autoColors[i].red *= 4;
- autoColors[i].green *= 4;
- autoColors[i].blue *= 4;
- if ( DEBUG ) Serial.print(numAutoColors); Serial.print(" Pattern Levels "); Serial.print(i); Serial.print(": "); Serial.print(autoColors[i].red); Serial.print(", "); Serial.print(autoColors[i].green); Serial.print(", "); Serial.print(autoColors[i].blue); Serial.print(", "); Serial.print(autoColors[i].restDuration); Serial.print(" Ramp="); Serial.println(rampDuration);
- }
- return true;
- }
- // If we get a CMD_AUTODISABLE then disable autoMode and ramp back to the last static color levels
- if ( command == CMD_AUTODISABLE ) {
- autoMode = AUTO_DISABLED;
- numAutoColors = 1;
- autoColorTargetIndex = 0;
- autoColors[0].red = redStatic;
- autoColors[0].green = greenStatic;
- autoColors[0].blue = blueStatic;
- rampDuration = 1000;
- if ( DEBUG ) Serial.print("Resetting Levels to static: "); Serial.print(redStatic); Serial.print(", "); Serial.print(greenStatic); Serial.print(", "); Serial.print(blueStatic); Serial.print(", "); Serial.println(rampDuration);
- return true;
- }
- // If we get a CMD_OFF then set the levels to zero and ensure autoMode is disabled
- // The rampDuration is set to the same value as the step value during ramping (yes, this should probably be a constant or a #define)
- if ( command == CMD_OFF ) {
- autoMode = AUTO_DISABLED;
- numAutoColors = 1;
- autoColorTargetIndex = 0;
- rampDuration = 10;
- autoColors[0].restDuration = 10000;
- redStatic = 0;
- greenStatic = 0;
- blueStatic = 0;
- if ( DEBUG ) Serial.println("Shutting off LEDs");
- return true;
- }
- return false;
- }
- void loop() {
- static short redTarget = 0, greenTarget = 0, blueTarget = 0;
- static short redInitial = 0, greenInitial = 0, blueInitial = 0;
- static short redLevel = 0, greenLevel = 0, blueLevel = 0;
- static bool newColor = false;
- static unsigned long nextDIPSample = 0;
- unsigned long nowMillis = millis();
- static unsigned long rampStartMillis;
- static unsigned long restingEndMillis;
- static unsigned long reportMillis = 0;
- static unsigned long repCount = 0;
- if ( nowMillis >= reportMillis ) {
- repCount++;
- //Serial.print("Still alive... ("); Serial.print(repCount); Serial.println(")");
- reportMillis = nowMillis + 1000;
- }
- // Check to see if we have a new packet waiting and parse it out if we do
- int packetSize = listener.parsePacket();
- if ( packetSize ) {
- if ( processMessage() ) {
- // Always reset newColor and resting states when we get a new UDP color command
- newColor = true;
- resting = false;
- }
- }
- if ( newColor ) {
- // If the incoming auto-color pattern (from a CMD_AUTOPATTERN) has a single all zero color, and autoMode is AUTO_ACTIVE then generate colors randomly instead of from the pattern
- if ( (autoMode == AUTO_ACTIVE) && (numAutoColors == 1) && (autoColors[0].red == 0) && (autoColors[0].green == 0) && (autoColors[0].blue == 0) ) {
- redTarget = random(1, 512);
- greenTarget = random(1, 512);
- blueTarget = random(1, 512);
- } else {
- redTarget = autoColors[autoColorTargetIndex].red;
- greenTarget = autoColors[autoColorTargetIndex].green;
- blueTarget = autoColors[autoColorTargetIndex].blue;
- }
- redInitial = redLevel;
- greenInitial = greenLevel;
- blueInitial = blueLevel;
- newColor = false;
- rampStartMillis = nowMillis;
- if ( DEBUG ) Serial.print("Switching to new color: "); Serial.print(" C="); Serial.print(redInitial); Serial.print(","); Serial.print(greenInitial); Serial.print(","); Serial.print(blueInitial); Serial.print(" T="); Serial.print(redTarget); Serial.print(","); Serial.print(greenTarget); Serial.print(","); Serial.print(blueTarget); Serial.print(" Index="); Serial.println(autoColorTargetIndex);
- }
- if ( (redLevel != redTarget) || (greenLevel != greenTarget) || (blueLevel != blueTarget) ) {
- // Calculate the current rampInterval (how many milliseconds between start of ramp and now)
- unsigned long rampInterval = nowMillis - rampStartMillis;
- // If nowMillis wrapped around the max INT32 we will just go straight to the last iteration of the ramp
- if ( rampInterval > rampDuration ) rampInterval = rampDuration;
- // If we aren't at the target values yet, map the current number of milliseconds into the ramp (rampInterval) to the (color)Initial -> (color)Target values
- if ( redLevel != redTarget ) {
- redLevel = map(rampInterval, 1, rampDuration, redInitial, redTarget);
- if ( (redLevel == redTarget) || ((nowMillis % 10) == 0) ) analogWrite(GPIO_RED, redLevel);
- }
- if ( greenLevel != greenTarget ) {
- greenLevel = map(rampInterval, 1, rampDuration, greenInitial, greenTarget);
- if ( (greenLevel == greenTarget) || ((nowMillis % 10) == 0) ) analogWrite(GPIO_GREEN, greenLevel);
- }
- if ( blueLevel != blueTarget ) {
- blueLevel = map(rampInterval, 1, rampDuration, blueInitial, blueTarget);
- if ( (blueLevel == blueTarget) || ((nowMillis % 10) == 0) ) analogWrite(GPIO_BLUE, blueLevel);
- }
- // If all the colors are at their targets and we aren't resting, then start resting
- } else if ( !resting ) {
- resting = true;
- restingEndMillis = nowMillis + autoColors[autoColorTargetIndex].restDuration;
- if ( DEBUG ) Serial.print("Now resting for: "); Serial.print(autoColors[autoColorTargetIndex].restDuration); Serial.print(" on "); Serial.println(autoColorTargetIndex);
- // If we are resting and the restingEndMillis passes then it is time to ramp to the next color IF AND ONLY IF we are in a pattern (i.e. don't keep ramping if we're on a static color)
- } else if ( (nowMillis >= restingEndMillis) && (autoMode == AUTO_ACTIVE) ) {
- resting = false;
- newColor = true;
- autoColorTargetIndex = (autoColorTargetIndex < (numAutoColors - 1)) ? autoColorTargetIndex + 1 : 0;
- }
- // If the DIP switches change, go ahead and adjust myTargetID accordingly. Saves having to restart.
- // In order to save clock cycles this is only done every 10 seconds.
- if ( ID_SWITCHED && (nowMillis >= nextDIPSample) ) {
- byte newVal = 0;
- bitWrite(newVal, 0, ((digitalRead(ID_BIT_0) == HIGH) ? 1 : 0));
- bitWrite(newVal, 1, ((digitalRead(ID_BIT_1) == HIGH) ? 1 : 0));
- bitWrite(newVal, 2, ((digitalRead(ID_BIT_2) == HIGH) ? 1 : 0));
- bitWrite(newVal, 3, ((digitalRead(ID_BIT_3) == HIGH) ? 1 : 0));
- if ( myTargetID != newVal ) {
- myTargetID = newVal;
- Serial.print("New Target ID Detected: ");
- Serial.println(myTargetID);
- nextDIPSample = nowMillis + 10000; // Sample the DIP switches every 10 seconds
- }
- }
- yield();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement