PlowmanPlow

ARDColors

Mar 2nd, 2016
76
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <ESP8266WiFi.h>
  2. #include <WiFiUdp.h>
  3. #include <stdlib.h>
  4.  
  5. // The GPIO pin numbers for the three colors. Make sure these match your wiring/schematic.
  6. #define GPIO_RED 13
  7. #define GPIO_GREEN 12
  8. #define GPIO_BLUE 15
  9.  
  10. // The target ID of this device on the network if ID_SWITCHED is false
  11. // Commands sent to target ID 0 (zero) will be executed by ALL targets
  12. #define TARGET_ID_FIXED 1
  13.  
  14. // 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
  15. #define ID_SWITCHED true
  16. #define ID_BIT_0 16
  17. #define ID_BIT_1 14
  18. #define ID_BIT_2 4
  19. #define ID_BIT_3 5
  20.  
  21. // Used to turn debug serial output on/off
  22. #define DEBUG true
  23.  
  24. // UDP Command values
  25. #define CMD_OFF         0x00
  26. #define CMD_SETLEVELS   0x01
  27. #define CMD_AUTOPATTERN 0x02
  28. #define CMD_AUTODISABLE 0x03
  29.  
  30. // Auto-cycler state conditions
  31. #define AUTO_DISABLED   0x00
  32. #define AUTO_ACTIVE     0x01
  33.  
  34. // Our WiFi credentials
  35. const char* ssid     = "yourssid";
  36. const char* password = "yourpassword";
  37.  
  38. // Struct for storing color value sets
  39. // Colors are obvious. restDuration is how long to rest on this color.
  40. struct colorTriplet {
  41.    short red;
  42.    short green;
  43.    short blue;
  44.    unsigned long restDuration;
  45.  
  46.    colorTriplet() {
  47.       red = 0;
  48.       green = 0;
  49.       blue = 0;
  50.       restDuration = 0;
  51.    }
  52. };
  53.  
  54. // 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)
  55. byte myTargetID = 0;
  56.  
  57. // Variables for keeping the state of automatic color switching
  58. byte autoMode = AUTO_DISABLED;
  59. bool autoActive = false;
  60.  
  61. // For storing automatic color values
  62. #define MAX_AUTO_COLORS 35
  63. unsigned int rampDuration;
  64. byte numAutoColors = 0;
  65. struct colorTriplet autoColors[MAX_AUTO_COLORS];
  66. byte autoColorTargetIndex = 0;
  67. short redStatic = 0;
  68. short greenStatic = 0;
  69. short blueStatic = 0;
  70. bool resting = false;
  71.  
  72. // We're going to listen on port 6565
  73. WiFiUDP listener;
  74.  
  75. // Variables to track message IDs so we don't process duplicate messages
  76. unsigned int lastMessageID = 0;
  77. unsigned int curMessageID = 0;
  78.  
  79. void setup() {
  80.    // Set the three color PWM pins to output
  81.    pinMode(GPIO_RED, OUTPUT);
  82.    pinMode(GPIO_GREEN, OUTPUT);
  83.    pinMode(GPIO_BLUE, OUTPUT);
  84.  
  85.    // If ID_SWITCHED is true then set myTargetID from the dip switch, otherwise set it from TARGET_ID_FIXED
  86.    if ( ID_SWITCHED ) {
  87.       pinMode(ID_BIT_0, INPUT_PULLUP);
  88.       pinMode(ID_BIT_1, INPUT_PULLUP);
  89.       pinMode(ID_BIT_2, INPUT_PULLUP);
  90.       pinMode(ID_BIT_3, INPUT_PULLUP);
  91.       bitWrite(myTargetID, 0, ((digitalRead(ID_BIT_0) == HIGH) ? 1 : 0));
  92.       bitWrite(myTargetID, 1, ((digitalRead(ID_BIT_1) == HIGH) ? 1 : 0));
  93.       bitWrite(myTargetID, 2, ((digitalRead(ID_BIT_2) == HIGH) ? 1 : 0));
  94.       bitWrite(myTargetID, 3, ((digitalRead(ID_BIT_3) == HIGH) ? 1 : 0));
  95.       //pinMode(ID_BIT_1, INPUT);
  96.    } else {
  97.       myTargetID = TARGET_ID_FIXED;
  98.    }
  99.  
  100.    // Start up the serial console output
  101.    Serial.begin(115200);
  102.    Serial.println("--- Serial Output Started ---");
  103.    delay(10);
  104.  
  105.    // Show our ID!
  106.    Serial.println();
  107.    Serial.print("My target ID: ");
  108.    Serial.println(myTargetID);
  109.    
  110.    // We start by connecting to a WiFi network
  111.    Serial.println();
  112.    Serial.println();
  113.    Serial.print("Connecting to ");
  114.    Serial.println(ssid);
  115.  
  116.    WiFi.begin(ssid, password);
  117.  
  118.    // Idle here until WiFi is connected. Blink the blue output while waiting
  119.    bool blueState = false;
  120.    while (WiFi.status() != WL_CONNECTED) {
  121.      blueState = !blueState;
  122.      if ( blueState ) {
  123.         analogWrite(GPIO_BLUE, 255);
  124.      } else {
  125.         analogWrite(GPIO_BLUE, 0);
  126.      }
  127.      delay(500);
  128.      Serial.print(".");
  129.    }
  130.    analogWrite(GPIO_BLUE, 0);
  131.  
  132.    Serial.println("");
  133.    Serial.println("WiFi connected");  
  134.    Serial.println("IP address: ");
  135.    Serial.println(WiFi.localIP());
  136.  
  137.    // Start listening for packets on port 6565 (yes, this should probably be defined at the top)
  138.    listener.begin(6565);
  139. }
  140.  
  141. bool processMessage() {
  142.    struct colorTriplet colorBlank;
  143.    byte command;
  144.    unsigned long long targetBitField;
  145.    
  146.    Serial.println("Got UDP packet!");
  147.    
  148.    // Read in the packet data to buff (up to 1024 bytes which is way more than we would ever need)
  149.    char buff[1024];
  150.    listener.read(buff, 1024);
  151.    listener.flush();
  152.  
  153.    // Parse out the command, target, and messageID fields
  154.    memcpy(&command, (char*)buff, 1);
  155.    memcpy(&targetBitField, (char*)buff + 1, 8);
  156.    memcpy(&curMessageID, (char*)buff + 9, 4);
  157.  
  158.    // If we've seen the message before, skip it, otherwise update lastMessageID
  159.    if ( curMessageID == lastMessageID ) return false;
  160.    lastMessageID = curMessageID;
  161.  
  162.    // If this packet isn't destined for ID=0 (all targets) or ID=TARGET_ID (our ID) then stop processing
  163.    if ( (myTargetID != 0 ) && (targetBitField != 0) && (bitRead(targetBitField, myTargetID - 1) != 1) ) return false;
  164.  
  165.    // Clear out the global autoColors[] array
  166.    memset(autoColors, 0, sizeof(autoColors));
  167.  
  168.    // If we get a CMD_SETLEVELS then disable autoMode, set the new static values and ramp to that color
  169.    if ( command == CMD_SETLEVELS ) {
  170.       autoMode = AUTO_DISABLED;
  171.       numAutoColors = 1;
  172.       autoColorTargetIndex = 0;
  173.       memcpy(&rampDuration, (char*)buff + 13, 4);
  174.       memcpy(&autoColors[0].red, (char*)buff + 17, 1);
  175.       memcpy(&autoColors[0].green, (char*)buff + 18, 1);
  176.       memcpy(&autoColors[0].blue, (char*)buff + 19, 1);
  177.       autoColors[0].red *= 4;
  178.       autoColors[0].green *= 4;
  179.       autoColors[0].blue *= 4;
  180.       redStatic = autoColors[0].red;
  181.       greenStatic = autoColors[0].green;
  182.       blueStatic = autoColors[0].blue;
  183.       if ( DEBUG ) Serial.print("Setting Levels: "); Serial.print(redStatic); Serial.print(", "); Serial.print(greenStatic); Serial.print(", "); Serial.print(blueStatic); Serial.print(", "); Serial.println(rampDuration);
  184.       return true;
  185.    }
  186.  
  187.    // If we get a CMD_AUTOPATTERN then build up the autoColors array and set autoMode to AUTO_ACTIVE
  188.    if ( command == CMD_AUTOPATTERN ) {
  189.       autoMode = AUTO_ACTIVE;
  190.       autoColorTargetIndex = 0;
  191.       memcpy(&rampDuration, (char*)buff + 13, 4);
  192.       memcpy(&numAutoColors, (char*)buff + 17, 1);
  193.       if ( numAutoColors > MAX_AUTO_COLORS ) numAutoColors = MAX_AUTO_COLORS;
  194.       for ( int i=0; i<numAutoColors; i++ ) {
  195.          memcpy(&autoColors[i].red, (char*)buff + 18 + (i*7), 1);
  196.          memcpy(&autoColors[i].green, (char*)buff + 19 + (i*7), 1);
  197.          memcpy(&autoColors[i].blue, (char*)buff + 20 + (i*7), 1);
  198.          memcpy(&autoColors[i].restDuration, (char*)buff + 21 + (i*7), 4);
  199.          autoColors[i].red *= 4;
  200.          autoColors[i].green *= 4;
  201.          autoColors[i].blue *= 4;
  202.          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);
  203.       }
  204.       return true;
  205.    }
  206.  
  207.    // If we get a CMD_AUTODISABLE then disable autoMode and ramp back to the last static color levels
  208.    if ( command == CMD_AUTODISABLE ) {
  209.       autoMode = AUTO_DISABLED;
  210.       numAutoColors = 1;
  211.       autoColorTargetIndex = 0;
  212.       autoColors[0].red = redStatic;
  213.       autoColors[0].green = greenStatic;
  214.       autoColors[0].blue = blueStatic;
  215.       rampDuration = 1000;
  216.       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);
  217.       return true;
  218.    }
  219.  
  220.    // If we get a CMD_OFF then set the levels to zero and ensure autoMode is disabled
  221.    // The rampDuration is set to the same value as the step value during ramping (yes, this should probably be a constant or a #define)
  222.    if ( command == CMD_OFF ) {
  223.       autoMode = AUTO_DISABLED;
  224.       numAutoColors = 1;
  225.       autoColorTargetIndex = 0;
  226.       rampDuration = 10;
  227.       autoColors[0].restDuration = 10000;
  228.       redStatic = 0;
  229.       greenStatic = 0;
  230.       blueStatic = 0;
  231.       if ( DEBUG ) Serial.println("Shutting off LEDs");
  232.       return true;
  233.    }
  234.    
  235.    return false;
  236. }
  237.  
  238. void loop() {
  239.    static short redTarget = 0, greenTarget = 0, blueTarget = 0;
  240.    static short redInitial = 0, greenInitial = 0, blueInitial = 0;
  241.    static short redLevel = 0, greenLevel = 0, blueLevel = 0;
  242.    static bool newColor = false;
  243.    static unsigned long nextDIPSample = 0;
  244.    unsigned long nowMillis = millis();
  245.    static unsigned long rampStartMillis;
  246.    static unsigned long restingEndMillis;
  247.    static unsigned long reportMillis = 0;
  248.    static unsigned long repCount = 0;
  249.  
  250.    if ( nowMillis >= reportMillis ) {
  251.       repCount++;
  252.       //Serial.print("Still alive... ("); Serial.print(repCount); Serial.println(")");
  253.       reportMillis = nowMillis + 1000;
  254.    }
  255.  
  256.    // Check to see if we have a new packet waiting and parse it out if we do
  257.    int packetSize = listener.parsePacket();
  258.    if ( packetSize ) {
  259.       if ( processMessage() ) {
  260.          // Always reset newColor and resting states when we get a new UDP color command
  261.          newColor = true;
  262.          resting = false;
  263.       }
  264.    }
  265.  
  266.    if ( newColor ) {
  267.       // 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
  268.       if ( (autoMode == AUTO_ACTIVE) && (numAutoColors == 1) && (autoColors[0].red == 0) && (autoColors[0].green == 0) && (autoColors[0].blue == 0) ) {
  269.          redTarget = random(1, 512);
  270.          greenTarget = random(1, 512);
  271.          blueTarget = random(1, 512);
  272.       } else {
  273.          redTarget = autoColors[autoColorTargetIndex].red;
  274.          greenTarget = autoColors[autoColorTargetIndex].green;
  275.          blueTarget = autoColors[autoColorTargetIndex].blue;
  276.       }
  277.       redInitial = redLevel;
  278.       greenInitial = greenLevel;
  279.       blueInitial = blueLevel;
  280.       newColor = false;
  281.       rampStartMillis = nowMillis;
  282.       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);
  283.    }
  284.  
  285.    if ( (redLevel != redTarget) || (greenLevel != greenTarget) || (blueLevel != blueTarget) ) {
  286.       // Calculate the current rampInterval (how many milliseconds between start of ramp and now)
  287.       unsigned long rampInterval = nowMillis - rampStartMillis;
  288.  
  289.       // If nowMillis wrapped around the max INT32 we will just go straight to the last iteration of the ramp
  290.       if ( rampInterval > rampDuration ) rampInterval = rampDuration;
  291.  
  292.       // 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
  293.       if ( redLevel != redTarget ) {
  294.          redLevel = map(rampInterval, 1, rampDuration, redInitial, redTarget);
  295.          if ( (redLevel == redTarget) || ((nowMillis % 10) == 0) ) analogWrite(GPIO_RED, redLevel);
  296.       }
  297.       if ( greenLevel != greenTarget ) {
  298.          greenLevel = map(rampInterval, 1, rampDuration, greenInitial, greenTarget);
  299.          if ( (greenLevel == greenTarget) || ((nowMillis % 10) == 0) ) analogWrite(GPIO_GREEN, greenLevel);
  300.       }
  301.       if ( blueLevel != blueTarget ) {
  302.          blueLevel = map(rampInterval, 1, rampDuration, blueInitial, blueTarget);
  303.          if ( (blueLevel == blueTarget) || ((nowMillis % 10) == 0) ) analogWrite(GPIO_BLUE, blueLevel);
  304.       }
  305.    // If all the colors are at their targets and we aren't resting, then start resting
  306.    } else if ( !resting ) {
  307.       resting = true;
  308.       restingEndMillis = nowMillis + autoColors[autoColorTargetIndex].restDuration;
  309.       if ( DEBUG ) Serial.print("Now resting for: "); Serial.print(autoColors[autoColorTargetIndex].restDuration); Serial.print(" on "); Serial.println(autoColorTargetIndex);
  310.    // 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)
  311.    } else if ( (nowMillis >= restingEndMillis) && (autoMode == AUTO_ACTIVE) ) {
  312.       resting = false;
  313.       newColor = true;
  314.       autoColorTargetIndex = (autoColorTargetIndex < (numAutoColors - 1)) ? autoColorTargetIndex + 1 : 0;
  315.    }
  316.  
  317.    // If the DIP switches change, go ahead and adjust myTargetID accordingly. Saves having to restart.
  318.    // In order to save clock cycles this is only done every 10 seconds.
  319.    if ( ID_SWITCHED && (nowMillis >= nextDIPSample) ) {
  320.       byte newVal = 0;
  321.       bitWrite(newVal, 0, ((digitalRead(ID_BIT_0) == HIGH) ? 1 : 0));
  322.       bitWrite(newVal, 1, ((digitalRead(ID_BIT_1) == HIGH) ? 1 : 0));
  323.       bitWrite(newVal, 2, ((digitalRead(ID_BIT_2) == HIGH) ? 1 : 0));
  324.       bitWrite(newVal, 3, ((digitalRead(ID_BIT_3) == HIGH) ? 1 : 0));
  325.       if ( myTargetID != newVal ) {
  326.          myTargetID = newVal;
  327.          Serial.print("New Target ID Detected: ");
  328.          Serial.println(myTargetID);
  329.          nextDIPSample = nowMillis + 10000; // Sample the DIP switches every 10 seconds
  330.       }
  331.    }
  332.  
  333.    yield();
  334. }
RAW Paste Data