The Linksys MX4200 routers have a built in EFR32MG21 chip, which is the same chip used in the Home Assistant Connect ZBT-1 dongle. It is connected via a serial port. After forwarding the port to TCP via ser2net, the chip can be flashed with the ZBT-1 firmware and added to Home Assistant as a Zigbee Coordinator (tested with ZHA).
Looking at the device tree in the OpenWRT source
it can be seen that the chip uses hsuart_pins as well as iot_pins.
iot_pins are defined in the same file as gpio21 for reset and gpio22 for recovery
hsuart_pins are defined in ipq8074.dtsi
as "gpio46", "gpio47", "gpio48", "gpio49", which correspond to TX, RX, CTS, RTS so the port has hardware flow control.
The chip is connected to the /dev/ttyMSM1 port.
To verify its operation, it can be reset using the GPIO pins.
Open two SSH sessions to the router.
gpio21 and gpio22 are located on gpiochip512.
To verify this you can run
cat /sys/kernel/debug/gpioAdding the base offset of 512 to gpio21 and gpio22
we get gpio533 for the reset and gpio534 for the recovery.
Export both to make them available in Linux:
echo "533" > /sys/class/gpio/export
echo "534" > /sys/class/gpio/exportThey are now available in /sys/class/gpio/.
The next step is optional but improves clarity when using the pins.
Add symlinks to the gpio directories:
ln -s /sys/class/gpio/gpio533 reset
ln -s /sys/class/gpio/gpio534 recoveryYou need to install the coreutils-stty package for this step.
In the other SSH session, configure the serial port and open it with hexdump:
stty -F /dev/ttyMSM1 115200 raw -echo
hexdump -C /dev/ttyMSM1The chip can be reset by simply setting the reset pin to output, pulling it low, and setting it back to input, which pulls it high through the pull-up resistor.
echo "out" > reset/direction
echo "in" > reset/directionYou should see the output of the chip in the other session.
Note that hexdump buffers the input into 16 byte lines, while the reset output
of the chip is only 29 bytes, so only the first 16 bytes will be shown.
Reset the chip multiple times to get see the rest of the output.
The full output is something like:
root@OpenWrt:~# hexdump -C /dev/ttyMSM1
00000000 03 01 06 95 01 00 00 a0 12 01 00 02 00 0d 00 0a |................|
00000010 00 a7 01 03 00 0a 01 01 00 61 96 5a 4d |.........a.ZM |
Using the recovery pin, the chip can also be put into bootloader mode. Set recovery pin to output and high, and reset the chip:
echo "out" > recovery/direction
echo "1" > recovery/value
echo "out" > reset/direction
echo "in" > reset/direction
echo "0" > recovery/value
echo "in" > recovery/directionThe output of the bootloader is something like:
root@OpenWrt:~# hexdump -C /dev/ttyMSM1
00000000 00 0d 0a 47 65 63 6b 6f 20 42 6f 6f 74 6c 6f 61 |...Gecko Bootloa|
00000010 64 65 72 20 76 31 2e 41 2e 33 0d 0a 31 2e 20 75 |der v1.A.3..1. u|
00000020 70 6c 6f 61 64 20 67 62 6c 0d 0a 32 2e 20 72 75 |pload gbl..2. ru|
00000030 6e 0d 0a 33 2e 20 65 62 6c 20 69 6e 66 6f 0d 0a |n..3. ebl info..|
00000040 42 4c 20 3e 20 00 |BL > . |
- Install
luci-app-ser2net, this will also installser2net. - Refresh the webpage.
- Go to Services > ser2net > Proxies.
- Delete all proxies except one.
- My settings:
- Enabled: yes
- Service port: 5000
- Protocol: Raw
- Timeout: 0
- Device: /dev/ttyMSM1
- Baud rate: 115200
- Data bits: 8
- Parity: none
- Stop bits: 1
- Use RTS and CTS lines: yes
- Ignore modem control signals: no
- Allow the RFC 2217 protocol: no
- Save & Apply
You can test the forwarding by connecting to the port and resetting the chip:
telnet <router-ip> 5000or
nc <router-ip> 5000you should see some garbage containing ZM or the Gecko Bootloader, depending on the recovery pin.
Caution
Flashing this firmware will destroy the stock firmware that Linksys uses. I don't know if the firmware is ever updated by the stock router firmware, so if you continue, the stock router firmware will probably no longer be able to use the chip!
Make a pair of ports (in my case COM35 and COM36)
In a terminal window run to connect to one of the ports from the pair.
com2tcp.exe --baud 115200 \\.\COM36 <router-ip> 5000In another terminal run
mkdir universal-silabs-flasher
cd universal-silabs-flasher
python -m venv venv
venv\Scripts\activate
pip install universal-silabs-flasherOn the router run
echo "out" > recovery/direction
echo "1" > recovery/value
echo "out" > reset/direction
echo "in" > reset/direction
echo "0" > recovery/value
echo "in" > recovery/directionuniversal-silabs-flasher --device COM35 probeYou should see
INFO Probing ApplicationType.GECKO_BOOTLOADER at 115200 baud
INFO Detected bootloader version '1.A.3' (1.3)
INFO Detected ApplicationType.GECKO_BOOTLOADER, version '1.A.3' (1.3) at 115200 baudrate (bootloader baudrate 115200)
Flash firmware. The firmware in this repo was downloaded from NabuCasa/silabs-firmware-builder
universal-silabs-flasher --device COM35 flash --firmware /path/to/skyconnect_zigbee_ncp_7.5.1.0.gblThis can take a few minutes.
When the flash is done, stop com2tcp so you can continue with the next step.
- Open Home Assistant
- Go to Settings > Devices & services
- + Add integration
- Find Zigbee Home Automation
- For the Serial device path select Enter manually
- Enter
socket://<router-ip>:5000 - Submit
From here on it is a standard ZHA setup.
Enjoy!
