MagicMirror2 - a stable integration for the monitor controls in 2024

I built my magicmirror years ago, it was my first venture into smarthome stuff, having just discovered HA back then I wanted to have HA control it.
I have made posts about the integration to HA before, but I’ll give this update to the integration of it.

I first made an attempt to get it set up with HTTP requests, which I also showed here, and it worked ok, not great though.
Shortly after the build, a MQTT integration for the MagicMirror was launched, it was the only proper option, but it is a rather convoluted MQTT integration, it worked quite stable, and could turn the monitor on and off from HA.
The MQTT gave a lot of possibilities for integration, but it was quite complex to set up.

Then some time later, a year or two, @sindrebroch made an excellent integration for MagicMirror into Home Assistant, big cudos to him. It could do a lot of stuff, like control of modules in the mirror, rebooting, all sorts of very cool features.

At some point, some updates either in MM or in HA gave the integration quite a lot of challenges. It made it unusable for me. Unfortunately @sindrebroch could not find the problems, even though he did a seperate branch of the module he interfaced to for the MagicMirror (MMM-Remote-Control), it worked for a while, but I, and quite a few others, could still not get it to work reliantly.

So I first went back to setting up the MQTT integration, and it worked ok, but I missed it’s ability to dim the light in the monitor. I could make commands to set it to different levels, but I really wanted the smooth adjustments provided from the integration.

As I’m not a coder, and can’t make an alternative integration, I decided to work with the little knowledge I had of how to define a light.

The MMM-Remote-Control module is still the target for the integration as it also provides a RESTful(-ish) API, it’s not completely RESTful, but close enough for this purpose.

Problem is that you can’t define a light as REST, so I had to make a small detour.
I made the light a template light, that uses actions, and these actions can then be REST commands.

First of I needed to create the REST commands for this endeavour, I made three, one to turn the monitor on, one to turn it off, and a third to set the brightness, and these are the only functions I need for my purpose.

rest_command:
  turn_on_bathroom_monitor:
    url: "http://1.2.3.4:8080/api/monitor/on?apiKey=xxx"
    method: get

  turn_off_bathroom_monitor:
    url: "http://1.2.3.4:8080/api/monitor/off?apiKey=xxx"
    method: get

  set_bathroom_monitor_brightness:
    url: "http://1.2.3.4:8080/api/brightness/{{ brightness }}?apiKey=xxx"
    method: get

Then I needed some sensors to fetch the status of the monitor:

sensor:
- platform: rest
  name: Bathroom Monitor state
  resource: "http://1.2.3.4:8080/api/monitor/?apiKey=xxx"
  method: GET
  value_template: "{{ value_json.monitor }}"
- platform: rest
  name: Bathroom Monitor brightness
  resource: "http://1.2.3.4:8080/api/brightness/?apiKey=xxx"
  method: GET
  value_template: "{{ (value_json.result | float * 1.275) | round(0) }}"
  scan_interval: 60

(Weird that “get” has to be in small letters in the sensors, and capitals in commands?)

With these I could build the template light:

light:
  - platform: template
    lights:
      bathroom_monitor:
        friendly_name: "MagicMirror Bathroom Monitor"
        unique_id: "e2d0359d-aafe-4140-a234-f59054e93f30"
        turn_on:
          - action: rest_command.turn_on_bathroom_monitor
          - delay: 1
          - action: homeassistant.update_entity
            data:
              entity_id: sensor.bathroom_monitor
        turn_off:
          - action: rest_command.turn_off_bathroom_monitor
          - delay: 1
          - action: homeassistant.update_entity
            data:
              entity_id: sensor.bathroom_monitor
        level_template: "{{ states('sensor.bathroom_monitor_brightness') | int }}"
        set_level:
          - action: rest_command.turn_on_bathroom_monitor
          - delay: 1
          - action: rest_command.set_bathroom_monitor_brightness
            data_template:
              brightness: "{{ (brightness / 1.275) | int }}"
          - delay: 1
          - action: homeassistant.update_entity
            data:
              entity_id: sensor.bathroom_monitor_brightness
        icon_template: >-
          mdi:mirror-rectangle

As the sensors only update periodically via the rest interface, I added the update_entity on a tip from @tom_l .
I also found out that if I set the brightness without turning the light on first, it wouldn’t work, so I added that step as well.
This works quite well, and I know the great integration by @sindrebroch uses the exact same ‘mechanism’ for the integration, but for some reason this works better.
There is some confusion of the brightness scale in MMM-Remote-control.
The API documentation says it goes from 1-100, the documentation for the integration itself mentions the scale going from 10-200, and as far as I can see, the latter is the correct scale, that is why there is a small conversion from the HA range 1-255.

This is the fourth of fifth method for the MagicMirror2, I hope it’s usefull to somebody else than me :slight_smile:

3 Likes

I just expanded the light with the availability template.
I also moved the api key to the secret file, so it will not be in the backup or if I choose to share the config (like now).
The secret.yaml now has a line like
bathroom_monitor_api: XXX

It requires a new sensor, and a modification to the template light.
The sensor needed:

