Created
April 28, 2024 22:44
-
-
Save djdunc/3e4f5bc030f9ae58fec22b79d06121ac to your computer and use it in GitHub Desktop.
Arduino sketch for neopixel client responding to MQTT messages
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
// works with D1 Mini 8266 and 12 Neopixel ring | |
// https://adafruit.github.io/Adafruit_NeoPixel/html/class_adafruit___neo_pixel.html | |
#include <Adafruit_NeoPixel.h> | |
#include <ESP8266WiFi.h> | |
#include <PubSubClient.h> | |
#include <ArduinoJson.h> | |
#include "arduino_secrets.h" | |
// USER SET VARIABLE FOR EACH DEPLOYMENT START | |
// Each device should connect to the feed that belongs to it | |
// e.g. light/1/ or light/2/ etc. | |
const char* mqtt_topic_pixel = "student/CASA0014/light/1/pixel/"; | |
const char* mqtt_topic_all = "student/CASA0014/light/1/all/"; | |
#define LIGHT 1 | |
// USER SET VARIABLE FOR EACH DEPLOYMENT END | |
#define PIN 2 // data pin of neopixel | |
#define NUMPIXELS 12 // length of neopixels | |
#define STARTBRIGHT 100 // value from 0 to 255 | |
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRBW + NEO_KHZ800); | |
// Array to store RGBW values for each NeoPixel | |
uint8_t pixelColorsArray[NUMPIXELS][4]; // Each element is an array [R, G, B, W] | |
/* | |
**** please enter your sensitive data in the Secret tab/arduino_secrets.h | |
**** using format below | |
#define SECRET_SSID "ssid name" | |
#define SECRET_PASS "ssid password" | |
#define SECRET_MQTTUSER "user name - eg student" | |
#define SECRET_MQTTPASS "password"; | |
*/ | |
const char* ssid = SECRET_SSID; | |
const char* password = SECRET_PASS; | |
const char* mqtt_username = SECRET_MQTTUSER; | |
const char* mqtt_password = SECRET_MQTTPASS; | |
const char* mqtt_server = "mqtt.cetools.org"; | |
const int mqtt_port = 1884; | |
WiFiClient espClient; | |
PubSubClient client(espClient); | |
// Function to handle incoming MQTT messages | |
void callback(char* topic, byte* payload, unsigned int length) { | |
Serial.print("Message received on topic: "); | |
Serial.println(topic); | |
// Check which topic the message is received from | |
if (strcmp(topic, mqtt_topic_pixel) == 0) { | |
handlePixelUpdate(payload, length); | |
} else if (strcmp(topic, mqtt_topic_all) == 0) { | |
handleAllUpdate(payload, length); | |
} else { | |
Serial.println("Unknown topic"); | |
} | |
} | |
// Function to handle messages received on topic1 | |
void handlePixelUpdate(byte* payload, unsigned int length) { | |
// Parse JSON | |
DynamicJsonDocument doc(200); | |
deserializeJson(doc, payload, length); | |
/* | |
expecting to receive a JSON packet in this format | |
{ | |
"pixelid": 1, | |
"R": 255, | |
"G": 0, | |
"B": 128, | |
"W": 200 | |
} | |
*/ | |
// Extract values | |
int pixelid = doc["pixelid"]; | |
int R = doc["R"]; | |
int G = doc["G"]; | |
int B = doc["B"]; | |
int W = doc["W"]; | |
setPixelColor(pixelid, R, G, B, W); | |
// Print values | |
Serial.print("Pixel ID: "); | |
Serial.println(pixelid); | |
Serial.print("R: "); | |
Serial.println(R); | |
Serial.print("G: "); | |
Serial.println(G); | |
Serial.print("B: "); | |
Serial.println(B); | |
Serial.print("W: "); | |
Serial.println(W); | |
} | |
// Function to handle messages received on topic2 | |
void handleAllUpdate(byte* payload, unsigned int length) { | |
// Parse JSON | |
DynamicJsonDocument doc(200); | |
deserializeJson(doc, payload, length); | |
/* | |
expecting to receive a JSON packet in this format | |
{ | |
"method": "clear" | |
} | |
*/ | |
// Check if the method is "clear" | |
const char* method = doc["method"]; | |
if (strcmp(method, "clear") == 0) { | |
setAllPixels(0); // set all values to 0 "off" | |
} else if (strcmp(method, "onerandom") == 0) { | |
setOneRGBPixelRandom(); | |
} else if (strcmp(method, "allrandom") == 0) { | |
setAllPixelsRandom(); | |
} else { | |
Serial.println("Unknown method"); | |
} | |
} | |
void setup() { | |
Serial.begin(115200); | |
delay(10); | |
// configure neopixels | |
pinMode(LED_BUILTIN, OUTPUT); | |
pixels.begin(); | |
pixels.setBrightness(STARTBRIGHT); | |
// Connect to WiFi | |
Serial.println(); | |
Serial.print("Connecting to "); | |
Serial.println(ssid); | |
WiFi.begin(ssid, password); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println(""); | |
Serial.println("WiFi connected"); | |
// quick test to see if all leds are working | |
// i use this rather than pulseWhite so that i can see if all rgb leds are also working | |
setAllPixels(100); // set all values to 100 | |
breatheEffect(1, 12); // 2 loops, 12 msec delay | |
setAllPixels(0); // set all values to 0 "off" | |
// Connect to MQTT broker | |
client.setServer(mqtt_server, mqtt_port); | |
client.setCallback(callback); | |
while (!client.connected()) { | |
Serial.println("Connecting to MQTT..."); | |
if (client.connect("ESP8266Client-test-ucjtdjw", mqtt_username, mqtt_password)) { | |
Serial.println("connected"); | |
} else { | |
Serial.print("failed, rc="); | |
Serial.print(client.state()); | |
Serial.println(" try again in 5 seconds"); | |
delay(5000); | |
} | |
} | |
// Subscribe to the topic you want to listen to | |
client.subscribe(mqtt_topic_pixel); | |
client.subscribe(mqtt_topic_all); | |
// on setup complete do a final breathe | |
setAllPixels(100); // set all values to 100 | |
breatheEffect(1, 12); // 2 loops, 12 msec delay | |
setAllPixels(0); // set all values to 0 "off" | |
} | |
void loop() { | |
// keep mqtt alive | |
client.loop(); | |
// setAllPixelsRandom(); | |
// setOneRGBPixelRandom(); | |
// printPixelsValues(); | |
writeAllPixels(255); // leave as same colour set in random 255/255 = 1 | |
pixels.show(); | |
} | |
void breatheEffect(int loops, int speed) { | |
// Define the breathing speed (adjust as needed) | |
int breatheSpeed = speed; | |
int breatheLimit = 30; // the value from 0-255 | |
for (int n = 0; n < loops; n++) { | |
for (int i = 0; i < breatheLimit; i++) { | |
int brightness = sin(i * 3.14159 / 256.0) * 255; | |
writeAllPixels(brightness); | |
delay(breatheSpeed); | |
} | |
for (int i = breatheLimit; i >= 0; i--) { | |
int brightness = sin(i * 3.14159 / 256.0) * 255; | |
writeAllPixels(brightness); | |
delay(breatheSpeed); | |
} | |
} | |
} | |
void printPixelsValues() { | |
for (int i = 0; i < NUMPIXELS; i++) { | |
Serial.print(pixelColorsArray[i][0]); | |
Serial.print(","); | |
Serial.print(pixelColorsArray[i][1]); | |
Serial.print(","); | |
Serial.print(pixelColorsArray[i][2]); | |
Serial.print(","); | |
Serial.print(pixelColorsArray[i][3]); | |
Serial.println(" --- "); | |
} | |
} | |
void writeAllPixels(uint8_t brightness) { | |
for (int i = 0; i < NUMPIXELS; i++) { | |
pixels.setPixelColor(i, pixels.Color(pixelColorsArray[i][0] * brightness / 255, | |
pixelColorsArray[i][1] * brightness / 255, | |
pixelColorsArray[i][2] * brightness / 255, | |
pixelColorsArray[i][3] * brightness / 255)); | |
} | |
pixels.show(); | |
} | |
void setPixelColor(int pixelIndex, uint8_t red, uint8_t green, uint8_t blue, uint8_t white) { | |
// Ensure the pixelIndex is within bounds | |
if (pixelIndex >= 0 && pixelIndex < NUMPIXELS) { | |
pixelColorsArray[pixelIndex][0] = red; | |
pixelColorsArray[pixelIndex][1] = green; | |
pixelColorsArray[pixelIndex][2] = blue; | |
pixelColorsArray[pixelIndex][3] = white; | |
} | |
} | |
void setAllPixels(int n){ | |
// Initialize the array of all pixelColorsArray values to value passed in e.g. to 0 at start | |
for (int i = 0; i < NUMPIXELS; i++) { | |
for (int j = 0; j < 4; j++) { | |
pixelColorsArray[i][j] = n; | |
} | |
} | |
} | |
void setAllPixelsRandom(){ | |
for (int i = 0; i < NUMPIXELS; i++) { | |
for (int j = 0; j < 3; j++) { | |
pixelColorsArray[i][j] = random(20, 100); | |
} | |
pixelColorsArray[i][3] = 0; // turn off the white pixel | |
} | |
} | |
void setOneRGBPixelRandom(){ | |
int p = random(0,NUMPIXELS); | |
for (int j = 0; j < 3; j++) { | |
pixelColorsArray[p][j] = random(20, 120); | |
} | |
pixelColorsArray[p][3] = 0; // turn off the white pixel | |
} | |
void pulseWhite(uint8_t wait) { | |
for(int j=0; j<256; j++) { // Ramp up from 0 to 255 | |
// Fill entire pixel with white at gamma-corrected brightness level 'j': | |
pixels.fill(pixels.Color(0, 0, 0, pixels.gamma8(j))); | |
pixels.show(); | |
delay(wait); | |
} | |
for(int j=255; j>=0; j--) { // Ramp down from 255 to 0 | |
pixels.fill(pixels.Color(0, 0, 0, pixels.gamma8(j))); | |
pixels.show(); | |
delay(wait); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment