Skip to content

Commit 9b68144

Browse files
committed
Fix circadian light temperature handling
1 parent 862a3c4 commit 9b68144

19 files changed

Lines changed: 592 additions & 110 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ node_modules/
1515
node_modules/
1616
npm-debug.log
1717
patch-files/
18+
*.backup/
1819
*.old/
1920

2021
# Old version
@@ -35,4 +36,4 @@ codebase-manifest.*
3536
*.old
3637

3738
# Project Documentation (AI-generated, kept local)
38-
PROJECT_DOCUMENTATION.md
39+
PROJECT_DOCUMENTATION.md

no.tiwas.booleantoolbox/.homeychangelog.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,11 @@
5858
},
5959
"1.10.3": {
6060
"en": "Fiddled with capability detection and some code. Also removed devices with only on_off from list as...there's nothing to do with them."
61+
},
62+
"1.10.4": {
63+
"en": "Bug squashing and icons"
64+
},
65+
"1.10.5": {
66+
"en": "Fixed a bug where tuneable lights became more blue instead of less in the evening."
6167
}
6268
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
'use strict';
2+
3+
jest.mock('homey', () => ({
4+
Device: class {},
5+
}), { virtual: true });
6+
7+
const CircadianLightGroupDevice = require('./drivers/circadian-light-group/device');
8+
9+
function createDeviceHarness() {
10+
const device = Object.create(CircadianLightGroupDevice.prototype);
11+
device.debug = jest.fn();
12+
return device;
13+
}
14+
15+
function setable(value) {
16+
return { setable: true, value };
17+
}
18+
19+
describe('CircadianLightGroupDevice capability selection', () => {
20+
test('does not switch to color mode when red target cannot write hue and saturation', () => {
21+
const device = createDeviceHarness();
22+
const writes = device.getCapabilitiesToSet(
23+
{ redModeAllowed: true },
24+
{ mode: 'color', hue: 0, saturation: 1, temperature: 0.05, dim: 0.2 },
25+
{
26+
light_mode: setable('color'),
27+
light_temperature: setable(0.8),
28+
light_hue: { setable: true },
29+
dim: setable(0.5),
30+
},
31+
true
32+
);
33+
34+
expect(writes).toContainEqual(['light_mode', 'temperature']);
35+
expect(writes).toContainEqual(['light_temperature', 0.95]);
36+
expect(writes).not.toContainEqual(['light_mode', 'color']);
37+
expect(writes.some(([cap]) => cap === 'light_hue')).toBe(false);
38+
});
39+
40+
test('writes explicit red for full color-capable lights', () => {
41+
const device = createDeviceHarness();
42+
const writes = device.getCapabilitiesToSet(
43+
{ redModeAllowed: true },
44+
{ mode: 'color', hue: 0, saturation: 0.9, temperature: 0.02, dim: 0.15 },
45+
{
46+
light_mode: setable('temperature'),
47+
light_temperature: setable(0.8),
48+
light_hue: setable(0.7),
49+
light_saturation: setable(0.4),
50+
},
51+
true
52+
);
53+
54+
expect(writes).toEqual([
55+
['light_mode', 'color'],
56+
['light_hue', 0],
57+
['light_saturation', 0.9],
58+
]);
59+
});
60+
61+
test('uses warm color fallback for RGB-only lights during temperature mode', () => {
62+
const device = createDeviceHarness();
63+
const writes = device.getCapabilitiesToSet(
64+
{ redModeAllowed: true },
65+
{ mode: 'temperature', hue: null, saturation: null, temperature: 0.25, dim: 0.45 },
66+
{
67+
light_mode: setable('temperature'),
68+
light_hue: setable(0.7),
69+
light_saturation: setable(0.2),
70+
},
71+
true
72+
);
73+
74+
expect(writes[0]).toEqual(['light_mode', 'color']);
75+
expect(writes[1][0]).toBe('light_hue');
76+
expect(writes[1][1]).toBeGreaterThanOrEqual(0);
77+
expect(writes[1][1]).toBeLessThanOrEqual(0.08);
78+
expect(writes[2][0]).toBe('light_saturation');
79+
expect(writes[2][1]).toBeGreaterThan(0.5);
80+
});
81+
82+
test('falls back to temperature when prewarming color is not supported', () => {
83+
const device = createDeviceHarness();
84+
const writes = device.getCapabilitiesToSet(
85+
{
86+
redModeAllowed: true,
87+
prewarmSupport: {
88+
light_hue: false,
89+
light_saturation: true,
90+
light_temperature: true,
91+
light_mode: true,
92+
},
93+
},
94+
{ mode: 'color', hue: 0, saturation: 1, temperature: 0.1, dim: 0.2 },
95+
{
96+
light_mode: setable('color'),
97+
light_temperature: setable(0.8),
98+
light_hue: setable(0.7),
99+
light_saturation: setable(0.4),
100+
},
101+
false
102+
);
103+
104+
expect(writes).toEqual([
105+
['light_mode', 'temperature'],
106+
['light_temperature', 0.9],
107+
]);
108+
});
109+
110+
test('can opt out of inverted temperature writes for drivers with opposite scale', () => {
111+
const device = createDeviceHarness();
112+
const writes = device.getCapabilitiesToSet(
113+
{ invertTemperature: false },
114+
{ mode: 'temperature', hue: null, saturation: null, temperature: 0.25, dim: 0.5 },
115+
{
116+
light_temperature: setable(0.8),
117+
},
118+
true
119+
);
120+
121+
expect(writes).toEqual([
122+
['light_temperature', 0.25],
123+
]);
124+
});
125+
});
-983 KB
Binary file not shown.

no.tiwas.booleantoolbox/assets/icon.svg

Lines changed: 127 additions & 14 deletions
Loading
-133 KB
Loading
-3.35 KB
Loading
-347 KB
Binary file not shown.
-191 KB
Loading
-5.56 KB
Loading

0 commit comments

Comments
 (0)