Skip to content

Instantly share code, notes, and snippets.

@lolarobins
Created January 24, 2023 21:52
Show Gist options
  • Save lolarobins/e5f52846dea5ebcf4fd8faca2a78c363 to your computer and use it in GitHub Desktop.
Save lolarobins/e5f52846dea5ebcf4fd8faca2a78c363 to your computer and use it in GitHub Desktop.
Progress (before serverside shtuff)
//
// 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