There's a certain satisfaction in automating something that was never designed to be automated. My SIBRILLE desk lamp is a perfectly nice lamp โ 22W, touch controls, remote, adjustable color temperature. But it has one frustrating quirk: every time power is cut and restored, it defaults to off. That means a smart plug alone can't control it. Plug it into a Kasa outlet, cut the power, restore it โ the lamp stays dark.
The obvious workaround is to just leave it plugged in and use the remote. But that's not nearly as interesting as wiring up an ESP32 IR blaster, a PIR motion sensor, and a handful of Home Assistant automations to make the whole thing happen automatically.
Here's how I built a system where the lamp turns itself on when I sit down at my desk, applies the right lighting preset based on time of day, and turns itself off when I leave โ all without ever touching a button.
The Hardware
The parts list is short and relatively inexpensive:
- Type-C D1 Mini ESP32 โ the brains of the operation
- 38kHz IR transmitter module โ sends commands to the lamp
- 38kHz IR receiver module โ used temporarily to capture codes from the existing remote
- HC-SR501 PIR motion sensor โ detects when I'm sitting at my desk
- Plenty of jumper ribbons for use in this and future projects
- A USB-C cable long enough to reach my lamp from the nearest outlet
- A USB-C wall charger for power
Most of the items were purchased in multipacks, so I have "leftovers" for later use.
There was one wrinkle I didn't anticipate: the D1 Mini ESP32 arrived without pre-soldered header pins. Just bare through-holes. Which meant that before I could connect a single jumper wire, I needed to learn how to solder.
A Brief Soldering Interlude
I want to be upfront: I had never soldered anything before this project. Undeterred, but barely knowing what I was looking for, I picked up a soldering iron station from Harbor Freight.
My preparation consisted of watching a few YouTube tutorials and asking Claude some very basic questions โ what temperature, how long to hold the iron, whether to tin the tip first (yes, always). The advice that actually clicked was deceptively simple: heat the pin, not the solder. Touch the iron to the pin and pad, let it get hot, then feed solder into the joint. The solder flows where the heat is.
My first few joints were a little lumpy. By the end of the board they looked considerably better. It turns out soldering header pins onto a development board is about as forgiving a first project as you can pick โ the pads are large, the pins are sturdy, and there's nothing nearby to accidentally bridge.
If you've been putting off a project because it requires soldering and you've never done it, this is a reasonable place to start.
The Architecture
The system has two layers working together:
ESPHome runs on the ESP32 and handles the low-level hardware โ firing IR codes at the lamp and reading the PIR sensor state. It exposes everything to Home Assistant as entities.
Home Assistant receives the PIR sensor state and runs automations that decide when to turn the lamp on or off and which preset to apply. Since IR is one-way (the ESP32 can send commands but can't read the lamp's current state back), I use an input_boolean helper in Home Assistant to track whether the lamp should be on or off โ preventing the power toggle from firing twice in a row and turning the lamp back off.
Capturing IR Codes
Before transmitting anything, I needed to know what to transmit. The SIBRILLE remote speaks 38kHz IR โ the same frequency as the receiver module I had purchased.
I temporarily wired the receiver to GPIO4 on the ESP32, flashed an ESPHome config with remote_receiver: dump: all, and started pressing buttons. The ESPHome logs spit out Pronto-format IR codes for each button press. I captured seven:
- Power toggle
- Brightness up / Brightness down
- Color temperature warm / cool
- Morning preset (warm, bright)
- Nighttime preset (dim, very warm)
One thing to note: every button press produces two codes โ the actual command and a short repeat signal. You only want the long one.
Wiring It Up
With codes captured, I swapped the receiver for the transmitter and added the PIR sensor. The final wiring is straightforward:
| Component | Connection |
|---|---|
| IR Transmitter VCC | 3.3V |
| IR Transmitter Signal | GPIO4 |
| PIR VCC | VCC (5V) |
| PIR OUT | GPIO16 |
| PIR GND | GND |
A couple of things I learned the hard way:
The HC-SR501 pin order isn't what you'd expect. With the dome facing you and the jumper on the left, it's GND, OUT, VCC โ right to left is power. I had it backwards initially, which produced either nothing or frantic rapid-fire false triggers. Fortunately I was able to find "documentation" on the Amazon product listing page that straightened things out for me.
The PIR also needs 5V, not 3.3V. And it has a 30-second warmup period after power-on before it starts detecting anything reliably.
The software pulldown (mode: input: true, pulldown: true in ESPHome) was necessary to prevent floating pin noise on the signal line.
One more gotcha worth mentioning: after all the wiring troubleshooting, the PIR still wasn't detecting reliably. The culprit turned out to be a bad solder joint on the VCC pin โ a connection that looked fine visually but wasn't making solid contact. Cleaning it up fixed everything. Lesson learned: when something isn't working after you've verified the software, look at the physical connections again.
The ESPHome Config
Though I'm only using three in my automations, the final YAML exposes seven button entities and the PIR sensor to Home Assistant:
remote_transmitter:
pin: GPIO4
carrier_duty_percent: 50%
binary_sensor:
- platform: gpio
pin:
number: GPIO16
mode:
input: true
pulldown: true
name: "Desk PIR"
device_class: motion
button:
- platform: template
name: "Desk Lamp Power"
on_press:
- remote_transmitter.transmit_pronto:
data: "0000 006D ..." # truncated for readability
- platform: template
name: "Desk Lamp Brightness Up"
on_press:
- remote_transmitter.transmit_pronto:
data: "0000 006D ..."
- platform: template
name: "Desk Lamp Brightness Down"
on_press:
- remote_transmitter.transmit_pronto:
data: "0000 006D ..."
- platform: template
name: "Desk Lamp Color Temp Warm"
on_press:
- remote_transmitter.transmit_pronto:
data: "0000 006D ..."
- platform: template
name: "Desk Lamp Color Temp Cool"
on_press:
- remote_transmitter.transmit_pronto:
data: "0000 006D ..."
- platform: template
name: "Desk Lamp Morning Preset"
on_press:
- remote_transmitter.transmit_pronto:
data: "0000 006D ..."
- platform: template
name: "Desk Lamp Nighttime Preset"
on_press:
- remote_transmitter.transmit_pronto:
data: "0000 006D ..."
One important ESPHome detail: my Home Assistant instance runs as a Container type LXC on Proxmox, which means it doesn't support the Add-on Store. ESPHome had to be deployed as its own separate LXC rather than as an HA add-on. If you're running a similar setup, that's the path you want.
The Home Assistant Automations
Two automations drive the whole thing.
Lamp On โ triggered by motion:
Trigger: Desk PIR โ Detected
Condition: Desk Lamp State helper = off
Action: Choose:
If 6:00 AM โ 6:00 PM:
Press Desk Lamp Power
Wait 1 second
Press Desk Lamp Morning Preset
Otherwise:
Press Desk Lamp Power
Wait 1 second
Press Desk Lamp Nighttime Preset
Input Boolean Turn On โ Desk Lamp State
Lamp Off โ triggered by no motion:
Trigger: Desk PIR โ Clear, for 2 minutes
Condition: Desk Lamp State helper = on
Action: Press Desk Lamp Power
Input Boolean Turn Off โ Desk Lamp State
The 1-second wait between the power button and the preset button is important โ the lamp needs a moment to wake up before it can receive the preset command.
The input_boolean helper is the glue that makes everything reliable. Since IR is send-only, Home Assistant has no way to know whether the lamp actually turned on. The helper tracks the intended state, and the conditions on both automations prevent the power button from being pressed twice in a row and toggling the lamp back off. This does mean I have to avoid manually intervention and turning the lamp on myself, but that was kind of the whole purpose of this project!
What It Actually Does
When I sit down at my desk in the morning, the lamp turns on automatically within a few seconds and sets itself to a warm, bright daylight-appropriate setting. After 6 PM, sitting down triggers the nighttime preset instead โ dimmer, warmer, easier on the eyes. When I leave, the lamp waits a full two minutes (in case I'm just grabbing something) and then turns itself off.
The whole thing runs locally. No cloud dependency, no subscription, no "works with Google" sticker required.
What's Next
The ESP32 is zip-tied to the lamp base at the moment โ functional but not pretty. One of Eli's friends is going to 3D print a small case for the sensor, and I'll probably use foam tape to affix it to the lamp neck.
I also have two more ESP32s and several more PIR sensors from the same order. Not entirely sure what I'll do with those, but now that I have a taste of tinkering I'm excited to do more.
A Note on AI-Assisted Tinkering
I want to be honest about something: I would never have attempted this project a few years ago. Not because the individual pieces are that complicated, but because the combination of unfamiliar territory โ microcontrollers, IR protocols, ESPHome YAML, soldering, Home Assistant automations โ would have felt like too much to take on without a guide.
Claude was that guide throughout this project. Not in a "here's a copy-paste solution" way, but in a genuine back-and-forth where I could ask why something wasn't working, share a screenshot of a log, and get a real diagnosis. When the PIR was rapid-firing, we worked through it together. When the mDNS resolution failed, I got a clear explanation of why and exactly what to change. When I had never held a soldering iron before, I got patient, practical advice that actually worked.
I think there's a version of this hobby that's always been accessible in theory but intimidating in practice โ the kind of project where you could figure it out eventually if you read enough forum posts and had enough patience for trial and error. AI assistance compresses that dramatically. The knowledge was always out there. Having something that can apply it to your exact situation, in real time, changes the calculus on what's worth attempting.
If you've been eyeing a project like this and talking yourself out of it, that hesitation is worth revisiting.