Software KVM and other home controls with MQTT
I've been building my Home Assistant setup for about a year now, adding more integrations, connecting to my various smart devices, and building the dashboard. Last spring I bought a Waveshare 10" touch display and asked a colleague to print me some legs I found a design file for. This gave me a nice dashboard for my desk.
The next step was taking advantage of my Dell Ultrasharp's built-in KVM to switch between my work and personal computers without reaching behind to the controls. I know, it has built-in hotkeys for this functionality, but I'm not thrilled by the idea of something intercepting keystrokes and why go simple when you can over engineer.
Software monitor control
For those who have never heard of DDC/CI (Display Data Channel Command Interface) it implements a command protocol over I2C which most modern monitors support. You can send commands like change brightness, power off, and.... switch inputs. There's a package called ddcutil, and since my personal computers are all linux - an obvious synergy emerged, I could send commands to switch inputs, somehow.
MQTT
One of the great functionalities of HA is the MQTT integration it has, the ability to easily send messages. This felt like the perfect method to send commands to a remote listener on the desktop to issue these commands.
[
{
"command": "monitor",
"data":
{
"monitor": "left",
"input": "hdmi",
"power": "wake"
}
},
{
"command": "monitor",
"data":
{
"monitor": "right",
"input": "usbc"
}
},
{
"command": "speaker",
"data":
{
"volume": "up"
}
},
{
"command": "lock",
"data":
{
"unlock": true
}
}
]
Golang and Switcher
When I started this project learning Golang had been on my radar for a while, so I forced myself to use it. Python might have been simpler for my existing knowledge but actually with the help of Copilot it took less than a day to get a working prototype functioning simply called Switcher.
The more challenging piece was getting it running the way I wanted, I have dockerize about a dozen different services on this machine and wanted to do the same with Switcher
. Unfortunately after a lot of attempts and failures, I was able to map the proper I2C devices to the container but something just didn't quite work right and the application kept core dumping whenever it tried to run ddcutil. It wasn't worth the fight in this case so I went with Plan B, run it using Supervisor, it works.
But once working it was simple enough to add to my HA Dashboard. You can see these buttons in the bottom left of my desk display.
- type: horizontal-stack
cards:
- type: custom:mushroom-template-card
primary: Display
secondary: ''
icon: mdi:monitor
- type: custom:mushroom-template-card
primary: Laptop
secondary: ''
icon: mdi:laptop
tap_action:
action: call-service
service: mqtt.publish
service_data:
topic: /home/office/monitors
payload: >-
[{"command": "monitor", "data":
{"Input":"usbc","Monitor":"right"}}]
- type: custom:mushroom-template-card
primary: Desktop
secondary: ''
icon: mdi:desktop-tower
tap_action:
action: call-service
service: mqtt.publish
service_data:
topic: /home/office/monitors
payload: >-
[{"command": "monitor", "data":
{"Input":"hdmi","power":"wake","Monitor":"right"}},
{"command":"lock","data":{"unlock":true}}]
Enhancements
Now with this working I moved on to some enhancements. What about turning the display back on and unlocking the machine when switching. One of the slowest parts was after pushing the dashboard button the monitor had to switch all the USB inputs over, the computer has to notice the mouse again, then I had to wiggle it to turn off screen blanking. By using xset
to wake everything up it cut the switch time in half in cases when the desktop had blanked the screen.
As well, my long term plan is a headless Plexamp instance on a Pi which can be centrally controlled. This way when switching back and forth I'd have the same playlist going. This needed the ability change the volume on the host machine as well. So commands for amixer
for volume which Switcher
could handle too seemed obvious.
The final enhancement to come is switching the input of my Edifier speakers automatically. I've purchased some KY-005 Ir Emitters and found a fantastic write-up on how to use these with lirc
on a Pi. I'll publish another article when I get that working.