From 6312035032851036d2c5b8be5e7419be60f6ee9f Mon Sep 17 00:00:00 2001 From: Kendell R Date: Sun, 3 Oct 2021 15:08:46 -0700 Subject: [PATCH] Update the laundry card (#220) * Update the laundry card * Delete cardpic.png --- README.md | 182 ++++++++++++++--------------------------- washerpics/cardpic.png | Bin 12254 -> 0 bytes 2 files changed, 61 insertions(+), 121 deletions(-) delete mode 100644 washerpics/cardpic.png diff --git a/README.md b/README.md index 0b8701e0..16bd2696 100644 --- a/README.md +++ b/README.md @@ -181,151 +181,91 @@ Note: When something doesn't apply and/or is off, it may have a `-` as its value service: notify.notify ``` Substitute "dry" and "dryer" for "wet" and "washer" if you want to use with a washer. -- Custom card for dryer and washer (![Screenshot of laundry card](/washerpics/cardpic.png)) +- Custom card for dryer and washer (![Screenshot of laundry card](https://user-images.githubusercontent.com/10727862/135772833-de1a555a-3a88-4319-a82c-33dbe80fa4c5.png))
Hidden, click to expand Put this file in `/config/www/laundry.js`, and add a custom resource in **HA UI** > **Sidebar** > **Config** > **Dashboards** > **Resources** > **Plus** > **Add `/local/laundry.js`**. ```js -// card-tools for more-info. MIT license (This isn't a substantial portion) -function lovelace_view() { - var root = document.querySelector("hc-main"); - if(root) { - root = root && root.shadowRoot; - root = root && root.querySelector("hc-lovelace"); - root = root && root.shadowRoot; - root = root && root.querySelector("hui-view") || root.querySelector("hui-panel-view"); - return root; - } - root = document.querySelector("home-assistant"); - root = root && root.shadowRoot; - root = root && root.querySelector("home-assistant-main"); - root = root && root.shadowRoot; - root = root && root.querySelector("app-drawer-layout partial-panel-resolver"); - root = root && root.shadowRoot || root; - root = root && root.querySelector("ha-panel-lovelace"); - root = root && root.shadowRoot; - root = root && root.querySelector("hui-root"); - root = root && root.shadowRoot; - root = root && root.querySelector("ha-app-layout #view"); - root = root && root.firstElementChild; - return root; -} -function fireEvent(ev, detail, entity=null) { - ev = new Event(ev, { - bubbles: true, - cancelable: false, - composed: true, - }); - ev.detail = detail || {}; - if(entity) { - entity.dispatchEvent(ev); - } else { - var root = lovelace_view(); - if (root) root.dispatchEvent(ev); - } -} -function moreInfo(entity, large=false) { - const root = document.querySelector("hc-main") || document.querySelector("home-assistant"); - fireEvent("hass-more-info", {entityId: entity}, root); - const el = root._moreInfoEl; - el.large = large; - return el; -} -class LgLaundryCard extends HTMLElement { +class LaundryCard extends HTMLElement { + // Whenever states are updated set hass(hass) { const entityId = this.config.entity; const state = hass.states[entityId]; - if (!state) { - throw new Error('Entity not found. Maybe check to make sure it exists.'); - } - const stateStr = state ? state.state : 'unavailable'; - const friendlyName = state.attributes.friendly_name; - const friendlyNameStr = friendlyName ? " " + friendlyName : ""; - const courseName = state.attributes.current_course; - const courseNameStr = courseName ? " " + courseName : "an unknown cycle"; - const stageName = state.attributes.run_state; - const stageNameStr = stageName ? " " + stageName : "unknown"; - const iconName = state.attributes.icon; - const iconNameStr = iconName ? iconName : ""; - const remainTime = state.attributes.remain_time; - const remainTimeStr = remainTime ? remainTime : "unknown"; - const totalTime = state.attributes.initial_time; - const totalTimeStr = totalTime ? totalTime : "unknown"; - var worked; - var percentDone; - try { - const minRemain = (parseInt(remainTimeStr.split(":")[0]) * 60) + parseInt(remainTimeStr.split(":")[1]); - const minTotal = (parseInt(totalTimeStr.split(":")[0]) * 60) + parseInt(totalTimeStr.split(":")[1]); - percentDone = String(Math.round((minTotal - minRemain) / minTotal * 100)) + "%"; - worked = !isNaN(Math.round((minTotal - minRemain) / minTotal * 100)); - } catch(err) { - console.log(err); - worked = false; - } + // Set data definitions + const friendlyName = state.attributes["friendly_name"] || state.entity_id; + const icon = state.attributes["icon"]; if (!this.content) { - this.contenta = document.createElement('a'); - this.contenta.href = "#"; - this.contenta.style.textDecoration = "unset"; - this.contenta.style.color = "unset"; - function laundryinfo() { - window.history.pushState({}, "", window.location.href.split("#")[0]); - moreInfo(this.entityId); - } - this.contenta.onclick = laundryinfo.bind({entityId: entityId}); - this.content = document.createElement('div'); - this.content.style.padding = '0 16px 16px'; - this.content.style.display = 'flex'; - const card = document.createElement('ha-card'); - card.header = friendlyNameStr; - this.contenta.appendChild(card); - card.appendChild(this.content); - this.appendChild(this.contenta); + this.innerHTML = ` + +
+ + +
+
+ `; + this.querySelector(".main").style.display = "grid"; + this.querySelector(".main").style.gridTemplateColumns = "33% 66%"; + this.querySelector("ha-icon").style.setProperty("--mdc-icon-size", "100%"); } - var conthtml = ''; - conthtml = ` - -
${friendlyNameStr} is currently ${stateStr}. - `; - if (stateStr == 'on') { - conthtml += ` -
The ${courseNameStr} progress is ${stageNameStr}. -
There's ${remainTimeStr} remaining out of ${totalTimeStr} total. - `; - if (worked) { - conthtml += ` -
-
-
- ${percentDone} -
-
-
- `; - conthtml = conthtml.replace("8px 9px 12px 5px", "16px 9px 12px 5px"); - } else { - conthtml += ""; - } + if (state.state == "on") { + const totalTime = state.attributes["initial_time"]; + const remainTime = state.attributes["remain_time"]; + const totalMinutes = (parseInt(totalTime.split(":")[0]) * 60) + parseInt(totalTime.split(":")[1]); + const remainMinutes = (parseInt(remainTime.split(":")[0]) * 60) + parseInt(remainTime.split(":")[1]); + this.querySelector("ha-icon").style.color = "var(--paper-item-icon-active-color)"; + this.querySelector("span").innerHTML = ` +${friendlyName} is running ${state.attributes["current_course"]}
+Currently ${state.attributes["run_state"]}
+${state.attributes["initial_time"]} total, ${state.attributes["remain_time"]} to go +
+
+
+ 50% +
+`; + this.querySelector(".progress-wrapper").style.backgroundColor = "var(--paper-item-icon-color)"; + this.querySelector(".progress").style.backgroundColor = "var(--paper-item-icon-active-color)"; + this.querySelector(".progress").style.width = (totalMinutes - remainMinutes) / totalMinutes * 100 + "%"; + this.querySelector(".progress-wrapper span").innerHTML = Math.round((totalMinutes - remainMinutes) / totalMinutes * 100) + "%"; } else { - conthtml += ""; + this.querySelector("ha-icon").style.color = "var(--paper-item-icon-color)"; + this.querySelector("span").innerHTML = `${friendlyName} is off`; } - this.content.innerHTML = conthtml; } + + // On updated config setConfig(config) { - if (!config.entity) { - throw new Error('You need to define a laundry entity'); + const states = document.querySelector("home-assistant").hass.states; + if (!config.entity || !states[config.entity] || !states[config.entity].state) { + throw new Error("You need to define an valid entity (eg sensor.my_washing_machine)"); } this.config = config; } + + // HA card size to distribute cards across columns, 50px getCardSize() { return 3; } + + // Return default config static getStubConfig() { + for (var state of Object.values(document.querySelector("home-assistant").hass.states)) { + if (state.attributes["run_state"] !== undefined) { + return { entity: state.entity_id }; + } + } return { entity: "sensor.my_washing_machine" }; } } -customElements.define('lg-laundry-card', LgLaundryCard); -window.customCards.push({type: "lg-laundry-card", name: "LG laundry card", description: "Card for LG laundry machines."}); +customElements.define('laundry-card', LaundryCard); +window.customCards.push( + { + type: "laundry-card", + name: "Laundry Card", + preview: true + } +); ``` Lovelace: diff --git a/washerpics/cardpic.png b/washerpics/cardpic.png deleted file mode 100644 index 60b29bf86781180a3463dfe4af74e45cf5bebaa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12254 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 Ki7GLp;Qs-9OsE0?