Skip to content

Commit 89dbd2e

Browse files
Tiwasclaude
andcommitted
feat(circadian): pre-warm capability auto-detection + new flow card
Adds a wizard step during pairing that briefly cycles each light to detect which of dim/light_temperature/light_hue/light_saturation can be safely pre-set while off. Per-capability results stored in config.devices[].prewarmSupport and respected by applyTargetToDevice; the master prewarmBeforeOn toggle now serves as fallback for untested caps only. Re-test available from Repair on each managed light. Probe uses makeCapabilityInstance for realtime onoff/value tracking (getDevice cache was not reliable after setCapabilityValue), with ensureOff() that retries up to 3 times and verifies via realtime state before continuing to the next capability test. Candidate filter now includes virtualClass==='light' (catches Hue/Z2M sockets) and any device with a setable dim/temp/hue/saturation cap (catches Z-Wave dimmer modules). New flow action clg_turn_on_member with autocomplete dropdown of group members; sets temp/colour/dim then onoff in one step to avoid the brief flash at the previous brightness on lamps without pre-warm. i18n strings for all new UI in 11 locales. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 65ccc8c commit 89dbd2e

20 files changed

Lines changed: 1000 additions & 22 deletions

File tree

HOMEY_COMMUNITY_LISTING.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
URL: https://community.homey.app/t/app-smart-components-toolkit-was-boolean-toolbox-create-advanced-logic-with-simple-formulas/143906
22

3-
Title: [APP] Smart (Components) Toolkit (was: Boolean Toolbox) - Create advanced logic with simple formulas
3+
Title: [APP] Smart (Components) Toolkit (was: Boolean Toolbox) - Create advanced logic with simple formulas [v1.9.2 stable / **v1.10.2 test — NEW: Circadian pre-warm auto-detection**]
44

