From e8dea133fc57da78dd9fe41b6a648f9829bca94f Mon Sep 17 00:00:00 2001 From: Jeffrey Bush Date: Thu, 10 Jan 2019 17:52:52 -0500 Subject: [PATCH 1/3] Adding better color choice based on HSV color system as mentioned in #4 --- src/touch_light.ino | 49 +++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/touch_light.ino b/src/touch_light.ino index 93d2d38..f983b1b 100644 --- a/src/touch_light.ino +++ b/src/touch_light.ino @@ -2,9 +2,11 @@ * Project: touch_light * Description: A touch light that syncs with other touch lights. Adapted from * http://www.instructables.com/id/Networked-RGB-Wi-Fi-Decorative-Touch-Lights/ - * Author: Patrick Blesi + * Original Author: Patrick Blesi * Date: 2017-12-09 * + * Modifications By: Jeff Bush (coderforlife) + * Date: 2018-12-21 */ #include "neopixel.h" @@ -576,27 +578,26 @@ void updateNeoPixels(uint32_t color) { // Wheel //------------------------------------------------------------ -uint32_t wheelColor(byte WheelPos, byte iBrightness) { - float R, G, B; - float brightness = iBrightness / 255.0; - - if (WheelPos < 85) { - R = WheelPos * 3; - G = 255 - WheelPos * 3; - B = 0; - } else if (WheelPos < 170) { - WheelPos -= 85; - R = 255 - WheelPos * 3; - G = 0; - B = WheelPos * 3; - } else { - WheelPos -= 170; - R = 0; - G = WheelPos * 3; - B = 255 - WheelPos * 3; - } - R = R * brightness + .5; - G = G * brightness + .5; - B = B * brightness + .5; - return strip.Color((byte) R,(byte) G,(byte) B); +byte scale(byte x, float scale) { + return (byte)(x * scale + .5); +} + +// Converts HSV color to RGB color +// hue is from 0 to 255 around the circle +// saturation is fixed to max +// value (brightness) is from 0 to 255 +uint32_t wheelColor(byte hue, byte value) { + //hue %= 256; + //if (hue < 0) { hue += 256; } + int H6 = 6*(int)hue; + byte R = 0, G = 0, B = 0; + // each 1/6 of a circle (42.5 is 1/6 of 255) + if (hue < 43) { R = 255; G = H6; } + else if (hue < 86) { R = 510-H6; G = 255; } + else if (hue < 128) { G = 255; B = H6-510; } + else if (hue < 171) { G = 1020-H6; B = 255; } + else if (hue < 213) { R = H6-1020; B = 255; } + else { R = 255; B = 1530-H6; } + float brightness = value / 255.0; + return strip.Color(scale(R, brightness), scale(G, brightness), scale(B, brightness)); } From fc7ba0d09d18f7165b7bef39447e79eca6d0546d Mon Sep 17 00:00:00 2001 From: Jeffrey Bush Date: Thu, 10 Jan 2019 17:58:05 -0500 Subject: [PATCH 2/3] Minor improvements to code quality and efficiency. --- src/touch_light.ino | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/touch_light.ino b/src/touch_light.ino index f983b1b..0b4ada8 100644 --- a/src/touch_light.ino +++ b/src/touch_light.ino @@ -21,8 +21,7 @@ String touchEventName = "touch_event"; -#define NUM_PARTICLES 4 // number of touch lights in your group -// Number each Filimin starting at 1. +// Number each starting at 1 String particleId[] = { "", // 0 "330022001547353236343033", // pblesi @@ -39,6 +38,9 @@ int particleColors[] = { 131 // Purple }; + +#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0]) + // TWEAKABLE VALUES FOR CAP SENSING. THE BELOW VALUES WORK WELL AS A STARTING PLACE: // BASELINE_VARIANCE: The higher the number the less the baseline is affected by // current readings. (was 4) @@ -111,7 +113,7 @@ int rPin = D3; unsigned char myId = 0; int currentEvent = tEVENT_NONE; -int eventTime = Time.now(); +int eventTime = 0; int eventTimePrecision = random(INT_MAX); int initColor = 0; @@ -167,7 +169,7 @@ void setup() pinMode(sPin, OUTPUT); attachInterrupt(rPin, touchSense, RISING); - myId = getMyId(particleId, NUM_PARTICLES); + myId = getMyId(particleId, ARRAY_SIZE(particleId)); flashWhite(&strip); @@ -258,19 +260,17 @@ void traverseColorWheel(Adafruit_NeoPixel* strip) { strip->setPixelColor(j, color); strip->show(); } - delay(1); } } void fade(Adafruit_NeoPixel* strip) { int numPixels = strip->numPixels(); - for (int j = 255; j >= 0; j--) { + for (int j = 255; j >= 0; j-=2) { uint32_t color = wheelColor(255, j); for (byte k = 0; k < numPixels; k++) { strip->setPixelColor(k, color); strip->show(); } - delay(1); } } @@ -418,8 +418,8 @@ void handleTouchEvent(const char *event, const char *data) { Particle.publish("touch_response", response, 61, PRIVATE); } - if (deviceId == myId) return; - if (serverEventTime < eventTime) return; + if (deviceId == myId) { return; } + if (serverEventTime < eventTime) { return; } // Race condition brought colors out of sync if ( serverEventTime == eventTime && @@ -431,7 +431,7 @@ void handleTouchEvent(const char *event, const char *data) { changeState(ATTACK, REMOTE_CHANGE); return; } - if (serverEventTime == eventTime && serverEventTimePrecision <= eventTimePrecision) return; + if (serverEventTime == eventTime && serverEventTimePrecision <= eventTimePrecision) { return; } // Valid remote update setEvent(serverEvent, serverEventTime, serverEventTimePrecision); @@ -558,14 +558,13 @@ int getCurrentColor(int finalColor, int initColor, int colorLoopCount) { } int calcColorChange(int currentColor, int finalColor) { - int colorChange = finalColor - currentColor; - int direction = (colorChange < 0) * 2 - 1; - colorChange += direction * (abs(colorChange) > 127) * 256; - return colorChange; + int d = currentColor - finalColor; + return abs(d) > 127 ? d : -d; } void updateNeoPixels(uint32_t color) { - for(char i = 0; i < strip.numPixels(); i++) { + uint16_t n = strip.numPixels(); + for (char i = 0; i < n; i++) { strip.setPixelColor(i, color); } strip.show(); From 346f0d61d780a25b8b0a6e7e052963b8ecf40fa2 Mon Sep 17 00:00:00 2001 From: Jeffrey Bush Date: Thu, 10 Jan 2019 18:01:54 -0500 Subject: [PATCH 3/3] Changing the dimming of the light. There are additional stages to dimming and it never goes completely off so that there is always a reference to the last color. This could be improved futher by making the system generalized so it is easy to change in the code. --- src/touch_light.ino | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/touch_light.ino b/src/touch_light.ino index 0b4ada8..771b7d1 100644 --- a/src/touch_light.ino +++ b/src/touch_light.ino @@ -63,13 +63,15 @@ const int minMaxColorDiffs[2][2] = { // END VALUE, TIME // 160 is approximately 1 second -const long envelopes[6][2] = { - {0, 0}, // NOT USED - {255, 30}, // ATTACK - {200, 240}, // DECAY - {200, 1000}, // SUSTAIN - {150, 60}, // RELEASE1 - {0, 1000000} // RELEASE2 (65535 is about 6'45") +const long envelopes[8][2] = { + {0, 0}, // NOT USED + {255, 30}, // ATTACK ~200 ms + {205, 240}, // DECAY ~1.5 sec + {205, 1000}, // SUSTAIN ~6.25 sec + {155, 60}, // RELEASE1 ~400 ms to go from ~80% brightness to ~60% brightness + {40, 300000}, // RELEASE2 ~30 min to go from ~60% brightness to ~15% brightness + {10, 300000}, // RELEASE3 ~30 min to go from ~15% brightness to ~4% brightness + {10, 0}, // HOLD will be held at ~4% brightness forever }; #define PERIODIC_UPDATE_TIME 5 // seconds @@ -83,7 +85,9 @@ const long envelopes[6][2] = { #define SUSTAIN 3 #define RELEASE1 4 #define RELEASE2 5 -#define OFF 6 +#define RELEASE3 6 +#define HOLD 7 +#define OFF 8 #define LOCAL_CHANGE 0 #define REMOTE_CHANGE 1 @@ -527,9 +531,19 @@ void updateState() { break; case RELEASE2: if (loopCount >= envelopes[RELEASE2][TIME]) { - changeState(OFF, LOCAL_CHANGE); + changeState(RELEASE3, LOCAL_CHANGE); + } + break; + case RELEASE3: + if (loopCount >= envelopes[RELEASE3][TIME]) { + changeState(HOLD, LOCAL_CHANGE); } break; + case HOLD: + /*if (loopCount >= envelopes[HOLD][TIME]) { + changeState(OFF, LOCAL_CHANGE); + }*/ + break; } currentBrightness = getCurrentBrightness(state, initBrightness, loopCount); @@ -545,6 +559,7 @@ void updateState() { int getCurrentBrightness(unsigned char state, int initBrightness, int loopCount) { if (state == OFF) return 0; + if (envelopes[state][TIME] == 0) return envelopes[state][END_VALUE]; int brightnessDistance = envelopes[state][END_VALUE] - initBrightness; int brightnessDistanceXElapsedTime = brightnessDistance * loopCount / envelopes[state][TIME]; return min(255, max(0, initBrightness + brightnessDistanceXElapsedTime));