A Night Light That Thinks for Itself
A light sensor, a threshold, and an LED. The device reads, decides and acts on its own; the dashboard only watches the value and tunes the threshold. At the end you switch the WiFi off and the night light keeps working. About 30 minutes.
What You'll Build
An analog input registered in firmware and read with
aread.A script that turns the LED on when it gets dark, without sending anything anywhere.
A
lightevent published only when the reading moves by more than a step, and a Value widget showing it.A
thresholdslider on the dashboard, retained, that the script reads back.A demonstration that none of this needs the network.
This is Edge Logic Deployment in one page: the logic lives on the device, the cloud is an observer.
Prerequisites
The board and the LED on GPIO13 from Dim an LED from a Slider, with the PlatformIO project at hand. You will upload once more.
A light-dependent resistor (LDR) and a 10 kΩ resistor, or a 10 kΩ potentiometer instead of both.
Step 1: Register the Analog Input
Wire the Sensor
The LDR and the resistor form a voltage divider: LDR from 3V3 to a free breadboard row, resistor from that row to GND, and the row to the analog pin, A0 on NodeMCU or GPIO34 on ESP32. With the LDR on the 3V3 side, light gives a high reading and darkness a low one, which is what the script assumes.
With a potentiometer, connect the outer legs to 3V3 and GND and the wiper to the analog pin. Turning towards GND is nightfall.
Edit main.cpp
Open src/main.cpp and make two changes: register the sensor, and add GPIO13 to the digital output line from Getting Started so the LED can be switched on and off as well as dimmed. The analog output line from the previous guide stays.
GPIO13 is now analog output 0 and digital output 1 at the same time; each primitive has its own index namespace. See Registering GPIO Pins. aread returns 0 to 1023 on both boards.
Upload with pio run --target upload. The device reconnects on its own and restarts the Dimmer script, which you replace in Step 2.
Step 2: Read and Log the Sensor
Open the Sandbox page and create a script called Night Light. The first version only prints the sensor: a task every 200 ms with one print block holding analog read register 0.
Select your device, press Compile, then play. Turn the Analog Read knob in the Emulator and watch the Logs panel: the printed value follows about half a second after you stop turning (Analog Read).
Press Deploy and open the device's Logs tab. Note the value in room light, then cover the sensor and note it again. Pick a threshold halfway between uncovered and covered; this guide uses 100.
Step 3: Decide on the Device
The script grows in three edits, and the LED works from the first one on.
Turn the LED On When It Gets Dark
The LED should be on whenever the reading is below a threshold. Outside the task, add set light to 0 and set threshold to your number. Inside it, replace the print block with set light to analog read 0, then a digital write to register 1 whose value is the comparison light < threshold.
Read — set light to analog read 0 stores the current reading:
(setq light (aread 0)). The0is the analog input index from Step 1.Decide and act — digital write light < threshold to pin 1 compiles to
(dwrite 1 (< light threshold))and lights digital output1while the reading is below the threshold. The comparison happens in the device's own memory; no event, no broker.
Compile and run. The Digital Write card now shows two registers; turn the knob below the threshold and register 1 lights. Deploy.
Publish Only Changes
The device should report the reading to the dashboard, but only when it has moved by more than 20 since the last report. Outside the task, add set last_sent to -100. At the end of the task, add an if whose condition is absolute of light - last_sent > 20: a comparison holding a math operation set to absolute and an arithmetic block. In its do slot, push event light with the value light, then set last_sent to light.
Distance —
(abs (- light last_sent))is how far the reading has drifted since the last publish. The if fires only when that exceeds20, about two percent of the range.Publish —
(push_event 'light light)sends the reading and(setq last_sent light)remembers what was sent. See push event.Start —
last_sentbegins at-100, further than20from any reading, so the first pass always publishes once.
Why not publish every reading? Five messages a second from every device, forever, mostly saying that nothing changed: broker load and dashboard noise for no information. The device has the previous value in memory and can tell when a change matters. That filtering is the device thinking, the same as the LED decision; the network carries information, not samples. The 20 is a policy, and a different project may want 5 or 100.
Accept a Threshold from the Dashboard
The dashboard should be able to move the threshold while the script runs. At the end of the task add a second if with is event threshold as its condition and set threshold to pop event threshold in its do slot.
Default stays — with no event, the
100at the top remains in force. The dashboard is optional.
This is the complete script, including the user-library block the editor adds. Save it; the checkpoint for this edit is in Step 4.
Step 4: Watch and Tune from the Dashboard
Open the Dashboard page, enter Edit Mode, and add two widgets with Add Widget:
A Value named
Light, eventlight, Decimal digits0.A Slider named
Threshold, eventthreshold, Min0, Max1023, Retain on.
Save both and drag the slider to the threshold from Step 2. See Widget Configuration.
Back in the Sandbox, compile and run with the Dashboard page next to the Emulator window. Turn the Analog Read knob slowly: the Light widget follows in jumps of at least 20 and stays still while the knob is still. Leave the knob at some value and drag the Threshold slider past it: register 1 on the Digital Write card flips as the slider crosses. Everything goes through the real broker, so the widgets see the Emulator exactly as they will see the device (Events).
Press Deploy in the Emulator's header. The device picks up the retained slider position on its first pass.
Step 5: Pull the Plug on WiFi
Switch the router off, or carry the board out of range. The onboard LED starts blinking as Uniot Core tries to reconnect. The breadboard LED does not care: cover the sensor and it lights, uncover it and it goes dark, at the threshold the slider last set. The script never stopped; the light events it tried to publish were simply dropped.
Bring the network back. The onboard LED goes dark, the broker replays the retained threshold, and the Light widget catches up on the next change of 20 or more. Nothing needed resetting or redeploying.
In the imperative model the device would stream readings and a cloud rule would send "turn on" back, so a dead link means a dark room. Here the cloud only ever saw a number and offered a threshold. The decision was the device's from the start, and losing the cloud loses nothing but the view.
Troubleshooting
The reading is stuck at 0 or 1023. The analog pin is not on the point between the LDR and the resistor, or the pin is wrong for the board: ESP32 needs GPIO32 to 39, and a bare ESP8266 module tops out at 1 V.
Dark gives a high number. The LDR and the resistor are swapped. Swap them back, or change the comparison to light > threshold.
The Light widget updates constantly. The reading jitters more than the step. Raise the 20 to 50, or move the sensor away from a flickering light.
The slider has no effect. The widget's Event and the script's event name differ (names are case-sensitive), or the slider is outside the range you saw in Step 2. If you toggled Retain, the broker forgot the value; drag the slider again.
The LED never lights, or the Emulator says "Registers are out of bounds". The device does not have the firmware from Step 1, or another device is selected. The Registers tab must list digital output 1 and analog input 0.
Nothing works after the network comes back. Check the device's Logs tab; a script error stops the interpreter. See Debugging Scripts.
The Emulator run stops on its own. A forever task stops after 9,999 iterations in the Emulator only, about half an hour at 200 ms; see Limits.
What's Next
Two Devices, One EventEdge Logic DeploymentPrimitivesLast updated