Home Assistant - Magic Mirror - Voice Assistants integration

Last time I checked, there was a way to send sensor data from HA to MM, but it didn’t look very nice and it wasn’t very useful (for me).
No seamless integration between the two platforms as far as I know…at least not very reliable…

Since I like to overcomplicate things I found a way to completely integrate Home Assistant and Magic Mirror for my home control hub and I also added voice control to this…because why not ?

WARNING: HEY GOOGLE COMMANDS: [ What day is it? | Turn ON office lights | Lights off ]

  • First voice command just activates a module (Calendar, above the clock) that is otherwise hidden and also provides the normal answer from the assistant; This can also be done manually from Home Assistant.
  • The second and third screens (home climate control and general UI) are activated manually from HA, (from a different device) because I didn’t want to abuse voice commands and turn whatever climate devices on or off in your homes.
  • The third and fourth (voice) commands are supposed to show the time between voice command (Google Assistant) to Home Assistant (that manages the lights through Zigbee2mqtt) and the fact that is showing changing the room light status in realtime on the mirror interface.

As long as you install HomeAssistant Core (python virtual env, not hassio or other method, so you can still have a fully operational Linux system) you can run Magic Mirror without problems on the same Pi

I have a full integration between HA and MM. I can fully control the mirror from HA and I can display HA on MM, but not by using a single dedicated module/integration.

The HA -> MM control is quite important, because this makes this integration really powerful. By using this you will be able to fully control your MM instance from literally anything: Home Assistant, voice assistants (Google Assistant, Alexa, etc.), Web App, MMM-RC API . . .whatever

This is achieved by MMM-Remote-Control

On the MM side you need to add 127.0.0.1 to your IP whitelist.

	port: 8080,
	ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.0.1/120", "192.168.0.1/24"],

and simply add the module to your config

		{		
   		 module: 'MMM-Remote-Control'			
   		},

On the HA side, you can simply define switches (or scripts) to control actions on the MM.

Example:

  - platform: command_line
    switches:
              
      mirror_clock:
        friendly_name: CLOCK 
        command_on: 'curl -k "http://192.168.0.100:8080/remote?action=SHOW&module=module_6_clock"'
        command_off: 'curl -k "http://192.168.0.100:8080/remote?action=HIDE&module=module_6_clock"'
        command_state: ""
        value_template: '{{ value == "0" }}'


      mirror_refresh:
        friendly_name: REFRESH MIRROR
        # command_on: 'curl -k "http://192.168.0.100:8080/remote?action=REFRESH"'
        command_on: 'sudo systemctl restart blackmirror.service'
        command_off: ''
        command_state: "0"

Here comes the interesting part - displaying HA -> MM

For this I’m using a combination of MMM-pages and MMM-iFrame but for my integration i needed a slightly modified version of iFrame so I can switch between URLs - You can find the CODE below, credit goes to @pooyasa

MMM-iFrame.js

Module.register("MMM-iFrame",{
        // Default module config.
        defaults: {
        frameWidth: "300",
        width:"100%",
        updateInterval: 60 * 60 * 1000,
        url:  ["http://192.168.0.100:8123/lovelace/climate", "http://192.168.0.100:8123/lovelace/UIX", "http://192.168.0.100:8123/lovelace/electricity", "http://192.168.0.100:8123/lovelace/entertainment", "http://192.168.0.100:8123/lovelace/presence", "http://192.168.0.100:8123/lovelace/maintenance", "http://192.168.0.100:8123/lovelace/extraX/", ],
        scrolling: "no"
        },
        
            start: function () {
                    self = this;
                    var count = 0;
                    window.strurl=0;
               
        },
    
     
   
        resume: function() {
            console.log("Resuming");
            return this.getDom();
        },
    
    
    
        getStyles: function() {
                    return [
                            "MMM-iFrame.css",
                    ];
        },
        
    
    
            // Override dom generator.
        getDom: function() {
                    var { width, height } = this.config;
                    var wrapper = document.createElement("div");
                    
                    wrapper.className = "mmm-iframe"
                    wrapper.style.width = `${this.config.frameWidth}px`;
        
    
    
                    
                    var html = `
                            <div class="mmm-iframe-wrapper" style="padding-top: ${100 / (width / height)}%;">`;
                    console.log(window.strurl);
                    if(window.strurl>=0){        
                            html+=`
                                    <iframe
                                            src="${this.config.url[window.strurl]}"
                                            width="${width}"
                                            height="${height}"
                                            scrolling="${this.config.scrolling}"
                                    ></iframe>`;}
                                    
                            html+=`        
                            </div>
                    `;
        
    
                    
                    wrapper.insertAdjacentHTML("afterbegin", html);
        
            return wrapper;
        },
        
        
        notificationReceived: function(notification, payload,sender) {
            if (notification == "pooya") {  
                window.strurl=payload;     
                console.log(window.strurl);           
                            this.updateDom();
                }
        
        
                },
        });

