mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-21 16:26:43 +00:00
Convert history calls to use new websocket endpoint (#12662)
This commit is contained in:
parent
4cfb6713cb
commit
f807618f75
@ -2,67 +2,74 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
||||
import { FrontendLocaleData } from "../../data/translation";
|
||||
import {
|
||||
updateIsInstalling,
|
||||
UpdateEntity,
|
||||
UPDATE_SUPPORT_PROGRESS,
|
||||
updateIsInstallingFromAttributes,
|
||||
} from "../../data/update";
|
||||
import { formatDate } from "../datetime/format_date";
|
||||
import { formatDateTime } from "../datetime/format_date_time";
|
||||
import { formatTime } from "../datetime/format_time";
|
||||
import { formatNumber, isNumericState } from "../number/format_number";
|
||||
import { formatNumber, isNumericFromAttributes } from "../number/format_number";
|
||||
import { LocalizeFunc } from "../translations/localize";
|
||||
import { computeStateDomain } from "./compute_state_domain";
|
||||
import { supportsFeature } from "./supports-feature";
|
||||
import { supportsFeatureFromAttributes } from "./supports-feature";
|
||||
import { formatDuration, UNIT_TO_SECOND_CONVERT } from "../datetime/duration";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
|
||||
export const computeStateDisplay = (
|
||||
localize: LocalizeFunc,
|
||||
stateObj: HassEntity,
|
||||
locale: FrontendLocaleData,
|
||||
state?: string
|
||||
): string => {
|
||||
const compareState = state !== undefined ? state : stateObj.state;
|
||||
): string =>
|
||||
computeStateDisplayFromEntityAttributes(
|
||||
localize,
|
||||
locale,
|
||||
stateObj.entity_id,
|
||||
stateObj.attributes,
|
||||
state !== undefined ? state : stateObj.state
|
||||
);
|
||||
|
||||
if (compareState === UNKNOWN || compareState === UNAVAILABLE) {
|
||||
return localize(`state.default.${compareState}`);
|
||||
export const computeStateDisplayFromEntityAttributes = (
|
||||
localize: LocalizeFunc,
|
||||
locale: FrontendLocaleData,
|
||||
entityId: string,
|
||||
attributes: any,
|
||||
state: string
|
||||
): string => {
|
||||
if (state === UNKNOWN || state === UNAVAILABLE) {
|
||||
return localize(`state.default.${state}`);
|
||||
}
|
||||
|
||||
// Entities with a `unit_of_measurement` or `state_class` are numeric values and should use `formatNumber`
|
||||
if (isNumericState(stateObj)) {
|
||||
if (isNumericFromAttributes(attributes)) {
|
||||
// state is duration
|
||||
if (
|
||||
stateObj.attributes.device_class === "duration" &&
|
||||
stateObj.attributes.unit_of_measurement &&
|
||||
UNIT_TO_SECOND_CONVERT[stateObj.attributes.unit_of_measurement]
|
||||
attributes.device_class === "duration" &&
|
||||
attributes.unit_of_measurement &&
|
||||
UNIT_TO_SECOND_CONVERT[attributes.unit_of_measurement]
|
||||
) {
|
||||
try {
|
||||
return formatDuration(
|
||||
compareState,
|
||||
stateObj.attributes.unit_of_measurement
|
||||
);
|
||||
return formatDuration(state, attributes.unit_of_measurement);
|
||||
} catch (_err) {
|
||||
// fallback to default
|
||||
}
|
||||
}
|
||||
if (stateObj.attributes.device_class === "monetary") {
|
||||
if (attributes.device_class === "monetary") {
|
||||
try {
|
||||
return formatNumber(compareState, locale, {
|
||||
return formatNumber(state, locale, {
|
||||
style: "currency",
|
||||
currency: stateObj.attributes.unit_of_measurement,
|
||||
currency: attributes.unit_of_measurement,
|
||||
minimumFractionDigits: 2,
|
||||
});
|
||||
} catch (_err) {
|
||||
// fallback to default
|
||||
}
|
||||
}
|
||||
return `${formatNumber(compareState, locale)}${
|
||||
stateObj.attributes.unit_of_measurement
|
||||
? " " + stateObj.attributes.unit_of_measurement
|
||||
: ""
|
||||
return `${formatNumber(state, locale)}${
|
||||
attributes.unit_of_measurement ? " " + attributes.unit_of_measurement : ""
|
||||
}`;
|
||||
}
|
||||
|
||||
const domain = computeStateDomain(stateObj);
|
||||
const domain = computeDomain(entityId);
|
||||
|
||||
if (domain === "input_datetime") {
|
||||
if (state !== undefined) {
|
||||
@ -97,36 +104,32 @@ export const computeStateDisplay = (
|
||||
} else {
|
||||
// If not trying to display an explicit state, create `Date` object from `stateObj`'s attributes then format.
|
||||
let date: Date;
|
||||
if (stateObj.attributes.has_date && stateObj.attributes.has_time) {
|
||||
if (attributes.has_date && attributes.has_time) {
|
||||
date = new Date(
|
||||
stateObj.attributes.year,
|
||||
stateObj.attributes.month - 1,
|
||||
stateObj.attributes.day,
|
||||
stateObj.attributes.hour,
|
||||
stateObj.attributes.minute
|
||||
attributes.year,
|
||||
attributes.month - 1,
|
||||
attributes.day,
|
||||
attributes.hour,
|
||||
attributes.minute
|
||||
);
|
||||
return formatDateTime(date, locale);
|
||||
}
|
||||
if (stateObj.attributes.has_date) {
|
||||
date = new Date(
|
||||
stateObj.attributes.year,
|
||||
stateObj.attributes.month - 1,
|
||||
stateObj.attributes.day
|
||||
);
|
||||
if (attributes.has_date) {
|
||||
date = new Date(attributes.year, attributes.month - 1, attributes.day);
|
||||
return formatDate(date, locale);
|
||||
}
|
||||
if (stateObj.attributes.has_time) {
|
||||
if (attributes.has_time) {
|
||||
date = new Date();
|
||||
date.setHours(stateObj.attributes.hour, stateObj.attributes.minute);
|
||||
date.setHours(attributes.hour, attributes.minute);
|
||||
return formatTime(date, locale);
|
||||
}
|
||||
return stateObj.state;
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
if (domain === "humidifier") {
|
||||
if (compareState === "on" && stateObj.attributes.humidity) {
|
||||
return `${stateObj.attributes.humidity} %`;
|
||||
if (state === "on" && attributes.humidity) {
|
||||
return `${attributes.humidity} %`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +139,7 @@ export const computeStateDisplay = (
|
||||
domain === "number" ||
|
||||
domain === "input_number"
|
||||
) {
|
||||
return formatNumber(compareState, locale);
|
||||
return formatNumber(state, locale);
|
||||
}
|
||||
|
||||
// state of button is a timestamp
|
||||
@ -144,12 +147,12 @@ export const computeStateDisplay = (
|
||||
domain === "button" ||
|
||||
domain === "input_button" ||
|
||||
domain === "scene" ||
|
||||
(domain === "sensor" && stateObj.attributes.device_class === "timestamp")
|
||||
(domain === "sensor" && attributes.device_class === "timestamp")
|
||||
) {
|
||||
try {
|
||||
return formatDateTime(new Date(compareState), locale);
|
||||
return formatDateTime(new Date(state), locale);
|
||||
} catch (_err) {
|
||||
return compareState;
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,30 +163,28 @@ export const computeStateDisplay = (
|
||||
// When the latest version is skipped, show the latest version
|
||||
// When update is not available, show "Up-to-date"
|
||||
// When update is not available and there is no latest_version show "Unavailable"
|
||||
return compareState === "on"
|
||||
? updateIsInstalling(stateObj as UpdateEntity)
|
||||
? supportsFeature(stateObj, UPDATE_SUPPORT_PROGRESS)
|
||||
return state === "on"
|
||||
? updateIsInstallingFromAttributes(attributes)
|
||||
? supportsFeatureFromAttributes(attributes, UPDATE_SUPPORT_PROGRESS)
|
||||
? localize("ui.card.update.installing_with_progress", {
|
||||
progress: stateObj.attributes.in_progress,
|
||||
progress: attributes.in_progress,
|
||||
})
|
||||
: localize("ui.card.update.installing")
|
||||
: stateObj.attributes.latest_version
|
||||
: stateObj.attributes.skipped_version ===
|
||||
stateObj.attributes.latest_version
|
||||
? stateObj.attributes.latest_version ??
|
||||
localize("state.default.unavailable")
|
||||
: attributes.latest_version
|
||||
: attributes.skipped_version === attributes.latest_version
|
||||
? attributes.latest_version ?? localize("state.default.unavailable")
|
||||
: localize("ui.card.update.up_to_date");
|
||||
}
|
||||
|
||||
return (
|
||||
// Return device class translation
|
||||
(stateObj.attributes.device_class &&
|
||||
(attributes.device_class &&
|
||||
localize(
|
||||
`component.${domain}.state.${stateObj.attributes.device_class}.${compareState}`
|
||||
`component.${domain}.state.${attributes.device_class}.${state}`
|
||||
)) ||
|
||||
// Return default translation
|
||||
localize(`component.${domain}.state._.${compareState}`) ||
|
||||
localize(`component.${domain}.state._.${state}`) ||
|
||||
// We don't know! Return the raw state.
|
||||
compareState
|
||||
state
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,13 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { computeObjectId } from "./compute_object_id";
|
||||
|
||||
export const computeStateNameFromEntityAttributes = (
|
||||
entityId: string,
|
||||
attributes: { [key: string]: any }
|
||||
): string =>
|
||||
attributes.friendly_name === undefined
|
||||
? computeObjectId(entityId).replace(/_/g, " ")
|
||||
: attributes.friendly_name || "";
|
||||
|
||||
export const computeStateName = (stateObj: HassEntity): string =>
|
||||
stateObj.attributes.friendly_name === undefined
|
||||
? computeObjectId(stateObj.entity_id).replace(/_/g, " ")
|
||||
: stateObj.attributes.friendly_name || "";
|
||||
computeStateNameFromEntityAttributes(stateObj.entity_id, stateObj.attributes);
|
||||
|
@ -3,6 +3,13 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
export const supportsFeature = (
|
||||
stateObj: HassEntity,
|
||||
feature: number
|
||||
): boolean => supportsFeatureFromAttributes(stateObj.attributes, feature);
|
||||
|
||||
export const supportsFeatureFromAttributes = (
|
||||
attributes: {
|
||||
[key: string]: any;
|
||||
},
|
||||
feature: number
|
||||
): boolean =>
|
||||
// eslint-disable-next-line no-bitwise
|
||||
(stateObj.attributes.supported_features! & feature) !== 0;
|
||||
(attributes.supported_features! & feature) !== 0;
|
||||
|
@ -7,8 +7,11 @@ import { round } from "./round";
|
||||
* @param stateObj The entity state object
|
||||
*/
|
||||
export const isNumericState = (stateObj: HassEntity): boolean =>
|
||||
!!stateObj.attributes.unit_of_measurement ||
|
||||
!!stateObj.attributes.state_class;
|
||||
isNumericFromAttributes(stateObj.attributes);
|
||||
|
||||
export const isNumericFromAttributes = (attributes: {
|
||||
[key: string]: any;
|
||||
}): boolean => !!attributes.unit_of_measurement || !!attributes.state_class;
|
||||
|
||||
export const numberFormatToLocale = (
|
||||
localeOptions: FrontendLocaleData
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
import { HomeAssistant } from "../types";
|
||||
import {
|
||||
computeHistory,
|
||||
fetchRecent,
|
||||
HistoryStates,
|
||||
HistoryResult,
|
||||
LineChartUnit,
|
||||
TimelineEntity,
|
||||
entityIdHistoryNeedsAttributes,
|
||||
fetchRecentWS,
|
||||
} from "./history";
|
||||
|
||||
export interface CacheConfig {
|
||||
@ -55,7 +55,7 @@ export const getRecent = (
|
||||
}
|
||||
|
||||
const noAttributes = !entityIdHistoryNeedsAttributes(hass, entityId);
|
||||
const prom = fetchRecent(
|
||||
const prom = fetchRecentWS(
|
||||
hass,
|
||||
entityId,
|
||||
startTime,
|
||||
@ -134,12 +134,12 @@ export const getRecentWithCache = (
|
||||
const noAttributes = !entityIdHistoryNeedsAttributes(hass, entityId);
|
||||
|
||||
const genProm = async () => {
|
||||
let fetchedHistory: HassEntity[][];
|
||||
let fetchedHistory: HistoryStates;
|
||||
|
||||
try {
|
||||
const results = await Promise.all([
|
||||
curCacheProm,
|
||||
fetchRecent(
|
||||
fetchRecentWS(
|
||||
hass,
|
||||
entityId,
|
||||
toFetchStartTime,
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../common/entity/compute_state_name";
|
||||
import { computeStateDisplayFromEntityAttributes } from "../common/entity/compute_state_display";
|
||||
import { computeStateNameFromEntityAttributes } from "../common/entity/compute_state_name";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { FrontendLocaleData } from "./translation";
|
||||
@ -27,7 +26,7 @@ const LINE_ATTRIBUTES_TO_KEEP = [
|
||||
|
||||
export interface LineChartState {
|
||||
state: string;
|
||||
last_changed: string;
|
||||
last_changed: number;
|
||||
attributes?: Record<string, any>;
|
||||
}
|
||||
|
||||
@ -47,7 +46,7 @@ export interface LineChartUnit {
|
||||
export interface TimelineState {
|
||||
state_localize: string;
|
||||
state: string;
|
||||
last_changed: string;
|
||||
last_changed: number;
|
||||
}
|
||||
|
||||
export interface TimelineEntity {
|
||||
@ -141,6 +140,21 @@ export interface StatisticsValidationResults {
|
||||
[statisticId: string]: StatisticsValidationResult[];
|
||||
}
|
||||
|
||||
export interface HistoryStates {
|
||||
[entityId: string]: EntityHistoryState[];
|
||||
}
|
||||
|
||||
interface EntityHistoryState {
|
||||
/** state */
|
||||
s: string;
|
||||
/** attributes */
|
||||
a: { [key: string]: any };
|
||||
/** last_changed; if set, also applies to lu */
|
||||
lc: number;
|
||||
/** last_updated */
|
||||
lu: number;
|
||||
}
|
||||
|
||||
export const entityIdHistoryNeedsAttributes = (
|
||||
hass: HomeAssistant,
|
||||
entityId: string
|
||||
@ -181,6 +195,27 @@ export const fetchRecent = (
|
||||
return hass.callApi("GET", url);
|
||||
};
|
||||
|
||||
export const fetchRecentWS = (
|
||||
hass: HomeAssistant,
|
||||
entityId: string,
|
||||
startTime: Date,
|
||||
endTime: Date,
|
||||
skipInitialState = false,
|
||||
significantChangesOnly?: boolean,
|
||||
minimalResponse = true,
|
||||
noAttributes?: boolean
|
||||
) =>
|
||||
hass.callWS<HistoryStates>({
|
||||
type: "history/history_during_period",
|
||||
start_time: startTime.toISOString(),
|
||||
end_time: endTime.toISOString(),
|
||||
significant_changes_only: significantChangesOnly || false,
|
||||
include_start_time_state: !skipInitialState,
|
||||
minimal_response: minimalResponse,
|
||||
no_attributes: noAttributes || false,
|
||||
entity_ids: [entityId],
|
||||
});
|
||||
|
||||
export const fetchDate = (
|
||||
hass: HomeAssistant,
|
||||
startTime: Date,
|
||||
@ -198,6 +233,27 @@ export const fetchDate = (
|
||||
}`
|
||||
);
|
||||
|
||||
export const fetchDateWS = (
|
||||
hass: HomeAssistant,
|
||||
startTime: Date,
|
||||
endTime: Date,
|
||||
entityId?: string
|
||||
) => {
|
||||
const params = {
|
||||
type: "history/history_during_period",
|
||||
start_time: startTime.toISOString(),
|
||||
end_time: endTime.toISOString(),
|
||||
minimal_response: true,
|
||||
no_attributes: !!(
|
||||
entityId && !entityIdHistoryNeedsAttributes(hass, entityId)
|
||||
),
|
||||
};
|
||||
if (entityId) {
|
||||
return hass.callWS<HistoryStates>({ ...params, entity_ids: [entityId] });
|
||||
}
|
||||
return hass.callWS<HistoryStates>(params);
|
||||
};
|
||||
|
||||
const equalState = (obj1: LineChartState, obj2: LineChartState) =>
|
||||
obj1.state === obj2.state &&
|
||||
// Only compare attributes if both states have an attributes object.
|
||||
@ -212,46 +268,47 @@ const equalState = (obj1: LineChartState, obj2: LineChartState) =>
|
||||
const processTimelineEntity = (
|
||||
localize: LocalizeFunc,
|
||||
language: FrontendLocaleData,
|
||||
states: HassEntity[]
|
||||
entityId: string,
|
||||
states: EntityHistoryState[]
|
||||
): TimelineEntity => {
|
||||
const data: TimelineState[] = [];
|
||||
const last_element = states.length - 1;
|
||||
|
||||
const last: EntityHistoryState = states[states.length - 1];
|
||||
for (const state of states) {
|
||||
if (data.length > 0 && state.state === data[data.length - 1].state) {
|
||||
if (data.length > 0 && state.s === data[data.length - 1].state) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Copy the data from the last element as its the newest
|
||||
// and is only needed to localize the data
|
||||
if (!state.entity_id) {
|
||||
state.attributes = states[last_element].attributes;
|
||||
state.entity_id = states[last_element].entity_id;
|
||||
}
|
||||
|
||||
data.push({
|
||||
state_localize: computeStateDisplay(localize, state, language),
|
||||
state: state.state,
|
||||
last_changed: state.last_changed,
|
||||
state_localize: computeStateDisplayFromEntityAttributes(
|
||||
localize,
|
||||
language,
|
||||
entityId,
|
||||
state.a || last.a,
|
||||
state.s
|
||||
),
|
||||
state: state.s,
|
||||
// lc (last_changed) may be omitted if its the same
|
||||
// as lu (last_updated).
|
||||
last_changed: (state.lc ? state.lc : state.lu) * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
name: computeStateName(states[0]),
|
||||
entity_id: states[0].entity_id,
|
||||
name: computeStateNameFromEntityAttributes(entityId, states[0].a),
|
||||
entity_id: entityId,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
const processLineChartEntities = (
|
||||
unit,
|
||||
entities: HassEntity[][]
|
||||
entities: HistoryStates
|
||||
): LineChartUnit => {
|
||||
const data: LineChartEntity[] = [];
|
||||
|
||||
for (const states of entities) {
|
||||
const last: HassEntity = states[states.length - 1];
|
||||
const domain = computeStateDomain(last);
|
||||
Object.keys(entities).forEach((entityId) => {
|
||||
const states = entities[entityId];
|
||||
const last: EntityHistoryState = states[states.length - 1];
|
||||
const domain = computeDomain(entityId);
|
||||
const processedStates: LineChartState[] = [];
|
||||
|
||||
for (const state of states) {
|
||||
@ -259,18 +316,24 @@ const processLineChartEntities = (
|
||||
|
||||
if (DOMAINS_USE_LAST_UPDATED.includes(domain)) {
|
||||
processedState = {
|
||||
state: state.state,
|
||||
last_changed: state.last_updated,
|
||||
state: state.s,
|
||||
last_changed: state.lu * 1000,
|
||||
attributes: {},
|
||||
};
|
||||
|
||||
for (const attr of LINE_ATTRIBUTES_TO_KEEP) {
|
||||
if (attr in state.attributes) {
|
||||
processedState.attributes![attr] = state.attributes[attr];
|
||||
if (attr in state.a) {
|
||||
processedState.attributes![attr] = state.a[attr];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
processedState = state;
|
||||
processedState = {
|
||||
state: state.s,
|
||||
// lc (last_changed) may be omitted if its the same
|
||||
// as lu (last_updated).
|
||||
last_changed: (state.lc ? state.lc : state.lu) * 1000,
|
||||
attributes: {},
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
@ -289,52 +352,53 @@ const processLineChartEntities = (
|
||||
|
||||
data.push({
|
||||
domain,
|
||||
name: computeStateName(last),
|
||||
entity_id: last.entity_id,
|
||||
name: computeStateNameFromEntityAttributes(entityId, last.a),
|
||||
entity_id: entityId,
|
||||
states: processedStates,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
unit,
|
||||
identifier: entities.map((states) => states[0].entity_id).join(""),
|
||||
identifier: Object.keys(entities).join(""),
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
const stateUsesUnits = (state: HassEntity) =>
|
||||
"unit_of_measurement" in state.attributes ||
|
||||
"state_class" in state.attributes;
|
||||
attributesHaveUnits(state.attributes);
|
||||
|
||||
const attributesHaveUnits = (attributes: { [key: string]: any }) =>
|
||||
"unit_of_measurement" in attributes || "state_class" in attributes;
|
||||
|
||||
export const computeHistory = (
|
||||
hass: HomeAssistant,
|
||||
stateHistory: HassEntity[][],
|
||||
stateHistory: HistoryStates,
|
||||
localize: LocalizeFunc
|
||||
): HistoryResult => {
|
||||
const lineChartDevices: { [unit: string]: HassEntity[][] } = {};
|
||||
const lineChartDevices: { [unit: string]: HistoryStates } = {};
|
||||
const timelineDevices: TimelineEntity[] = [];
|
||||
if (!stateHistory) {
|
||||
return { line: [], timeline: [] };
|
||||
}
|
||||
|
||||
stateHistory.forEach((stateInfo) => {
|
||||
Object.keys(stateHistory).forEach((entityId) => {
|
||||
const stateInfo = stateHistory[entityId];
|
||||
if (stateInfo.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entityId = stateInfo[0].entity_id;
|
||||
const currentState =
|
||||
entityId in hass.states ? hass.states[entityId] : undefined;
|
||||
const stateWithUnitorStateClass =
|
||||
!currentState &&
|
||||
stateInfo.find((state) => state.attributes && stateUsesUnits(state));
|
||||
stateInfo.find((state) => state.a && attributesHaveUnits(state.a));
|
||||
|
||||
let unit: string | undefined;
|
||||
|
||||
if (currentState && stateUsesUnits(currentState)) {
|
||||
unit = currentState.attributes.unit_of_measurement || " ";
|
||||
} else if (stateWithUnitorStateClass) {
|
||||
unit = stateWithUnitorStateClass.attributes.unit_of_measurement || " ";
|
||||
unit = stateWithUnitorStateClass.a.unit_of_measurement || " ";
|
||||
} else {
|
||||
unit = {
|
||||
climate: hass.config.unit_system.temperature,
|
||||
@ -348,12 +412,15 @@ export const computeHistory = (
|
||||
|
||||
if (!unit) {
|
||||
timelineDevices.push(
|
||||
processTimelineEntity(localize, hass.locale, stateInfo)
|
||||
processTimelineEntity(localize, hass.locale, entityId, stateInfo)
|
||||
);
|
||||
} else if (unit in lineChartDevices) {
|
||||
lineChartDevices[unit].push(stateInfo);
|
||||
} else if (unit in lineChartDevices && entityId in lineChartDevices[unit]) {
|
||||
lineChartDevices[unit][entityId].push(...stateInfo);
|
||||
} else {
|
||||
lineChartDevices[unit] = [stateInfo];
|
||||
if (!(unit in lineChartDevices)) {
|
||||
lineChartDevices[unit] = {};
|
||||
}
|
||||
lineChartDevices[unit][entityId] = stateInfo;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,10 @@ import type {
|
||||
import { BINARY_STATE_ON } from "../common/const";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
||||
import { supportsFeature } from "../common/entity/supports-feature";
|
||||
import {
|
||||
supportsFeature,
|
||||
supportsFeatureFromAttributes,
|
||||
} from "../common/entity/supports-feature";
|
||||
import { caseInsensitiveStringCompare } from "../common/string/compare";
|
||||
import { showAlertDialog } from "../dialogs/generic/show-dialog-box";
|
||||
import { HomeAssistant } from "../types";
|
||||
@ -35,8 +38,13 @@ export interface UpdateEntity extends HassEntityBase {
|
||||
}
|
||||
|
||||
export const updateUsesProgress = (entity: UpdateEntity): boolean =>
|
||||
supportsFeature(entity, UPDATE_SUPPORT_PROGRESS) &&
|
||||
typeof entity.attributes.in_progress === "number";
|
||||
updateUsesProgressFromAttributes(entity.attributes);
|
||||
|
||||
export const updateUsesProgressFromAttributes = (attributes: {
|
||||
[key: string]: any;
|
||||
}): boolean =>
|
||||
supportsFeatureFromAttributes(attributes, UPDATE_SUPPORT_PROGRESS) &&
|
||||
typeof attributes.in_progress === "number";
|
||||
|
||||
export const updateCanInstall = (
|
||||
entity: UpdateEntity,
|
||||
@ -49,6 +57,11 @@ export const updateCanInstall = (
|
||||
export const updateIsInstalling = (entity: UpdateEntity): boolean =>
|
||||
updateUsesProgress(entity) || !!entity.attributes.in_progress;
|
||||
|
||||
export const updateIsInstallingFromAttributes = (attributes: {
|
||||
[key: string]: any;
|
||||
}): boolean =>
|
||||
updateUsesProgressFromAttributes(attributes) || !!attributes.in_progress;
|
||||
|
||||
export const updateReleaseNotes = (hass: HomeAssistant, entityId: string) =>
|
||||
hass.callWS<string | null>({
|
||||
type: "update/release_notes",
|
||||
|
@ -25,7 +25,7 @@ import "../../components/ha-date-range-picker";
|
||||
import type { DateRangePickerRanges } from "../../components/ha-date-range-picker";
|
||||
import "../../components/ha-icon-button";
|
||||
import "../../components/ha-menu-button";
|
||||
import { computeHistory, fetchDate } from "../../data/history";
|
||||
import { computeHistory, fetchDateWS } from "../../data/history";
|
||||
import "../../layouts/ha-app-layout";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import { HomeAssistant } from "../../types";
|
||||
@ -177,7 +177,7 @@ class HaPanelHistory extends LitElement {
|
||||
|
||||
private async _getHistory() {
|
||||
this._isLoading = true;
|
||||
const dateHistory = await fetchDate(
|
||||
const dateHistory = await fetchDateWS(
|
||||
this.hass,
|
||||
this._startDate,
|
||||
this._endDate,
|
||||
|
Loading…
x
Reference in New Issue
Block a user