Skip to content

Instantly share code, notes, and snippets.

@djdunc
Created April 28, 2024 22:44
Show Gist options
  • Save djdunc/3e4f5bc030f9ae58fec22b79d06121ac to your computer and use it in GitHub Desktop.
Save djdunc/3e4f5bc030f9ae58fec22b79d06121ac to your computer and use it in GitHub Desktop.
Arduino sketch for neopixel client responding to MQTT messages
// 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