Custom firmware applications for Ubiquiti's mFi line of power monitoring and switching devices. Includes an MQTT client for Home Assistant integration, a REST API server, and a CLI tool — all built on a shared C++ library that wraps the mFi hardware interface.
mfi-mqtt-client ─┬─ hass_mqtt_device (Home Assistant MQTT discovery)
├─ mfi (hardware abstraction: sensors, relays, LEDs)
└─ shmuelie-shared (string utilities)
mfi-rest-server ─┬─ mgpp (Mongoose C++ wrapper)
├─ mfi
└─ shmuelie-shared
mfi-cli ─────────┬─ mfi
└─ shmuelie-shared
C++ library wrapping the mFi file-system-based hardware interface. Provides classes for reading sensor data (power, current, voltage, power factor), controlling relays, managing the device LED, and reading board/device configuration.
Fork of KodeZ/hass_mqtt_device — a C++ library for creating Home Assistant MQTT devices with auto-discovery. Supports switches, sensors, lights (on/off and dimmable), and number inputs. Uses Mosquitto for MQTT connectivity.
MQTT client that exposes mFi device ports to Home Assistant via MQTT auto-discovery. Each port is published as a set of sensor entities (power, current, voltage) and a switch entity (relay control). Only publishes updates when values change to minimize MQTT traffic.
MQTT Client for Ubiquiti's mFi Devices
Usage: ./mfi-mqtt-client [OPTIONS]
Options:
-h,--help Print this help message and exit
--version Display program version information and exit
--config :FILE Configuration file to load options from
--server TEXT REQUIRED The MQTT server to connect to
--port UINT [1883] The port to use when connecting to the MQTT server
--username TEXT REQUIRED The username to use when connecting to the MQTT server
--password TEXT REQUIRED The password to use when connecting to the MQTT server
--polling-rate UINT:UINT in [0 - 4294967295] [1000]
The polling rate in milliseconds
--log-level ENUM:value in {trace->0,debug->1,info->2,warn->3,error->4,critical->5,off->6} [2]
The log level to use
The client accepts a configuration file in TOML or INI format:
server = "mqtt.example.com"
port = 1883
username = "username"
password = "password"
polling_rate = 1000
log_level = 2HTTP REST API server for the mFi devices built on top of the mFi API and Mongoose.
REST API for Ubiquiti's mFi Devices
Usage: ./mfi-rest-server [OPTIONS]
Options:
-h,--help Print this help message and exit
--version Display program version information and exit
-i,--ip TEXT [0.0.0.0] The IP address to listen on
-p,--port UINT [8000] The port to listen on
-l,--log-level UINT [0] The log level to use
CLI tool for inspecting mFi device state. Mostly exists to test the mFi API.
CLI tool for Ubiquiti's mFi Devices
Usage: ./mfi-cli [OPTIONS] SUBCOMMAND
Options:
-h,--help Print this help message and exit
--version Display program version information and exit
Subcommands:
info Display information about the mFi device
C++ wrapper around Mongoose providing RAII-based resource management for the HTTP server, connections, and timers.
String helper functions (split, join, number parsing) shared across projects.
External tree for Buildroot to cross-compile for the mFi MIPS architecture. Thanks to cracauer/mFI-mPower-updated-sshd for helping figure this out.
Uses CMake to build/configure. All projects use CLI11 for command-line parsing.
bcbinutilsbuild-essentialbzip2cmakediffutilsfindutilsrsyncunzip
Required to build for the host system. Not needed for cross-compilation — the Buildroot submodule handles that.
libmosquitto-devnlohmann-json3-devpkg-configlibspdlog-devcatch2(for running tests)
CMakePresets.json provides four presets:
| Preset | Target | Build Type |
|---|---|---|
local-debug |
Host system | Debug |
local-release |
Host system | Release |
mips-debug |
mFi device (MIPS) | Debug |
mips-release |
mFi device (MIPS) | MinSizeRel |
When MFI_CROSS_COMPILE is ON, CMake configure will also run make on the
Buildroot submodule to build the MIPS cross-compilation toolchain.
# Configure and build for local development
cmake --preset local-debug
cmake --build --preset local-debug
# Cross-compile for mFi devices
cmake --preset mips-release
cmake --build --preset mips-releaseTests use Catch2 and are only built for local (non-cross-compile) targets. After building:
cd build/local-debug
ctest --output-on-failureThe mFi persistent flash storage is only 64 KB — far too small for the binaries
themselves. The recommended approach is to store binaries in /tmp (RAM disk)
and use a small boot script in persistent storage to download them on startup.
Release builds (mips-release) use -Os, LTO, -ffunction-sections,
-fdata-sections, and --gc-sections to minimize binary size. Typical stripped
sizes for MIPS static builds:
| Binary | Approximate Size |
|---|---|
mfi-mqtt-client |
~350 KB |
mfi-rest-server |
~230 KB |
mfi-cli |
~180 KB |
- Build with
mips-releasepreset. - Host the binaries on a local HTTP server or NAS accessible from the device.
- Create
/var/etc/persistent/rc.poststartto download and run on boot:
#!/bin/sh
BINARY_URL="http://your-server/mfi"
INSTALL_DIR="/tmp/mfi-bin"
mkdir -p "$INSTALL_DIR"
# Download binaries
wget -q -O "$INSTALL_DIR/mfi-mqtt-client" "$BINARY_URL/mfi-mqtt-client"
chmod +x "$INSTALL_DIR/mfi-mqtt-client"
# Start the MQTT client
"$INSTALL_DIR/mfi-mqtt-client" --config /var/etc/persistent/mqtt.conf &- Place your configuration file at
/var/etc/persistent/mqtt.conf(this is small enough for persistent storage). - Run
saveon the device to persist the script and config across reboots.
For testing, you can SCP binaries directly to /tmp:
scp build/mips-release/mfi-mqtt-client/mfi-mqtt-client admin@mfi-device:/tmp/
ssh admin@mfi-device '/tmp/mfi-mqtt-client --config /var/etc/persistent/mqtt.conf &'Note: /tmp is cleared on reboot, so this approach requires re-copying after
each restart.
/var/etc/persistent/is the home directory when you SSH in and the "persistent" folder.- The
savealias will save the persistent folder's data to flash memory, so it will be there after a reboot. The flash memory is only 128KB, split in half for backup — 64KB of usable space. - If
/var/etc/persistent/profileexists it will be run on login. - If
/var/etc/persistent/rc.poststartexists it will be run after the device starts up. NOTE: the firmware waits 3 minutes after startup before running your script.