feat v1.27.0: RGB light colors + red alarm pulse (issue #3)

- lightColorOf(): on+rgb_color tints icon/glow/ripple (explicit ripple color wins);
  brightness ignored by design; off/white/unavailable unchanged
- isAlarmState(): leak/smoke/gas/CO/safety/tamper/problem sensors and sirens in
  'on' pulse a red ring over any display mode; outages never alarm;
  prefers-reduced-motion honoured
- +2 unit tests, smoke_rgb_alarm.mjs, TESTING.md rows
This commit is contained in:
Matysh
2026-07-22 10:21:08 +03:00
parent 3bc25ad5ae
commit 794b02b84f
14 changed files with 262 additions and 58 deletions
+18 -1
View File
@@ -4,7 +4,7 @@ import {
lqiColor, snapToGrid, segKey, samePoint, pointInPolygon, markerIdForBinding, averageLqi,
fitView, declump, safeUrl, resolveTapAction, floorsOf, subst, spaceDisplayOf, roomFillColor,
segmentCm, formatLength, roomEdges, roomPoly, pointOnBoundary, pointStrictlyInside, roomsOverlap,
mergeRooms, splitRoom, polygonArea, closestPointOnBoundary, isActiveState, snapToWall, openingAmount, fillColorsOf, lerpColor, roomFillStyle, stateIcon,
mergeRooms, splitRoom, polygonArea, closestPointOnBoundary, isActiveState, snapToWall, openingAmount, fillColorsOf, lerpColor, roomFillStyle, stateIcon, lightColorOf, isAlarmState,
} from '../test-build/logic.js';
import {
iconFor, compileIconRules, isValidPattern, iconFromDeviceClasses,
@@ -496,3 +496,20 @@ test('stateIcon: doors/locks/bulbs reflect state; custom icons and outages never
assert.equal(stateIcon('mdi:custom', 'lock', undefined, 'unlocked', true), 'mdi:custom'); // user icon wins
assert.equal(stateIcon('mdi:cctv', 'camera', undefined, 'recording', false), 'mdi:cctv'); // unknown pair
});
test('lightColorOf: rgb of an on light; off/unavailable/no-color → null', () => {
assert.equal(lightColorOf({ state: 'on', attributes: { rgb_color: [255, 20, 40] } }), 'rgb(255, 20, 40)');
assert.equal(lightColorOf({ state: 'off', attributes: { rgb_color: [255, 20, 40] } }), null);
assert.equal(lightColorOf({ state: 'on', attributes: {} }), null);
assert.equal(lightColorOf({ state: 'unavailable', attributes: { rgb_color: [1, 2, 3] } }), null);
assert.equal(lightColorOf(undefined), null);
});
test('isAlarmState: leak/smoke/gas/siren fire; doors and outages do not', () => {
assert.ok(isAlarmState('binary_sensor', 'moisture', 'on'));
assert.ok(isAlarmState('binary_sensor', 'smoke', 'on'));
assert.ok(isAlarmState('siren', undefined, 'on'));
assert.ok(!isAlarmState('binary_sensor', 'door', 'on'));
assert.ok(!isAlarmState('binary_sensor', 'smoke', 'off'));
assert.ok(!isAlarmState('binary_sensor', 'smoke', 'unavailable'));
});