55
Content:
66
![xlarge|690x483](upload://iSxhJPUltgcgPQ7gy4z5iisCv5F.jpeg)
77

8-
# Smart (Components) Toolkit — v1.9.2 stable / **v1.10.0 test**
8+
# Smart (Components) Toolkit — v1.9.2 stable / **v1.10.2 test**
99

1010
> **📚 Full Documentation:** https://tiwas.github.io/SmartComponentsToolkit/
1111
@@ -15,10 +15,18 @@ Replace complex flow networks with powerful logic devices controlled by dynamic
1515

1616
---
1717

18-
## 🧪 New in test (v1.10.0): Circadian Light Group
18+
## 🧪 New in test (v1.10.2): Circadian Light Group
1919

2020
A virtual **light device** that adjusts brightness and color temperature for a group of real lights — automatically following a circadian rhythm. Available now in the [test channel](https://homey.app/a/no.tiwas.booleantoolbox/test/) only; the stable channel still ships v1.9.2 without this device.
2121

22+
### 🆕 New in v1.10.2
23+
24+
- **Pre-warm auto-detection during pairing.** A new wizard step tests each light by briefly cycling it off, pre-setting `dim` / `light_temperature` / `light_hue` / `light_saturation`, then turning back on to verify the value persisted. Each capability is marked ✓/✗ per device. No more guessing whether a lamp tolerates pre-warming — and no more turning lights on with the wrong colour.
25+
- **Re-test from Repair.** Each managed light has a "Test pre-warm" button so you can re-run the test after firmware updates or when adding new devices.
26+
- **Smarter candidate filter.** Lights registered as `socket` with `virtualClass: light` (Hue/Z2M-bridged lamps) and Z-Wave dimmer modules with a `dim` capability are now picked up automatically.
27+
- **New flow action: "Turn on light at current circadian level."** Pick any member of the group from a dropdown — the action sets temperature/colour and dim, then turns the light on, all in one step. Avoids the brief flash at the previous brightness for lamps that don't support pre-warming.
28+
- **Master "Prewarm before on" toggle** is now a fallback for untested capabilities only; tested capabilities use the actual test result.
29+
2230
**Why use it?**
2331
- Bright cool light during the day, warm dim light in the evening, deep red at night to preserve melatonin and night vision.
2432
- Works at any latitude — pick clock times, solar events, or lux-sensor thresholds per phase.
@@ -46,17 +54,17 @@ Choose how the device knows how bright it is outside:
4654
- **Open-Meteo / MET.no** (radiation-based estimate)
4755
- **External value** pushed from a Flow
4856

49-
### 24 new flow cards
57+
### 25 new flow cards
5058

5159
**Triggers**: phase changed, red mode started/ended, paused/resumed, turned on/off, target changed, error, outdoor light requested. Plus an **app-level "Solar event occurred"** card with all 14 events + offset, usable from any flow.
5260

5361
**Conditions**: is in phase, red mode active, is paused, is on.
5462

55-
**Actions**: pause (sec/min/hour), pause until time, pause until solar event, resume, turn on/off/toggle, set red threshold, **apply temporary state** (override dim/temp/saturation/red — restored on next tick, perfect for testing or quick "moods"), **force red mode** (with optional duration), apply now, set outdoor lux.
63+
**Actions**: pause (sec/min/hour), pause until time, pause until solar event, resume, turn on/off/toggle, set red threshold, **apply temporary state** (override dim/temp/saturation/red — restored on next tick, perfect for testing or quick "moods"), **force red mode** (with optional duration), apply now, set outdoor lux, **turn on light at current circadian level** (pick any group member from dropdown).
5664

5765
<a href="https://tiwas.github.io/SmartComponentsToolkit/docs/circadian-light-group.html" target="_blank">→ Read full Circadian Light Group guide</a>
5866

59-
<a href="https://homey.app/a/no.tiwas.booleantoolbox/test/" target="_blank">→ Install v1.10.0 test version</a>
67+
<a href="https://homey.app/a/no.tiwas.booleantoolbox/test/" target="_blank">→ Install v1.10.2 test version</a>
6068

6169
---
6270

@@ -125,7 +133,7 @@ THEN: Wait until coffee machine temperature ≥ 90°C (timeout 5 min)
125133
## Installation and Links
126134

127135
* **Homey App Store (stable v1.9.2):** <a href="https://homey.app/en-no/app/no.tiwas.booleantoolbox/" target="_blank">Install Smart (Components) Toolkit</a>
128-
* **Test channel (v1.10.0 — Circadian Light Group):** <a href="https://homey.app/a/no.tiwas.booleantoolbox/test/" target="_blank">Install test version</a>
136+
* **Test channel (v1.10.2 — Circadian Light Group + pre-warm auto-detection):** <a href="https://homey.app/a/no.tiwas.booleantoolbox/test/" target="_blank">Install test version</a>
129137
* **GitHub Repo:** <a href="https://github.com/tiwas/SmartComponentsToolkit" target="_blank">github.com/tiwas/SmartComponentsToolkit</a>
130138
* **Online Emulator:** <a href="https://tiwas.github.io/SmartComponentsToolkit/tools/emulator.html" target="_blank">Boolean Logic Emulator</a>
131139
* **Formula Builder:** <a href="https://tiwas.github.io/SmartComponentsToolkit/tools/formula-builder.html" target="_blank">Formula Builder</a>

no.tiwas.booleantoolbox/.homeychangelog.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,11 @@
4949
},
5050
"1.10.0": {
5151
"en": "Circadian Light Group - control lights to suit your circadian needs"
52+
},
53+
"1.10.1": {
54+
"en": "Added translations"
55+
},
56+
"1.10.2": {
57+
"en": "More user config options + test capabilities"
5258
}
5359
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"id": "clg_turn_on_member",
3+
"title": {
4+
"en": "Turn on light at current circadian level",
5+
"no": "Slå på lys med gjeldende dognrytmeniva"
6+
},
7+
"hint": {
8+
"en": "Sets temperature/color and dim, then turns the light on. Avoids the brief flash at the previous brightness.",
9+
"no": "Setter temperatur/farge og dim, deretter skrur lyset paa. Unngaar kort blink ved forrige lysstyrke."
10+
},
11+
"args": [
12+
{
13+
"type": "device",
14+
"name": "device",
15+
"filter": "driver_id=circadian-light-group"
16+
},
17+
{
18+
"type": "autocomplete",
19+
"name": "member",
20+
"title": {
21+
"en": "Light",
22+
"no": "Lys"
23+
}
24+
}
25+
],
26+
"titleFormatted": {
27+
"en": "Turn on [[member]] at current circadian level",
28+
"no": "Slå på [[member]] med gjeldende dognrytmeniva"
29+
}
30+
}

