diff --git a/src/panels/lovelace/cards/hui-plant-status-card.js b/src/panels/lovelace/cards/hui-plant-status-card.js deleted file mode 100644 index d45c8cc2a7..0000000000 --- a/src/panels/lovelace/cards/hui-plant-status-card.js +++ /dev/null @@ -1,26 +0,0 @@ -import "../../../cards/ha-plant-card"; - -import LegacyWrapperCard from "./hui-legacy-wrapper-card"; - -// should be interface when converted to TS -export const Config = { - name: "", - entity: "", -}; - -class HuiPlantStatusCard extends LegacyWrapperCard { - static async getConfigElement() { - await import(/* webpackChunkName: "hui-plant-status-card-editor" */ "../editor/config-elements/hui-plant-status-card-editor"); - return document.createElement("hui-plant-status-card-editor"); - } - - static getStubConfig() { - return {}; - } - - constructor() { - super("ha-plant-card", "plant"); - } -} - -customElements.define("hui-plant-status-card", HuiPlantStatusCard); diff --git a/src/panels/lovelace/cards/hui-plant-status-card.ts b/src/panels/lovelace/cards/hui-plant-status-card.ts new file mode 100644 index 0000000000..c31d5ce90a --- /dev/null +++ b/src/panels/lovelace/cards/hui-plant-status-card.ts @@ -0,0 +1,237 @@ +import { + html, + LitElement, + TemplateResult, + css, + CSSResult, + property, + customElement, +} from "lit-element"; + +import "../../../components/ha-card"; +import "../../../components/ha-icon"; + +import { HassEntity } from "home-assistant-js-websocket"; +import computeStateName from "../../../common/entity/compute_state_name"; + +import { LovelaceCardEditor, LovelaceCard } from "../types"; +import { HomeAssistant } from "../../../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; +import { fireEvent } from "../../../common/dom/fire_event"; + +const SENSORS = { + moisture: "hass:water", + temperature: "hass:thermometer", + brightness: "hass:white-balance-sunny", + conductivity: "hass:emoticon-poop", + battery: "hass:battery", +}; + +export interface PlantAttributeTarget extends EventTarget { + value?: string; +} + +export interface PlantStatusConfig extends LovelaceCardConfig { + name?: string; + entity: string; +} + +@customElement("hui-plant-status-card") +class HuiPlantStatusCard extends LitElement implements LovelaceCard { + public static async getConfigElement(): Promise { + await import(/* webpackChunkName: "hui-plant-status-card-editor" */ "../editor/config-elements/hui-plant-status-card-editor"); + return document.createElement("hui-plant-status-card-editor"); + } + + public static getStubConfig(): object { + return {}; + } + + @property() public hass?: HomeAssistant; + + @property() private _config?: PlantStatusConfig; + + public getCardSize(): number { + return 3; + } + + public setConfig(config: PlantStatusConfig): void { + if (!config.entity || config.entity.split(".")[0] !== "plant") { + throw new Error("Specify an entity from within the plant domain."); + } + + this._config = config; + } + + protected render(): TemplateResult | void { + if (!this.hass || !this._config) { + return html``; + } + + const stateObj = this.hass.states[this._config!.entity]; + + if (!stateObj) { + return html` + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} + `; + } + + return html` + + +
+ ${this.computeAttributes(stateObj).map( + (item) => html` +
+
+ +
+
+ ${stateObj.attributes[item]} +
+
+ ${stateObj.attributes.unit_of_measurement_dict[item] || ""} +
+
+ ` + )} +
+
+ `; + } + + static get styles(): CSSResult { + return css` + .banner { + display: flex; + align-items: flex-end; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + padding-top: 12px; + } + + .has-plant-image .banner { + padding-top: 30%; + } + + .header { + /* start paper-font-headline style */ + font-family: "Roboto", "Noto", sans-serif; + -webkit-font-smoothing: antialiased; /* OS X subpixel AA bleed bug */ + text-rendering: optimizeLegibility; + font-size: 24px; + font-weight: 400; + letter-spacing: -0.012em; + /* end paper-font-headline style */ + + line-height: 40px; + padding: 8px 16px; + } + + .has-plant-image .header { + font-size: 16px; + font-weight: 500; + line-height: 16px; + padding: 16px; + color: white; + width: 100%; + background: rgba(0, 0, 0, var(--dark-secondary-opacity)); + } + + .content { + display: flex; + justify-content: space-between; + padding: 16px 32px 24px 32px; + } + + .has-plant-image .content { + padding-bottom: 16px; + } + + ha-icon { + color: var(--paper-item-icon-color); + margin-bottom: 8px; + } + + .attributes { + cursor: pointer; + } + + .attributes div { + text-align: center; + } + + .problem { + color: var(--google-red-500); + font-weight: bold; + } + + .uom { + color: var(--secondary-text-color); + } + `; + } + + private computeAttributes(stateObj: HassEntity): string[] { + return Object.keys(SENSORS).filter((key) => key in stateObj.attributes); + } + + private computeIcon(attr: string, batLvl: number): string { + const icon = SENSORS[attr]; + if (attr === "battery") { + if (batLvl <= 5) { + return `${icon}-alert`; + } + if (batLvl < 95) { + return `${icon}-${Math.round(batLvl / 10 - 0.01) * 10}`; + } + } + return icon; + } + + private _handleMoreInfo(ev: Event): void { + const target = ev.currentTarget! as PlantAttributeTarget; + const stateObj = this.hass!.states[this._config!.entity]; + + if (target.value) { + fireEvent(this, "hass-more-info", { + entityId: stateObj.attributes.sensors[target.value], + }); + } + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-plant-status-card": HuiPlantStatusCard; + } +}