- platform: rest
  name: Bathroom Monitor state
  resource: "http://1.2.3.4:8080/api/monitor/?apiKey=!secret bathroom_monitor_api"
  method: GET
  headers:
    Content-Type: application/json
  value_template: "{{ value_json.monitor }}"
- platform: rest
  name: Bathroom Monitor brightness
  resource: "http://1.2.3.4:8080/api/brightness/?apiKey=!secret bathroom_monitor_api"
  method: GET
  headers:
    Content-Type: application/json
  value_template: "{{ (value_json.result | float * 1.275) | round(0) }}"
  scan_interval: 60
- platform: rest
  name: Bathroom Monitor availability
  resource: http://1.2.3.4:8080/api/test?apiKey=!secret bathroom_monitor_api"
  method: GET
  headers:
    Content-Type: application/json
  value_template: '{{ value_json.success  }}'
  json_attributes:
    - success
  scan_interval: 60

And the light then needed the extra availability line just before icon_template

- platform: template
    bathroom_monitor:
      friendly_name: "MagicMirror Bathroom Monitor"
      unique_id: "e2d0359d-aafe-4140-a234-f59054e93f30"
      turn_on:
        - action: rest_command.turn_on_bathroom_monitor
        - delay: 1
        - action: homeassistant.update_entity
          data:
            entity_id: sensor.bathroom_monitor
      turn_off:
        - action: rest_command.turn_off_bathroom_monitor
        - delay: 1
        - action: homeassistant.update_entity
          data:
            entity_id: sensor.bathroom_monitor
      level_template: "{{ states('sensor.bathroom_monitor_brightness') | int }}"
      set_level:
        - action: rest_command.turn_on_bathroom_monitor
        - delay: 1
        - action: rest_command.set_bathroom_monitor_brightness
          data_template:
            brightness: "{{ (brightness / 1.275) | int }}"
        - delay: 1
        - action: homeassistant.update_entity
          data:
            entity_id: sensor.bathroom_monitor_brightness
      availability_template: "{{ is_state('sensor.bathroom_monitor_availability', 'True') }}"
      icon_template: >-
        mdi:mirror-rectangle

Now it shows unavailable if the API test call fails.
Apparently the string returned by the sensor for availability returns True, and not true, so that had to be capitalized.

Hi! Thanks for sharing this, it looks very promising. I am trying to set this up but I am having a hard time figuring out the correct version with between the initial post and the update. Would you mind sharing a full snippet of the current state of this that is working for you?

I currently have these running, there is a problem with the sensor for measuring the brightness level, but I haven’t figured out what is wrong. It seems that HA has changed the way it reads template values or something, I’ve tried fixing it here, but it’s still not correct…

rest_command: 
  turn_on_bathroom_monitor:
    url: "http://10.11.14.7:8080/api/monitor/on?apiKey=xxx"
    method: get

  turn_off_bathroom_monitor:
    url: "http://10.11.14.7:8080/api/monitor/off?apiKey=xxx"
    method: get

  set_bathroom_monitor_brightness:
    url: "http://10.11.14.7:8080/api/brightness/{{ brightness }}?apiKey=xxx"
    method: get

template:
  - light:
    - unique_id: e2d0359d-aafe-4140-a234-f59054e93f30
      turn_on:
        - action: rest_command.turn_on_bathroom_monitor
        - delay: 0:00:01
        - action: homeassistant.update_entity
          data:
            entity_id: sensor.bathroom_monitor
      turn_off:
        - action: rest_command.turn_off_bathroom_monitor
        - delay: 0:00:01
        - action: homeassistant.update_entity
          data:
            entity_id: sensor.bathroom_monitor
      set_level:
        - action: rest_command.turn_on_bathroom_monitor
        - delay: 0:00:01
        - action: rest_command.set_bathroom_monitor_brightness
          data_template:
            brightness: "{{ (brightness / 1.275) | int }}"
        - delay: 0:00:01
        - action: homeassistant.update_entity
          data:
            entity_id: sensor.bathroom_monitor_brightness
      default_entity_id: light.bathroom_monitor
      icon: mdi:mirror-rectangle
      availability: "{{ is_state('sensor.bathroom_monitor_availability', 'True')
        }}"
      name: MagicMirror Bathroom Monitor
      level: "{{ states('sensor.bathroom_monitor_brightness') | int(0) }}"

sensor:
  - platform: rest
    name: Bathroom Monitor brightness
    resource: "http://10.11.14.7:8080/api/brightness/?apiKey=xxx"
    method: GET
    scan_interval: 30
    value_template: >
      {% if value is string and value | length > 0 %}
        {% set parsed = value | from_json %}
        {{ (parsed.result | float * 1.275) | round(0) }}
      {% else %}
        unknown
      {% endif %}
  - platform: rest
    name: Bathroom Monitor availability
    resource: "http://10.11.14.7:8080/api/test?apiKey=xxx"
    method: GET
    headers:
      Content-Type: application/json
    value_template: "{{ value_json.success  }}"
    json_attributes:
      - success
    scan_interval: 60
1 Like