Skip to content

Instantly share code, notes, and snippets.

@telent
Created December 1, 2020 17:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save telent/7c839170a89fe8bee30ee4d992416f32 to your computer and use it in GitHub Desktop.
Save telent/7c839170a89fe8bee30ee4d992416f32 to your computer and use it in GitHub Desktop.
#include <Adafruit_NeoPixel.h>
#include <math.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "wifi-config.h"
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(SSID, WPA_PASSPHRASE);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
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...");
// Create a random client ID
String clientId = "neoxmas-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str(),
MQTT_USERNAME, MQTT_PASSWORD )) {
Serial.println("connected");
client.subscribe("sensors/neoxmas");
Serial.print(client.state());
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
#define PIN 4 // https://chewett.co.uk/blog/1066/pin-numbering-for-wemos-d1-mini-esp8266/
#define STRIP_LENGTH 150
Adafruit_NeoPixel strip = Adafruit_NeoPixel(STRIP_LENGTH, PIN, NEO_GRB + NEO_KHZ800);
float zero = 0;
int rotation_speed = -20;
int brightness = 18;
struct hsv {
float h,s,v;
};
struct loc {
int offset;
struct hsv color;
};
// byte for loc, 3 bytes for h,s,v = 4 bytes per loc
// max message size inc headers is 256 bytes so ~ 64 points
struct loc initial_config[] = {
(struct loc){ 0, (struct hsv){ 0, 1, 0.10} },
(struct loc){ 10, (struct hsv){ 0, 0.8, 0.7} },
(struct loc){ 20, (struct hsv){ 0, 1, 0.10} },
(struct loc){ 50, (struct hsv){ 0, 1, 0.1} },
(struct loc){ 60, (struct hsv){ 120, 0.8, 0.7} },
(struct loc){ 70, (struct hsv){ 0, 1, 0.1} },
(struct loc){ 100, (struct hsv){ 0, 1, 0.1} },
(struct loc){ 110, (struct hsv){ 240, 0.8, 0.7} },
(struct loc){ 120, (struct hsv){ 0, 1, 0.5} },
(struct loc){ 999, (struct hsv){ 350, 0, 0} },
};
struct loc locations[256/4];
void mqtt_receive_cb(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
int loc=0;
rotation_speed = (int)payload[0];
for(int i=1; i< length; loc++, i+=4) {
locations[loc].offset = payload[i];
locations[loc].color.h = payload[i+1] * 360.0 / 256;
locations[loc].color.s = payload[i+2] / 256.0;
locations[loc].color.v = payload[i+3] / 256.0;
}
locations[loc].offset = -1;
for (int i = 0; i < length; i++) {
Serial.print((int)payload[i]);
Serial.print(" ");
}
Serial.println();
set_strip(locations);
}
void set_from_hsv(byte * rgb, struct hsv *hsv) {
float chroma = (1 - abs(2 * hsv->v - 1)) * hsv->s;
float h = hsv->h/60;
Serial.println(h);
float x = (1 - abs((int)h % 2 - 1)) * chroma;
float r, g, b;
r = g = b = 0;
if(h < 1) {
r=chroma; g=x; b=0;
} else if(h < 2) {
r = x; g=chroma; b=0;
} else if(h < 3) {
r=0;
g=chroma;
b=x;
} else if(h < 4) {
r=0;
g=x;
b=chroma;
} else if(h < 5) {
r=x; g=0; b=chroma;
} else {
r=chroma;
g=0;
b=x;
}
float m = hsv->v - chroma/2;
rgb[0] = (byte) brightness*(r+m);
rgb[1] = (byte) brightness*(g+m);
rgb[2] = (byte) brightness*(b+m);
}
byte lights[STRIP_LENGTH][3];
struct hsv *interpolate(struct hsv *start, struct hsv *target,
int width, int remaining) {
float proportion = 1.0 * remaining/width;
static hsv r;
hsv *result = &r;
result->h = start->h*(proportion) + target->h*(1-proportion);
result->s = start->s*(proportion) + target->s*(1-proportion);
result->v = start->v*(proportion) + target->v*(1-proportion);
return result;
}
void set_strip(struct loc targets[]) {
struct loc *target = targets;
int i = target->offset;
struct hsv * prev_color = &(target->color);
while(i< STRIP_LENGTH) {
target++;
int target_index = (target+1)->offset;
if((target->offset > STRIP_LENGTH) || (target->offset < 0)) {
/* wrap around */
target = targets;
target_index = target->offset + STRIP_LENGTH;
} else {
target_index = target->offset;
}
int distance = target_index - i;
while(i<= target_index) {
hsv *c = interpolate(prev_color, &(target->color),
distance, target_index - i);
set_from_hsv(lights[i % STRIP_LENGTH], c);
i++;
}
}
}
int rotated(int i) {
return ((int)floor(zero) + i + STRIP_LENGTH) % STRIP_LENGTH;
}
void setup() {
Serial.begin(115200);
while (!Serial) {;}
Serial.println("HEY ");
setup_wifi();
client.setServer(MQTT_SERVER, 1883);
client.setCallback(mqtt_receive_cb);
strip.begin();
set_strip(initial_config);
strip.show();
}
void loop() {
float dt = 0.01;
if (!client.connected()) reconnect();
client.loop();
delay(dt * 1000);
zero = (zero + dt*rotation_speed + STRIP_LENGTH) ;
while(zero > (1.0* STRIP_LENGTH)) zero -= STRIP_LENGTH;
for(int i = 0; i< STRIP_LENGTH; i++) {
byte *col = lights[rotated(i)];
strip.setPixelColor(i, strip.Color(col[0], col[1], col[2]));
}
strip.show();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment