Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/common/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,66 @@
/** Icon to use when no icon specified for domain. */
export const DEFAULT_DOMAIN_ICON = "hass:bookmark";

/** Icons for each domain */
export const FIXED_DOMAIN_ICONS = {
alert: "hass:alert",
alexa: "hass:amazon-alexa",
air_quality: "hass:air-filter",
automation: "hass:robot",
calendar: "hass:calendar",
camera: "hass:video",
climate: "hass:thermostat",
configurator: "hass:cog",
conversation: "hass:text-to-speech",
counter: "hass:counter",
device_tracker: "hass:account",
fan: "hass:fan",
google_assistant: "hass:google-assistant",
group: "hass:google-circles-communities",
homeassistant: "hass:home-assistant",
homekit: "hass:home-automation",
image_processing: "hass:image-filter-frames",
input_boolean: "hass:toggle-switch-outline",
input_datetime: "hass:calendar-clock",
input_number: "hass:ray-vertex",
input_select: "hass:format-list-bulleted",
input_text: "hass:form-textbox",
light: "hass:lightbulb",
mailbox: "hass:mailbox",
notify: "hass:comment-alert",
persistent_notification: "hass:bell",
person: "hass:account",
plant: "hass:flower",
proximity: "hass:apple-safari",
remote: "hass:remote",
scene: "hass:palette",
script: "hass:script-text",
sensor: "hass:eye",
simple_alarm: "hass:bell",
sun: "hass:white-balance-sunny",
switch: "hass:flash",
timer: "hass:timer-outline",
updater: "hass:cloud-upload",
vacuum: "hass:robot-vacuum",
water_heater: "hass:thermometer",
weather: "hass:weather-cloudy",
zone: "hass:map-marker-radius",
};

export const FIXED_DEVICE_CLASS_ICONS = {
current: "hass:current-ac",
energy: "hass:flash",
humidity: "hass:water-percent",
illuminance: "hass:brightness-5",
temperature: "hass:thermometer",
pressure: "hass:gauge",
power: "hass:flash",
power_factor: "hass:angle-acute",
signal_strength: "hass:wifi",
timestamp: "hass:clock",
voltage: "hass:sine-wave",
};

