ESPHome 2026.1.4
Loading...
Searching...
No Matches
zigbee_zephyr.cpp
Go to the documentation of this file.
1#include "zigbee_zephyr.h"
2#if defined(USE_ZIGBEE) && defined(USE_NRF52)
3#include "esphome/core/log.h"
4#include <zephyr/settings/settings.h>
5#include <zephyr/storage/flash_map.h>
6
7extern "C" {
8#include <zboss_api.h>
9#include <zboss_api_addons.h>
10#include <zb_nrf_platform.h>
11#include <zigbee/zigbee_app_utils.h>
12#include <zb_error_to_string.h>
13}
14
15namespace esphome::zigbee {
16
17static const char *const TAG = "zigbee";
18
19ZigbeeComponent *global_zigbee = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
20
21const uint8_t IEEE_ADDR_BUF_SIZE = 17;
22
24 zb_zdo_app_signal_hdr_t *sig_hndler = nullptr;
25 zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, &sig_hndler);
26 zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);
27
28 switch (sig) {
29 case ZB_ZDO_SIGNAL_SKIP_STARTUP:
30 ESP_LOGD(TAG, "ZB_ZDO_SIGNAL_SKIP_STARTUP, status: %d", status);
31 break;
32 case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
33 ESP_LOGD(TAG, "ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY, status: %d", status);
34 break;
35 case ZB_ZDO_SIGNAL_LEAVE:
36 ESP_LOGD(TAG, "ZB_ZDO_SIGNAL_LEAVE, status: %d", status);
37 break;
38 case ZB_BDB_SIGNAL_DEVICE_REBOOT:
39 ESP_LOGD(TAG, "ZB_BDB_SIGNAL_DEVICE_REBOOT, status: %d", status);
40 if (status == RET_OK) {
41 on_join_();
42 }
43 break;
44 case ZB_BDB_SIGNAL_STEERING:
45 break;
46 case ZB_COMMON_SIGNAL_CAN_SLEEP:
47 ESP_LOGV(TAG, "ZB_COMMON_SIGNAL_CAN_SLEEP, status: %d", status);
48 break;
49 case ZB_BDB_SIGNAL_DEVICE_FIRST_START:
50 ESP_LOGD(TAG, "ZB_BDB_SIGNAL_DEVICE_FIRST_START, status: %d", status);
51 break;
52 case ZB_NLME_STATUS_INDICATION:
53 ESP_LOGD(TAG, "ZB_NLME_STATUS_INDICATION, status: %d", status);
54 break;
55 case ZB_BDB_SIGNAL_TC_REJOIN_DONE:
56 ESP_LOGD(TAG, "ZB_BDB_SIGNAL_TC_REJOIN_DONE, status: %d", status);
57 break;
58 default:
59 ESP_LOGD(TAG, "zboss_signal_handler sig: %d, status: %d", sig, status);
60 break;
61 }
62
63 auto err = zigbee_default_signal_handler(bufid);
64 if (err != RET_OK) {
65 ESP_LOGE(TAG, "Zigbee_default_signal_handler ERROR %u [%s]", err, zb_error_to_string_get(err));
66 }
67
68 switch (sig) {
69 case ZB_BDB_SIGNAL_STEERING:
70 ESP_LOGD(TAG, "ZB_BDB_SIGNAL_STEERING, status: %d", status);
71 if (status == RET_OK) {
72 zb_ext_pan_id_t extended_pan_id;
73 char ieee_addr_buf[IEEE_ADDR_BUF_SIZE] = {0};
74 int addr_len;
75
76 zb_get_extended_pan_id(extended_pan_id);
77 addr_len = ieee_addr_to_str(ieee_addr_buf, sizeof(ieee_addr_buf), extended_pan_id);
78
79 for (int i = 0; i < addr_len; ++i) {
80 if (ieee_addr_buf[i] != '0') {
81 on_join_();
82 break;
83 }
84 }
85 }
86 break;
87 }
88
89 /* All callbacks should either reuse or free passed buffers.
90 * If bufid == 0, the buffer is invalid (not passed).
91 */
92 if (bufid) {
93 zb_buf_free(bufid);
94 }
95}
96
97void ZigbeeComponent::zcl_device_cb(zb_bufid_t bufid) {
98 zb_zcl_device_callback_param_t *p_device_cb_param = ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
99 zb_zcl_device_callback_id_t device_cb_id = p_device_cb_param->device_cb_id;
100 zb_uint16_t cluster_id = p_device_cb_param->cb_param.set_attr_value_param.cluster_id;
101 zb_uint16_t attr_id = p_device_cb_param->cb_param.set_attr_value_param.attr_id;
102 auto endpoint = p_device_cb_param->endpoint;
103
104 ESP_LOGI(TAG, "Zcl_device_cb %s id %hd, cluster_id %d, attr_id %d, endpoint: %d", __func__, device_cb_id, cluster_id,
105 attr_id, endpoint);
106
107 /* Set default response value. */
108 p_device_cb_param->status = RET_OK;
109
110 // endpoints are enumerated from 1
111 if (global_zigbee->callbacks_.size() >= endpoint) {
112 const auto &cb = global_zigbee->callbacks_[endpoint - 1];
113 if (cb) {
114 cb(bufid);
115 }
116 return;
117 }
118 p_device_cb_param->status = RET_ERROR;
119}
120
122 this->defer([this]() {
123 ESP_LOGD(TAG, "Joined the network");
124 this->join_trigger_.trigger();
125 this->join_cb_.call();
126 });
127}
128
129#ifdef USE_ZIGBEE_WIPE_ON_BOOT
131 const struct flash_area *fap;
132 flash_area_open(area, &fap);
133 flash_area_erase(fap, 0, fap->fa_size);
134 flash_area_close(fap);
135}
136#endif
137
139 global_zigbee = this;
140 auto err = settings_subsys_init();
141 if (err) {
142 ESP_LOGE(TAG, "Failed to initialize settings subsystem, err: %d", err);
143 return;
144 }
145
146#ifdef USE_ZIGBEE_WIPE_ON_BOOT
147 bool wipe = true;
148#ifdef USE_ZIGBEE_WIPE_ON_BOOT_MAGIC
149 // unique hash to store preferences for this component
150 uint32_t hash = 88498616UL;
151 uint32_t wipe_value = 0;
152 auto wipe_pref = global_preferences->make_preference<uint32_t>(hash, true);
153 if (wipe_pref.load(&wipe_value)) {
154 wipe = wipe_value != USE_ZIGBEE_WIPE_ON_BOOT_MAGIC;
155 ESP_LOGD(TAG, "Wipe value in preferences %u, in firmware %u", wipe_value, USE_ZIGBEE_WIPE_ON_BOOT_MAGIC);
156 }
157#endif
158 if (wipe) {
159 erase_flash_(FIXED_PARTITION_ID(ZBOSS_NVRAM));
160 erase_flash_(FIXED_PARTITION_ID(ZBOSS_PRODUCT_CONFIG));
161 erase_flash_(FIXED_PARTITION_ID(SETTINGS_STORAGE));
162#ifdef USE_ZIGBEE_WIPE_ON_BOOT_MAGIC
163 wipe_value = USE_ZIGBEE_WIPE_ON_BOOT_MAGIC;
164 wipe_pref.save(&wipe_value);
165#endif
166 }
167#endif
168
169 ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);
170 err = settings_load();
171 if (err) {
172 ESP_LOGE(TAG, "Cannot load settings, err: %d", err);
173 return;
174 }
175 zigbee_enable();
176}
177
178static const char *role() {
179 switch (zb_get_network_role()) {
180 case ZB_NWK_DEVICE_TYPE_COORDINATOR:
181 return "coordinator";
182 case ZB_NWK_DEVICE_TYPE_ROUTER:
183 return "router";
184 case ZB_NWK_DEVICE_TYPE_ED:
185 return "end device";
186 }
187 return "unknown";
188}
189
190static const char *get_wipe_on_boot() {
191#ifdef USE_ZIGBEE_WIPE_ON_BOOT
192#ifdef USE_ZIGBEE_WIPE_ON_BOOT_MAGIC
193 return "ONCE";
194#else
195 return "YES";
196#endif
197#else
198 return "NO";
199#endif
200}
201
203 char ieee_addr_buf[IEEE_ADDR_BUF_SIZE] = {0};
204 zb_ieee_addr_t addr;
205 zb_get_long_address(addr);
206 ieee_addr_to_str(ieee_addr_buf, sizeof(ieee_addr_buf), addr);
207 zb_ext_pan_id_t extended_pan_id;
208 char extended_pan_id_buf[IEEE_ADDR_BUF_SIZE] = {0};
209 zb_get_extended_pan_id(extended_pan_id);
210 ieee_addr_to_str(extended_pan_id_buf, sizeof(extended_pan_id_buf), extended_pan_id);
211 ESP_LOGCONFIG(TAG,
212 "Zigbee\n"
213 " Wipe on boot: %s\n"
214 " Device is joined to the network: %s\n"
215 " Current channel: %d\n"
216 " Current page: %d\n"
217 " Sleep threshold: %ums\n"
218 " Role: %s\n"
219 " Long addr: 0x%s\n"
220 " Short addr: 0x%04X\n"
221 " Long pan id: 0x%s\n"
222 " Short pan id: 0x%04X",
223 get_wipe_on_boot(), YESNO(zb_zdo_joined()), zb_get_current_channel(), zb_get_current_page(),
224 zb_get_sleep_threshold(), role(), ieee_addr_buf, zb_get_short_address(), extended_pan_id_buf,
225 zb_get_pan_id());
226}
227
228static void send_attribute_report(zb_bufid_t bufid, zb_uint16_t cmd_id) {
229 ESP_LOGD(TAG, "Force zboss scheduler to wake and send attribute report");
230 zb_buf_free(bufid);
231}
232
233void ZigbeeComponent::flush() { this->need_flush_ = true; }
234
236 if (this->need_flush_) {
237 this->need_flush_ = false;
238 zb_buf_get_out_delayed_ext(send_attribute_report, 0, 0);
239 }
240}
241
243 ESP_LOGD(TAG, "Factory reset");
244 ZB_SCHEDULE_APP_CALLBACK(zb_bdb_reset_via_local_action, 0);
245}
246
247} // namespace esphome::zigbee
248
249extern "C" void zboss_signal_handler(zb_uint8_t param) {
251}
252#endif
uint8_t status
Definition bl0942.h:8
ESPDEPRECATED("Use const char* overload instead. Removed in 2026.7.0", "2026.1.0") void defer(const std voi defer)(const char *name, std::function< void()> &&f)
Defer a callback to the next loop() call.
Definition component.h:492
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
void trigger(const Ts &...x)
Inform the parent automation that the event has triggered.
Definition automation.h:238
static void zcl_device_cb(zb_bufid_t bufid)
CallbackManager< void()> join_cb_
std::array< std::function< void(zb_bufid_t bufid)>, ZIGBEE_ENDPOINTS_COUNT > callbacks_
void zboss_signal_handler_esphome(zb_bufid_t bufid)
uint16_t addr_len
const char *const TAG
Definition spi.cpp:7
ZigbeeComponent * global_zigbee
const uint8_t IEEE_ADDR_BUF_SIZE
ESPPreferences * global_preferences
void zboss_signal_handler(zb_uint8_t param)