MQTT software for Ambient light

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

// 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
const char *ssid		 			= "YourNetworkName";
const char *password			= "YourNetworkPassword";

// Mosquitto MQTT server credentials
const char* mqtt_server		= "MQTT_Server_IP";// 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 to be set as retained in the brocker
const char* topic_colorL     = "ambient/CL"; //Left lamp Color in HSB format
const char* topic_colorR     = "ambient/CR"; //Right lamp Color in HSB format
const char* topic_gain       = "ambient/LG"; //Set gain for color sensor from 1 to 60
const char* topic_brightness = "ambient/LB"; //Brightness 0 to 31 as per APA102 datasheet
const char* topic_mode       = "ambient/LM"; //0 = user color, 1 = color from sensor
const char* topic_effect     = "ambient/LE"; //0 = none, 1 = rainbow 2...
const char* topic_lampPower  = "ambient/LP"; //LED strip power

const char* topic_volts      = "ambient/SV"; //Sensor reading for Volts
const char* topic_amps       = "ambient/SI"; //Sensor reading for Current
const char* topic_watts      = "ambient/SW"; //Sensor reading for Power
const 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
const uint8_t ArrLen  = 11;
const uint8_t DMA_Len = 13; // (ArrLen + 2 Markers)
const uint8_t sMarker = 60;//<
const uint8_t eMarker = 62;//>
//R=255, G=0, B=0,Brightness =7, User mode, Lamp OFF


//Array positions
//0 to 5 are the 2x 3 bytes for each HSB color
const uint8_t Gain       = 6; //Gain for sensors
const uint8_t Brightness = 7; //APA102 Brightness
const uint8_t Mode       = 8; //Lamp mode
const uint8_t Effect     = 9; //Lamp effect
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();
		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 = 0;
    if(pos) {
        tmp = 3;
    }

    uint16_t h = Hue % 360;  // Ensure hue is within 0-359 range
    // Convert percentage values to 0-255 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;  // Determine the color sector
    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;
    // Assign the appropriate values to RGB channels based on the sector
    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 valus 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, 1883);
	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.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 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

Who’s online

We have 31 guests and no members online