1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
//! Build Philips Hue–compatible Zigbee lights on the ESP32-C6 / ESP32-H2.
//!
//! Any LED — on/off, dimmable, CCT, or a full-colour WS2812B strip — becomes a
//! device that pairs directly with a real Hue Bridge. Construct a light with one
//! of the entry points ([`on_off`], [`dimmable`], [`cct`], [`color`],
//! [`rgb_strip`], [`custom`]), customise it with the [`Light`] builder, then
//! call [`Light::launch`].
//!
//! ```no_run
//! // Cool/warm white CCT light on GPIO 19 / 18; pairs with any Hue Bridge.
//! huesmith::cct(19, 18).starts_on().launch();
//! ```
//!
//! Platform-agnostic logic (color math, state machine, scene parsing) lives in the
//! companion `huesmith-core` crate. This crate provides the ESP-IDF hardware backends
//! and the Zigbee (ZBOSS) integration.
pub
pub
// Re-export the `huesmith-core` types that appear in this crate's public API, so
// a user writing a `custom()` backend or passing an `.identity()` preset does not
// have to add (and version-lock) a second `huesmith-core` dependency by hand.
// Exported under their original names to match the rustdoc examples.
pub use HueDeviceType;
pub use ;
pub use LightSnapshot;
pub use LightOutput;
// ── Builder entry points ─────────────────────────────────────────────────────
/// Create a dimmable LED light on a single PWM GPIO.
///
/// Active-high by default (GPIO high = on); chain [`Light::inverted`] when the
/// GPIO sinks current directly from the LED's cathode instead.
/// The Hue Bridge sees this as a dimmable white bulb.
/// Create an on/off light on a single GPIO (no dimming).
///
/// Active-high by default; chain [`Light::inverted`] for direct-sink wiring.
/// The Hue Bridge sees this as an on/off light with no level control.
/// Create a CCT (warm + cool white) light on two PWM GPIOs.
///
/// The default polarity is **active-high**: each GPIO drives a low-side switch
/// (N-MOSFET or transistor) that carries the channel current, with the lamp's
/// common positive on the supply rail. For a small lamp whose negative wires
/// are soldered **directly to the GPIOs** (the GPIO itself sinks the current),
/// chain [`Light::inverted`] to flip the electrical duty accordingly.
///
/// The Hue Bridge sees this as a color-temperature tunable bulb.
///
/// # Arguments
/// * `cool_gpio` — GPIO for the cool white (high K) channel.
/// * `warm_gpio` — GPIO for the warm white (low K) channel.
/// Create a WS2812B RGB color light on a single data GPIO.
///
/// The Hue Bridge sees this as a full color (RGB + CCT) bulb.
/// Chain `.leds(n)` to drive a strip of n LEDs (default: 1).
/// Create a WS2812B RGB strip with a given LED count.
///
/// Equivalent to `color(gpio).leds(count)`. Convenience entry point
/// for multi-LED strips.
///
/// # Panics
/// Panics if `count` is 0 or exceeds 300.
/// Create a light driven by your own [`LightOutput`] backend.
///
/// This is the escape hatch when the built-in GPIO/LEDC/RMT backends don't fit
/// your hardware — an I²C PWM controller, a DALI gateway, a relay board, an
/// exotic LED protocol, custom gamma/calibration curves, or effects of your
/// own. Implement [`LightOutput`] (only `set_on`, `set_brightness`, and
/// `set_rgb` are required; see the trait's call contract), pick the
/// [`HueDeviceType`] that matches the capabilities your hardware really has
/// (it decides which Zigbee clusters are advertised), and the full Hue
/// pairing, scene, transition, and identify machinery drives your
/// implementation.
///
/// # Value domains your backend receives
///
/// | Callback | Values | Range |
/// |---|---|---|
/// | `set_brightness(level)` | ZCL level | `0-254` (254 = full; never 255) |
/// | `set_rgb(r, g, b)` | converted color | `0-255` per channel, linear |
/// | `set_color_temp(mireds)` | raw color temperature | `153-500` mireds |
/// | `state_update(&LightSnapshot)` | **every raw field, no `Option`s** | on, brightness + rendered_brightness `0-254`, hue/sat `0-254`, enhanced hue `0-65535`, CIE x/y `0-65535`, mireds |
///
/// `state_update` fires after every render — including each ~20-33 ms frame of
/// a smooth transition — so effects can key off the raw values directly
/// instead of reverse-engineering them from RGB. `brightness` is the logical
/// target level; `rendered_brightness` is what is being driven right now (it
/// ramps during fades — key visual effects off it). **Pick one lane:** simple
/// hardware implements the `set_*` methods and ignores the hook; an
/// effects/full-control backend treats the hook as its single source of truth
/// and leaves the `set_*` bodies empty.
///
/// # Running your own effects (threads welcome)
///
/// `LightOutput` methods are called on the Zigbee stack's task and must return
/// quickly (microseconds-to-a-few-ms; never block on delays). For animations,
/// own a thread and feed it state — full `std` is available on ESP-IDF:
///
/// ```no_run
/// use huesmith::{HueDeviceType, LightOutput, LightSnapshot};
/// use std::sync::mpsc;
///
/// struct FxDriver {
/// tx: mpsc::Sender<LightSnapshot>,
/// }
///
/// impl LightOutput for FxDriver {
/// fn set_on(&mut self, _on: bool) {}
/// fn set_brightness(&mut self, _level: u8) {}
/// fn set_rgb(&mut self, _r: u8, _g: u8, _b: u8) {}
/// // Forward the raw state; the effect thread decides what it means.
/// fn state_update(&mut self, state: &LightSnapshot) {
/// let _ = self.tx.send(*state);
/// }
/// }
///
/// fn main() {
/// let (tx, rx) = mpsc::channel::<LightSnapshot>();
///
/// // The effect thread owns the LED hardware and its own timing:
/// // brightness 10 → blink, brightness 50 → breathe, anything else → solid.
/// std::thread::spawn(move || {
/// let mut latest: Option<LightSnapshot> = None;
/// loop {
/// while let Ok(state) = rx.try_recv() {
/// latest = Some(state);
/// }
/// if let Some(state) = latest {
/// match state.brightness {
/// 10 => { /* toggle the LED — blink */ }
/// 50 => { /* sine-ramp the LED — breathe */ }
/// _ => { /* drive state.rendered_brightness as-is */ }
/// }
/// }
/// std::thread::sleep(std::time::Duration::from_millis(40));
/// }
/// });
///
/// huesmith::custom(HueDeviceType::DimmableLight, FxDriver { tx }).launch();
/// }
/// ```
// ── Light builder ────────────────────────────────────────────────────────────
/// Builder for a Hue-compatible Zigbee light.
///
/// Construct via the module-level free functions ([`dimmable`], [`on_off`],
/// [`cct`], [`color`], [`custom`]) and finish with [`Light::launch`].
///
/// # Example
/// ```no_run
/// huesmith::cct(19, 18)
/// .name("Philips", "LTW015")
/// .starts_on()
/// .launch();
/// ```
pub