✨ Use RCAPP and get 5% off 👇
Skip to content
Free Delivery on Orders Above Rs 999/- Pan-India
Cash on Delivery Available for Orders above Rs.500/- and Upto Rs 3000/-
SAVE more when you BUY more. Upto 30% Off on BULK PURCHASE
GST Invoices for Your Business
Dedicated Technical Support Team
Safely Delivering Genuine Products PAN INDIA

AMBIENT LIGHT INTENSITY MONITORING SYSTEM WITH LORA AND ESP32

AMBIENT LIGHT INTENSITY MONITORING SYSTEM WITH LORA AND ESP32
D
Written By Daniel D'Souza
📅 Updated on 17 Jun 2026
Summarize with AI
✅ Prompt copied

The 'Ambient Light Monitoring System is designed in such a way that once a specific mode is toggled on, the sensors in the environment will monitor and maintain the lux value (measure of intensity of ambient light) set by the user.

Let's have a look at all the components that we will need for this project:​

1. ESP32 NodeMCU modules

2. Witty Fox OPT3001 Ambient light Sensor 

3. WS2812 LED Strips

4. Lora Modules 

5. Potentiometer 

6. Jumpers Wires

7. Breadboards

8. Resistors

9. Switches

 

For a detailed step by step assembly process, please refer to the video below:​

Components and Supplies

