mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 08:28:31 +00:00
yellow means working: one principle for the glowing icon
Research on the owner's install (verified live): the radiator heads that glowed yellow were the ones with SCALE PROTECTION on, and the ones actually heating stayed dark. Cause: the primary-entity search ran domains outside tiers, and switch outranks climate — so a vendor's config switch (anti scaling, child lock) became the device's primary, driving the color, the icon morphing and tap-toggle alike. The principle now: yellow = the device is doing its main job RIGHT NOW. - primaryEntity: tiers outside, domains inside — a service entity never beats the visible main function; a hidden lamp still beats a visible config switch (grouped lights), and a plug's switch stays primary. - climate joins the state table: yellow by hvac_action (heating/cooling/ drying/fan) — 'which radiators are heating', not 'enabled for winter'; the coarser state is only a fallback when the integration reports no action. - one truth for light: litLightEntity() is asked by BOTH the glow pool and the icon color, in every fill mode — the pool and the icon can no longer disagree. The 'is a light source' flag keeps counting controls first. - README (en+ru): the color table, in words. Tests: TRV + plug primary units, litLightEntity unit, smoke_yellow_principle (heating yellow / idle dark / off dark / fallback / lit-light wins / forced source). Inventory: 142 / 51 / 43 / 67.
This commit is contained in:
+42
-1
@@ -1,6 +1,6 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { buildDevices, lightGroups, primaryEntity, lqiFor, tempFor, humFor, areaLights, areaTemp, areaHum, areaLightStats, sourceValue , areaClimate, areaClimateMap } from '../test-build/devices.js';
|
||||
import { buildDevices, lightGroups, primaryEntity, lqiFor, tempFor, humFor, areaLights, areaTemp, areaHum, areaLightStats, sourceValue , areaClimate, areaClimateMap, litLightEntity } from '../test-build/devices.js';
|
||||
import { compileIconRules, iconFor } from '../test-build/rules.js';
|
||||
|
||||
/** Minimal fake hass around the pieces buildDevices reads. */
|
||||
@@ -483,3 +483,44 @@ test('areaClimateMap: температура и влажность живут в
|
||||
};
|
||||
assert.deepEqual(areaClimateMap(hass).get('hall'), { temp: 21.4, hum: 48 });
|
||||
});
|
||||
|
||||
|
||||
test('primaryEntity: a service switch never beats the visible main function (TRV)', () => {
|
||||
// the owner's radiator heads, verified live: switch outranks climate in the
|
||||
// domain list, and the old inner-tier loop let a CONFIG switch (anti
|
||||
// scaling, child lock) become primary — the icon glowed yellow because
|
||||
// scale protection was on, while the head actually heating stayed dark
|
||||
const hass = {
|
||||
entities: {
|
||||
'climate.trv': {},
|
||||
'sensor.trv_temp': {},
|
||||
'switch.trv_anti_scaling': { entity_category: 'config' },
|
||||
'switch.trv_child_lock': { entity_category: 'config' },
|
||||
},
|
||||
states: {},
|
||||
};
|
||||
assert.equal(
|
||||
primaryEntity(hass, ['switch.trv_anti_scaling', 'switch.trv_child_lock', 'climate.trv', 'sensor.trv_temp'], 'mdi:thermostat'),
|
||||
'climate.trv',
|
||||
);
|
||||
// but a device whose only functional entity IS a switch keeps it
|
||||
const plug = { entities: { 'switch.plug': {}, 'sensor.plug_power': {} }, states: {} };
|
||||
assert.equal(primaryEntity(plug, ['sensor.plug_power', 'switch.plug'], 'mdi:power-socket'), 'switch.plug');
|
||||
});
|
||||
|
||||
test('litLightEntity: one truth for "this thing is shining"', () => {
|
||||
const hass = { states: {
|
||||
'light.a': { state: 'off' }, 'light.b': { state: 'on' },
|
||||
'switch.wall': { state: 'on' }, 'sensor.x': { state: '5' },
|
||||
} };
|
||||
// a lit light.* anywhere in the device
|
||||
assert.equal(litLightEntity(hass, { entities: ['light.a', 'light.b'] }), 'light.b');
|
||||
assert.equal(litLightEntity(hass, { entities: ['light.a'] }), null);
|
||||
// without the flag a lit switch is NOT a light
|
||||
assert.equal(litLightEntity(hass, { entities: ['switch.wall'] }), null);
|
||||
// with "is a light source" any lit entity counts, controls first
|
||||
assert.equal(
|
||||
litLightEntity(hass, { entities: ['sensor.x'], marker: { is_light: true, controls: ['switch.wall'] } }),
|
||||
'switch.wall',
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user