LINKS
Find the code to the Smart Mirror LED Strip Controller on Github here.
ABSTRACT
I added an LED strip to my Smart Mirror’s Raspberry Pi and wrote a REST API to control it from around the house. I then linked it to my HomeAssistant instance for weather notifications, sensor feedback and more!
In this article, we will use the Smart Mirror LED strip to:
- Turn on when motion is detected
- Indicate how much battery our phone has left
- Provide feedback on volume changes in the speaker
CONTENTS
HARDWARE
My smart mirror is running on a Raspberry Pi 5 4GB.
I used an APA102 LED strip with approximately 120 LEDs.
I used the wiring from https://pimylifeup.com/raspberry-pi-led-strip-apa102/
I stuck the strip to the back of the mirror around its border.
For the example, I also connected a PIR Motion Sensor, though this is not necessary.
SOFTWARE
The mirror is a forked version of the Magic Mirror platform (you can see my changes here if you’re curious).
I wrote the REST API in Python using FastAPI (here), and was controlled it via pm2. There are many ways to automatically run and manage the program; I chose pm2 because I already use it for MagicMirror.
# Smart Mirror LED Strip startup
source PATH/TO/PYTHON/VENV
cd ~/Workspace/Python/led-strip-control
python main.py
The API uses the apa102-pi package to control the LEDs. For quick configuration changes, you can modify the config.py file. However, this was designed for people to extend it to better match their use case.
MOTION SENSOR
This was the quickest to implement, as I already have a module MMM-PIR
with callback scripts for when the display turns on or off.
The endpoint I hit on my REST API was the default /circle
request:
curl -X GET http://0.0.0.0:3001/api/circle
This automatically runs a rainbow loop around the Smart Mirror LED strip, which lasts for a few seconds.
Depending on how you’ve implemented your motion control, all you need to do is hit that endpoint when motion is detected.
BATTERY INDICATOR
This was a little more involved in the backend. I used the /percentage
endpoint which, depending on the percentage you provide in the body, will light up some number of LEDs. The colour will flow from red to green, and flash at the end.
I first added the following template to my configuration.yaml
, which uses the RESTful Command integration:
rest_command:
mirror_light_percentage:
url: "http://[SMART_MIRROR_ADDRESS]/api/percentage"
content_type: "application/json"
method: POST
payload: '{"percentage": "{{ percentage }}"}'
This means I can use it in an automation, and dynamically provide the percentage to use for the Smart Mirror LED Strip.
I used the HomeAssistant Companion App entity, which acts as a sensor for my phone
alias: LEDs when charging
description: "Controlling Smart Mirror LED Strip"
triggers:
- entity_id:
- sensor.phone_battery_state
to: charging
trigger: state
conditions: []
actions:
- action: rest_command.mirror_light_percentage
data:
percentage: "{{ states('sensor.phone_battery_level') |int }}"
mode: single
Now, when I plug in my phone to charge, a little animation plays on my smart mirror! Do I need it? No. Is it cool? Absolutely yes.
I would probably modify this to play when my battery reaches certain thresholds (50%, 20% etc.) so the feedback is more useful. It would simply be a change to the trigger
in the configuration above.
VOLUME CHANGE
This was very similar to the previous one, but I kept the rest commands simpler. We have two separate entries to the /pulse
endpoint for left and right directions.
rest_command:
mirror_light_pulse_right:
url: "http://[SMART_MIRROR_ADDRESS]/api/pulse-direction?direction=3"
mirror_light_pulse_left:
url: "http://[SMART_MIRROR_ADDRESS]/api/pulse-direction?direction=1"
The trigger here is my controller, which is connected to my HomeAssistant server via bluetooth. The trigger is passed through as a keyboard_remote_command_received
event, and you just need to find the right keycode that maps to your button.
alias: RTSpeakerUp
description: ""
triggers:
- trigger: event
event_type: keyboard_remote_command_received
event_data:
device_descriptor: /dev/input/eventx
key_code: 706
type: key_down
conditions: []
actions:
- action: media_player.volume_up
metadata: {}
data: {}
target:
device_id: [SOME_ID]
- action: rest_command.mirror_light_pulse_right
metadata: {}
data: {}
mode: single
alias: LTSpeakerDown
description: ""
triggers:
- trigger: event
event_type: keyboard_remote_command_received
event_data:
device_descriptor: /dev/input/eventx
key_code: 707
type: key_down
conditions: []
actions:
- action: media_player.volume_down
target:
device_id:
- [SOME_ID]
data: {}
- action: rest_command.mirror_light_pulse_left
metadata: {}
data: {}
mode: single
As before, this briefly flashes the Smart Mirror LED strip whenever you turn the volume up via the controller. You could also modify it to be triggered by the volume state change, so it runs no matter what you use.
FUTURE WORK
This was a super fun project, but could be so much cooler!
Some areas I would improve on if I had more time (perhaps an exercise for the reader …)
- The logic for controlling the LEDs is rudimentary, and cannot be interrupted, have ambient settings, have schedules etc. Having a shared, central instance of the controller can open up much more
- If you link it to your media player and implement some fourier transforms, you can use it as a music visualiser!
- A lot of the projects we work on would benefit from an accessible visualisation, like reflecting the sentiment of the news story being displayed on the mirror.
Let me know if you have any more cool ideas to use a Smart Mirror LED Strip!