Its magic! Controlling a Magic Mirror with a motion sensor from Home Assistant to save energy

Published by Oliver on

A magic mirror is a stunning piece of furniture and tech but running it constantly draws a lot of power. I am switching mine on and off based on a motion sensor using Home Assistant. Here is how to do that.

The Magic Mirror

I have described how I built my magic mirror before in this article. Basically it is an old TV screen mounted behind a semi transparent mirror that is showing relevant data like a weather forecast in white on black. This makes the text appear to be floating in the mirror. The Raspberry Pi itself that is running the software part does not draw too much power but a TV can be different. I already disconnected all components that are not needed anymore, like speakers, but the panel is still running 24/7.

To fix this I need a way of controlling the screen itself. I see two options here: using a smart relay like the Sonoff S20 I use in my smart light system or software control. TVs are not made to quickly turn on or off (takes some time and shows a logo first) so the hardware option only means more hardware that is drawing power but no huge advantage.

Instead I am relying on software and HDMI right now. The Pi is connected to the TV via a HDMI cable and HDMI can not only transport image data but also simple commands via a protocol called CEC. As described before the Pi supports this protocol and can send on or off commands like this:

# needed
sudo apt install cec-utils

# 0 is the TV, 1 is the pi itself - check via echo 'scan' | cec-client -s -d 1
# now you can turn the screen off
echo 'standby' | cec-client -s -d 1
# or on
echo 'on' | cec-client -s -d 1
# or get the current state
echo 'pow' | cec-client -s -d 1

The motion sensor

I came up with two different ways of automating the Magic Mirror. The simple idea is to use a time based trigger and simply shut down the screen during the night or maybe when I am not at home. The new schedule helper might be a good tool for this.

Aqara motion sensor
Sonoff S26 as a hardware alternative (with Tasmota) or Aqara plug via Zigbee
If you are interested in buying Zigbee devices for your smart home consider doing it via my affiliate links above.

Instead I opted to go for a bit more precise solution and reuse the motion sensors from my smart lights. The doorway that houses the Magic Mirror already has a motion sensor for the lights. I can just use the same events to turn on or off the mirror itself.

The small Zigbee motion sensors I am using

This works well although you have to keep in mind that turning on the screen via CEC takes around 10-15 seconds. For me this is not a problem though as I will only need the screen when I am in the room for a bit longer, not just passing through.

To not turn off the screen too soon I also added a timeout of currently five minutes without any motion before turning off again.

The code

To be able to send commands from anywhere to the Magic Mirror I installed a module called MMM-Remote-Control which provides a web UI and REST endpoints to control the screen. You can also configure custom commands for monitor off and on. After cloning the module to the modules folder with git I added this configuration to my config/config.js file.

address: ""
modules: [
// ...
        module: 'MMM-Remote-Control',
        config: {
                customCommand: {
                        monitorOnCommand: "echo 'on' | cec-client -s -d 1",
                        monitorOffCommand: "echo 'standby' | cec-client -s -d 1"
                showModuleApiMenu: false,
                secureEndpoints: false, // Optional, See API/

Note that my configuration makes the Magic Mirror listen to outside traffic (instead of running just on localhost) and disables a couple of security features. This is fine in my case as it is only available via my (secured) network but be careful if outside access is possible.

After a restart of the Magic Mirror software you can now test this by sending a GET request to http://magicmirror:8080/api/monitor/off to turn off the monitor. On Windows you could use a software like Postman to do this.

Home Assistant is the controller of my smart home and is already connected to the motion sensor via Zigbee and ZHA. The next step is to make it send requests to the REST API provided by Magic Mirror. This can be done by adding custom rest commands in the configuration.yaml file. Mine looks like this

    url: http://magicmirror:8080/api/monitor/on
    url: http://magicmirror:8080/api/monitor/off

You can test this by using the built in developer tools to call the new services and see if the screen reacts.

Testing the new services in the developer tools

If this works the final step is to actually build an automation. Mine is quite simple and just listens to the motion sensor indicating motion. Once it detects motion it will turn on the screen. It will then wait for the motion sensor to turn off again (there is I believe a reset time of around 90 seconds for the Aqara sensor) and wait some additional 30 seconds afterwards. Then it shuts the mirror off again.

If during that time new motion is detected the automation restarts itself so the screen is kept on. That is done by setting the mode of the automation to restart. This whole system works very similar to my blueprint from the smart light system.

Change the mode on the upper right by clicking “Change mode”

The final automation looks like this

Automation that controls the magic mirror

or as code:

alias: Magic mirror on/off
description: ""
  - type: motion
    platform: device
    device_id: abc
    entity_id: binary_sensor.motion_hallway
    domain: binary_sensor
    id: "on"
condition: []
  - service: rest_command.magic_mirror_on
    data: {}
  - wait_for_trigger:
      - type: no_motion
        platform: device
        device_id: abc
        entity_id: binary_sensor.motion_hallway
        domain: binary_sensor
    continue_on_timeout: false
  - delay:
      hours: 0
      minutes: 0
      seconds: 30
      milliseconds: 0
  - service: rest_command.magic_mirror_off
    data: {}
mode: restart

So far this has been working great for me. It takes a couple of seconds to turn on but in the long run this will save a lot of energy and prolong the life of the hardware.