no.tiwas.booleantoolbox/drivers/circadian-light-group/device.js

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,15 +349,17 @@ class CircadianLightGroupDevice extends Homey.Device {
349349
const maxDim = Number.isFinite(Number(item.maxDim)) ? Number(item.maxDim) : 1;
350350
const canUseRed = item.redModeAllowed !== false;
351351
const mode = target.mode === 'color' && canUseRed ? 'color' : 'temperature';
352+
const prewarm = item.prewarmSupport || {};
353+
const prewarmAllowed = (capId) => isOn || prewarm[capId] !== false;
352354

353355
if (caps.light_mode?.setable && caps.light_mode.value !== mode) {
354356
result.push(['light_mode', mode]);
355357
}
356358

357359
if (mode === 'color' && caps.light_hue?.setable && caps.light_saturation?.setable) {
358-
result.push(['light_hue', target.hue]);
359-
result.push(['light_saturation', target.saturation]);
360-
} else if (caps.light_temperature?.setable) {
360+
if (prewarmAllowed('light_hue')) result.push(['light_hue', target.hue]);
361+
if (prewarmAllowed('light_saturation')) result.push(['light_saturation', target.saturation]);
362+
} else if (caps.light_temperature?.setable && prewarmAllowed('light_temperature')) {
361363
const temperature = item.invertTemperature === true ? 1 - target.temperature : target.temperature;
362364
result.push(['light_temperature', clamp(temperature)]);
363365
}
@@ -489,6 +491,59 @@ class CircadianLightGroupDevice extends Homey.Device {
489491
};
490492
}
491493

494+
async onFlowTurnOnMember(args) {
495+
const memberId = args.member?.id;
496+
if (!memberId) throw new Error('No light selected');
497+
498+
const config = this.getConfig();
499+
const item = (Array.isArray(config.devices) ? config.devices : []).find(d => d.id === memberId);
500+
if (!item) throw new Error('Light is not a member of this group');
501+
502+
let outdoor;
503+
try {
504+
outdoor = await this.outdoorProvider.getOutdoorLight(config.outdoorLight || {});
505+
} catch (error) {
506+
outdoor = await this.outdoorProvider.getAstronomical(config.outdoorLight || {}, new Date(), 'fallback');
507+
}
508+
const geo = this.getGeo();
509+
const luxCrossings = await this.getStoreValue('luxCrossings') || {};
510+
const target = calculateTarget(config.profile || {}, outdoor, new Date(), { ...geo, luxCrossings });
511+
this.applyOverridesToTarget(target);
512+
513+
const apiDevice = await this.homey.app.api.devices.getDevice({ id: item.id });
514+
const caps = apiDevice.capabilitiesObj || {};
515+
516+
const minDim = Number.isFinite(Number(item.minDim)) ? Number(item.minDim) : 0.05;
517+
const maxDim = Number.isFinite(Number(item.maxDim)) ? Number(item.maxDim) : 1;
518+
const canUseRed = item.redModeAllowed !== false;
519+
const mode = target.mode === 'color' && canUseRed ? 'color' : 'temperature';
520+
521+
const writes = [];
522+
if (caps.light_mode?.setable && caps.light_mode.value !== mode) {
523+
writes.push(['light_mode', mode]);
524+
}
525+
if (mode === 'color' && caps.light_hue?.setable && caps.light_saturation?.setable) {
526+
writes.push(['light_hue', target.hue]);
527+
writes.push(['light_saturation', target.saturation]);
528+
} else if (caps.light_temperature?.setable) {
529+
const temperature = item.invertTemperature === true ? 1 - target.temperature : target.temperature;
530+
writes.push(['light_temperature', clamp(temperature)]);
531+
}
532+
if (caps.dim?.setable) {
533+
writes.push(['dim', clamp(target.dim, minDim, maxDim)]);
534+
}
535+
536+
for (const [capability, value] of writes) {
537+
await apiDevice.setCapabilityValue(capability, value);
538+
await new Promise(resolve => setTimeout(resolve, APPLY_CAPABILITY_DELAY));
539+
}
540+
541+
if (caps.onoff?.setable && caps.onoff.value !== true) {
542+
await apiDevice.setCapabilityValue('onoff', true);
543+
}
544+
return true;
545+
}
546+
492547
// ---- Flow action handlers ----
493548

494549
async onFlowApplyNow() {

no.tiwas.booleantoolbox/drivers/circadian-light-group/driver.compose.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
{
4444
"id": "select_devices"
4545
},
46+
{
47+
"id": "test_capabilities"
48+
},
4649
{
4750
"id": "edit_configuration"
4851
}
@@ -83,7 +86,8 @@
8386
{ "id": "clg_toggle" },
8487
{ "id": "clg_set_red_threshold" },
8588
{ "id": "clg_apply_state" },
86-
{ "id": "clg_force_red_mode" }
89+
{ "id": "clg_force_red_mode" },
90+
{ "id": "clg_turn_on_member" }
8791
]
8892
}
8993
}

0 commit comments

Comments
 (0)