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
//Optimize for speed not for size as default
#pragma GCC optimize("-O3")
// Import required libraries
#include <ESP8266WiFi.h>
#include "PubSubClient.h" // Connect and publish to the MQTT broker
#include <EEPROM.h> // To store the values in ESP EEPROM
//Uncomment line below for debug
//#define debug
// Replace with your network credentials
const char *ssid = "YourNetworkName";
const char *password = "YourNetworkPassword";
// Mosquitto MQTT server credentials
const char* mqtt_server = "10.0.1.2";// IP of the MQTT broker
const char* mqtt_username = "MQTT_UserName"; // MQTT username
const char* mqtt_password = "MQTT_PassWord"; // MQTT password
const char* clientID = "AmbientLights";
//Topics for MQTT
#define topic_colorL "ambient/CL" //Left lamp Color in HSB format
#define topic_colorR "ambient/CR" //Right lamp Color in HSB format
#define topic_gain "ambient/LG" //set gain for color sensor from 1 to 60
#define topic_intensity "ambient/LB" //Brightness 0 to 31 as per APA102 datasheet
#define topic_mode "ambient/LM" //0 = user color, 1 = color from sensor
#define topic_effect "ambient/LE" //0 = none, 1 = rainbow 2...
#define topic_lampPower "ambient/LP" //LED strip power
#define topic_volts "ambient/SV" //Sensor reading for Volts
#define topic_amps "ambient/SI" //Sensor reading for Current
#define topic_watts "ambient/SW" //Sensor reading for Power
#define topic_energy "ambient/SE" //Sensor reading for Energy
//We nee 11 bytes to store the values received
//6 bytes for colors, 1 byte for gain, 1 byte for intensity, 1 byte for color mode, 1 byte for effect, 1 byte for lamp power
#define ArrLen 11
#define DMA_Len (ArrLen + 2)
const uint8_t sMarker = 60;//<
const uint8_t eMarker = 62;//>
//R=255, G=0, B=0,Intensity =7, User mode, Lamp OFF
//Array positions
//const uint8_t c_R1 = 0;
//const uint8_t c_G1 = 1;
//const uint8_t c_B1 = 2;
//const uint8_t c_R2 = 3;
//const uint8_t c_G2 = 4;
//const uint8_t c_B2 = 5;
const uint8_t Gain = 6; //Gain for sensors
const uint8_t c_I = 7; //APA102 Brightness
const uint8_t Mode = 8; //Lamp mode
const uint8_t Effect = 9; //Lamp mode
const uint8_t LedPow = 10; //Lamp power
const 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 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("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]);
}
EPROM.commit();
}
//Check https://www.rapidtables.com/convert/color/hsv-to-rgb.html
//Convert OpenHAB color to RGB
void HSB2RGB(uint8_t idx, uint16_t H, uint8_t S, uint8_t B){
uint8_t tmp = 0;
if(idx) {
tmp = 3;
}
float s = (float)S/100.0;
float v = (float)B/100.0;
float C = s*v;
float X = C*(1-abs(fmod(H/60.0, 2)-1));
float m = v-C;
float r,g,b;
if(H < 60){
r = C;
g = X;
b = 0;
} else if(H < 120){
r = X;
g = C;
b = 0;
} else if(H < 180){
r = 0;
g = C;
b = X;
} else if(H < 240){
r = 0;
g = X;
b = C;
} else if(H < 300){
r = X;
g = 0;
b = C;
} else if(H < 360){
r = C;
g = 0;
b = X;
}
vals[tmp] = (r+m)*255;
vals[tmp + 1] = (g+m)*255;
vals[tmp + 2] = (b+m)*255;
}
//Convert the valus from ESP EEPROM to string in order to send them to MQTT
String RGB2HSB(uint8_t idx){
uint16_t H;
uint8_t S, B;
uint8_t tmp = 0;
if(idx) {
tmp = 3;
}
float r = vals[tmp]/255;
float g = vals[tmp + 1]/255;
float b = vals[tmp + 2]/255;
float Cmax = max(r, g);
Cmax = max(Cmax, b);
float Cmin = min(r, g);
Cmin = min(Cmin, b);
float delta = Cmax - Cmin;
if(delta == 0.0){
H = 0;
} else {
if(Cmax == r){
H = 60*((int)((g - b)/delta)%6);
} else if(Cmax == g){
H = 60*(((b - r)/delta)+2);
} else if(Cmax == b){
H = 60*(((r - g)/delta)+4);
}
}
if(Cmax = 0.0){
S = 0;
} else {
S = delta/Cmax;
}
B = Cmax;
return String(H) + "," + String(S) + "," + String(B);
}
//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 stored in ESP to MQTT server
void publishToMqtt(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 the valus of MQTT topics to bytes in order to store them in ESP EEPROM
void RGBtoBytes(uint8_t idxC, String Value){
#ifdef debug
Serial.println("RGBtoBytes");
#endif
uint8_t idx = Value.length() + 1;
char buff[idx];
char *tmpVal;
uint16_t tmpArr[3];
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], tmpArr[1], tmpArr[2]);
}
void setup(){
pinMode(LED_BUILTIN, OUTPUT);
pinMode(0, OUTPUT);
// Serial port for debugging purposes
Serial.begin(115200);
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();
//printArray();
//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);
WiFi.mode(WIFI_STA);
//WiFi.persistent(false);
WiFi.hostname("AmbientalLights");
WiFi.begin(ssid, password);
// MsgTime = millis();
//Wait to connect to WiFi
while (WiFi.status() != WL_CONNECTED) {
// Serial.println("*");
delay(msTime);
}
// Serial.print("Connected to WiFi in ");Serial.println(millis() - MsgTime);
// MsgTime = millis();
// Connect to MQTT Broker
mqtt_Client.setServer(mqtt_server, 1883);
mqtt_Client.setCallback(callback);
ConnectToServer();
digitalWrite(LED_BUILTIN, HIGH);
// Serial.print("IP address: "); Serial.println(WiFi.localIP());
ClearBuffer();
// MsgTime = millis();
//Inform STM board that we are ready (leave the wait loop)
SendToStm();
delay(msTime);
SendToStm();
}
void loop(){
if (!mqtt_Client.connected()) {
mqtt_reconnect();
}
//If we get new data from MQTT broker, we send it to STM board and save it in EEPROM
if(newData){
#ifdef debug
printArray();
#endif
SendToStm();
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();
}
void mqtt_reconnect(){
while (!mqtt_Client.connected()) {
ConnectToServer;
delay(msTime);
}
}
void ConnectToServer(){
if (mqtt_Client.connect(clientID, mqtt_username, mqtt_password)) {
//We first publish the values we have stored in ESP EEPROM
publishToMqtt(topic_colorL, RGB2HSB(0));
publishToMqtt(topic_colorR, RGB2HSB(1));
publishToMqtt(topic_gain, String(vals[Gain]));
publishToMqtt(topic_intensity, String(vals[c_I]));
publishToMqtt(topic_mode, String(vals[Mode]));
publishToMqtt(topic_effect, String(vals[Effect]));
publishToMqtt(topic_lampPower, String(vals[LedPow]));
publishToMqtt(topic_volts, String(0.0));
publishToMqtt(topic_amps, String(0.0));
publishToMqtt(topic_watts, String(0.0));
publishToMqtt(topic_energy, String(0.0));
mqtt_Client.subscribe(topic_colorL);
mqtt_Client.subscribe(topic_colorR);
mqtt_Client.subscribe(topic_gain);
mqtt_Client.subscribe(topic_intensity);
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 "); Serial.println(millis() - MsgTime);
#endif
}
// else {
// Serial.println("Connection to MQTT Broker failed...");
// mqtt_Client.state(); //Will provide more information
// }
}
void callback(char* topic, byte* payload, unsigned int length){
#ifdef debug
Serial.println();
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("]\n ");
#endif
String messageTemp;
for (int i = 0; i < length; i++){
#ifdef debug
Serial.print((char)payload[i]);
#endif
messageTemp += (char)payload[i];
}
#ifdef debug
Serial.println();
#endif
if (strcmp(topic, topic_colorL) == 0){
//we get the color as RGB
RGBtoBytes(0, messageTemp);
newData = true;
}
if (strcmp(topic, topic_colorR) == 0){
//we get the color as RGB
RGBtoBytes(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_intensity) == 0){
//we get an int 0 to 31
vals[c_I] = 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