Created
January 24, 2023 21:52
-
-
Save lolarobins/e5f52846dea5ebcf4fd8faca2a78c363 to your computer and use it in GitHub Desktop.
Progress (before serverside shtuff)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// esp32 rgb controller | |
// | |
// hardware: | |
// > Wemos D1 R32 'ESPDuino-32' (https://amazon.ca/CANADUINO-ESPDuino-32-Bluetooth-Dual-Core-Processor/dp/B07P1L7839) | |
// -- note: may not upload if speed is too high, set to 115200 if errors occur | |
// > Velleman Arduino RGB Shield KA01 (https://www.velleman.eu/products/view/?id=412138) | |
// > random rgb strip from somewhere | |
// authors: | |
// > lola robins (lola@robinssoftware.ca) | |
// license: | |
// > GNU GPL v3 | |
// | |
// !~ user cfg ~! | |
// hostname | |
#define DEVICE_HOSTNAME "ESP32RGB" | |
// wifi netword ssid | |
#define WIFI_SSID "XXXX" | |
// comment ln for insecure wifi | |
#define WIFI_PW "XXXX" | |
// port to listen on | |
#define SOCKET_PORT 9260 | |
// password for socket | |
#define SOCKET_PASS "XXXX" | |
// led pwm pins | |
#define R_LED 25 | |
#define G_LED 16 | |
#define B_LED 27 | |
// pwm frequency (in Hz) | |
#define FREQ_CH 4000 | |
// !~ program ~! | |
#include <WiFi.h> | |
#define R_CH 0 | |
#define G_CH 1 | |
#define B_CH 2 | |
#define RES_CH 8 | |
// global vars to help aid connection/reconnection | |
volatile bool connected; // is connected? (for loop) | |
uint8_t reconnect_times; // times reconnection has attempted | |
uint32_t reconnect_delay; // time to delay reconnection attempt until | |
typedef enum led_animation_t | |
{ | |
ANIM_STATIC, // static animation, no vars | |
ANIM_GRADIENT, // linear gradient, no vars | |
ANIM_VAR_GRADIENT, // variable linear gradient, var = 0x[XX][YY] where x = progress out of y | |
} led_animation_t; | |
// individiual segment struct | |
typedef struct led_segment_t | |
{ | |
led_animation_t animation; // animation id | |
uint16_t ttl; // time to live | |
uint8_t r1, g1, b1, r2, g2, b2; // first and second color opts | |
uint16_t var; // allow animation 2 bytes of variable setting | |
} led_segment_t; | |
// led mode master struct | |
typedef struct led_mode_t | |
{ | |
led_segment_t **seg; // ptr to allocated array of seg ptrs | |
uint8_t seg_size; // amount of segment ptrs in allocated array | |
} led_mode_t; | |
// current mode, null = no lights | |
led_mode_t *mode; | |
// animation render data | |
uint8_t segment; // segment animation is at out of # of segments | |
uint16_t progress; // progress out of ttl | |
// recognize connection, disconnection | |
void wifi_connect_e(WiFiEvent_t e, WiFiEventInfo_t inf) | |
{ | |
connected = true; | |
reconnect_times = 0; | |
} | |
void wifi_disconnect_e(WiFiEvent_t e, WiFiEventInfo_t inf) | |
{ | |
connected = false; | |
} | |
// connect/reconnect function | |
void wifi_connect() | |
{ | |
// disconnect from attempt ?! feels safe this way | |
WiFi.disconnect(); | |
#ifdef WIFI_PW | |
WiFi.begin(WIFI_SSID, WIFI_PW); | |
#else | |
WiFi.begin(WIFI_SSID); | |
#endif | |
reconnect_times++; | |
reconnect_delay = millis() + 3 * reconnect_times * 1000; | |
} | |
// set the rgb vals | |
void led_rgb(uint8_t r, uint8_t g, uint8_t b) | |
{ | |
ledcWrite(R_CH, r); | |
ledcWrite(G_CH, g); | |
ledcWrite(B_CH, b); | |
} | |
// create new mode | |
led_mode_t *led_mode_create() | |
{ | |
return (led_mode_t *)calloc(1, sizeof(led_mode_t)); | |
} | |
// remove active node | |
void led_mode_remove() | |
{ | |
if (!mode) | |
return; | |
// fetch and nullify the global active mode | |
led_mode_t *removal = mode; | |
mode = NULL; | |
// kill | |
if (removal->seg_size) | |
{ | |
for (uint8_t i = 0; i < removal->seg_size; i++) | |
free(removal->seg[i]); | |
free(removal->seg); | |
} | |
free(removal); | |
} | |
// removes and unallocates the active mode and replaces it with a newly constructed one | |
void led_mode_set(led_mode_t *m) | |
{ | |
led_mode_remove(); | |
mode = m; | |
} | |
// raw segment creation field, can be destroyed with free(*seg); | |
led_segment_t *led_segment_create(led_animation_t animation, uint8_t r1, uint8_t g1, uint8_t b1, | |
uint8_t r2, uint8_t g2, uint8_t b2, | |
uint16_t duration, uint16_t var) | |
{ | |
led_segment_t *seg = (led_segment_t *)calloc(1, sizeof(led_segment_t)); | |
seg->animation = animation; | |
seg->r1 = r1; | |
seg->r2 = r2; | |
seg->g1 = g1; | |
seg->g2 = g2; | |
seg->b1 = b1; | |
seg->b2 = b2; | |
seg->ttl = duration; | |
seg->var = var; | |
return seg; | |
} | |
// create a static colour segment, can be destroyed with free(*seg); | |
led_segment_t *led_segment_create_static(uint8_t r, uint8_t g, uint8_t b, uint16_t duration) | |
{ | |
return led_segment_create(ANIM_STATIC, r, g, b, 0, 0, 0, duration, 0); | |
} | |
// create a transitioning gradient, can be destroyed with free(*seg); | |
led_segment_t *led_segment_create_gradient(uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2, uint8_t g2, uint8_t b2, uint16_t duration) | |
{ | |
return led_segment_create(ANIM_GRADIENT, r1, g1, b1, r2, g2, b2, duration, 0); | |
} | |
// removes a segment at a position | |
void led_segment_remove(led_mode_t *m, uint8_t pos) | |
{ | |
if (!m || m->seg_size <= pos) | |
return; | |
free(m->seg[pos]); | |
m->seg_size--; | |
for (uint8_t i = pos; i < m->seg_size; i++) | |
m->seg[i] = m->seg[i + 1]; | |
if (m->seg_size) | |
m->seg = (led_segment_t **)realloc(m->seg, m->seg_size * sizeof(led_segment_t *)); | |
else | |
free(m->seg); | |
} | |
// gets the segment at a position | |
led_segment_t *led_segment_get(led_mode_t *m, uint8_t pos) | |
{ | |
if (!m || pos < m->seg_size) | |
return NULL; | |
return m->seg[pos]; | |
} | |
// set segment at position to new segment, frees old | |
void led_segment_set(led_mode_t *m, uint8_t pos, led_segment_t *seg) | |
{ | |
if (!seg) | |
led_segment_remove(m, pos); | |
if (pos >= m->seg_size || !seg) | |
return; | |
free(m->seg[pos]); | |
m->seg[pos] = seg; | |
} | |
// appends segment to end of current mode | |
void led_segment_append(led_mode_t *m, led_segment_t *seg) | |
{ | |
if (!m || !seg) | |
return; // why even (error prevention) | |
m->seg_size++; | |
m->seg = (led_segment_t **)realloc(m->seg, m->seg_size * sizeof(led_segment_t *)); | |
m->seg[m->seg_size - 1] = seg; | |
} | |
uint8_t led_segment_size(led_mode_t *m) | |
{ | |
if (!m) | |
return 0; | |
return m->seg_size; | |
} | |
// arduino | |
void setup() | |
{ | |
Serial.begin(115200); | |
// led channel setup and configuration | |
ledcSetup(R_CH, FREQ_CH, RES_CH); | |
ledcSetup(G_CH, FREQ_CH, RES_CH); | |
ledcSetup(B_CH, FREQ_CH, RES_CH); | |
ledcAttachPin(R_LED, R_CH); | |
ledcAttachPin(G_LED, G_CH); | |
ledcAttachPin(B_LED, B_CH); | |
// wifi setup | |
WiFi.setHostname(DEVICE_HOSTNAME); | |
// register connects, disconnects | |
WiFi.onEvent(wifi_connect_e, ARDUINO_EVENT_WIFI_STA_CONNECTED); | |
WiFi.onEvent(wifi_disconnect_e, ARDUINO_EVENT_WIFI_STA_DISCONNECTED); | |
wifi_connect(); | |
// -- test mode -- | |
mode = led_mode_create(); | |
led_segment_append(mode, led_segment_create_gradient(256, 0, 0, 255, 154, 0, 250)); // 0 - 1 | |
led_segment_append(mode, led_segment_create_gradient(255, 154, 0, 208, 222, 33, 250)); // 1 - 2 | |
led_segment_append(mode, led_segment_create_gradient(208, 222, 33, 79, 220, 74, 250)); // 2 - 3 | |
led_segment_append(mode, led_segment_create_gradient(79, 220, 74, 63, 218, 216, 250)); // 3 - 4 | |
led_segment_append(mode, led_segment_create_gradient(63, 218, 216, 47, 201, 226, 250)); // 4 - 5 | |
led_segment_append(mode, led_segment_create_gradient(47, 201, 226, 28, 127, 238, 250)); // 5 - 6 | |
led_segment_append(mode, led_segment_create_gradient(28, 127, 238, 95, 21, 242, 250)); // 6 - 7 | |
led_segment_append(mode, led_segment_create_gradient(95, 21, 242, 186, 12, 248, 250)); // 7 - 8 | |
led_segment_append(mode, led_segment_create_gradient(186, 12, 248, 215, 7, 217, 250)); // 8 - 9 | |
led_segment_append(mode, led_segment_create_gradient(215, 7, 217, 255, 0, 0, 250)); // 9 - 0 | |
} | |
void loop() | |
{ | |
// timer | |
static uint32_t last = millis(); | |
uint32_t delta = millis() - last; | |
last = millis(); | |
// stay connected to wifi and/or diagnose own connection | |
if (connected) | |
; // do nothing :/ | |
else if (!reconnect_delay) | |
wifi_connect(); // reconnect | |
else if (reconnect_delay < millis()) | |
reconnect_delay = 0; // reset delay to then retry on next loop | |
// animate and light! (but not if no mode, or mode has no segments) | |
if (mode && mode->seg_size) | |
{ | |
led_segment_t *selected = mode->seg[segment]; | |
// only care to do animation time changes if ttl exists | |
if (selected->ttl) | |
{ | |
progress += delta; | |
// segment expired | |
if (progress >= selected->ttl) | |
{ | |
// increment seg and dont rollover | |
segment++; | |
if (segment == mode->seg_size) | |
segment = 0; | |
selected = mode->seg[segment]; | |
// reset progress | |
progress = 0; | |
} | |
} | |
// update animation! | |
float percent = selected->ttl ? (float)progress / selected->ttl : 0.0F; | |
switch (selected->animation) | |
{ | |
// static colour | |
case ANIM_STATIC: | |
led_rgb(selected->r1, selected->g1, selected->b1); | |
break; | |
// gradients | |
case ANIM_VAR_GRADIENT: | |
percent = (float)progress / selected->ttl; // override progress | |
case ANIM_GRADIENT: // purposed fallthrough | |
led_rgb( | |
selected->r1 + (percent * (selected->r2 - selected->r1)), | |
selected->g1 + (percent * (selected->g2 - selected->g1)), | |
selected->b1 + (percent * (selected->b2 - selected->b1))); | |
break; | |
} | |
} | |
else | |
led_rgb(0x00, 0x00, 0x00); // cut the lights! | |
// device rollover will just cause it to die | |
if (millis() > 0xFFFFF000) | |
ESP.restart(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment