mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 08:28:31 +00:00
v1.44.6: room climate counts only air temperature
After v1.44.5 read the area registry instead of visible icons, every hidden temperature entity in the area became a candidate, including ones measuring something other than room air. Verified against a live 60-area install: a NAS processor temperature, kettle water, a 90 C sauna heater and a virtual better_thermostat all leaked into room averages. - areaClimate(): skip entity_category (diagnostic/config), skip EXCLUDED_DOMAINS platforms, skip entity ids naming a non-air medium (water/coolant/flow_temp/ return_temp/target/setpoint/chip/cpu/processor/board/device_temp/batter/ freezer/fridge/oven/kettle/boiler). - rules.ts: kettle/thermopot -> mdi:kettle, sauna/harvia -> mdi:hot-tub, so they no longer fall through to the generic thermometer rule. - test: all four real false positives asserted out, one real sensor left. - docs: CHANGELOG.md + CHANGELOG.ru.md + STATUS.md snapshot.
This commit is contained in:
@@ -13,7 +13,7 @@ FILES_URL = "/houseplan_files/files"
|
||||
CONTENT_URL = "/api/houseplan/content"
|
||||
FILES_DIR = "houseplan/files"
|
||||
CONF_ADMIN_ONLY = "admin_only"
|
||||
VERSION = "1.44.5"
|
||||
VERSION = "1.44.6"
|
||||
|
||||
DEFAULT_CONFIG: dict = {
|
||||
"spaces": [],
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
"issue_tracker": "https://github.com/Matysh/houseplan-card/issues",
|
||||
"requirements": [],
|
||||
"single_config_entry": true,
|
||||
"version": "1.44.5"
|
||||
"version": "1.44.6"
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
+13
-13
File diff suppressed because one or more lines are too long
@@ -1,5 +1,23 @@
|
||||
# Changelog
|
||||
|
||||
## v1.44.6 — 2026-07-27
|
||||
- **Only room *air* counts as room climate.** After v1.44.5 started reading the
|
||||
area registry instead of the visible icons, every hidden temperature entity in
|
||||
the area became a candidate — including ones that measure something other than
|
||||
the air. Three guards now run before averaging: entities marked
|
||||
diagnostic/config are skipped, entities from curated-out integrations are
|
||||
skipped, and entity ids naming a non-air medium are skipped
|
||||
(`water`, `coolant`, `flow_temp`, `return_temp`, `target`, `setpoint`, `chip`,
|
||||
`cpu`, `processor`, `board`, `device_temp`, `batter`, `freezer`, `fridge`,
|
||||
`oven`, `kettle`, `boiler`).
|
||||
On a live 60-area install this removed four real false positives: a NAS
|
||||
processor temperature, the water in a smart kettle, a 90 °C sauna heater and a
|
||||
virtual `better_thermostat` duplicating the real sensor.
|
||||
- **New icon rules:** kettles/thermopots get `mdi:kettle`, saunas
|
||||
(`sauna`, `harvia`, `парная`) get `mdi:hot-tub` — previously both fell through
|
||||
to the generic thermometer rule, which is also what made them count as room
|
||||
climate.
|
||||
|
||||
## v1.44.5 — 2026-07-27
|
||||
- **Room climate now counts every sensor in the area**, including devices that
|
||||
are not placed on the plan (hidden by curation or by you). Previously the
|
||||
|
||||
@@ -6,6 +6,23 @@
|
||||
> **Правило проекта:** оба файла пополняются в одном коммите с самим
|
||||
> изменением — как и остальная документация (см. docs/STATUS.md).
|
||||
|
||||
## v1.44.6 — 2026-07-27
|
||||
- **Климатом комнаты считается только температура *воздуха*.** После v1.44.5,
|
||||
когда данные стали браться из реестра зон, а не с видимых значков,
|
||||
кандидатами стали все скрытые датчики температуры в зоне — в том числе те,
|
||||
что меряют вовсе не воздух. Перед усреднением теперь работают три фильтра:
|
||||
пропускаются сущности с категорией диагностика/настройка, сущности
|
||||
исключённых интеграций и сущности, в id которых назван не-воздушный носитель
|
||||
(`water`, `coolant`, `flow_temp`, `return_temp`, `target`, `setpoint`, `chip`,
|
||||
`cpu`, `processor`, `board`, `device_temp`, `batter`, `freezer`, `fridge`,
|
||||
`oven`, `kettle`, `boiler`).
|
||||
На живой установке с 60 зонами это убрало четыре реальных ложных
|
||||
срабатывания: температуру процессора NAS, воду в умном чайнике, сауну с 90 °C
|
||||
и виртуальный `better_thermostat`, дублирующий настоящий датчик.
|
||||
- **Новые правила иконок:** чайники и термопоты получают `mdi:kettle`, сауны
|
||||
(`sauna`, `harvia`, `парная`) — `mdi:hot-tub`. Раньше и те и другие попадали
|
||||
под общее правило термометра, из-за чего и учитывались в климате комнаты.
|
||||
|
||||
## v1.44.5 — 2026-07-27
|
||||
- **Климат комнаты считается по всем датчикам зоны**, включая устройства,
|
||||
которых нет на плане (скрыты курированием или вами). Раньше среднее бралось
|
||||
|
||||
+4
-4
@@ -11,18 +11,18 @@
|
||||
> (versions, publication, infrastructure), DEVELOPMENT.md for new gotchas,
|
||||
> ARCHITECTURE.md for design changes, ROADMAP.md when plans move.
|
||||
|
||||
## Snapshot (2026-07-24)
|
||||
## Snapshot (2026-07-27)
|
||||
|
||||
| Item | State |
|
||||
|---|---|
|
||||
| Version | **v1.41.0** everywhere (manifest, const.py, package.json, CARD_VERSION); deployed to the home instance |
|
||||
| Version | **v1.44.6** everywhere (manifest, const.py, package.json, CARD_VERSION); deployed to the home instance |
|
||||
| Workflow | Since 2026-07-22: minor changes go to branch **`dev`** (build + smokes → deploy home → commit → push, NO release); releases are batched on the owner's command (merge dev→main, one tag, one release with a summary changelog, CI checked on dev beforehand) |
|
||||
| GitHub | https://github.com/Matysh/houseplan-card — `main` = releases up to **v1.40.1**; `dev` ahead with v1.40.2+ (speaker icons, kiosk). Push via SSH key `ha_jb` (remote git@github.com:…); API releases via the fine-grained PAT in `~/.git-credentials` (Contents R/W, issued 2026-07-23) |
|
||||
| CI | validate.yml (hacs + hassfest + frontend + backend) green; release.yml attaches the bundle on release publish |
|
||||
| HACS | Custom repository works. **Inclusion PR: hacs/default#9004** — open, valid, labeled; ~864 older open PRs but merge rate ≈180/mo; realistic ETA 1–3 months (checked 2026-07-24) |
|
||||
| Home instance | ha.jbstudio.pro (SSH port 323, key `ha_jb`), deployed **v1.41.0** via direct copy (HACS custom repo also installed) |
|
||||
| Home instance | ha.jbstudio.pro (SSH port 323, key `ha_jb`), deployed **v1.44.6** via direct copy (HACS custom repo also installed) |
|
||||
| Localization | UI en/ru (src/i18n/*.json), everything user-visible localized incl. kiosk popover |
|
||||
| Tests | 111 frontend (node:test) + 12 pure backend + 12 HA-harness (CI, py3.13); ~30 demo smoke suites (headless chromium) |
|
||||
| Tests | 121 frontend (node:test) + 12 pure backend + 12 HA-harness (CI, py3.13); ~30 demo smoke suites (headless chromium) |
|
||||
| Community | **Telegram chat: https://t.me/ha_houseplan** (created 2026-07-27) — the primary user-facing support channel; GitHub issues stay for bugs/features. Link it from any new release notes and posts |
|
||||
| Product scope | docs/SCOPE.md (2026-07-22) is the feature guard rail — check before accepting any feature |
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "houseplan-card",
|
||||
"version": "1.44.5",
|
||||
"version": "1.44.6",
|
||||
"description": "Interactive house plan Lovelace card for Home Assistant",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
+22
-1
@@ -2,7 +2,7 @@
|
||||
* Building the device list from HA registries: curation, light groups,
|
||||
* markers (overrides/virtual). No Lit/DOM — only the hass object.
|
||||
*/
|
||||
import { iconFor, iconFromDeviceClasses, DOMAIN_PRIORITY, FALLBACK_ICON, type CompiledIconRule } from './rules';
|
||||
import { iconFor, iconFromDeviceClasses, DOMAIN_PRIORITY, FALLBACK_ICON, type CompiledIconRule, EXCLUDED_DOMAINS } from './rules';
|
||||
import { averageLqi } from './logic';
|
||||
import type { DevItem, Marker, ServerConfig } from './types';
|
||||
|
||||
@@ -400,6 +400,20 @@ export function areaHum(
|
||||
return Math.round(vals.reduce((a, b) => a + b, 0) / vals.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entity ids that measure something other than room air, however honest their
|
||||
* device_class is: water and coolant loops, chip/CPU/board temperatures,
|
||||
* battery temperature, setpoints (target/external) and the like.
|
||||
*/
|
||||
const NON_AIR_RE = new RegExp(
|
||||
[
|
||||
'water', 'voda', 'coolant', 'flow_?temp', 'return_?temp', 'target', 'setpoint',
|
||||
'chip', 'cpu', 'processor', 'board', 'core_temp', 'device_temp',
|
||||
'batter', 'akkum', 'freezer', 'fridge', 'oven', 'kettle', 'boiler',
|
||||
].join('|'),
|
||||
'i',
|
||||
);
|
||||
|
||||
/**
|
||||
* Room climate from EVERY sensor of the area — including devices that are not
|
||||
* placed on the plan (hidden by curation or by the user). The old helpers read
|
||||
@@ -420,6 +434,13 @@ export function areaClimate(
|
||||
const dev = reg.device_id ? hass.devices?.[reg.device_id] : null;
|
||||
const entArea = reg.area_id || dev?.area_id || null;
|
||||
if (entArea !== area) continue;
|
||||
// Not every "temperature" is room air. Real finds on a live install: the
|
||||
// NAS processor temperature, the water in a smart kettle, a sauna heater at
|
||||
// 90 C and a virtual better_thermostat duplicating the real sensor (field
|
||||
// question, 2026-07-27). Three guards, cheapest first:
|
||||
if (reg.entity_category) continue; // diagnostic/config readings
|
||||
if (EXCLUDED_DOMAINS.has(reg.platform)) continue; // curated-out integrations
|
||||
if (NON_AIR_RE.test(eid)) continue; // water/chip/flow/target/...
|
||||
const key = reg.device_id || eid;
|
||||
if (!groups.has(key)) {
|
||||
const st = hass.states?.[eid];
|
||||
|
||||
@@ -32,7 +32,7 @@ import './space-card';
|
||||
import { cardStyles } from './styles';
|
||||
import { langOf, t, type I18nKey } from './i18n';
|
||||
|
||||
const CARD_VERSION = '1.44.5';
|
||||
const CARD_VERSION = '1.44.6';
|
||||
const LS_KEY = 'houseplan_card_layout_v1';
|
||||
const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering
|
||||
const LS_ZOOM = 'houseplan_card_zoom_v1';
|
||||
|
||||
@@ -29,6 +29,8 @@ export const DEFAULT_ICON_RULES: IconRule[] = [
|
||||
{ pattern: 'клапан|valve', icon: 'mdi:pipe-valve' },
|
||||
{ pattern: 'дым|smoke', icon: 'mdi:smoke-detector' },
|
||||
{ pattern: 'термоголов|trv|radiator', icon: 'mdi:radiator' },
|
||||
{ pattern: 'чайник|kettle|термопот', icon: 'mdi:kettle' },
|
||||
{ pattern: 'сауна|sauna|harvia|парная|парилк', icon: 'mdi:hot-tub' },
|
||||
{ pattern: 'температ|temperature|climate sensor', icon: 'mdi:thermometer' },
|
||||
{ pattern: 'qingping|air monitor|молекул|air quality', icon: 'mdi:air-filter' },
|
||||
{ pattern: 'штор|curtain|blind|shade', icon: 'mdi:roller-shade' },
|
||||
|
||||
@@ -400,3 +400,39 @@ test('areaClimate: counts sensors that are NOT on the plan (field report)', () =
|
||||
};
|
||||
assert.equal(areaClimate(hass2, 'kitchen', 'temp'), null);
|
||||
});
|
||||
|
||||
test('areaClimate: only ROOM AIR counts (field question, 2026-07-27)', () => {
|
||||
const hass = {
|
||||
devices: {
|
||||
good: { id: 'good', name: 'Датчик температуры спальня', area_id: 'bed' },
|
||||
kettle: { id: 'kettle', name: 'Polaris PWK-1725CGLD', model: 'Kettle', area_id: 'bed' },
|
||||
nas: { id: 'nas', name: 'System Monitor', area_id: 'bed' },
|
||||
sauna: { id: 'sauna', name: 'Сауна Harvia', area_id: 'bed' },
|
||||
trv: { id: 'trv', name: 'Термоголовка в спальне', area_id: 'bed' },
|
||||
bt: { id: 'bt', name: 'Спальня better thermostat', area_id: 'bed' },
|
||||
zb: { id: 'zb', name: 'SLZB-06MU', area_id: 'bed' },
|
||||
},
|
||||
entities: {
|
||||
'sensor.good_t': { device_id: 'good', platform: 'mqtt' },
|
||||
// вода в чайнике
|
||||
'sensor.kettle_current_temperature': { device_id: 'kettle', platform: 'syncleo_kettle' },
|
||||
// температура процессора: и diagnostic, и исключённая интеграция
|
||||
'sensor.nas_processor_temperature': { device_id: 'nas', platform: 'systemmonitor', entity_category: 'diagnostic' },
|
||||
'sensor.sauna_temperature': { device_id: 'sauna', platform: 'harvia_sauna' },
|
||||
'sensor.trv_local_temperature': { device_id: 'trv', platform: 'mqtt' },
|
||||
'sensor.bt_temperature': { device_id: 'bt', platform: 'better_thermostat' },
|
||||
'sensor.zb_core_chip_temp': { device_id: 'zb', platform: 'smlight', entity_category: 'diagnostic' },
|
||||
},
|
||||
states: {
|
||||
'sensor.good_t': { state: '22.0', attributes: { device_class: 'temperature', unit_of_measurement: '°C' } },
|
||||
'sensor.kettle_current_temperature': { state: '95', attributes: { device_class: 'temperature', unit_of_measurement: '°C' } },
|
||||
'sensor.nas_processor_temperature': { state: '61', attributes: { device_class: 'temperature', unit_of_measurement: '°C' } },
|
||||
'sensor.sauna_temperature': { state: '90', attributes: { device_class: 'temperature', unit_of_measurement: '°C' } },
|
||||
'sensor.trv_local_temperature': { state: '24', attributes: { device_class: 'temperature', unit_of_measurement: '°C' } },
|
||||
'sensor.bt_temperature': { state: '22.0', attributes: { device_class: 'temperature', unit_of_measurement: '°C' } },
|
||||
'sensor.zb_core_chip_temp': { state: '48', attributes: { device_class: 'temperature', unit_of_measurement: '°C' } },
|
||||
},
|
||||
};
|
||||
// остаётся ровно один настоящий датчик воздуха
|
||||
assert.equal(areaClimate(hass, 'bed', 'temp'), 22);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user