On the MM side, integration is quite straightforward.

		{		// https://github.com/edward-shen/MMM-pages
			module: 'MMM-pages',  
			config: {
					modules:
					[
						["currentweather", "updatenotification", "compliments", "newsfeed", "calendar_monthly", "clock", "weatherforecast", "MMM-PushBulletNotifications", "MMM-SimpleLogo", "MMM-Parcel", "mmm-systemtemperature", "MMM-Snow",],
						["MMM-iFrame", "clock", "currentweather",]

					],
					//excludes: ["updatenotification"],
			}
		},


		{		// https://github.com/alberttwong/MMM-iFrame  ---  MODIFIED CODE FOR PAGE SWITCHING
			module: 'MMM-iFrame',
			position: 'center',
			config: {
					url: ["http://192.168.0.100:8123/lovelace/climate", "http://192.168.0.100:8123/lovelace/UIX", "http://192.168.0.100:8123/lovelace/electricity", "http://192.168.0.100:8123/lovelace/entertainment", "http://192.168.0.100:8123/lovelace/presence", "http://192.168.0.100:8123/lovelace/maintenance", "http://192.168.0.100:8123/lovelace/extraX/",],  // ["URL1", "URL2"] 
					updateInterval: 60 * 60 * 1000,
					width: "1920",
					height: "1080", 
					frameWidth: "1800" 

			}
		},

What I’m doing here is very simple. I’m using MMM-Pages to define 2 different pages/interfaces for my mirror; First one is basically the mirror with all the modules; the second page contains the (modified) MMM-iFrame that displays the Home Assitant interface.

As you can see in the code above, the list of URLs defined in the MMM-iFrame allow me to switch between HomeAssistant tabs (you can use any HA tab, all or just one - if you only want to display a single page, you don’t need the modified version)

To change to the ‘page’ that has the HomeAssistant iFrame a simple command_line switch in HA could be used:

- platform: command_line
    switches:
      mirror_page:              
        friendly_name: PAGE
        command_on: 'curl -k "http://192.168.0.100:8080/remote?action=NOTIFICATION&notification=PAGE_INCREMENT"'
        command_off: 'curl -k "http://192.168.0.100:8080/remote?action=NOTIFICATION&notification=PAGE_DECREMENT"'
        command_state: ""
        value_template: '{{ value == "0" }}'

Voice assistant integration comes in the form of routines as long as you have the Home Assistant entities (reasonable for mirror control) exposed to Home Assistant Cloud - DOCUMENTATION

Example for exposing entity to Google Assistant:

filter:
  include_entities:
   - switch.mirror_page  
  
entity_config:
  switch.mirror_page:
    name: "INTERFACE"
    room: MIRROR

Example for exposing entity to Alexa:

filter:
  include_entities:
   - switch.mirror_page  
  
entity_config:
  switch.mirror_page:
    name: "INTERFACE"
    display_categories: SWITCH

The routine can be created in the Google Home app, Alexa, etc.

Here is an Example for Google Home:

This is how the “What day is it” routine looks like

One last step…

To make things look ‘propper’ on the mirror I have created a special theme that you can find below

theme.yaml - blackmirror:

