Skip to content

Commit

Permalink
Update state icons (piitaya#931)
Browse files Browse the repository at this point in the history
  • Loading branch information
piitaya committed Jan 6, 2023
1 parent 84d6db8 commit ef25c01
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 91 deletions.
10 changes: 6 additions & 4 deletions src/utils/icons/binary-sensor-icon.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { HassEntity } from "home-assistant-js-websocket";

export const binarySensorIcon = (state?: string, entity?: HassEntity) => {
export const binarySensorIcon = (state?: string, stateObj?: HassEntity) => {
const isOff = state === "off";
switch (entity?.attributes.device_class) {
switch (stateObj?.attributes.device_class) {
case "battery":
return isOff ? "mdi:battery" : "mdi:battery-outline";
case "battery_charging":
return isOff ? "mdi:battery" : "mdi:battery-charging";
case "carbon_monoxide":
return isOff ? "mdi:smoke-detector" : "mdi:smoke-detector-alert";
case "cold":
return isOff ? "mdi:thermometer" : "mdi:snowflake";
case "connectivity":
Expand All @@ -23,11 +25,11 @@ export const binarySensorIcon = (state?: string, entity?: HassEntity) => {
case "tamper":
return isOff ? "mdi:check-circle" : "mdi:alert-circle";
case "smoke":
return isOff ? "mdi:check-circle" : "mdi:smoke";
return isOff ? "mdi:smoke-detector-variant" : "mdi:smoke-detector-variant-alert";
case "heat":
return isOff ? "mdi:thermometer" : "mdi:fire";
case "light":
return isOff ? "mdi:brightness5" : "mdi:brightness-7";
return isOff ? "mdi:brightness-5" : "mdi:brightness-7";
case "lock":
return isOff ? "mdi:lock" : "mdi:lock-open";
case "moisture":
Expand Down
20 changes: 15 additions & 5 deletions src/utils/icons/cover-icon.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { HassEntity } from "home-assistant-js-websocket";

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

switch (entity?.attributes.device_class) {
switch (stateObj?.attributes.device_class) {
case "garage":
switch (state) {
case "opening":
Expand All @@ -28,7 +28,7 @@ export const coverIcon = (state?: string, entity?: HassEntity): string => {
case "door":
return open ? "mdi:door-open" : "mdi:door-closed";
case "damper":
return open ? "md:circle" : "mdi:circle-slice-8";
return open ? "mdi:circle" : "mdi:circle-slice-8";
case "shutter":
switch (state) {
case "opening":
Expand All @@ -52,16 +52,26 @@ export const coverIcon = (state?: string, entity?: HassEntity): string => {
return "mdi:curtains";
}
case "blind":
switch (state) {
case "opening":
return "mdi:arrow-up-box";
case "closing":
return "mdi:arrow-down-box";
case "closed":
return "mdi:blinds-horizontal-closed";
default:
return "mdi:blinds-horizontal";
}
case "shade":
switch (state) {
case "opening":
return "mdi:arrow-up-box";
case "closing":
return "mdi:arrow-down-box";
case "closed":
return "mdi:blinds";
return "mdi:roller-shade-closed";
default:
return "mdi:blinds-open";
return "mdi:roller-shade";
}
case "window":
switch (state) {
Expand Down
171 changes: 90 additions & 81 deletions src/utils/icons/domain-icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { alarmPanelIcon } from "./alarm-panel-icon";
import { binarySensorIcon } from "./binary-sensor-icon";
import { coverIcon } from "./cover-icon";
import { sensorIcon } from "./sensor-icon";
import { weatherIcon } from "./weather-icon";

const DEFAULT_DOMAIN_ICON = "mdi:bookmark";

Expand Down Expand Up @@ -51,16 +52,18 @@ const FIXED_DOMAIN_ICONS = {
zone: "mdi:map-marker-radius",
};

export function domainIcon(domain: string, entity?: HassEntity, state?: string): string {
export function domainIcon(domain: string, stateObj?: HassEntity, state?: string): string {
const compareState = state !== undefined ? state : stateObj?.state;

switch (domain) {
case "alarm_control_panel":
return alarmPanelIcon(state);
return alarmPanelIcon(compareState);

case "binary_sensor":
return binarySensorIcon(state, entity);
return binarySensorIcon(compareState, stateObj);

case "button":
switch (entity?.attributes.device_class) {
switch (stateObj?.attributes.device_class) {
case "restart":
return "mdi:restart";
case "update":
Expand All @@ -70,25 +73,36 @@ export function domainIcon(domain: string, entity?: HassEntity, state?: string):
}

case "cover":
return coverIcon(state, entity);
return coverIcon(compareState, stateObj);

case "device_tracker":
if (entity?.attributes.source_type === "router") {
return state === "home" ? "mdi:lan-connect" : "mdi:lan-disconnect";
if (stateObj?.attributes.source_type === "router") {
return compareState === "home" ? "mdi:lan-connect" : "mdi:lan-disconnect";
}
if (["bluetooth", "bluetooth_le"].includes(entity?.attributes.source_type)) {
return state === "home" ? "mdi:bluetooth-connect" : "mdi:bluetooth";
if (["bluetooth", "bluetooth_le"].includes(stateObj?.attributes.source_type)) {
return compareState === "home" ? "mdi:bluetooth-connect" : "mdi:bluetooth";
}
return state === "not_home" ? "mdi:account-arrow-right" : "mdi:account";
return compareState === "not_home" ? "mdi:account-arrow-right" : "mdi:account";

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

case "input_boolean":
return state === "on" ? "mdi:check-circle-outline" : "mdi:close-circle-outline";
return compareState === "on" ? "mdi:check-circle-outline" : "mdi:close-circle-outline";

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

case "lock":
switch (state) {
switch (compareState) {
case "unlocked":
return "mdi:lock-open";
case "jammed":
Expand All @@ -101,102 +115,97 @@ export function domainIcon(domain: string, entity?: HassEntity, state?: string):
}

case "media_player":
return state === "playing" ? "mdi:cast-connected" : "mdi:cast";

case "switch":
switch (entity?.attributes.device_class) {
case "outlet":
return state === "on" ? "mdi:power-plug" : "mdi:power-plug-off";
case "switch":
return state === "on" ? "mdi:toggle-switch" : "mdi:toggle-switch-off";
switch (stateObj?.attributes.device_class) {
case "speaker":
switch (compareState) {
case "playing":
return "mdi:speaker-play";
case "paused":
return "mdi:speaker-pause";
case "off":
return "mdi:speaker-off";
default:
return "mdi:speaker";
}
case "tv":
switch (compareState) {
case "playing":
return "mdi:television-play";
case "paused":
return "mdi:television-pause";
case "off":
return "mdi:television-off";
default:
return "mdi:television";
}
case "receiver":
switch (compareState) {
case "off":
return "mdi:audio-video-off";
default:
return "mdi:audio-video";
}
default:
return "mdi:flash";
switch (compareState) {
case "playing":
case "paused":
return "mdi:cast-connected";
case "off":
return "mdi:cast-off";
default:
return "mdi:cast";
}
}

case "weather":
switch (state) {
case "clear-night":
return "mdi:weather-night";
case "cloudy":
return "mdi:weather-cloudy";
case "exceptional":
return "mdi:alert-circle-outline";
case "fog":
return "mdi:weather-fog";
case "hail":
return "mdi:weather-hail";
case "lightning":
return "mdi:weather-lightning";
case "lightning-rainy":
return "mdi:weather-lightning-rainy";
case "partlycloudy":
return "mdi:weather-partly-cloudy";
case "pouring":
return "mdi:weather-pouring";
case "rainy":
return "mdi:weather-rainy";
case "snowy":
return "mdi:weather-snowy";
case "snowy-rainy":
return "mdi:weather-snowy-rainy";
case "sunny":
return "mdi:weather-sunny";
case "windy":
return "mdi:weather-windy";
case "windy-variant":
return "mdi:weather-windy-variant";
default:
return "mdi:weather-cloudy";
}
case "person":
return compareState === "not_home" ? "mdi:account-arrow-right" : "mdi:account";

case "zwave":
switch (state) {
case "dead":
return "mdi:emoticon-dead";
case "sleeping":
return "mdi:sleep";
case "initializing":
return "mdi:timer-sand";
case "switch":
switch (stateObj?.attributes.device_class) {
case "outlet":
return compareState === "on" ? "mdi:power-plug" : "mdi:power-plug-off";
case "switch":
return compareState === "on"
? "mdi:toggle-switch-variant"
: "mdi:toggle-switch-variant-off";
default:
return "mdi:z-wave";
return "mdi:toggle-switch-variant";
}

case "sensor": {
const icon = sensorIcon(entity);
const icon = sensorIcon(stateObj);
if (icon) {
return icon;
}

break;
}

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

case "sun":
return entity?.state === "above_horizon"
return stateObj?.state === "above_horizon"
? FIXED_DOMAIN_ICONS[domain]
: "mdi:weather-night";

case "switch_as_x":
return "mdi:swap-horizontal";

case "threshold":
return "mdi:chart-sankey";

case "update":
return entity?.state === "on"
? updateIsInstalling(entity as UpdateEntity)
return stateObj?.state === "on"
? updateIsInstalling(stateObj as UpdateEntity)
? "mdi:package-down"
: "mdi:package-up"
: "mdi:package";

case "weather":
return weatherIcon(stateObj?.state);
}

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

// eslint-disable-next-line
console.warn(`Unable to find icon for domain ${domain}`);
return DEFAULT_DOMAIN_ICON;
}
18 changes: 17 additions & 1 deletion src/utils/icons/sensor-icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,23 @@ import { UNIT_C, UNIT_F } from "../../ha";
const FIXED_DEVICE_CLASS_ICONS = {
apparent_power: "mdi:flash",
aqi: "mdi:air-filter",
atmospheric_pressure: "mdi:thermometer-lines",
// battery: "mdi:battery", => not included by design since `sensorIcon()` will dynamically determine the icon
carbon_dioxide: "mdi:molecule-co2",
carbon_monoxide: "mdi:molecule-co",
current: "mdi:current-ac",
data_rate: "mdi:transmission-tower",
data_size: "mdi:database",
date: "mdi:calendar",
distance: "mdi:arrow-left-right",
duration: "mdi:progress-clock",
energy: "mdi:lightning-bolt",
frequency: "mdi:sine-wave",
gas: "mdi:gas-cylinder",
gas: "mdi:meter-gas",
humidity: "mdi:water-percent",
illuminance: "mdi:brightness-5",
irradiance: "mdi:sun-wireless",
moisture: "mdi:water-percent",
monetary: "mdi:cash",
nitrogen_dioxide: "mdi:molecule",
nitrogen_monoxide: "mdi:molecule",
Expand All @@ -23,14 +31,22 @@ const FIXED_DEVICE_CLASS_ICONS = {
pm25: "mdi:molecule",
power: "mdi:flash",
power_factor: "mdi:angle-acute",
precipitation: "mdi:weather-rainy",
precipitation_intensity: "mdi:weather-pouring",
pressure: "mdi:gauge",
reactive_power: "mdi:flash",
signal_strength: "mdi:wifi",
sound_pressure: "mdi:ear-hearing",
speed: "mdi:speedometer",
sulphur_dioxide: "mdi:molecule",
temperature: "mdi:thermometer",
timestamp: "mdi:clock",
volatile_organic_compounds: "mdi:molecule",
voltage: "mdi:sine-wave",
volume: "mdi:car-coolant-level",
water: "mdi:water",
weight: "mdi:weight",
wind_speed: "mdi:weather-windy",
};

const SENSOR_DEVICE_CLASS_BATTERY = "battery";
Expand Down
24 changes: 24 additions & 0 deletions src/utils/icons/weather-icon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const weatherIcons = {
"clear-night": "mdi:weather-night",
cloudy: "mdi:weather-cloudy",
exceptional: "mdi:alert-circle-outline",
fog: "mdi:weather-fog",
hail: "mdi:weather-hail",
lightning: "mdi:weather-lightning",
"lightning-rainy": "mdi:weather-lightning-rainy",
partlycloudy: "mdi:weather-partly-cloudy",
pouring: "mdi:weather-pouring",
rainy: "mdi:weather-rainy",
snowy: "mdi:weather-snowy",
"snowy-rainy": "mdi:weather-snowy-rainy",
sunny: "mdi:weather-sunny",
windy: "mdi:weather-windy",
"windy-variant": "mdi:weather-windy-variant",
};

export const weatherIcon = (state?: string, nightTime?: boolean): string =>
!state
? undefined
: nightTime && state === "partlycloudy"
? "mdiWeatherNightPartlyCloudy"
: weatherIcons[state];

0 comments on commit ef25c01

Please sign in to comment.