|
3 | 3 |
|
4 | 4 | This page is for developers who want to understand how Zigbee2Tasmota (Z2T) works and its implementation details.
|
5 | 5 |
|
6 |
| -## CC2530 ZNP protocol |
| 6 | +## CC2530 Serial protocol |
7 | 7 | The CC2530 is flashed with Texas Instrument ZNP Software version 1.2. The protocol is build on a serial communication between the main cpu and the CC2530.
|
8 | 8 |
|
9 |
| -[Z-Stack 1.2 Monitor and Test API](https://tasmota.github.io/docs_media/zigbee/Z-Stack_API_1_2.pdf) |
| 9 | +[Z-Stack 1.2 Monitor and Test API](/docs/_media/zigbee/Z-Stack_API_1_2.pdf) |
10 | 10 |
|
11 | 11 | Serial communication is configured as 8N1, 115200 bauds. We suggest to use GPIO13/15 because they have hardware serial support. Please note that there is only one usable hardware serial, either on GPIO1/3 or GPIO13/15.
|
12 | 12 |
|
@@ -38,3 +38,112 @@ Still the first byte in the message could have been wrong. Fortunately, the firs
|
38 | 38 |
|
39 | 39 | With these two schemes, software serial for Zigbee proved to be extremely reliable, even at 80MHz. It is highly recommended though to run at 160MHz.
|
40 | 40 |
|
| 41 | +## State machine - CC2530 initialization and configuration |
| 42 | +After Tasmota boots, it sends the sequence `410001` to force a CC2530 hardware reset. Z2T implements an asynchronous state machine to handle the initialization and configuration of the CC2530. The state machine sends commands and waits for responses (with time-outs) and takes different branches depending on the responses. |
| 43 | + |
| 44 | +### Instruction set |
| 45 | + |
| 46 | +The program is encoded as a list of 32 bits instructions, stored in Flash in the `zb_prog` array of type `Zigbee_Instruction[]`. There is a PC (program counter) that is increased at each tick (i.e. every 50ms). |
| 47 | + |
| 48 | +The state machine has very simple instructions. |
| 49 | + |
| 50 | +Instructions encoded with 4 bytes: |
| 51 | + |
| 52 | +* `NOOP`: no-operation, do nothing and move to the next instruction |
| 53 | +* `LABEL(x)`: no-operation, and defines a Label (8 bits) that can be called by code. |
| 54 | +* `GOTO(x)`: moves the PC to the instruction with LABEL(x) |
| 55 | +* `ZI_ON_ERROR_GOTO(x)`: if an error occurs, move to label <x> |
| 56 | +* `ZI_ON_TIMEOUT_GOTO(x)`: if a timeout occurs, move to lavel <x> |
| 57 | +* `WAIT(y)`: wait for <y> milliseconds (unsigned 16 bits). Note the granularity is 50ms and the wait is non-blocking |
| 58 | +* `WAIT_FOREVER`: pause the state machine and wait for an external goto |
| 59 | +* `STOP`: stop completely the state machine, only used after an unrecoverable error |
| 60 | + |
| 61 | +Instructions encoded with 8 bytes: |
| 62 | + |
| 63 | +* `CALL(f, x)`: call a function, <f> is the address of the function of type `uint32_t f(uint8_t)`. The input parameter is <x>. The response is according to callbacks responses, except `-1` (time-out) simply continues the flow. |
| 64 | +* `LOG(m)`: log the string <m>. <m> can be in PROGMEM. For debugging only. |
| 65 | +* `MQTT_STATE(x, m)`: sends a MQTT `ZbState` message, with status code <x> and message <m>. <m> can be in PROGMEM. |
| 66 | +* `SEND(d)`: send a ZNP sequence to CC2530. <d> is an array of <uint8_t>, a macro computes automatically the size of the array. <d> can be in PROGMEM. |
| 67 | +* `WAIT_RECV(x, m)`: wait for a specific message <m> to be received with a time-out of <x> (uint16_t). Messages take into account are owly those matching the first 2 bytes. The complete message match is expected or an error is generated. If the message received is longer than <m>, additional bytes are ignored |
| 68 | +* `WAIT_UNTIL(x, m)`: similar to `WAIT_RECV` but message that don't match are ignored, until a matching message is received. |
| 69 | +* `ON_RECV_UNEXPECTED(f)`: if we received an unexpected (or unsupported) zigbee message, call function <f> |
| 70 | + |
| 71 | + |
| 72 | +Instructions encoded with 12 bytes: |
| 73 | + |
| 74 | + * `WAIT_RECV_FUNC(x, m, f)`: similar to `WAIT_RECV` and a function <f> is called when the message matches. |
| 75 | + |
| 76 | +All callbacks return `int32_t` with the following effect: |
| 77 | + |
| 78 | +* `> 0`: goto the corresponding label |
| 79 | +* `0`: continue |
| 80 | +* `-1`: signal a time-out |
| 81 | +* `< -1`: trigger an error (goto on\_error) |
| 82 | + |
| 83 | +### Initialization code for the state machine |
| 84 | +At Tasmota start-up, the state-machine fires. The current Z2T pseudo-code does the following: |
| 85 | + |
| 86 | +Init: |
| 87 | + |
| 88 | +* Set-up all the error handling functions |
| 89 | +* Wait for 10.5 seconds after boot |
| 90 | +* Send a RESET to CC2530 |
| 91 | +* Wait for CC2530 boot |
| 92 | + |
| 93 | +Check configuration (if something is wrong, go to CONFIGURE): |
| 94 | + |
| 95 | +* Check if the CC2530 was previously configured. It uses the same 1-byte Non-Volatile 0xF00 address and stores 0x55. |
| 96 | +* Checks the Z-Stack version |
| 97 | +* Checks the internal configuration: PanID, Ext PanID, Channel, PFGK and PFGKEN. |
| 98 | +* If all good, emit an MQTT message saying Zigbee is configured |
| 99 | +* Goto Start |
| 100 | + |
| 101 | +Configure (only if needed): |
| 102 | + |
| 103 | +* Emit an MQTT message for reconfiguration |
| 104 | +* Do a factory reset of CC2530 |
| 105 | +* Reset the device once again |
| 106 | +* Configure the following: PanId, Ext PanId, Channel, set type to Coordinator, PFKEY, PFKEYEN, Security Module |
| 107 | +* Create NF 0xF00 location and store 0x55 |
| 108 | +* Goto Start |
| 109 | + |
| 110 | +Start: |
| 111 | + |
| 112 | +* Wait for CC2530 message saying the coordinator sucessfully started |
| 113 | +* Query DeviceInfo |
| 114 | +* Query Node Descriptor |
| 115 | +* Query Active Endpoints |
| 116 | +* Register 2 endpoints with profile 0x0104 (Home Automation) : 0x01 (default), 0x0B (for Xiaomi) |
| 117 | +* Query Active Endpoints to verify 0x01 and 0x0B are active |
| 118 | +* Close PermitJoin: don't accept any pairing |
| 119 | +* Emit an MQTT message to indicate Zigbee started |
| 120 | +* Mark Zigbee as initialized, accept incoming messages |
| 121 | +* Load device configuration from Flash |
| 122 | +* Query any lights declared with `ZbLight` to read their current states |
| 123 | +* Pause the state machine |
| 124 | + |
| 125 | +## Pairing devices |
| 126 | +When you open pairing with `ZbPermitJoin 1` (60 seconds) or `ZbPermitJoin 99` (until next reboot), you allow new devices to join the network. |
| 127 | + |
| 128 | +Example below is for an OSRAM Plug. |
| 129 | + |
| 130 | +When a new devices joins, Z2T receives a TC Device Indication: `ZDO_TC_DEV_IND` (45CA) message with the device short (16 bits) address and IEEEAddress (64 bits). |
| 131 | + |
| 132 | +```json |
| 133 | +16:39:26 MQT: tele/Zigbee_home/RESULT = {"ZbState":{"Status":30,"IEEEAddr":"0x7CB03EAA0A0292DD","ShortAddr":"0xF75D","PowerSource":true,"ReceiveWhenIdle":true,"Security":false}} |
| 134 | +``` |
| 135 | + |
| 136 | +Z2T then queries the device for additional information, like `ZbProbe` would do. |
| 137 | + |
| 138 | +First probe for Active Endpoint `ZDO_ACTIVE_EP_REQ` |
| 139 | + |
| 140 | +```json |
| 141 | +16:39:26 MQT: tele/Zigbee_home/RESULT = {"ZbState":{"Status":32,"ActiveEndpoints":["0x03"]}} |
| 142 | +``` |
| 143 | + |
| 144 | +Finally query for the following general attributes: Manufacturer Id and Model Id. |
| 145 | + |
| 146 | +``` |
| 147 | +16:39:26 ZIG: ZbZCLRawReceived: {"0xF75D":{"0000/0004":"OSRAM","0000/0005":"Plug 01"}} |
| 148 | +16:39:26 MQT: tele/tasmota/Zigbee_home/SENSOR = {"ZbReceived":{"0xF75D":{"Manufacturer":"OSRAM","ModelId":"Plug 01","Endpoint":3,"LinkQuality":36}}} |
| 149 | +``` |
0 commit comments