blackmirror:
# SPLIT
splitter_card: “#3f6388
splitter_background: “white”
# Main colors
primary-color: “BLACK” # Header
accent-color: “#1c91ff” # Accent color
dark-primary-color: “var(–primary-color)” # Hyperlinks
light-primary-color: “var(–primary-color)” # Horizontal line in about
# Text colors
primary-text-color: “WHITE” # Primary text colour, here is referencing dark-primary-color
text-primary-color: “var(–primary-text-color)” # Primary text colour
secondary-text-color: “#999999” # For secondary titles in more info boxes etc.
disabled-text-color: “var(–primary-text-color)” # Disabled text colour
label-badge-border-color: “var(–primary-color)” # Label badge border, just a reference value
# Background colors
primary-background-color: “var(–primary-color)” # Settings background
secondary-background-color: “#222222” # Main card UI background
divider-color: “var(–primary-color)” # Divider
# Table rows
table-row-background-color: “var(–primary-color)” # Table row
table-row-alternative-background-color: “var(–primary-color)” # Table row alternative
# Nav Menu
paper-listbox-color: “white” # Navigation menu selection hoover
paper-listbox-background-color: “#020202” # Navigation menu background
paper-grey-50: “var(–primary-text-color)”
paper-grey-200: “#414A59” # Navigation menu selection
sidebar-icon-color: “var(–primary-color)”
sidebar-background-color: “var(–primary-color)”
pp-header-text-color: “var(–primary-color)”
# Paper card
paper-card-header-color: “grey” # Card header text colour
card-background-color: “#020202” # Card background colour
paper-dialog-background-color: “#1b1b1b” # Card dialog background colour
paper-item-icon-color: “#666666” # Icon color
paper-item-icon-active-color: “var(–accent-color)” # Icon color active
paper-item-icon_-color: “var(–primary-color)”
paper-item-selected
-_background-color: “#434954” # Popup item select
paper-tabs-selection-bar-color: “var(–primary-color)”
app-header-text-color: “var(–primary-color)”
# Labels
label-badge-red: “var(–accent-color)” # References the brand colour label badge border
label-badge-text-color: “var(–primary-text-color)” # Now same as label badge border but that"s a matter of taste
label-badge-background-color: “#2E333A” # Same, but can also be set to transparent here
# Switches
paper-toggle-button-checked-button-color: “var(–accent-color)”
paper-toggle-button-checked-bar-color: “var(–accent-color)”
paper-toggle-button-checked-ink-color: “var(–accent-color)”
paper-toggle-button-unchecked-button-color: “#666666
paper-toggle-button-unchecked-bar-color: “var(–disabled-text-color)”
paper-toggle-button-unchecked-ink-color: “var(–disabled-text-color)”
# Sliders
paper-slider-knob-color: “var(–accent-color)”
paper-slider-knob-start-color: “var(–accent-color)”
paper-slider-pin-color: “var(–accent-color)”
paper-slider-active-color: “var(–accent-color)”
paper-slider-container-color: “linear-gradient(var(–primary-background-color), var(–secondary-background-color)) no-repeat”
paper-slider-secondary-color: “var(–secondary-background-color)”
paper-slider-disabled-active-color: “var(–disabled-text-color)”
paper-slider-disabled-secondary-color: “var(–disabled-text-color)”
# Google colors
google-red-500: “#E45E65
google-green-500: “#39E949

split_theme:
card-background-color: “var(–splitter_card)”
primary-background-color: “var(–splitter_background)”
accent-color: “#1c91ff

Obviously, you need to copy this new theme to your theme.yaml file, but most important, when you will use the iFrame module for the first time, HomeAssistant will ask you to log in; after doing so go to your profile page and set the theme to blackmirror, ON THE MIRROR. The theme is set locally, on each device, so it will not change it across other devices.

Have fun!

5 Likes

This looks amazing!

I am considering building a large home control screen in the kitchen using this device (I can get one really cheap):

You think that would work well with this application?

I googled the Samsung Flip and it seems it has a web browser, so it will work, but unless you get it cheaper than an old (maybe non-smart) TV of the same size it would be a bit overkill as a control center.

Also, it seems it has HDMI OUT only…I believe that any screen you chose should have HDMI IN functionality for a smart home control center so you can link a RPI or any SBC you like to it and have a standalone system

But to answer shortly, since i don’t know what oter applications you have for that board, it will work in the web browser

Very cool! I wrote the MMM-Remote-Control module’s REST API a couple years ago with the hope of expanding more control of my MagicMirror and better integrating it with my home automation. I got sucked in on Home Assistant and never got the time to go back and really implement something like this. It’s awesome to see that you were able to bring the two together!

Also, for your multiple pages, an alternative would be MMM-Carousel, with most modules on one slide and the iframe on a second.

1 Like

In this case, I need to thank you for your work; that module is absolutely amazing and it’s basically the base for every automation I have regarding the mirror.

I remember MMM-Carousel but I can’t remember why I didn’t used it… I think I had some problems with it but it was some time ago and I can’t remember.

This is fantastic!
My problem is that I have installed the hassio version on raspberry and switching to core would mean a lot of work. Can I run the mirror on another raspberry and have the same integration?

Sure. No problem. Just use the IP of the PI with the mirror when needed and it will work