/** Domains that have a state card. */
export const DOMAINS_WITH_CARD = [
"climate",
Expand Down Expand Up @@ -63,6 +123,10 @@ export const DOMAINS_MORE_INFO_NO_HISTORY = ["camera", "configurator", "scene"];
/** States that we consider "off". */
export const STATES_OFF = ["closed", "locked", "off"];

/** Binary States */
export const BINARY_STATE_ON = "on";
export const BINARY_STATE_OFF = "off";

/** Domains where we allow toggle in Lovelace. */
export const DOMAINS_TOGGLE = new Set([
"fan",
Expand Down
6 changes: 3 additions & 3 deletions src/common/entity/binary_sensor_icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { HassEntity } from "home-assistant-js-websocket";

/** Return an icon representing a binary sensor state. */

export const binarySensorIcon = (state: HassEntity) => {
const is_off = state.state && state.state === "off";
switch (state.attributes.device_class) {
export const binarySensorIcon = (state?: string, stateObj?: HassEntity) => {
const is_off = state === "off";
switch (stateObj?.attributes.device_class) {
case "battery":
return is_off ? "hass:battery" : "hass:battery-outline";
case "battery_charging":
Expand Down
19 changes: 11 additions & 8 deletions src/common/entity/compute_state_display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ import { computeStateDomain } from "./compute_state_domain";
export const computeStateDisplay = (
localize: LocalizeFunc,
stateObj: HassEntity,
language: string
language: string,
state?: string
): string => {
if (stateObj.state === UNKNOWN || stateObj.state === UNAVAILABLE) {
return localize(`state.default.${stateObj.state}`);
const compareState = state !== undefined ? state : stateObj.state;

if (compareState === UNKNOWN || compareState === UNAVAILABLE) {
return localize(`state.default.${compareState}`);
}

if (stateObj.attributes.unit_of_measurement) {
return `${stateObj.state} ${stateObj.attributes.unit_of_measurement}`;
return `${compareState} ${stateObj.attributes.unit_of_measurement}`;
}

const domain = computeStateDomain(stateObj);
Expand Down Expand Up @@ -56,7 +59,7 @@ export const computeStateDisplay = (
}

if (domain === "humidifier") {
if (stateObj.state === "on" && stateObj.attributes.humidity) {
if (compareState === "on" && stateObj.attributes.humidity) {
return `${stateObj.attributes.humidity}%`;
}
}
Expand All @@ -65,11 +68,11 @@ export const computeStateDisplay = (
// Return device class translation
(stateObj.attributes.device_class &&
localize(
`component.${domain}.state.${stateObj.attributes.device_class}.${stateObj.state}`
`component.${domain}.state.${stateObj.attributes.device_class}.${compareState}`
)) ||
// Return default translation
localize(`component.${domain}.state._.${stateObj.state}`) ||
localize(`component.${domain}.state._.${compareState}`) ||
// We don't know! Return the raw state.
stateObj.state
compareState
);
};
28 changes: 18 additions & 10 deletions src/common/entity/cover_icon.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
/** Return an icon representing a cover state. */
import { HassEntity } from "home-assistant-js-websocket";
import { domainIcon } from "./domain_icon";

export const coverIcon = (state: HassEntity): string => {
const open = state.state !== "closed";
export const coverIcon = (state?: string, stateObj?: HassEntity): string => {
const open = state !== "closed";

switch (state.attributes.device_class) {
switch (stateObj?.attributes.device_class) {
case "garage":
switch (state.state) {
switch (state) {
case "opening":
return "hass:arrow-up-box";
case "closing":
Expand All @@ -18,7 +17,7 @@ export const coverIcon = (state: HassEntity): string => {
return "hass:garage-open";
}
case "gate":
switch (state.state) {
switch (state) {
case "opening":
case "closing":
return "hass:gate-arrow-right";
Expand All @@ -32,7 +31,7 @@ export const coverIcon = (state: HassEntity): string => {
case "damper":
return open ? "hass:circle" : "hass:circle-slice-8";
case "shutter":
switch (state.state) {
switch (state) {
case "opening":
return "hass:arrow-up-box";
case "closing":
Expand All @@ -44,7 +43,7 @@ export const coverIcon = (state: HassEntity): string => {
}
case "blind":
case "curtain":
switch (state.state) {
switch (state) {
case "opening":
return "hass:arrow-up-box";
case "closing":
Expand All @@ -55,7 +54,7 @@ export const coverIcon = (state: HassEntity): string => {
return "hass:blinds-open";
}
case "window":
switch (state.state) {
switch (state) {
case "opening":
return "hass:arrow-up-box";
case "closing":
Expand All @@ -65,7 +64,16 @@ export const coverIcon = (state: HassEntity): string => {
default:
return "hass:window-open";
}
}

switch (state) {
case "opening":
return "hass:arrow-up-box";
case "closing":
return "hass:arrow-down-box";
case "closed":
return "hass:window-closed";
default:
return domainIcon("cover", state.state);
return "hass:window-open";
}
};
117 changes: 44 additions & 73 deletions src/common/entity/domain_icon.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,24 @@
import { HassEntity } from "home-assistant-js-websocket";
/**
* Return the icon to be used for a domain.
*
* Optionally pass in a state to influence the domain icon.
*/
import { DEFAULT_DOMAIN_ICON } from "../const";
import { DEFAULT_DOMAIN_ICON, FIXED_DOMAIN_ICONS } from "../const";
import { binarySensorIcon } from "./binary_sensor_icon";
import { coverIcon } from "./cover_icon";
import { sensorIcon } from "./sensor_icon";

const fixedIcons = {
alert: "hass:alert",
alexa: "hass:amazon-alexa",
air_quality: "hass:air-filter",
automation: "hass:robot",
calendar: "hass:calendar",
camera: "hass:video",
climate: "hass:thermostat",
configurator: "hass:cog",
conversation: "hass:text-to-speech",
counter: "hass:counter",
device_tracker: "hass:account",
fan: "hass:fan",
google_assistant: "hass:google-assistant",
group: "hass:google-circles-communities",
homeassistant: "hass:home-assistant",
homekit: "hass:home-automation",
image_processing: "hass:image-filter-frames",
input_boolean: "hass:toggle-switch-outline",
input_datetime: "hass:calendar-clock",
input_number: "hass:ray-vertex",
input_select: "hass:format-list-bulleted",
input_text: "hass:form-textbox",
light: "hass:lightbulb",
mailbox: "hass:mailbox",
notify: "hass:comment-alert",
persistent_notification: "hass:bell",
person: "hass:account",
plant: "hass:flower",
proximity: "hass:apple-safari",
remote: "hass:remote",
scene: "hass:palette",
script: "hass:script-text",
sensor: "hass:eye",
simple_alarm: "hass:bell",
sun: "hass:white-balance-sunny",
switch: "hass:flash",
timer: "hass:timer-outline",
updater: "hass:cloud-upload",
vacuum: "hass:robot-vacuum",
water_heater: "hass:thermometer",
weather: "hass:weather-cloudy",
zone: "hass:map-marker-radius",
};

export const domainIcon = (domain: string, state?: string): string => {
if (domain in fixedIcons) {
return fixedIcons[domain];
}
export const domainIcon = (
domain: string,
stateObj?: HassEntity,
state?: string
): string => {
const compareState = state !== undefined ? state : stateObj?.state;

switch (domain) {
case "alarm_control_panel":
switch (state) {
switch (compareState) {
case "armed_home":
return "hass:bell-plus";
case "armed_night":
Expand All @@ -71,35 +32,24 @@ export const domainIcon = (domain: string, state?: string): string => {
}

case "binary_sensor":
return state && state === "off"
? "hass:radiobox-blank"
: "hass:checkbox-marked-circle";
return binarySensorIcon(compareState, stateObj);

case "cover":
switch (state) {
case "opening":
return "hass:arrow-up-box";
case "closing":
return "hass:arrow-down-box";
case "closed":
return "hass:window-closed";
default:
return "hass:window-open";
}
return coverIcon(compareState, stateObj);

case "humidifier":
return state && state === "off"
? "hass:air-humidifier-off"
: "hass:air-humidifier";

case "lock":
return state && state === "unlocked" ? "hass:lock-open" : "hass:lock";
return compareState === "unlocked" ? "hass:lock-open" : "hass:lock";

case "media_player":
return state && state === "playing" ? "hass:cast-connected" : "hass:cast";
return compareState === "playing" ? "hass:cast-connected" : "hass:cast";

case "zwave":
switch (state) {
switch (compareState) {
case "dead":
return "hass:emoticon-dead";
case "sleeping":
Expand All @@ -110,11 +60,32 @@ export const domainIcon = (domain: string, state?: string): string => {
return "hass:z-wave";
}

default:
// eslint-disable-next-line
console.warn(
"Unable to find icon for domain " + domain + " (" + state + ")"
);
return DEFAULT_DOMAIN_ICON;
case "sensor": {
const icon = sensorIcon(stateObj);
if (icon) {
return icon;
}

break;
}

case "input_datetime":
if (!stateObj?.attributes.has_date) {
return "hass:clock";
}
if (!stateObj.attributes.has_time) {
return "hass:calendar";
}
break;
}

if (domain in FIXED_DOMAIN_ICONS) {
return FIXED_DOMAIN_ICONS[domain];
}

// eslint-disable-next-line
console.warn(
"Unable to find icon for domain " + domain + " (" + stateObj + ")"
);
return DEFAULT_DOMAIN_ICON;
};
13 changes: 0 additions & 13 deletions src/common/entity/input_dateteime_icon.ts

This file was deleted.

Loading