ESP32 NodeMCU (38-Pin) WiFi + BLE – Ideal for IoT. -Nodemcu ESP Board -RobocrazeESP32 NodeMCU (38-Pin) WiFi + BLE – Ideal for IoT. -Nodemcu ESP Board -Robocraze

    ESP32 (38 Pin) WiFi + Bluetooth NodeMCU-32 Development Board

    ESP32 (38 Pin) WiFi + Bluetooth NodeMCU-32 Development Board The ESP32 Development Board is a powerful and feature-rich microcontroller platform designed for modern IoT, automation, and wireless communication projects. Powered by the reliable ESP-WROOM-32 module, this compact and versatile ESP32 dev board combines high-speed...
    Rs 399/-
    Rs 399/-
    Rs 599/-
    Save Rs 200/-
    GL12 840 Points Solderless Breadboard for Large Prototyping - Electronic Components -RobocrazeGL12 840 Points Solderless Breadboard for Large Prototyping - Electronic Components -Robocraze

      GL12 840 Points Solderless Breadboard

      GL12 MB102 840 Points Solderless Breadboard Introducing the GL12 840 Points Breadboard at Robocraze! This solderless breadboard is an essential tool for any electronics engineer or hobbyist. It allows you to make temporary prototypes for your electronics projects, making it perfect for experimenting with...
      Rs 70/-
      Rs 70/-
      Rs 90/-
      Save Rs 20/-
      Jumper Wire Set - M2M, M2F, F2F (40 pcs each) – Ideal for Arduino & prototyping. Electronic Components - RobocrazeJumper Wire Set - M2M, M2F, F2F (40 pcs each) – Ideal for Arduino & prototyping. Electronic Components - Robocraze

        Jumper Wire Set - M2M, M2F, F2F (40 pcs each)

        Jumper Wire Set - M2M, M2F, F2F (40 pcs each) These DuPont jumper wires for electronics is a premium quality wire manufactured by using quality assured material and advanced techniques, which make them up to the standard in this highly challenging field. This 120pcs...
        Rs 135/-
        Rs 135/-
        Rs 169/-
        Save Rs 34/-
        LoRa-E5 (STM32WLE5JC) Module-RobocrazeLoRa-E5 (STM32WLE5JC) Module-Robocraze

        LoRa-E5 (STM32WLE5JC) Module

        LoRa-E5 (STM32WLE5JC) Module LoRa-E5 is a low-cost, ultra-low power, extremely compact, and high-performance LoRaWAN Module designed by Seeed Technology Co., Ltd. It contains ST system-level package chip STM32WLE5JC. This module is also embedded with ARM Cortex M4 ultra-low-power MCU and LoRa SX126X and therefore...
        Rs 1,175/-
        Rs 1,175/-
        Rs 1,441/-
        Save Rs 266/-
        Digital Potentiometer Module – Electronic variable resistor for digital control.-Electronic Components -RobocrazeDigital Potentiometer Module – Electronic variable resistor for digital control.-Electronic Components -Robocraze

        Digital Potentiometer Board Module

        Digital Potentiometer Board Module This is a X9C103S DC 3-5V Digital Potentiometer Board Module for Arduino. The X9C103 is a digitally controlled (XDCP) potentiometer. It consists of a resistor array, wiper switch, control section and non-volatile memory. Wiper position is controlled via a 3-wire...
        Rs 315/-
        Rs 315/-
        Rs 339/-
        Save Rs 24/-
        Witty Fox OPT3001 Digital Ambient Light Sensor - Precise LUX meter sensor for light detection. -Light Sensor -RobocrazeWitty Fox OPT3001 Digital Ambient Light Sensor - Precise LUX meter sensor for light detection. -Light Sensor -Robocraze

        Witty Fox - OPT3001 Digital Ambient Light Sensor | Precise LUX meter sensor

        Witty Fox - OPT3001 Digital Ambient Light Sensor OPT3001 Digital Ambient Light Sensor is a single-chip lux meter that measures the intensity of light as visible by the human eye. Measurements can be made from 0.01 lux up to 83k lux without manually selecting full-scale...
        Rs 597/-
        Rs 597/-
        Rs 675/-
        Save Rs 78/-

        Base Station Code explanation:

        The base station code can be broken down into three major constituents, which are:

        1. The communication between the base station and end devices using Lora Modules.

        2. The potentiometer code which allows the user to increase/decrease the brightness of each room to the desired lux reading.

        3. Code for the switch which toggles the control mode on end devices.

        End Device Code:

        Like the base station, the code for end devices can be broken down into constituents,

        which are:

        1. The communication between the end devices and base station using Lora Modules.

        2. The code for the LED strip brightness, which will vary based on the user defined input at the base station during manual mode.

        3. Code to control the LED strip brightness during 'maintain Lux value mode'.

        Code for base station:

         #include <Arduino.h>

        #include <FastLED.h>

        #include <SPI.h>

        #include <LoRa.h>

        #define debounceInterval 200

        const int csPin = 5;

        const int resetPin = 4;

        const int irqPin = 2;

        byte localAddress = 0xAA;

        byte destinationAddress = 0xBB;

        byte address;  

        unsigned long lastMillis = 0;  

        unsigned long lastInterruptMillis = 0;

        int val;  

        long lastSendTime = 0;  

        int interval = random(500) + 100;  

        String command;  

        boolean buttonPrevState = false;  

        boolean buttonPressed = false;

        void receiveMessage(int packetSize);

        void IRAM_ATTR toggle();

        void sendMessage(String outgoing, byte destinationAddress);

        void setup()

        {

         

          Serial.begin(115200);

          pinMode(14, INPUT);

          pinMode(25, INPUT_PULLUP);

          attachInterrupt(25, toggle, FALLING);

          Serial.println("Start LoRa duplex");

          LoRa.setPins(csPin, resetPin, irqPin);

          if (!LoRa.begin(433E6))

          {

         

            Serial.println("LoRa init failed. Check your connections.");

            while (true)

         

            {

         

            }

         

          }

         

          LoRa.setSpreadingFactor(12);

         

        }

         

        void loop()

         

        {

         

          val = analogRead(14);

          val = map(val, 0, 4095, 0, 100);

          sendMessage(String(val), 0xBB);

          if (buttonPressed == true)

         

          {

         

            if (millis() - lastInterruptMillis > debounceInterval)

         

            {

         

              Serial.println("Button Pressed");

              sendMessage("ModeChange", 0xBB);

              delay(100);

              buttonPrevState = !buttonPrevState;

              buttonPressed = false;

              lastInterruptMillis = millis();

         

            }

         

          }

         

          else

         

          {

         

            buttonPressed = false;

         

          }

         

          receiveMessage(LoRa.parsePacket());

         

        }

         

        void IRAM_ATTR toggle()

         

        {

         

          if (digitalRead(25) == 0)

         

          {

         

            buttonPressed = !buttonPressed;

         

          }

         

        }

         

        void sendMessage(String outgoing, byte destinationAddress)

         

        {

         

          LoRa.beginPacket();

          LoRa.write(destinationAddress);

          LoRa.write(localAddress);

          LoRa.write(outgoing.length());

          LoRa.print(outgoing);

          LoRa.endPacket();

         

        }

         

        void receiveMessage(int packetSize)

         

        {

         

          if (packetSize == 0)

         

            return;

         

          int recipient = LoRa.read();

          byte sender = LoRa.read();

          byte incomingLength = LoRa.read();

         

          String incoming = "";

         

          while (LoRa.available())

         

          {

         

            incoming += (char)LoRa.read();

         

          }

         

          if (incomingLength != incoming.length())

         

          {

         

            Serial.println("Error: Message length does not match length");

         

            return;

         

          }

         

           if (recipient != localAddress)

         

          {

         

            return;

         

          }

         

        }

        Code for End Devices: 

        #include <Arduino.h>

        #include <FastLED.h>

        #include <Wire.h>

        #include <ClosedCube_OPT3001.h>

        #include <SPI.h>

        #include <LoRa.h>

         

        #define debounceInterval 200

        #define LED_PIN 15

        #define NUM_LEDS 64

        #define OPT3001_ADDRESS 0x44

         

        const int csPin = 5;

        const int resetPin = 4;

        const int irqPin = 2;

        byte localAddress = 0xBB;

        byte destinationAddress = 0xAA;

        long lastSendTime = 0;

        int interval = random(500) + 100;

         

        byte address;

        String command;

         

        boolean buttonPrevState = false;

        boolean buttonPressed = false;

        unsigned long lastMillis = 0;

        unsigned long lastInterruptMillis = 0;

        int val;

         

        CRGB leds[NUM_LEDS];

        ClosedCube_OPT3001 opt3001;

         

        void configureSensor();

        void printResult(String text, OPT3001 result);

        void printError(String text, OPT3001_ErrorCode error);

        void receiveMessage(int packetSize);

         

        void setup()

         

        {

         

          Serial.begin(115200);

          pinMode(34, INPUT);

          pinMode(12, OUTPUT);

          pinMode(13, OUTPUT);

          pinMode(15, OUTPUT);

          digitalWrite(13, HIGH);

          digitalWrite(12, LOW);

          FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);

          opt3001.begin(OPT3001_ADDRESS);

          Serial.print("OPT3001 Manufacturer ID");

          Serial.println(opt3001.readManufacturerID());

          Serial.print("OPT3001 Device ID");

          Serial.println(opt3001.readDeviceID());

         

          configureSensor();

         

          printResult("High-Limit", opt3001.readHighLimit());

          printResult("Low-Limit", opt3001.readLowLimit());

          Serial.println("----");

         

          Serial.println("Start LoRa duplex");

         

          LoRa.setPins(csPin, resetPin, irqPin);

         

          if (!LoRa.begin(433E6))

         

          {

         

            Serial.println("LoRa init failed. Check your connections.");

            while (true)

         

            {

         

            }

         

          }

         

          LoRa.setSpreadingFactor(12);

         

        }

         

        void loop()

         

        {

         

          for (int j = 0; j < NUM_LEDS; j++)

         

          {

         

            leds[j] = CRGB(255, 255, 255);

         

          }

         

          FastLED.setBrightness(val);

          FastLED.show();

         

          if (buttonPressed == true)

         

          {

         

            if (millis() - lastInterruptMillis > debounceInterval)

         

            {

         

              OPT3001 result = opt3001.readResult();

         

              int setBrightnessValue = result.lux;

         

              Serial.print("To be set brightness = ");

         

              Serial.println(setBrightnessValue);

         

              delay(1000);

         

              buttonPrevState = !buttonPrevState;

         

              buttonPressed = false;

         

              lastInterruptMillis = millis();

         

              while (buttonPrevState == true && buttonPressed == false)

         

              {

         

                OPT3001 result = opt3001.readResult();

         

                int toBeSetBrightness = result.lux;

         

                printResult("OPT3001", result);

         

                if (toBeSetBrightness > setBrightnessValue)

         

                {

         

                  FastLED.setBrightness(val--);

         

                  FastLED.show();

         

                  Serial.println("Decreasing Brightness");

         

                  Serial.println(val);

         

                  delay(200);

         

                }

         

                else if (toBeSetBrightness < setBrightnessValue)

         

                {

         

                  FastLED.setBrightness(val++);

         

                  FastLED.show();

         

                  Serial.println("Increasing Brightness");

         

                  Serial.println(val);

         

                  delay(200);

         

                }

         

                else

         

                {

         

                  Serial.println("in this else");

         

                }

         

              }

         

            }

         

            else

         

            {

         

              buttonPressed = false;

         

            }

         

          }

         

          receiveMessage(LoRa.parsePacket());

         

        }

         

         

         

        void configureSensor()

         

        {

         

          OPT3001_Config newConfig;

         

          newConfig.RangeNumber = B1100;

         

          newConfig.ConvertionTime = B0;

         

          newConfig.Latch = B1;

         

          newConfig.ModeOfConversionOperation = B11;

         

         

         

          OPT3001_ErrorCode errorConfig = opt3001.writeConfig(newConfig);

         

          if (errorConfig != NO_ERROR)

         

            printError("OPT3001 configuration", errorConfig);

         

          else

         

          {

         

            OPT3001_Config sensorConfig = opt3001.readConfig();

         

            Serial.println("OPT3001 Current Config:");

         

            Serial.println("------------------------------");

         

            Serial.print("Conversion ready (R):");

         

            Serial.println(sensorConfig.ConversionReady, HEX);

         

         

            Serial.print("Conversion time (R/W):");

         

            Serial.println(sensorConfig.ConvertionTime, HEX);

         

            Serial.print("Fault count field (R/W):");

         

            Serial.println(sensorConfig.FaultCount, HEX);

         

            Serial.print("Flag high field (R-only):");

         

            Serial.println(sensorConfig.FlagHigh, HEX);

         

         

            Serial.print("Flag low field (R-only):");

         

            Serial.println(sensorConfig.FlagLow, HEX);

         

         

         

            Serial.print("Latch field (R/W):");

         

            Serial.println(sensorConfig.Latch, HEX);

         

         

            Serial.print("Mask exponent field (R/W):");

         

            Serial.println(sensorConfig.MaskExponent, HEX);

         

         

            Serial.print("Mode of conversion operation (R/W):");

         

            Serial.println(sensorConfig.ModeOfConversionOperation, HEX);

         

         

            Serial.print("Polarity field (R/W):");

         

            Serial.println(sensorConfig.Polarity, HEX);

         

         

         

            Serial.print("Overflow flag (R-only):");

         

            Serial.println(sensorConfig.OverflowFlag, HEX);

         

         

         

            Serial.print("Range number (R/W):");

         

            Serial.println(sensorConfig.RangeNumber, HEX);

         

         

            Serial.println("------------------------------");

         

          }

         

        }

         

         

         

        void printResult(String text, OPT3001 result)

         

        {

         

          if (result.error == NO_ERROR)

         

          {

         

            Serial.print(text);

         

            Serial.print(": ");

         

            Serial.print(result.lux);

         

            Serial.println(" lux");

         

          }

         

          else

         

          {

         

            printError(text, result.error);

         

          }

         

        }

         

         

         

        void printError(String text, OPT3001_ErrorCode error)

         

        {

         

          Serial.print(text);

         

          Serial.print(": [ERROR] Code #");

         

          Serial.println(error);

         

        }

         

         

         

        void sendMessage(String outgoing, byte destinationAddress)

         

        {

         

          LoRa.beginPacket();

         

          LoRa.write(destinationAddress);

         

          LoRa.write(localAddress);

         

          LoRa.write(outgoing.length());

         

          LoRa.print(outgoing);

         

          LoRa.endPacket();

         

         

        }

         

        void receiveMessage(int packetSize)

         

        {

         

          if (packetSize == 0)

         

            return;

         

         

         

          int recipient = LoRa.read();

         

          byte sender = LoRa.read();

         

          byte incomingLength = LoRa.read();

         

         

         

          String incoming = "";

         

         

         

          while (LoRa.available())

         

          {

         

            incoming += (char)LoRa.read();

         

          }

         

          if (incomingLength != incoming.length())

         

          {

         

            Serial.println("Error: Message length does not match length");

         

            return;

         

          }

         

         

         

          if (recipient != localAddress)

         

          {

         

            return;

         

          }

         

         

          if (sender == destinationAddress)

         

          {

         

            if (incoming == "ModeChange")

         

            {

         

              buttonPressed = !buttonPressed;

         

            }

         

            else

         

            {

         

              String data = incoming;

         

              data += '\n';

         

              char buff[100];

         

              data.toCharArray(buff, 100);

         

              val = data.toInt();

         

              Serial.print("Received Value from POT is: ");

         

              Serial.println(val);

         

         

         

            }

         

          }

         

        Working:​

        Base station: The base station reads the potentiometer's analog input value and constantly transmits to the end device using the LoRa module.

        The base station also has a switch which toggles the end device between 'manual mode' and 'maintain lux value mode'.

        Whenever this switch is pressed, a message is transmitted through the L0Ra module indicating to the end device to switch the control mode.​

         

        End device: The end device takes potentiometer readings received by LoRa module and controls

        the brightness of the LED strip (when in manual mode). Whenever the end device receives a mode toggling message,

        the end device increases or decreases the brightness of the LED strip to maintain the lux value of the environment when the switch is pressed.

         During this time, the value transmitted by the potentiometer does not affect the LED strip's brightness.​

         

        Hope you implement this project idea and let us know how it went.

        Feel free to come up with other cool ideas and share them with us.

        You can buy all the components required from our store Robocraze.

         

        Comment below if you get stuck or have any further questions.

        Prev Post
        Next Post

        Leave a comment

        Please note, comments need to be approved before they are published.

        Thanks for subscribing!

        This email has been registered!

        Shop the look

        Choose Options

        Edit Option
        Back In Stock Notification
        Compare
        Product SKU Description Collection Availability Product Type Other Details

        Choose Options

        this is just a warning
        Login
        Shopping Cart
        0 items
        FREE SHIPPING!
        ₹100 OFF
        ₹200 OFF
        ₹999
        ₹2500
        ₹4900
        WhatsApp Chat Chat