Install and Run Zigbee2Mqtt on your Mac

I had an old MacBook Air with a faulty battery gathering dust, so instead of getting a RaspberryPi for my new home I decided to use the Air as my “home server” to run Homeassistant, the family cookbook wiki and a couple of other light services. In this post I explain how I got mi installation up and running.

These instructions explain how to run Zigbee2MQTT on Mac OS. I am using Mojave (10.14.6) but should be similar in other versions. This instructions require you to run commands on your console, use a text editor software to create/edit text files and use Homebrew (brew) to install required software. Since we are changing some system settings, some of the console commands need you to use sudo command. Make sure you understand what the commands are doing. Finally, this guide has two set of instructions. One, is based on the official Linux install instructions, which will use a system wide Node JS installation. The second, if you prefer to have a separate Node JS installation, is based on the virtual environment instructions.

Prerequisites

In order to run Zigbee2MQTT you need a Zigbee adapter and a MQTT broker/server. For the first case, you will also need Node JS.

The Zigbee adapter

The Zigbee2MQTT page has a list of recommended adapters. I personally have had an excellent experience with tubezb. If you are using a network adapter, you need its IP adrress. If you are using a USB adapter, you will need to determine the location of the adapter as explained next:

Determine location of the adapter

We first need to determine the location of the adapter within the PC devices. Connect the adapter to your Mac computer. The location of the adapter will vary depending on your computer and the adapter manufacturer, but it will be listed under your dev folder.

The /dev directory contains files that represent devices attached to the system, including physical devices, such as serial ports, and pseudodevices, such as a random number generator.

Mac OS X for Unix Geeks by Ernest E. Rothman, Brian Jepson (O’Reilly)

In my case, the adapter was listed as “usbmodem” (it is an old CC2530 chip that used serial connection), so this is how I found it:

$ ls /dev/tty.usbmodem*
tty.usbmodem14101

If you don’t get any matches, then just execute

$ ls /dev

and go over the list and try to figure out which one is the adapter. You can run the command with the adapter connected, then disconnect the adapter and run it again and compare the results to find the adapter name.

The MQTT server

Mosquitto is the recommended MQTT broker but others should also work fine. The easiest way to install is is using brew:

$ brew install mosquitto

Node JS (Non-virtual environment)

Zigbee2MQTT runs requires Node JS version above 14 and up to 20 (at the time of writing). You can check the required version in the Zigbee2MQTT package.json settings, under the engines section.

First, we can check if we have it installed and if so, what version we are running. Open a terminal window and type the command node --version:

$ node --version
v.16.13.0

If you get a command not found message instead of the version number, then you need to install node. I recommend using the official Node JS MacOS installer. If you already have node, you should have v.14 at least (I assume that if you have it you know how to upgrade).

Installing Zigbee2MQTT

We run Zigbee2MQTT from source, so we need to clone (copy) the source to our Mac. First decide on a location for “installing” (i.e. where we will copy the code) Zigbee2MQTT. I try to put all my applications on the Applications folder. The command is:

$ git clone --depth 1 https://github.com/Koenkk/zigbee2mqtt.git /Applications/zigbee2mqtt

A little explanation. The zigbee2mqtt source code is stored in a git repository in GitHub. Git is a software/system useful for developers. The git clone command will download all the code from github. Git keeps track of all the history of code. Since we don’t need all that information to tun Zigbee2MQTT,, we add the --depth 1 option to only bring the latest information. Finally, replace the /Applications/zigbee2mqtt for your selected location for installation.

Installing Node JS and required packages

Non-virtual environment

Now that we have to code, we need to get all the node libraries required by Zigbee2MQTT.

$ cd /Applications/zigbee2mqtt
$ npm ci

This will take some time depending on your computer specs and network speed. If everything went correctly the output of npm ci is similar to (the number of packages and seconds is probably different on your device):

added 383 packages in 111.613s

Virtual environment

For this option, we use a python virtual environment in order to be able to install a separate Node JS version. The following commands are copied form the official guide (make sure all the cd commands use the folder you chose for the installation):

# Enter folder
cd /Applications/zigbee2mqtt
# Install python env
python3 -m venv .
# Activate environment
source /Applications/zigbee2mqtt/bin/activate
# Upgrade pip, wheel and setuptools
pip install --upgrade pip wheel setuptools
# Install node environment
pip install nodeenv
# Init node environment
nodeenv -p -n 16.15.0
# Deactivate and activate environment to be sure
deactivate
source /Applications/zigbee2mqtt/bin/activate
# Install dependencies
cd /Applications/zigbee2mqtt
npm ci
# Deactivate environment
deactivate

