MQTT software for Ambient light
Discover how to create stunning lighting effects with our Arduino software running on ESP8266 to control APA102 LED strips.
This step-by-step code example will help you build a DIY lighting system that is easy to use and customizable to fit your unique needs.
From setting up your hardware to programming your software, we provide all the tools you need to create an amazing lighting experience.
Get started today and unleash your creativity with our APA102 LED strip control!
This is a Arduino IDE software running on ESP-01 or ESP8266 used in Ambient light with sensors and MQTT
// Import required libraries
#include <ESP8266WiFi.h>
#include "PubSubClient.h" // Connect and publish to the MQTT broker
// Use if you want to store the MQTT topic values in EEPROM
#include <EEPROM.h> // To store the values in ESP EEPROM
// Uncomment line below for debug
//#define debug
// Replace with your network credentials
constexpr char *ssid = "Your_WiFi_Network_SSID";
constexpr char *password = "Your_WiFi_Network_Password";
// Mosquitto MQTT server credentials
constexpr char *mqtt_server = "Your_MQTT_Server_IP"; // IP of the MQTT broker
constexpr uint16_t mqtt_port = Your_MQTT_Server_PORT; // IP of the MQTT broker
constexpr char *mqtt_username = "Your_MQTT_Server_UserName"; // MQTT username
constexpr char *mqtt_password = "Your_MQTT_Server_Password"; // MQTT password
constexpr char *clientID = "AmbientLights";
// Topics for MQTT to be set as retained in the broker
constexpr char *topic_colorL = "ambient/CL"; // Left lamp Color in HSB format
constexpr char *topic_colorR = "ambient/CR"; // Right lamp Color in HSB format
constexpr char *topic_gain = "ambient/LG"; // Set gain for color sensor from 1 to 60
constexpr char *topic_brightness = "ambient/LB"; // Brightness 0 to 31 as per APA102 datasheet
constexpr char *topic_mode = "ambient/LM"; // 0 = user color, 1 = color from sensor
constexpr char *topic_effect = "ambient/LE"; // 0 = none, 1 = rainbow 2...
constexpr char *topic_lampPower = "ambient/LP"; // LED strip power
constexpr char *topic_volts = "ambient/SV"; // Sensor reading for Volts
constexpr char *topic_amps = "ambient/SI"; // Sensor reading for Current
constexpr char *topic_watts = "ambient/SW"; // Sensor reading for Power
constexpr char *topic_energy = "ambient/SE"; // Sensor reading for Energy
// We need 11 bytes to store the values received
// 6 bytes for colors, 1 byte for gain, 1 byte for brightness, 1 byte for color mode, 1 byte for effect, 1 byte for lamp power
constexpr uint8_t ArrLen = 11;
constexpr uint8_t DMA_Len = 13; // (ArrLen + 2 Markers)
constexpr uint8_t sMarker = 60; // <
constexpr uint8_t eMarker = 62; // >
// Array positions
// 0 to 5 are the 2x 3 bytes for each HSB color
constexpr uint8_t Gain = 6; // Gain for sensors
constexpr uint8_t Brightness = 7; // APA102 Brightness
constexpr uint8_t Mode = 8; // Lamp mode
constexpr uint8_t Effect = 9; // Lamp effect
constexpr uint8_t LedPow = 10; // Lamp power
constexpr uint8_t msTime = 50;
// Local variables to hold the values
uint8_t vals[ArrLen];
uint8_t cnt;
uint32_t MsgTime;
bool newData = false;
union byteToFloat {
byte b[4];
float fval;
} myFloat;
// WiFi and MQTT objects
WiFiClient wifi_Client;
PubSubClient mqtt_Client(wifi_Client);
// Show data in the serial window
void printArray()
{
Serial.println("Vals Array");
for (cnt = 0; cnt < ArrLen; cnt++)
{
Serial.print("->");
Serial.print(cnt);
Serial.print(": ");
Serial.println(vals[cnt]);
}
}
// Raw data for STM board (the actual brain)
void SendToStm()
{
// We use markers for start and end of the packet
uint8_t DMA_Arr[DMA_Len] = {sMarker, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, eMarker};
// It is 2.4 times faster than loop with optimization flag
// It is 3 times faster than loop with no optimization flag
memcpy(DMA_Arr + 1, vals, ArrLen);
#ifdef debug
Serial.println();
Serial.println("DMA Array");
for (cnt = 0; cnt < DMA_Len; cnt++)
{
Serial.print("*>");
Serial.print(cnt);
Serial.print(": ");
Serial.println(DMA_Arr[cnt]);
}
#endif
Serial.write(DMA_Arr, DMA_Len);
}
//Get data from EEPROM
void ReadEEPROM() {
for(cnt = 0; cnt < ArrLen; cnt++) {
vals[cnt] = EEPROM.read(cnt);
}
}
//Store default values in EEPROM
void WriteDefault() {
const uint8_t default_val[ArrLen] = {76, 0, 255, 255, 47, 0, 1, 8, 0, 0, 0};
for(cnt = 0; cnt < ArrLen; cnt++) {
EEPROM.write(cnt, default_val[cnt]);
}
//The actual saving is done after we put all values in memory
EEPROM.commit();
}
//Store data in EEPROM
void WriteEEPROM() {
for(cnt = 0; cnt < ArrLen; cnt++) {
EEPROM.write(cnt, vals[cnt]);
}
EEPROM.commit();
}
// Serial.flush() function does not empty the input buffer.
// It is only relevant when the Arduino is sending data,
// and its purpose is to block the Arduino until all outgoing data has been sent.
void ClearBuffer()
{
while (Serial.available() > 0)
{
Serial.read();
}
}
// Send values from Lamp Control Board to MQTT server
void publishToMqtt(const char *mqtt_topic, String mqtt_value)
{
if (!mqtt_Client.publish(mqtt_topic, mqtt_value.c_str()))
{
mqtt_Client.connect(clientID, mqtt_username, mqtt_password);
delay(10); // This delay ensures that client.publish doesn't clash with the client.connect call
mqtt_Client.publish(mqtt_topic, mqtt_value.c_str());
}
}
// Convert OpenHAB color to RGB
static void HSB2RGB(uint8_t pos, uint16_t Hue, uint8_t Sat, uint8_t Bright)
{
uint8_t tmp = pos ? 3 : 0; // Adjust tmp based on the position
uint16_t h = Hue % 360; // Ensure hue is within 0-359 range
uint8_t s = Sat * 255 / 100;
uint8_t v = Bright * 255 / 100;
if (s == 0)
{
vals[tmp] = vals[tmp + 1] = vals[tmp + 2] = v;
return;
}
uint8_t sector = h / 60;
uint8_t remainder = (h % 60) * 255 / 60;
uint8_t p = v * (255 - s) / 255;
uint8_t q = v * (255 - (s * remainder) / 255) / 255;
uint8_t t = v * (255 - (s * (255 - remainder)) / 255) / 255;
switch (sector)
{
case 0:
vals[tmp] = v;
vals[tmp + 1] = t;
vals[tmp + 2] = p;
break;
case 1:
vals[tmp] = q;
vals[tmp + 1] = v;
vals[tmp + 2] = p;
break;
case 2:
vals[tmp] = p;
vals[tmp + 1] = v;
vals[tmp + 2] = t;
break;
case 3:
vals[tmp] = p;
vals[tmp + 1] = q;
vals[tmp + 2] = v;
break;
case 4:
vals[tmp] = t;
vals[tmp + 1] = p;
vals[tmp + 2] = v;
break;
default:
vals[tmp] = v;
vals[tmp + 1] = p;
vals[tmp + 2] = q;
break;
}
}
// Convert the string H,S,B values of MQTT topics to bytes in order to send them to STM
void HSBtoBytes(uint8_t idxC, String Value)
{
#ifdef debug
Serial.println("HSBtoBytes");
#endif
uint8_t idx = Value.length() + 1;
char buff[idx];
char *tmpVal;
uint16_t tmpArr[4];
Value.toCharArray(buff, idx);
idx = 0;
tmpVal = strtok(buff, ",");
while (tmpVal != NULL)
{
tmpArr[idx] = atoi(tmpVal);
#ifdef debug
Serial.println(tmpArr[idx]);
#endif
idx++;
tmpVal = strtok(NULL, ",");
}
HSB2RGB(idxC, tmpArr[0], (uint8_t)tmpArr[1], (uint8_t)tmpArr[2]);
}
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
pinMode(0, OUTPUT);
// Serial port speed
Serial.begin(57600);
delay(msTime);
// commit 11 bytes of ESP8266 flash (for "EEPROM" emulation)
EEPROM.begin(ArrLen);
// Save some default values in EEPROM, use only at first run
// WriteDefault();
// Get the values stored in EEPROM
ReadEEPROM();
// Static IP address configuration
IPAddress staticIP(10, 0, 1, 125); // ESP static ip
IPAddress gateway(10, 0, 1, 1); // IP Address of your WiFi Router (Gateway)
IPAddress subnet(255, 255, 255, 0); // Subnet mask
IPAddress dns(10, 0, 1, 1); // DNS
// Start by disconnecting from WiFi ??? bug in library??
// WiFi.disconnect();
WiFi.config(staticIP, subnet, gateway, dns);
// Go DHCP
WiFi.mode(WIFI_STA);
// WiFi.persistent(false);
WiFi.hostname(clientID);
WiFi.begin(ssid, password);
#ifdef debug
MsgTime = millis();
#endif
// Wait to connect to WiFi
while (WiFi.status() != WL_CONNECTED)
{
#ifdef debug
Serial.println("*");
#endif
// Wait some time between the calls
delay(msTime);
}
#ifdef debug
Serial.print("Connected to WiFi in ms");
Serial.println(millis() - MsgTime);
MsgTime = millis();
#endif
// Connect to MQTT Broker
mqtt_Client.setServer(mqtt_server, mqtt_port);
mqtt_Client.setCallback(callback);
ConnectToServer();
digitalWrite(LED_BUILTIN, HIGH);
#ifdef debug
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
#endif
ClearBuffer();
delay(msTime);
// Inform STM board that we are ready (leave the wait loop)
SendToStm();
}
void loop()
{
if (!mqtt_Client.connected())
{
while (!mqtt_Client.connected())
{
ConnectToServer();
delay(msTime);
}
}
// If we get new data from MQTT broker, we send it to STM board
if (newData)
{
#ifdef debug
printArray();
#endif
SendToStm();
// Save to EEPROM only when the power is turned on
if (vals[LedPow])
WriteEEPROM();
newData = false;
}
// If we get data from STM with power measurements
if (Serial.available() > 17)
{
uint8_t tmp_arr[18];
for (cnt = 0; cnt < 18; cnt++)
{
tmp_arr[cnt] = Serial.read();
}
if ((tmp_arr[0] == sMarker) && (tmp_arr[17] == eMarker))
{
float tmpValue;
myFloat.b[0] = tmp_arr[1];
myFloat.b[1] = tmp_arr[2];
myFloat.b[2] = tmp_arr[3];
myFloat.b[3] = tmp_arr[4];
tmpValue = myFloat.fval;
publishToMqtt(topic_volts, String(myFloat.fval, 6));
myFloat.b[0] = tmp_arr[5];
myFloat.b[1] = tmp_arr[6];
myFloat.b[2] = tmp_arr[7];
myFloat.b[3] = tmp_arr[8];
publishToMqtt(topic_amps, String(myFloat.fval, 6));
myFloat.b[0] = tmp_arr[9];
myFloat.b[1] = tmp_arr[10];
myFloat.b[2] = tmp_arr[11];
myFloat.b[3] = tmp_arr[12];
publishToMqtt(topic_watts, String(myFloat.fval, 6));
myFloat.b[0] = tmp_arr[13];
myFloat.b[1] = tmp_arr[14];
myFloat.b[2] = tmp_arr[15];
myFloat.b[3] = tmp_arr[16];
publishToMqtt(topic_energy, String(myFloat.fval, 6));
}
else
{
ClearBuffer();
}
}
mqtt_Client.loop();
}
// When connected to MQTT server subscribe to topics
void ConnectToServer()
{
if (mqtt_Client.connect(clientID, mqtt_username, mqtt_password))
{
// We first subscribe to MQTT topics
mqtt_Client.subscribe(topic_colorL);
mqtt_Client.subscribe(topic_colorR);
mqtt_Client.subscribe(topic_gain);
mqtt_Client.subscribe(topic_brightness);
mqtt_Client.subscribe(topic_mode);
mqtt_Client.subscribe(topic_effect);
mqtt_Client.subscribe(topic_lampPower);
// mqtt_Client.subscribe(topic_volts);
// mqtt_Client.subscribe(topic_amps);
// mqtt_Client.subscribe(topic_watts);
// mqtt_Client.subscribe(topic_energy);
#ifdef debug
Serial.print("Connected to MQTT Broker in ms");
Serial.println(millis() - MsgTime);
#endif
}
#ifdef debug
else
{
Serial.println("Connection to MQTT Broker failed...");
mqtt_Client.state(); // Will provide more information
}
#endif
}
void callback(char* topic, byte* payload, unsigned int length) {
#ifdef debug
Serial.println();
Serial.print("Message arrived [");
Serial.print(topic);
Serial.println("]");
#endif
String messageTemp;
for (unsigned int i = 0; i < length; ++i) {
messageTemp += static_cast<char>(payload[i]);
}
#ifdef debug
Serial.println();
#endif
if (strcmp(topic, topic_colorL) == 0) {
// We get the LEFT color as RGB
HSBtoBytes(0, messageTemp);
newData = true;
}
if (strcmp(topic, topic_colorR) == 0) {
// We get the RIGHT color as RGB
HSBtoBytes(1, messageTemp);
newData = true;
}
if (strcmp(topic, topic_gain) == 0) {
// We get an int 0 or 1
vals[Gain] = messageTemp.toInt();
newData = true;
}
if (strcmp(topic, topic_brightness) == 0) {
// We get an int 0 to 31
vals[Brightness] = messageTemp.toInt();
newData = true;
}
if (strcmp(topic, topic_mode) == 0) {
// We get an int 0 or 1
vals[Mode] = messageTemp.toInt();
newData = true;
}
if (strcmp(topic, topic_effect) == 0) {
// We get an int 0 or 1
vals[Effect] = messageTemp.toInt();
newData = true;
}
if (strcmp(topic, topic_lampPower) == 0) {
vals[LedPow] = messageTemp.toInt();
newData = true;
}
}
Comments powered by CComment