/
state-badge.ts
137 lines (125 loc) · 3.97 KB
/
state-badge.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import {
LitElement,
TemplateResult,
css,
CSSResult,
html,
property,
PropertyValues,
query,
} from "lit-element";
import "../ha-icon";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { stateIcon } from "../../common/entity/state_icon";
import { HassEntity } from "home-assistant-js-websocket";
// Not duplicate, this is for typing.
// tslint:disable-next-line
import { HaIcon } from "../ha-icon";
import { HomeAssistant } from "../../types";
class StateBadge extends LitElement {
public hass?: HomeAssistant;
@property() public stateObj?: HassEntity;
@property() public overrideIcon?: string;
@property() public overrideImage?: string;
@query("ha-icon") private _icon!: HaIcon;
protected render(): TemplateResult | void {
const stateObj = this.stateObj;
if (!stateObj) {
return html``;
}
return html`
<ha-icon
id="icon"
data-domain=${computeStateDomain(stateObj)}
data-state=${stateObj.state}
.icon=${this.overrideIcon || stateIcon(stateObj)}
></ha-icon>
`;
}
protected updated(changedProps: PropertyValues) {
if (!changedProps.has("stateObj") || !this.stateObj) {
return;
}
const stateObj = this.stateObj;
const iconStyle: Partial<CSSStyleDeclaration> = {
color: "",
filter: "",
};
const hostStyle: Partial<CSSStyleDeclaration> = {
backgroundImage: "",
};
if (stateObj) {
// hide icon if we have entity picture
if (
(stateObj.attributes.entity_picture && !this.overrideIcon) ||
this.overrideImage
) {
let imageUrl = this.overrideImage || stateObj.attributes.entity_picture;
if (this.hass) {
imageUrl = this.hass.hassUrl(imageUrl);
}
hostStyle.backgroundImage = `url(${imageUrl})`;
iconStyle.display = "none";
} else {
if (stateObj.attributes.hs_color) {
const hue = stateObj.attributes.hs_color[0];
const sat = stateObj.attributes.hs_color[1];
if (sat > 10) {
iconStyle.color = `hsl(${hue}, 100%, ${100 - sat / 2}%)`;
}
}
if (stateObj.attributes.brightness) {
const brightness = stateObj.attributes.brightness;
if (typeof brightness !== "number") {
const errorMessage = `Type error: state-badge expected number, but type of ${
stateObj.entity_id
}.attributes.brightness is ${typeof brightness} (${brightness})`;
// tslint:disable-next-line
console.warn(errorMessage);
}
// lowest brighntess will be around 50% (that's pretty dark)
iconStyle.filter = `brightness(${(brightness + 245) / 5}%)`;
}
}
}
Object.assign(this._icon.style, iconStyle);
Object.assign(this.style, hostStyle);
}
static get styles(): CSSResult {
return css`
:host {
position: relative;
display: inline-block;
width: 40px;
color: var(--paper-item-icon-color, #44739e);
border-radius: 50%;
height: 40px;
text-align: center;
background-size: cover;
line-height: 40px;
vertical-align: middle;
}
ha-icon {
transition: color 0.3s ease-in-out, filter 0.3s ease-in-out;
}
/* Color the icon if light or sun is on */
ha-icon[data-domain="light"][data-state="on"],
ha-icon[data-domain="switch"][data-state="on"],
ha-icon[data-domain="binary_sensor"][data-state="on"],
ha-icon[data-domain="fan"][data-state="on"],
ha-icon[data-domain="sun"][data-state="above_horizon"] {
color: var(--paper-item-icon-active-color, #fdd835);
}
/* Color the icon if unavailable */
ha-icon[data-state="unavailable"] {
color: var(--state-icon-unavailable-color);
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"state-badge": StateBadge;
}
}
customElements.define("state-badge", StateBadge);