Zigbee2MQTT Configuration

Before we can start Zigbee2MQTT we need to edit the configuration.yaml file. This file contains the configuration which will be used by Zigbee2MQTT.

Open the configuration file using your favourite text editor. I like to use vsCodium for this tasks. The configuration file is located in /<install dir>/zigbee2mqtt/data/configuration.yaml.

The main thing changes we need to make is the MQTT server url/authentication and the adapter information (serial port).

  • If you are running Mosquitto locally, make sure you change the ‘server’ value to add the mosquitto port (1883). If you installed another MQTT broker then use the correct port. If you configured your broker to use authentication via user/password, you need to add them to the configuration.
  • To use our dongle, we need to change ‘port’ value in the ‘serial’ section. Use ‘dev’ information we found at the beginning. If you are using a network adapter, then use its IP address, e.g. tcp://192.168.68.124:6638. Note that the IP address uses the tcp protocol (not http).
# MQTT settings
mqtt:
  # MQTT base topic for Zigbee2MQTT MQTT messages
  base_topic: zigbee2mqtt
  # MQTT server URL
  server: 'mqtt://localhost:1883'
  # MQTT server authentication, uncomment if required:
  # user: my_user
  # password: my_password
# Serial settings
serial:
  # Location of the adapter (USB) or IP address with port (network) 
  port: /dev/tty.usbmodem14101

It is recommended to use a custom network key for Zigbee2MQTT. The easiest way is to let Zigbee2MQTT generate one. This can be done by adding the following to your configuration.yaml:

advanced:
    network_key: GENERATE

I also recommend reading about how to improve your network stability. In particular I like to channel the zigbee network channel. The reason is that zigbee use the same frequency as Wi-Fi: 2.4GHz, so your Wi-Fi signals can cause interference with your zigbee signals. I use an android app called Wifi Analyzer to scan all existing Wi-Fi networks in the vicinity of my house and pick an unused channel. If not possible (e.g. living in a block of flats), then pick the one with the less congestion, i.e. lower number of networks and/or lower signal strength. This post has a very good explanation on how to pick a zigbee channel. To change the Zigbee channel Zigbee2MQTT uses you have to set the channel in configuration.yaml under the ‘advanced’ options. For example, this will change the channel to 11:

advanced:
    channel: 11

Starting Zigbee2MQTT

Note: Your MQTT broker must be running. If you installed mosquitto with brew, you need to run brew services start mosquitto.

Now that we have setup everything correctly we can start Zigbee2MQTT.

Non-virtual environment

$ cd /Applications/zigbee2mqtt
$ npm start

When started successfully, you will see something like:

