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 ]
https://imgur.com/gallery/A6AO54L
- 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¬ification=PAGE_INCREMENT"'
command_off: 'curl -k "http://192.168.0.100:8080/remote?action=NOTIFICATION¬ification=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
-
First action triggers a switch exposed from HA, that controls the visibility of the ‘calendar’ on MM
-
Second action is a custom command that is entirely handled by Google Assistant
-
Third action is the toggles the same switch as the first one and hides the calendar after the Google Assistant response was issued.
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!