All I Wanted Was to Control Three Dimmers Locally
Three Varilight V-Pro Smart dimmers, a small Proxmox box and a dislike of unnecessary software turned into protocol analysis, a local controller, MQTT, Home Assistant discovery and a surprisingly complete management UI.
All I wanted was…
to control three dimmers locally without running another full software stack.
Then it escalated quickly.
Three dimmers did not need a datacentre
The starting point was not especially ambitious.
I already had three VARILIGHT V-Pro Smart dimmers.
The hardware worked. The stock firmware worked. The wall controls worked.
What I wanted was a lightweight local control path into Home Assistant.
The normal route uses the SUPLA ecosystem. That is perfectly reasonable, but for my particular setup it meant considerably more server-side machinery than I wanted to dedicate to three dimmers.
My Proxmox box is useful.
It is not a hyperscaler.
So the question became:
Can I keep the Varilight hardware and stock firmware, but replace only the server side with something small and local?
That sentence caused trouble.
First, find out what the dimmer actually expects
The useful part of reverse engineering is often discovering how little of a large protocol a particular device actually needs.
The tested V-Pro Smart firmware talks to its server over a legacy TLS connection and uses a small, repeatable subset of the SUPLA protocol.
For the hardware I have tested, the important pieces turned out to be:
- firmware
2.8.55 - protocol version
12 - one dimmer channel
- channel
0, type4000 - TLS 1.1 using
AES128-SHA - brightness represented literally as
0..100 - device-originated state changes reported back to the server
That was enough to move the problem from run the whole stack to implement the part these dimmers actually use.
No replacement firmware.
No opening the dimmers.
No pretending to be a different product.
The stock firmware simply points at a local controller instead.
AI wrote a lot of it. I kept asking the annoying questions.
This was also an experiment in building with AI.
I drove the investigation, decided what to test, compared behaviour against real hardware and kept pushing whenever the easy explanation did not fit.
AI did a large amount of the implementation work: protocol analysis, controller code, tests, MQTT integration, UI work and documentation.
The important bit was the feedback loop.
A theory was not accepted because it looked convincing in code.
It had to survive the actual dimmer.
That distinction became important more than once.
The local path
The finished control path is deliberately small:
VARILIGHT V-Pro Smart
│
│ stock firmware
│ TLS / observed protocol subset
▼
mksi-varilightd
│
├── MQTT ── Home Assistant / automations
│
└── local management API
│
▼
MKSI web UI
Home Assistant does not need a custom integration.
The controller publishes standard MQTT discovery and state.
The dimmer reports physical changes back.
The controller reports those changes through MQTT.
The UI and Home Assistant therefore show what the device says it is doing rather than merely assuming a command succeeded.
Then a controller became a small product
Once basic ON/OFF and brightness worked, the rough test harness was no longer enough.
If this was going to stay in the house, I wanted it to behave like infrastructure rather than a science experiment.
So the project gained:
- MQTT availability and retained state
- Home Assistant MQTT discovery
- stable GUID-based device identity
- local Add / Enroll
- friendly-name changes without changing device identity
- Delete and Re-add
- reconnect-safe command handling
- diagnostics for device-originated changes
- a small local web UI
- a test suite covering protocol, MQTT, lifecycle and management behaviour
The local UI is intentionally not another Home Assistant.
It exists for the low-level things that belong next to the controller: onboarding, status, diagnostics and direct testing.
Day-to-day control still belongs in Home Assistant.
The 28% bug
One of the best bugs arrived after the project looked finished.
Physical brightness changes were read correctly.
ON and OFF worked.
But dragging the brightness slider in Home Assistant caused the new value to appear briefly and then snap back to the old brightness.
The logs made it look almost absurd:
brightness 80 -> accepted
ON -> target 28
set_value -> 28
device_state -> 28
Home Assistant was not failing to set the value.
Our MQTT discovery definition caused it to publish a brightness command and then an ON command.
The controller quite reasonably interpreted ON as restore the last known non-zero brightness.
Which happened to be 28%.
So a perfectly valid 80 was immediately replaced with a perfectly valid 28.
The fix was one discovery option:
"on_command_type": "brightness"
That tells Home Assistant that the brightness command itself turns the light on.
No redundant ON.
No snap back.
And this is a good example of why testing the real behaviour matters more than staring at code and declaring it correct.
I initially went looking at the command queue.
The clue was simpler: the slider changed correctly first, then something changed it back.
The human noticed the behaviour.
The logs told us why.
AI still needs me occasionally.
The protocol value is the slider value
Another useful result of the investigation is that brightness is not being translated through a mystery scale inside this controller.
If the UI asks for 47, the controller sends 47.
If the dimmer reports 47, Home Assistant sees 47.
That does not mean 47% necessarily equals 47% of measured lumens. The physical dimming curve and the LED load can be non-linear.
But at the integration layer, the value is literal and round-trips cleanly.
Keeping the project small was the point
The irony is obvious.
I did not want to run more software.
So I wrote software.
But the result is still much smaller in operational terms than the problem I was trying to avoid.
The runtime path is essentially:
- one small controller
- MQTT
- Home Assistant
- an optional local UI
No MariaDB.
No PHP application stack.
No separate cloud service required for normal control.
The dimmers remain ordinary Varilight dimmers at the wall.
That is exactly what I wanted.
Being nice to the manufacturer matters too
VARILIGHT support have been helpful while I have been investigating the hardware, including offering a spare module for testing.
So I am not treating this as a dramatic vendor defeated story.
It is an independent interoperability project built around hardware I already own.
Before making the code publicly available, I am asking Varilight for their view and giving them a chance to flag anything about product naming, compatibility wording or presentation that they would prefer handled differently.
The project contains my controller, tests, UI and documentation.
It does not distribute Varilight firmware or proprietary source.
That seems like the decent way to do it.
Where it fits in the LAN of Things
This project is really one concrete implementation of the broader idea behind my LAN of Things.
The device can keep speaking the protocol it was designed to speak.
A narrow local adapter understands it.
MQTT and Home Assistant get a boring, consistent interface.
The house does not need to care how strange the device-specific side is.
Read the wider LAN of Things story →
Was this necessary?
No.
There were easier ways to control three lights.
But the final result is useful:
- the stock dimmers still work normally
- physical control is reflected back into Home Assistant
- control stays local
- the runtime is small
- the integration is inspectable
- the behaviour is covered by tests
- adding another compatible dimmer no longer requires rebuilding the system
All I wanted was to control three dimmers locally without running another full software stack.
I now have a protocol implementation, MQTT discovery, a device-management UI, fifty-five tests and a GitHub project waiting for its public debut.
Perfectly normal lighting project.
MKSI Varilight Local is an independent interoperability/community project. It is not affiliated with, endorsed by, or supported by VARILIGHT, SUPLA or Zamel. Product and project names belong to their respective owners.