Zigbee2MQTT:info  2019-11-09T13:04:01: Logging to directory: '/Applications/zigbee2mqtt/data/log/2019-11-09.14-04-01'
Zigbee2MQTT:info  2019-11-09T13:04:01: Starting Zigbee2MQTT version 1.6.0 (commit #720e393)
Zigbee2MQTT:info  2019-11-09T13:04:01: Starting zigbee-herdsman...
Zigbee2MQTT:info  2019-11-09T13:04:03: zigbee-herdsman started
Zigbee2MQTT:info  2019-11-09T13:04:03: Coordinator firmware version: '{"type":"zStack30x","meta":{"transportrev":2,"product":2,"majorrel":2,"minorrel":7,"maintrel":2,"revision":20190425}}'
Zigbee2MQTT:info  2019-11-09T13:04:03: Currently 0 devices are joined:
Zigbee2MQTT:warn  2019-11-09T13:04:03: `permit_join` set to  `true` in configuration.yaml.
Zigbee2MQTT:warn  2019-11-09T13:04:03: Allowing new devices to join.
Zigbee2MQTT:warn  2019-11-09T13:04:03: Set `permit_join` to `false` once you joined all devices.
Zigbee2MQTT:info  2019-11-09T13:04:03: Zigbee: allowing new devices to join.
Zigbee2MQTT:info  2019-11-09T13:04:03: Connecting to MQTT server at mqtt://localhost
Zigbee2MQTT:info  2019-11-09T13:04:03: Connected to MQTT server

Zigbee2MQTT can be stopped by pressing CTRL + C.

Virtual Environment

For running inside a virtual environment, we need to activate the environment first:

# Enter folder
cd /Applications/zigbee2mqtt
# Activate environment
source /Applications/zigbee2mqtt/bin/activate
# Start
npm start
# ctrl + c to quit
# Deactivate environment
deactivate

(Optional)  Running as a daemon with launchctl [in the background]

To run Zigbee2MQTT as service (in background) and start it automatically on boot we will run Zigbee2MQTT with launchd. Personally, I like to run it manually when adding new devices so I can see the output in the console and get a sense of what is going on.

The plist file

To run Zigbee2MQTT a service, we need to create a plist file. The plist file defines several keys. Some of these are the same for the non- and virtual environments.

  • Label: Must match the name of the plist file.
  • EnvironmentVariables: we need to make sure the user/local/bin and /usr/bin folders are on your PATH.
  • WorkingDirectory: We make sure the commands are run in the installation directory.
  • RunAtLoad: Make sure that Zigbee2MQTT starts when your system reboots.

Non-virtual environment

For a non virtual environment, the ProgramArguments are used to run node (via npm) and execute the start command (similar to what we do from the command line). The plist in this case looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>zigbe2mqtt.application.plist</string>
<key>EnvironmentVariables</key>
<dict>
    <key>PATH</key>
    <string><![CDATA[/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin]]></string>
</dict>
<key>WorkingDirectory</key>
<string>/Applications/zigbee2mqtt</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/npm</string>
<string>start</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

Virtual environment

The key difference here, is that we need to activate the virtual environment.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>zigbe2mqtt.application.plist</string>
<key>EnvironmentVariables</key>
<dict>
    <key>PATH</key>
    <string><![CDATA[/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin]]></string>
</dict>
<key>WorkingDirectory</key>
<string>/Applications/zigbee2mqtt</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash -c 'source /Applications/zigbee2mqtt/bin/activate; /Applications/zigbee2mqtt/bin/npm start</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

To create the plist file, open your text editor and add the contents detailed previously. Then save the file to /Library/LaunchDaemons. This is a system folder, so your text editor should ask you to try saving it as administrator (for which you will need to provide your credentials). If not, you can save the file somewhere else, and then copy and paste it to the folder (this will also require admin rights).

Directing std and error output

In order to monitor your Zigbee2MQTT instance it is useful to redirect the launchctl output to log files in your system that you can check when things are not working. For this, I created a stdout.log and stderr.log files in a ~/Zigbee2MQTT folder. For launchctl to be able to use these files, it must own them:

$ cd ~
$ mkdir Zigbee2MQTT
$ cd Zigbee2MQTT
$ touch sdtout.log
$ touch stderr.log
$ sudo chown root stdout.log
$ sudo chown root stderr.log

Then, add this lines to the plist file (replace <myuser> with your user name):

<key>StandardErrorPath</key>
<string>/Users/<myuser>/zigbee2mqtt/stderr.log</string>
<key>StandardOutPath</key>
<string>/Users/<myuser>/zigbee2mqtt/stdout.log</string>

To enable and start your application run the following commands (technically the start command is not needed since we configured the daemon as RunAtLoad):

$ launchctl load /Library/LaunchDaemons/zigbe2mqtt.application.plist
$ launchctl start /Library/LaunchDaemons/zigbe2mqtt.application.plist

To stop the application run (e.g to change your configuration):

$ launchctl stop /Library/LaunchDaemons/zigbe2mqtt.application.plist

If you modify the plist file, you need to unload it and then reload it.

$ launchctl unload /Library/LaunchDaemons/zigbe2mqtt.application.plist

Updating Zigbee2MQTT

For updating to the latest version all that you need to do is ‘pull’ the latest version of the git repository. If you are running the deamon, you must first stop and unload the plist to make sure zigbee2mqtt is not running:

$ launchctl stop /Library/LaunchDaemons/zigbe2mqtt.application.plist
$ launchctl unload /Library/LaunchDaemons/zigbe2mqtt.application.plist

After that you can pull the latest version (if using a virtual environment make sure to activate it first)

# Creating backup of configuration..
$ cp -R data data-backup
# Update
$ git pull –allow-unrelated-histories
# Installing dependencies...
npm ci
# Building...
npm run build
# Restore configuration...
cp -R data-backup/* data
rm -rf data-backup

NOTE: A quick search will probably advice you against using ‘–allow-unrelated-histories’ flag. However, in this case is fine because 1) we did a shallow clone and 2) we are not going to do any development on the repository.

After the pull completes, you updated the npm and restored your data, you can start the app or load your daemon again.