# Zigbee on Host

[![Version](https://img.shields.io/npm/v/zigbee-on-host.svg)](https://npmjs.org/package/zigbee-on-host)
[![CI](https://github.com/Nerivec/zigbee-on-host/actions/workflows/ci.yaml/badge.svg)](https://github.com/Nerivec/zigbee-on-host/actions/workflows/ci.yaml)
[![CodeQL](https://github.com/Nerivec/zigbee-on-host/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/Nerivec/zigbee-on-host/actions/workflows/github-code-scanning/codeql)

Open Source Zigbee stack designed to run on a host and communicate with a radio co-processor (RCP).

Current implementation aims for compatibility with OpenThread RCP firmware. That base provides compatibility with any chip manufacturer that supports it (Silabs, TI, etc.) with the only requirements being proper implementation of the `STREAM_RAW` mechanism of the `Spinel` protocol (which allows to send raw 802.15.4 frames, including... Zigbee!) and hardware MAC ACKing.

_This library can also serve as a base for pentesting Zigbee networks thanks to the ability to easily craft various payloads at any layer of the specification and send them through the raw stream using any network parameters._

> [!IMPORTANT]
> Work in progress! Expect breaking changes without backwards compatibility for a while!

## Development

[CONTRIBUTING](./CONTRIBUTING.md)

### Current status

> Percentages generated by copilot based on overall compliance to coordinator/Trust Center functionality.

| Protocol | Status | Pending |
| --- | --- | --- |
| Spinel & HDLC | 100% | — |
| IEEE 802.15.4 MAC | 100% | — |
| Zigbee NWK | 90% | Route discovery table, R23 TLV handling, route table normalization |
| Zigbee APS | 85% | APS security enablement, R23 TLV handling, fragmentation safeguards |
| Zigbee Green Power | 80% | Commissioning TLVs, security checking, counter persistence, security review (MIC/auth tag flows & key usage) |

| Feature | Status | Pending |
| --- | --- | --- |
| Network forming & state | 100% | — |
| Joining & rejoining workflow | 90% | Rejoin TLV validation, TRANSPORT_KEY resend policy, trust center policy gating |
| Indirect transmission mechanism | 90% | Indirect queue bounds, macTransactionPersistenceTime enforcement |
| Source routing | 80% | Route discovery table, source-route normalization, MTORR aging metrics |
| Route repairing | 60% | Automated path rebuild flow, failure threshold tuning |
| Coordinator LQI/routing | 80% | Age/diversity metrics, reporting hooks, runtime calibration |
| LQI reporting & mapping | 85% | Adaptive calibration, min/max persistence |
| Install code | 100% | — |
| APS application link keys | 80% | Usage (currently `DISALLOWED`), per-pair derivation, attribute persistence, rotation tooling |
| InterPAN / Touchlink | 0% | Entire feature set |
| R23 compliance (commissioning & TLVs) | 40% | Commissioning TLVs, Zigbee Direct, optional behaviors |
| Trust Center key rotation | 50% | Scheduler, alerting |
| Security hardening | 80% | Rejoin anomaly detection, Trust Center policy gating, alert fan-out |
| Metrics & statistics | 0% | Collection/export of telemetry items |

And of course a bunch of `TODO`s in the code!

You can also contribute by submitting sniffs/captures. [More information here](https://github.com/Nerivec/zigbee-on-host/discussions/14).

### OpenThread RCP firmware notes

- [Texas Instruments] Some CC13xx/CC26xx boards require skipping the bootloader on startup. If ZoH does not want to start (timeout on first contact), set `"tiSerialSkipBootloader": true` in [custom stack config](#custom-stack-config).
- [Texas Instruments] Does not currently implement `PHY_CCA_THRESHOLD` (cannot read or write value)

## Testing

#### Current Status

- CI: ~95% coverage
- Stress-testing: pending
- Firmware stability:
  - Silicon Labs: ongoing
  - Texas Instruments: ongoing
  - Nordic Semiconductor: [pending](https://github.com/Nerivec/zigbee-on-host/discussions/18)
- Usage in test networks: ongoing
- Usage in live networks: pending

### Firmware

Use the appropriate OpenThread RCP firmware for your adapter:
- Silicon Labs: https://github.com/Nerivec/silabs-firmware-builder/releases
- Texas Instruments: https://github.com/Koenkk/OpenThread-TexasInstruments-firmware/releases
- Nordic Semiconductor: https://github.com/Nerivec/zigbee-on-host/discussions/18

### Zigbee2MQTT

Zigbee2MQTT 2.1.3-dev (after [PR #26742](https://github.com/Koenkk/zigbee2mqtt/pull/26742)) and later versions should allow the use of the `zoh` adapter.
Make sure you followed the above steps to get the proper firmware, then configure your `configuration.yaml`, including:

> [!TIP]
> It is currently recommended you use Zigbee2MQTT `latest-dev` (`edge`) to get the latest fixes when testing this implementation!

```yaml
serial:
  port: /dev/serial/by-id/my-device-id-here
  adapter: zoh
  # unused for TCP-based coordinator
  baudrate: 921600
  # as appropriate for your coordinator/firmware, unused for TCP-based coordinator
  rtscts: true
```

> [!TIP]
> Zigbee on Host saves the current state of the network in the file `zoh.save`. _It is similar to the NVRAM of an NCP coordinator._
> This file contains everything needed to re-establish the network on start, hence, a `coordinator_backup.json` is never created by Zigbee2MQTT. It is located alongside the `database.db` in the `data` folder.

> [!TIP]
> The EUI64 (IEEE address) in the firmware of the coordinator is ignored in this mode. One is set by Zigbee2MQTT instead, allowing you to change coordinators at will on the same network (although you may encounter device-related troubles when radio specs vary wildly).

#### Custom stack config

Starting with [zigbee-herdsman 6.4.0](https://github.com/Koenkk/zigbee-herdsman/releases/tag/v6.4.0), it is possible to provide a custom stack configuration via JSON (similar to [ember's](https://www.zigbee2mqtt.io/guide/adapters/emberznet.html#expert-customizing-stack-configuration)).

```ts
interface StackConfigJSON {
    /** for TI hw only, required for some CC13xx/CC26xx with auto-entering of bootloader on plug in */
    tiSerialSkipBootloader: boolean;
    /** EUI64 used for the adapter -- 0x${hex} format */
    eui64: string;
    /** @see https://nerivec.github.io/zigbee-on-host/types/spinel_spinel.StreamRawConfig.html */
    ccaBackoffAttempts: number;
    /** @see https://nerivec.github.io/zigbee-on-host/types/spinel_spinel.StreamRawConfig.html */
    ccaRetries: number;
    /** @see https://nerivec.github.io/zigbee-on-host/types/spinel_spinel.StreamRawConfig.html */
    enableCSMACA: boolean;
}
```
Defaults are:
```json
{
    "tiSerialSkipBootloader": false,
    "eui64": "0x4d325a6e6f486f5a",
    "ccaBackoffAttempts": 1,
    "ccaRetries": 4,
    "enableCSMACA": true
}
```

### CLI & Utils

Clone the repository.

```bash
git clone https://github.com/Nerivec/zigbee-on-host
cd zigbee-on-host
```

Install dev dependencies and build:

```bash
npm ci
npm run build
```

> [!IMPORTANT]
> Running `npm run build:prod` omits the `src/dev` directory (for production). If you do, you will not be able to use `dev:*` commands.

> [!TIP]
> If having issues with building, try removing the `*.tsbuildinfo` incremental compilation files (or run `npm run clean` first).

#### Utils

##### Create a 'zoh.save' from the content of a Zigbee2MQTT data folder

```bash
npm run dev:z2z ./path/to/data/
```

> [!TIP]
> This allows you to quickly take over a network created with `zstack` or `ember`. You then just need to change the `configuration.yaml` to `adapter: zoh` and `baudrate: 921600` (and `port` as appropriate).

##### Print and save the content of the 'zoh.save' in the given directory in human-readable format (as JSON, in same directory)

```bash
npm run dev:z2r ./path/to/data/
```

##### CLI

Get a list of supported commands with:

```bash
npm run dev:cli help
```

> [!TIP]
> `dev:cli` commands can be configured in more details using the file `dist/dev/conf.json`. Some environment variables are also available to quickly configure the adapter & wireshark. _The effective config is printed at the start of every command (`help` included)._

##### Using Docker

###### Prerequisites

```bash
git clone https://github.com/Nerivec/zigbee-on-host
cd zigbee-on-host
docker compose -f docker-dev/compose.yaml up -d --pull never
docker compose -f docker-dev/compose.yaml exec zigbee-on-host npm ci
docker compose -f docker-dev/compose.yaml exec zigbee-on-host npm run build
```

###### Running util commands

Create 'zoh.save' (details above):

```bash
docker compose -f docker-dev/compose.yaml exec zigbee-on-host npm run dev:z2z ./path/to/data
```

Print readable 'zoh.save' content (details above):

```bash
docker compose -f docker-dev/compose.yaml exec zigbee-on-host npm run dev:z2r ./path/to/data
```

CLI:

```bash
docker compose -f docker-dev/compose.yaml exec zigbee-on-host npm run dev:cli help
```

> [!TIP]
> `dev:cli` commands can be configured in more details using the file `dist/dev/conf.json`. Some environment variables are also available to configure the adapter & wireshark from the compose file. _The effective config is printed at the start of every command (`help` included)._

###### Stopping & removing the container

```bash
docker compose -f docker-dev/compose.yaml down
```
