Skip to content
 
 

Repository files navigation

MMM-HomeAssistant

A MagicMirror² module that creates an MQTT device with Home Assistant autodiscovery.

Note: This module was greatly inspired by MMM-Remote-Control.

Example of MMM-HomeAssistant Example: MagicMirror entities in Home Assistant

How it works

When the MagicMirror starts, the first browser client to load the module will establish the MQTT connection and handle all communication with Home Assistant. This ensures only one active MQTT connection per MagicMirror instance, even if multiple browsers are open.

The module uses MQTT autodiscovery to automatically create entities in Home Assistant, allowing you to control your MagicMirror from the Home Assistant dashboard or automations without manual configuration.

Features

  • MQTT device integration with Home Assistant via autodiscovery
  • Control MagicMirror monitor (on/off)
  • Adjust MagicMirror brightness
  • Control visibility of individual MagicMirror modules as switches
  • Read and set the active MMM-ProfileSwitcher profile as a select entity
  • Restart MagicMirror process via Home Assistant
  • Execute custom bash commands/scripts via Home Assistant

Installation

Install

In your terminal, go to your MagicMirror² Module folder and clone MMM-HomeAssistant:

cd ~/MagicMirror/modules
git clone https://github.com/ambarusa/MMM-HomeAssistant/
cd MMM-HomeAssistant
npm install

Update

cd ~/MagicMirror/modules/MMM-HomeAssistant
git pull
npm install

Using the module

To use this module, add it to the modules array in the config/config.js file:

{
    module: 'MMM-HomeAssistant',
    config: {
        mqttServer: 'mqtt://localhost',
        mqttPort: 1883,
        username: 'mqtt_username',
        password: 'mqtt_password',
        deviceName: 'My MagicMirror',
        autodiscoveryTopic: 'homeassistant',
        monitorControl: true,
        brightnessControl: true,
        moduleControl: true,
        profileControl: true,
        profiles: ['Photos', 'Work', 'Weather', 'Media', 'Night'],
        monitorStatusCommand: 'xrandr --query | awk \'/Screen/ {print ($8 > 320) ? "true" : "false"}\'',
        monitorOnCommand: 'xrandr -d :0 --output HDMI-1 --auto --rotate right',
        monitorOffCommand: 'xrandr -d :0 --output HDMI-1 --off',
        pm2ProcessName: 'mm',
        refreshBrowser: true,
        customCommands: [
            {
                name: 'Update MagicMirror',
                command: 'bash ~/MagicMirror/modules/MMM-HomeAssistant/custom_commands/update_MM.sh'
            }
        ]
    }
},

Wayland

Using Wayland, the xrandr commands to pull monitor status and control on/off do not work. Replace the following in the 'config/config.js' file to use with wayland.

        monitorStatusCommand: 'wlr-randr | awk \'/HDMI-A-2/ {found=1} found && /Enabled:/ {print ($2 == "yes") ? "true" : "false"; exit} END {if(!found) print "false"}\'',
        monitorOnCommand: 'wlr-randr --output HDMI-A-2 --on',
        monitorOffCommand: 'wlr-randr --output HDMI-A-2 --off',

Example config for a Raspberry Pi 4B running MagicMirror server and client with PM2

Configuration options

Option Type Default Description
mqttServer string mqtt://localhost MQTT server address (e.g., mqtt://localhost).
mqttPort int 1883 MQTT port.
username string (none) (Optional) MQTT username. If omitted, connects anonymously.
password string (none) (Optional) MQTT password.
deviceName string My MagicMirror MQTT device name.
autodiscoveryTopic string homeassistant Autodiscovery topic for Home Assistant.
monitorControl boolean false Treat the display as an ON/OFF light entity.
brightnessControl boolean false Treat the display as a light entity with brightness. Enables monitorControl!
monitorStatusCommand string echo true Shell command to check the monitor status; must return true/false or 0/1 for correct operation.
monitorOnCommand string (none) Shell command to turn on the monitor.
monitorOffCommand string (none) Shell command to turn off the monitor.
moduleControl boolean true Make modules controllable as switch entities.
profileControl boolean false Expose the active MMM-ProfileSwitcher profile as a select entity. Requires profiles. See Profile control.
profiles array (none) The profile names to offer, e.g. ["Photos", "Work", "Night"]. Required when profileControl is on.
pm2ProcessName string (none) If set, allows MagicMirror to be restarted via Home Assistant.
refreshBrowser boolean true If enabled, will programmatically open and close a browser to refresh MagicMirror clients on other instances.
customCommands array (none) Array of custom commands to execute. See Custom Commands section below.
cleanupStaleEntities boolean true Remove Home Assistant entities for modules that no longer exist. See Stale entities.

Individual modules may also set haEntityId in their own config to pin their Home Assistant entity name. See Naming module switches.

Home Assistant Integration

Entities will appear automatically in Home Assistant if MQTT autodiscovery is enabled. You can control your MagicMirror from the Home Assistant dashboard or automations.

Profile control

With MMM-ProfileSwitcher installed, profileControl: true publishes a select entity for the active profile:

select.my_magicmirror_profile
{
    module: "MMM-HomeAssistant",
    config: {
        profileControl: true,
        profiles: ["Photos", "Work", "Weather", "Media", "Night"],
    }
}

The names must match the profile class names MMM-ProfileSwitcher uses, because Home Assistant only accepts options from this list. There is no way to discover them automatically - a profile is only ever a class name on some module.

