mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 08:28:31 +00:00
feat v1.17.0 (issue #1): place individual entities as their own icons (not just whole devices) — binding picker surfaces entities while searching; entity markers get an auto icon (name/device_class) + temperature. +1 test.
This commit is contained in:
+6
-2
@@ -261,18 +261,22 @@ export function buildDevices(ctx: BuildCtx): DevItem[] {
|
||||
const area = m.area || reg?.area_id || (reg?.device_id && h.devices[reg.device_id]?.area_id) || '';
|
||||
const space = (area && areaToSpace[area]) || m.space || firstSpaceId;
|
||||
const st = h.states[ref];
|
||||
const nm = reg?.name || st?.attributes?.friendly_name || ref;
|
||||
let icon = resolveIcon(h, nm, '', [ref], iconRules);
|
||||
if (ref.startsWith('lock.')) icon = 'mdi:lock';
|
||||
const item: DevItem = {
|
||||
id: m.id,
|
||||
name: reg?.name || st?.attributes?.friendly_name || ref,
|
||||
name: nm,
|
||||
model: '',
|
||||
area,
|
||||
space,
|
||||
icon: 'mdi:shape-outline',
|
||||
icon,
|
||||
entities: [ref],
|
||||
primary: ref,
|
||||
bindingKind: 'entity',
|
||||
bindingRef: ref,
|
||||
};
|
||||
if (icon === 'mdi:thermometer' || icon === 'mdi:air-filter') item.temp = tempFor(h, [ref]);
|
||||
applyMarker(item, m);
|
||||
rest.push(item);
|
||||
} else {
|
||||
|
||||
+18
-1
@@ -26,7 +26,7 @@ import './space-card';
|
||||
import { cardStyles } from './styles';
|
||||
import { langOf, t, type I18nKey } from './i18n';
|
||||
|
||||
const CARD_VERSION = '1.16.2';
|
||||
const CARD_VERSION = '1.17.0';
|
||||
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';
|
||||
@@ -1262,6 +1262,23 @@ class HouseplanCard extends LitElement {
|
||||
sub: eid.split('.')[0] + ' · ' + (reg.platform === 'group' ? this._t('marker.sub_group') : this._t('marker.sub_helper')),
|
||||
});
|
||||
}
|
||||
// Individual entities — surfaced only while searching (avoids a huge default list); lets you
|
||||
// place a single entity of a multi-entity device (e.g. the humidity of a climate sensor) as
|
||||
// its own icon. Uses the same entity: binding as helpers/groups.
|
||||
const q = (this._markerDialog?.bindingFilter || '').toLowerCase().trim();
|
||||
if (q) {
|
||||
const seen = new Set(list.map((o) => o.value));
|
||||
for (const [eid, reg] of Object.entries<any>(h.entities)) {
|
||||
const v = 'entity:' + eid;
|
||||
if (taken.has(v) || seen.has(v) || reg.hidden) continue;
|
||||
const stt = h.states[eid];
|
||||
const label = reg.name || stt?.attributes?.friendly_name || eid;
|
||||
const dev = reg.device_id ? h.devices[reg.device_id] : null;
|
||||
const devName = dev ? (dev.name_by_user || dev.name || '') : '';
|
||||
if (!(label + ' ' + eid + ' ' + devName).toLowerCase().includes(q)) continue;
|
||||
list.push({ value: v, label, sub: eid.split('.')[0] + ' · ' + this._t('marker.sub_entity') + (devName ? ' · ' + devName : '') });
|
||||
}
|
||||
}
|
||||
const f = (this._markerDialog?.bindingFilter || '').toLowerCase().trim();
|
||||
const filtered = f
|
||||
? list.filter((o) => (o.label + ' ' + o.sub + ' ' + o.value).toLowerCase().includes(f))
|
||||
|
||||
+2
-1
@@ -178,5 +178,6 @@
|
||||
"editor.show_button": "Show button",
|
||||
"editor.button_label": "Button label",
|
||||
"editor.button_target": "Target dashboard path",
|
||||
"editor.aspect_ratio": "Aspect ratio (e.g. 16:9 or auto)"
|
||||
"editor.aspect_ratio": "Aspect ratio (e.g. 16:9 or auto)",
|
||||
"marker.sub_entity": "entity"
|
||||
}
|
||||
|
||||
+2
-1
@@ -178,5 +178,6 @@
|
||||
"editor.show_button": "Показывать кнопку",
|
||||
"editor.button_label": "Текст кнопки",
|
||||
"editor.button_target": "Путь дашборда (куда вести)",
|
||||
"editor.aspect_ratio": "Соотношение сторон (напр. 16:9 или auto)"
|
||||
"editor.aspect_ratio": "Соотношение сторон (напр. 16:9 или auto)",
|
||||
"marker.sub_entity": "сущность"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user