Featured

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

// 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