Selecting an option sends CURRENT_PROFILE, which is the same notification the on-screen profile buttons send, so both routes behave identically.

The state is read back from MMM-ProfileSwitcher's CHANGED_PROFILE notification, which it emits for every change including the one it makes at startup. The entity therefore reflects what the mirror is really showing, even when the profile was changed by a button on the mirror rather than from Home Assistant. That is what makes it usable as a trigger in automations.

If profileControl is on and profiles is empty, the entity is skipped and an error is logged; everything else keeps working.

Naming module switches

By default each module gets an entity named after the module, with a numeric suffix when several instances of the same module exist:

switch.my_magicmirror_clock_switch
switch.my_magicmirror_homeassistantsensors_1_switch
switch.my_magicmirror_homeassistantsensors_2_switch

Those generated names depend on how many instances exist and in what order. Add or remove one module and the suffixes shift, so an entity that used to be ..._2_switch may become ..._3_switch - and the old one is left behind in Home Assistant. The same happens when a count drops to one, because the suffix is then dropped entirely.

To pin an entity to a module regardless of ordering, set haEntityId in that module's own config:

{
  module: "MMM-homeassistant-sensors",
  position: "top_right",
  config: {
    haEntityId: "weather_station",
    // ... the module's own options
  }
}

which gives switch.my_magicmirror_weather_station_switch.

The key is read straight from the module's config and ignored by the module itself, so it is safe to add to any module.

Rules:

  • The value must be unique across all modules. A duplicate is logged as an error and that module falls back to the generated name.
  • It is lowercased and anything outside a-z, 0-9 and _ becomes _, since the value ends up in both the MQTT topic and the entity id.
  • Pin all instances of a module type, or none. Pinning one makes its unpinned siblings renumber from 1, which renames their entities.

Stale entities

Discovery configs are published retained, so Home Assistant keeps recreating an entity even after the module is gone from config.js. On every connect this module compares what it just published against what is retained for this device and clears the difference by publishing an empty retained payload, which tells Home Assistant to drop the entity.

Only this device's per-module switch configs are pruned. The device light and the button entities are never touched, and nothing is pruned on a run where the module list was not available - otherwise a startup race could wipe every entity.

It is attempted once per process, whatever the outcome. The client reconnects on its own, so retrying would turn a single failure into a loop: publish, fail, reconnect, find the same topics, publish again. Worst case is now one error at startup.

Set cleanupStaleEntities: false to turn it off. Worth doing if the log shows the removals failing on every start. Two causes are known:

  • A broker with an ACL on the discovery prefix refuses the empty publishes.
  • On at least one arm64 host (Raspberry Pi 4, Debian 13, Node 22, mqtt 5.13) the write fails with EFAULT out of mqtt-packet's uncork. The same publishes from a standalone script on the same machine and broker succeed, so it is something about the client this module holds rather than the platform, but it is not yet understood. x86_64 hosts are unaffected.

Custom Commands

You can define custom bash commands or scripts that Home Assistant can trigger. Each command will appear as a button entity in Home Assistant.

Update script (update_MM.sh)

The sample script at custom_commands/update_MM.sh performs a full MagicMirror update cycle with logging and safety checks. In short, it:

  • Rotates its log every 5 runs and writes to custom_commands/update_MM.log.
  • Uses a lock file to prevent concurrent runs.
  • Updates the MagicMirror base repo with git pull, then runs npm run install-mm if changes were pulled.
  • Updates every MMM-* module under modules/ with git pull and npm install when needed.
  • Restarts MagicMirror with pm2 restart if updates were applied (configurable via PM2_PROCESS_NAME, default mm).

Notes:

  • The script does a git reset --hard HEAD in the base repo and in each module to avoid conflicts. If you keep local changes, they will be discarded.
  • You can pass a MagicMirror path as the first argument; otherwise it defaults to ~/MagicMirror.
  • If pm2 is not installed, the script will skip restart and log a reminder.

Configuration

Add a customCommands array to your config:

customCommands: [
  {
    name: 'Update MagicMirror',
    command: 'bash ~/MagicMirror/modules/MMM-HomeAssistant/custom_commands/update_MM.sh'
  },
  {
    name: 'Say Hello',
    command: 'echo "Hello from MagicMirror!"'
  }
]

Custom Command Properties

Property Type Required Description
name string Yes Display name for the command in Home Assistant. Internal name will be automatically converted to lowercase with underscores.
command string Yes Bash command or script path to execute.

Troubleshooting

  • Open your browser's developer console to check for JavaScript errors or warnings.
  • Check the MagicMirror logs for errors or warnings (run npm start npm run server or pm2 restart xx; pm2 logs xx from your MagicMirror directory and watch the terminal output).
  • Use MQTT Explorer or a similar tool to easily investigate MQTT messages and topics.
  • Optionally, you can temporarily change the autodiscoveryTopic in your config to something like debug to see what messages are intended to be sent for Home Assistant autodiscovery.
  • If the entities still look healthy in Home Assistant but nothing you do there reaches the mirror, check whether the mirror is connected to the broker at all - ss -tn state established | grep 1883 on the mirror. An empty answer means the module is not talking to MQTT, whatever Home Assistant shows, and the mirror will keep serving its own web interface as if nothing were wrong.

Developer commands

  • npm install - Install devDependencies like ESLint.
  • npm run lint - Run linting and formatter checks.
  • npm run lint:fix - Fix linting and formatter issues.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages