mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
Validate / hacs (push) Failing after 44s
Validate / hassfest (push) Failing after 1m19s
Validate / frontend (push) Successful in 4m49s
Validate / golden (push) Failing after 2m9s
Validate / smoke (push) Failing after 2m15s
Validate / backend (push) Failing after 7m27s
Validate / performance_smoke (push) Failing after 6m30s
148 lines
7.7 KiB
JavaScript
148 lines
7.7 KiB
JavaScript
// Опция «Использовать датчик температуры устройства» (marker.use_climate_temp):
|
|
// климат-устройства (кондиционеры, термостаты) знают температуру комнаты
|
|
// (attributes.current_temperature). По умолчанию ВЫКЛ — ни плашки, ни вклада
|
|
// в среднюю. Включена через диалог (реальный клик по чекбоксу): плашка .tval
|
|
// у значка + голос в средней комнаты (термометр 20 + климат 23.5 → 21.75,
|
|
// т.е. 21.8 по сетке карточки 0.1°). Unavailable-климат не ломает ничего.
|
|
import { launch, check, checkAll, finish } from './serve.mjs';
|
|
const { page, browser } = await launch();
|
|
const out = {};
|
|
|
|
// --- впрыскиваем климат-устройства в демо-hass ---------------------------
|
|
await page.evaluate(() => {
|
|
const c = window.__card;
|
|
const h = window.__mkHass();
|
|
const inject = (hass) => ({
|
|
...hass,
|
|
devices: {
|
|
...hass.devices,
|
|
d_ac: { id: 'd_ac', name: 'Air conditioner', model: 'AC-12', area_id: 'living_room', identifiers: [['demo', 'd_ac']], entry_type: null, via_device_id: null },
|
|
d_trv: { id: 'd_trv', name: 'Radiator valve', model: 'TRV-1', area_id: 'bedroom', identifiers: [['demo', 'd_trv']], entry_type: null, via_device_id: null },
|
|
},
|
|
entities: {
|
|
...hass.entities,
|
|
'climate.ac': { entity_id: 'climate.ac', device_id: 'd_ac', platform: 'demo' },
|
|
'climate.trv': { entity_id: 'climate.trv', device_id: 'd_trv', platform: 'demo' },
|
|
},
|
|
states: {
|
|
...hass.states,
|
|
// термометр гостиной — ровно 20, чтобы средняя с климатом была детерминированной
|
|
'sensor.living_temp': { ...hass.states['sensor.living_temp'], state: '20' },
|
|
'climate.ac': { entity_id: 'climate.ac', state: 'cool', attributes: { friendly_name: 'Air conditioner', current_temperature: 23.5, temperature: 24 } },
|
|
// мёртвый климат: state unavailable, атрибутов нет
|
|
'climate.trv': { entity_id: 'climate.trv', state: 'unavailable', attributes: { friendly_name: 'Radiator valve' } },
|
|
},
|
|
});
|
|
window.__injectClimate = () => { c.hass = inject(window.__mkHass()); };
|
|
window.__injectClimate();
|
|
c._regSignature = '';
|
|
c._maybeRebuildDevices();
|
|
c.requestUpdate();
|
|
});
|
|
await page.waitForFunction(() => window.__card._devices.some((d) => d.entities?.includes('climate.ac')));
|
|
|
|
// --- без опции: ни плашки, ни вклада в среднюю ---------------------------
|
|
Object.assign(out, await page.evaluate(async () => {
|
|
const o = {};
|
|
const c = window.__card;
|
|
await c.updateComplete;
|
|
const ac = c._devices.find((d) => d.entities?.includes('climate.ac'));
|
|
o.acBuilt = !!ac;
|
|
o.noBadgeByDefault = c._liveTemp(ac) === null;
|
|
o.avgWithoutOption = c._climate().get('living_room')?.temp; // === 20
|
|
return o;
|
|
}), { avgWithoutOption: 20 });
|
|
|
|
// --- диалог: чекбокс есть у климат-устройства, нет у обычного, клик мышью --
|
|
Object.assign(out, await page.evaluate(async () => {
|
|
const o = {};
|
|
const c = window.__card;
|
|
const sr = () => c.shadowRoot || c.renderRoot;
|
|
// у обычного термометра чекбокса нет
|
|
const th = c._devices.find((d) => d.entities?.includes('sensor.living_temp'));
|
|
c._openMarkerDialog(th); await c.updateComplete;
|
|
o.noCheckboxForThermometer = !sr().querySelector('hp-dialog .climrow');
|
|
c._markerDialog = null; await c.updateComplete;
|
|
// у кондиционера — есть и по умолчанию снят
|
|
const ac = c._devices.find((d) => d.entities?.includes('climate.ac'));
|
|
c._openMarkerDialog(ac); await c.updateComplete;
|
|
const row = sr().querySelector('hp-dialog .climrow input');
|
|
o.checkboxForClimate = !!row;
|
|
o.uncheckedByDefault = !!row && !row.checked;
|
|
if (row) row.scrollIntoView({ block: 'center' });
|
|
return o;
|
|
}));
|
|
|
|
// реальный клик по чекбоксу — координатами, через весь стек событий
|
|
const box = await page.evaluate(() => {
|
|
const c = window.__card;
|
|
const sr = c.shadowRoot || c.renderRoot;
|
|
const r = sr.querySelector('hp-dialog .climrow input')?.getBoundingClientRect();
|
|
return r ? { x: r.x + r.width / 2, y: r.y + r.height / 2 } : null;
|
|
});
|
|
check('checkboxClickable', !!box);
|
|
if (box) await page.mouse.click(box.x, box.y);
|
|
Object.assign(out, await page.evaluate(async () => {
|
|
const o = {};
|
|
const c = window.__card;
|
|
await c.updateComplete;
|
|
o.clickTicksState = c._markerDialog?.useClimateTemp === true;
|
|
await c._saveMarker(); await c.updateComplete;
|
|
const m = (c._serverCfg.markers || []).find((x) => x.binding === 'device:d_ac');
|
|
o.savedInMarker = m?.use_climate_temp === true;
|
|
return o;
|
|
}));
|
|
|
|
// --- с опцией: плашка «23.5°», средняя пересчиталась ----------------------
|
|
Object.assign(out, await page.evaluate(async () => {
|
|
const o = {};
|
|
const c = window.__card;
|
|
const sr = () => c.shadowRoot || c.renderRoot;
|
|
await c.updateComplete;
|
|
const ac = c._devices.find((d) => d.entities?.includes('climate.ac'));
|
|
o.liveTempFromClimate = c._liveTemp(ac); // === 23.5
|
|
const badges = [...sr().querySelectorAll('.dev .value-badge')].map((el) => el.textContent.trim());
|
|
o.badgeVisible = badges.includes('23.5°');
|
|
// средняя гостиной: (20 + 23.5) / 2 = 21.75 → 21.8 по сетке карточки (0.1°)
|
|
o.avgWithOption = c._climate().get('living_room')?.temp;
|
|
// и на КАРТОЧКЕ КОМНАТЫ: включаем метрику температуры и читаем текст
|
|
const sp = c._serverCfg.spaces.find((s) => s.id === 'f1');
|
|
sp.settings = { ...(sp.settings || {}), label_temp: true, show_names: true };
|
|
c.requestUpdate(); await c.updateComplete;
|
|
const labels = [...sr().querySelectorAll('.roomlabel .rlm')].map((el) => el.textContent.trim());
|
|
o.roomCardShowsAvg = labels.some((t) => t.includes('21.8°'));
|
|
return o;
|
|
}), { liveTempFromClimate: 23.5, avgWithOption: 21.8 });
|
|
|
|
// --- unavailable-климат: опция включена, но ни плашки, ни вклада ----------
|
|
Object.assign(out, await page.evaluate(async () => {
|
|
const o = {};
|
|
const c = window.__card;
|
|
c._serverCfg.markers = [...c._serverCfg.markers,
|
|
{ id: 'd_trv', binding: 'device:d_trv', use_climate_temp: true, hidden: false }];
|
|
c._cfgEpoch++; c._regSignature = '';
|
|
c._maybeRebuildDevices(); c.requestUpdate(); await c.updateComplete;
|
|
const trv = c._devices.find((d) => d.entities?.includes('climate.trv'));
|
|
o.unavailNoBadge = !!trv && c._liveTemp(trv) === null;
|
|
o.unavailNoVote = c._climate().get('bedroom')?.temp ?? null; // в спальне нет термометров
|
|
// а гостиная как была 21.8
|
|
o.avgStillCorrect = c._climate().get('living_room')?.temp;
|
|
return o;
|
|
}), { unavailNoVote: null, avgStillCorrect: 21.8 });
|
|
|
|
// --- чекбокс переживает пересоздание диалога ------------------------------
|
|
Object.assign(out, await page.evaluate(async () => {
|
|
const o = {};
|
|
const c = window.__card;
|
|
const sr = () => c.shadowRoot || c.renderRoot;
|
|
const ac = c._devices.find((d) => d.entities?.includes('climate.ac'));
|
|
c._openMarkerDialog(ac); await c.updateComplete;
|
|
o.survivesReopen = c._markerDialog?.useClimateTemp === true;
|
|
o.checkboxChecked = sr().querySelector('hp-dialog .climrow input')?.checked === true;
|
|
c._markerDialog = null;
|
|
return o;
|
|
}));
|
|
|
|
checkAll(out, { avgWithoutOption: 20, liveTempFromClimate: 23.5, avgWithOption: 21.8, unavailNoVote: null, avgStillCorrect: 21.8 });
|
|
await finish(browser, out);
|