diff --git a/dist/rpi-monitor-card.js b/dist/rpi-monitor-card.js index 86eebde..8fe71e6 100644 --- a/dist/rpi-monitor-card.js +++ b/dist/rpi-monitor-card.js @@ -1,56 +1,56 @@ -function t(t,e,i,o){var s,n=arguments.length,r=n<3?e:null===o?o=Object.getOwnPropertyDescriptor(e,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,i,o);else for(var a=t.length-1;a>=0;a--)(s=t[a])&&(r=(n<3?s(r):n>3?s(e,i,r):s(e,i))||r);return n>3&&r&&Object.defineProperty(e,i,r),r +function t(t,e,o,i){var s,n=arguments.length,r=n<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,o):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,o,i);else for(var a=t.length-1;a>=0;a--)(s=t[a])&&(r=(n<3?s(r):n>3?s(e,o,r):s(e,o))||r);return n>3&&r&&Object.defineProperty(e,o,r),r /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */}const e=window,i=e.ShadowRoot&&(void 0===e.ShadyCSS||e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,o=Symbol(),s=new WeakMap;class n{constructor(t,e,i){if(this._$cssResult$=!0,i!==o)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const e=this.t;if(i&&void 0===t){const i=void 0!==e&&1===e.length;i&&(t=s.get(e)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),i&&s.set(e,t))}return t}toString(){return this.cssText}}const r=(t,...e)=>{const i=1===t.length?t[0]:e.reduce(((e,i,o)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+t[o+1]),t[0]);return new n(i,t,o)},a=i?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return(t=>new n("string"==typeof t?t:t+"",void 0,o))(e)})(t):t + */}const e=window,o=e.ShadowRoot&&(void 0===e.ShadyCSS||e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),s=new WeakMap;class n{constructor(t,e,o){if(this._$cssResult$=!0,o!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const e=this.t;if(o&&void 0===t){const o=void 0!==e&&1===e.length;o&&(t=s.get(e)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),o&&s.set(e,t))}return t}toString(){return this.cssText}}const r=(t,...e)=>{const o=1===t.length?t[0]:e.reduce(((e,o,i)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(o)+t[i+1]),t[0]);return new n(o,t,i)},a=o?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const o of t.cssRules)e+=o.cssText;return(t=>new n("string"==typeof t?t:t+"",void 0,i))(e)})(t):t /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */;var l;const c=window,h=c.trustedTypes,d=h?h.emptyScript:"",u=c.reactiveElementPolyfillSupport,p={toAttribute(t,e){switch(e){case Boolean:t=t?d:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let i=t;switch(e){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},m=(t,e)=>e!==t&&(e==e||t==t),_={attribute:!0,type:String,converter:p,reflect:!1,hasChanged:m};class f extends HTMLElement{constructor(){super(),this._$Ei=new Map,this.isUpdatePending=!1,this.hasUpdated=!1,this._$El=null,this.u()}static addInitializer(t){var e;this.finalize(),(null!==(e=this.h)&&void 0!==e?e:this.h=[]).push(t)}static get observedAttributes(){this.finalize();const t=[];return this.elementProperties.forEach(((e,i)=>{const o=this._$Ep(i,e);void 0!==o&&(this._$Ev.set(o,i),t.push(o))})),t}static createProperty(t,e=_){if(e.state&&(e.attribute=!1),this.finalize(),this.elementProperties.set(t,e),!e.noAccessor&&!this.prototype.hasOwnProperty(t)){const i="symbol"==typeof t?Symbol():"__"+t,o=this.getPropertyDescriptor(t,i,e);void 0!==o&&Object.defineProperty(this.prototype,t,o)}}static getPropertyDescriptor(t,e,i){return{get(){return this[e]},set(o){const s=this[t];this[e]=o,this.requestUpdate(t,s,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)||_}static finalize(){if(this.hasOwnProperty("finalized"))return!1;this.finalized=!0;const t=Object.getPrototypeOf(this);if(t.finalize(),void 0!==t.h&&(this.h=[...t.h]),this.elementProperties=new Map(t.elementProperties),this._$Ev=new Map,this.hasOwnProperty("properties")){const t=this.properties,e=[...Object.getOwnPropertyNames(t),...Object.getOwnPropertySymbols(t)];for(const i of e)this.createProperty(i,t[i])}return this.elementStyles=this.finalizeStyles(this.styles),!0}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const t of i)e.unshift(a(t))}else void 0!==t&&e.push(a(t));return e}static _$Ep(t,e){const i=e.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}u(){var t;this._$E_=new Promise((t=>this.enableUpdating=t)),this._$AL=new Map,this._$Eg(),this.requestUpdate(),null===(t=this.constructor.h)||void 0===t||t.forEach((t=>t(this)))}addController(t){var e,i;(null!==(e=this._$ES)&&void 0!==e?e:this._$ES=[]).push(t),void 0!==this.renderRoot&&this.isConnected&&(null===(i=t.hostConnected)||void 0===i||i.call(t))}removeController(t){var e;null===(e=this._$ES)||void 0===e||e.splice(this._$ES.indexOf(t)>>>0,1)}_$Eg(){this.constructor.elementProperties.forEach(((t,e)=>{this.hasOwnProperty(e)&&(this._$Ei.set(e,this[e]),delete this[e])}))}createRenderRoot(){var t;const o=null!==(t=this.shadowRoot)&&void 0!==t?t:this.attachShadow(this.constructor.shadowRootOptions);return((t,o)=>{i?t.adoptedStyleSheets=o.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet)):o.forEach((i=>{const o=document.createElement("style"),s=e.litNonce;void 0!==s&&o.setAttribute("nonce",s),o.textContent=i.cssText,t.appendChild(o)}))})(o,this.constructor.elementStyles),o}connectedCallback(){var t;void 0===this.renderRoot&&(this.renderRoot=this.createRenderRoot()),this.enableUpdating(!0),null===(t=this._$ES)||void 0===t||t.forEach((t=>{var e;return null===(e=t.hostConnected)||void 0===e?void 0:e.call(t)}))}enableUpdating(t){}disconnectedCallback(){var t;null===(t=this._$ES)||void 0===t||t.forEach((t=>{var e;return null===(e=t.hostDisconnected)||void 0===e?void 0:e.call(t)}))}attributeChangedCallback(t,e,i){this._$AK(t,i)}_$EO(t,e,i=_){var o;const s=this.constructor._$Ep(t,i);if(void 0!==s&&!0===i.reflect){const n=(void 0!==(null===(o=i.converter)||void 0===o?void 0:o.toAttribute)?i.converter:p).toAttribute(e,i.type);this._$El=t,null==n?this.removeAttribute(s):this.setAttribute(s,n),this._$El=null}}_$AK(t,e){var i;const o=this.constructor,s=o._$Ev.get(t);if(void 0!==s&&this._$El!==s){const t=o.getPropertyOptions(s),n="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==(null===(i=t.converter)||void 0===i?void 0:i.fromAttribute)?t.converter:p;this._$El=s,this[s]=n.fromAttribute(e,t.type),this._$El=null}}requestUpdate(t,e,i){let o=!0;void 0!==t&&(((i=i||this.constructor.getPropertyOptions(t)).hasChanged||m)(this[t],e)?(this._$AL.has(t)||this._$AL.set(t,e),!0===i.reflect&&this._$El!==t&&(void 0===this._$EC&&(this._$EC=new Map),this._$EC.set(t,i))):o=!1),!this.isUpdatePending&&o&&(this._$E_=this._$Ej())}async _$Ej(){this.isUpdatePending=!0;try{await this._$E_}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){var t;if(!this.isUpdatePending)return;this.hasUpdated,this._$Ei&&(this._$Ei.forEach(((t,e)=>this[e]=t)),this._$Ei=void 0);let e=!1;const i=this._$AL;try{e=this.shouldUpdate(i),e?(this.willUpdate(i),null===(t=this._$ES)||void 0===t||t.forEach((t=>{var e;return null===(e=t.hostUpdate)||void 0===e?void 0:e.call(t)})),this.update(i)):this._$Ek()}catch(t){throw e=!1,this._$Ek(),t}e&&this._$AE(i)}willUpdate(t){}_$AE(t){var e;null===(e=this._$ES)||void 0===e||e.forEach((t=>{var e;return null===(e=t.hostUpdated)||void 0===e?void 0:e.call(t)})),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$Ek(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$E_}shouldUpdate(t){return!0}update(t){void 0!==this._$EC&&(this._$EC.forEach(((t,e)=>this._$EO(e,this[e],t))),this._$EC=void 0),this._$Ek()}updated(t){}firstUpdated(t){}} + */;var l;const c=window,h=c.trustedTypes,d=h?h.emptyScript:"",u=c.reactiveElementPolyfillSupport,p={toAttribute(t,e){switch(e){case Boolean:t=t?d:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let o=t;switch(e){case Boolean:o=null!==t;break;case Number:o=null===t?null:Number(t);break;case Object:case Array:try{o=JSON.parse(t)}catch(t){o=null}}return o}},_=(t,e)=>e!==t&&(e==e||t==t),m={attribute:!0,type:String,converter:p,reflect:!1,hasChanged:_};class g extends HTMLElement{constructor(){super(),this._$Ei=new Map,this.isUpdatePending=!1,this.hasUpdated=!1,this._$El=null,this.u()}static addInitializer(t){var e;this.finalize(),(null!==(e=this.h)&&void 0!==e?e:this.h=[]).push(t)}static get observedAttributes(){this.finalize();const t=[];return this.elementProperties.forEach(((e,o)=>{const i=this._$Ep(o,e);void 0!==i&&(this._$Ev.set(i,o),t.push(i))})),t}static createProperty(t,e=m){if(e.state&&(e.attribute=!1),this.finalize(),this.elementProperties.set(t,e),!e.noAccessor&&!this.prototype.hasOwnProperty(t)){const o="symbol"==typeof t?Symbol():"__"+t,i=this.getPropertyDescriptor(t,o,e);void 0!==i&&Object.defineProperty(this.prototype,t,i)}}static getPropertyDescriptor(t,e,o){return{get(){return this[e]},set(i){const s=this[t];this[e]=i,this.requestUpdate(t,s,o)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)||m}static finalize(){if(this.hasOwnProperty("finalized"))return!1;this.finalized=!0;const t=Object.getPrototypeOf(this);if(t.finalize(),void 0!==t.h&&(this.h=[...t.h]),this.elementProperties=new Map(t.elementProperties),this._$Ev=new Map,this.hasOwnProperty("properties")){const t=this.properties,e=[...Object.getOwnPropertyNames(t),...Object.getOwnPropertySymbols(t)];for(const o of e)this.createProperty(o,t[o])}return this.elementStyles=this.finalizeStyles(this.styles),!0}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const o=new Set(t.flat(1/0).reverse());for(const t of o)e.unshift(a(t))}else void 0!==t&&e.push(a(t));return e}static _$Ep(t,e){const o=e.attribute;return!1===o?void 0:"string"==typeof o?o:"string"==typeof t?t.toLowerCase():void 0}u(){var t;this._$E_=new Promise((t=>this.enableUpdating=t)),this._$AL=new Map,this._$Eg(),this.requestUpdate(),null===(t=this.constructor.h)||void 0===t||t.forEach((t=>t(this)))}addController(t){var e,o;(null!==(e=this._$ES)&&void 0!==e?e:this._$ES=[]).push(t),void 0!==this.renderRoot&&this.isConnected&&(null===(o=t.hostConnected)||void 0===o||o.call(t))}removeController(t){var e;null===(e=this._$ES)||void 0===e||e.splice(this._$ES.indexOf(t)>>>0,1)}_$Eg(){this.constructor.elementProperties.forEach(((t,e)=>{this.hasOwnProperty(e)&&(this._$Ei.set(e,this[e]),delete this[e])}))}createRenderRoot(){var t;const i=null!==(t=this.shadowRoot)&&void 0!==t?t:this.attachShadow(this.constructor.shadowRootOptions);return((t,i)=>{o?t.adoptedStyleSheets=i.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet)):i.forEach((o=>{const i=document.createElement("style"),s=e.litNonce;void 0!==s&&i.setAttribute("nonce",s),i.textContent=o.cssText,t.appendChild(i)}))})(i,this.constructor.elementStyles),i}connectedCallback(){var t;void 0===this.renderRoot&&(this.renderRoot=this.createRenderRoot()),this.enableUpdating(!0),null===(t=this._$ES)||void 0===t||t.forEach((t=>{var e;return null===(e=t.hostConnected)||void 0===e?void 0:e.call(t)}))}enableUpdating(t){}disconnectedCallback(){var t;null===(t=this._$ES)||void 0===t||t.forEach((t=>{var e;return null===(e=t.hostDisconnected)||void 0===e?void 0:e.call(t)}))}attributeChangedCallback(t,e,o){this._$AK(t,o)}_$EO(t,e,o=m){var i;const s=this.constructor._$Ep(t,o);if(void 0!==s&&!0===o.reflect){const n=(void 0!==(null===(i=o.converter)||void 0===i?void 0:i.toAttribute)?o.converter:p).toAttribute(e,o.type);this._$El=t,null==n?this.removeAttribute(s):this.setAttribute(s,n),this._$El=null}}_$AK(t,e){var o;const i=this.constructor,s=i._$Ev.get(t);if(void 0!==s&&this._$El!==s){const t=i.getPropertyOptions(s),n="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==(null===(o=t.converter)||void 0===o?void 0:o.fromAttribute)?t.converter:p;this._$El=s,this[s]=n.fromAttribute(e,t.type),this._$El=null}}requestUpdate(t,e,o){let i=!0;void 0!==t&&(((o=o||this.constructor.getPropertyOptions(t)).hasChanged||_)(this[t],e)?(this._$AL.has(t)||this._$AL.set(t,e),!0===o.reflect&&this._$El!==t&&(void 0===this._$EC&&(this._$EC=new Map),this._$EC.set(t,o))):i=!1),!this.isUpdatePending&&i&&(this._$E_=this._$Ej())}async _$Ej(){this.isUpdatePending=!0;try{await this._$E_}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){var t;if(!this.isUpdatePending)return;this.hasUpdated,this._$Ei&&(this._$Ei.forEach(((t,e)=>this[e]=t)),this._$Ei=void 0);let e=!1;const o=this._$AL;try{e=this.shouldUpdate(o),e?(this.willUpdate(o),null===(t=this._$ES)||void 0===t||t.forEach((t=>{var e;return null===(e=t.hostUpdate)||void 0===e?void 0:e.call(t)})),this.update(o)):this._$Ek()}catch(t){throw e=!1,this._$Ek(),t}e&&this._$AE(o)}willUpdate(t){}_$AE(t){var e;null===(e=this._$ES)||void 0===e||e.forEach((t=>{var e;return null===(e=t.hostUpdated)||void 0===e?void 0:e.call(t)})),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$Ek(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$E_}shouldUpdate(t){return!0}update(t){void 0!==this._$EC&&(this._$EC.forEach(((t,e)=>this._$EO(e,this[e],t))),this._$EC=void 0),this._$Ek()}updated(t){}firstUpdated(t){}} /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -var g;f.finalized=!0,f.elementProperties=new Map,f.elementStyles=[],f.shadowRootOptions={mode:"open"},null==u||u({ReactiveElement:f}),(null!==(l=c.reactiveElementVersions)&&void 0!==l?l:c.reactiveElementVersions=[]).push("1.6.0");const v=window,y=v.trustedTypes,b=y?y.createPolicy("lit-html",{createHTML:t=>t}):void 0,$=`lit$${(Math.random()+"").slice(9)}$`,w="?"+$,C=`<${w}>`,A=document,I=(t="")=>A.createComment(t),S=t=>null===t||"object"!=typeof t&&"function"!=typeof t,E=Array.isArray,x=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,T=/-->/g,k=/>/g,U=RegExp(">|[ \t\n\f\r](?:([^\\s\"'>=/]+)([ \t\n\f\r]*=[ \t\n\f\r]*(?:[^ \t\n\f\r\"'`<>=]|(\"|')|))|$)","g"),D=/'/g,R=/"/g,M=/^(?:script|style|textarea|title)$/i,F=(t=>(e,...i)=>({_$litType$:t,strings:e,values:i}))(1),P=Symbol.for("lit-noChange"),O=Symbol.for("lit-nothing"),N=new WeakMap,V=A.createTreeWalker(A,129,null,!1);class H{constructor({strings:t,_$litType$:e},i){let o;this.parts=[];let s=0,n=0;const r=t.length-1,a=this.parts,[l,c]=((t,e)=>{const i=t.length-1,o=[];let s,n=2===e?"":"",r=x;for(let e=0;e"===l[0]?(r=null!=s?s:x,c=-1):void 0===l[1]?c=-2:(c=r.lastIndex-l[2].length,a=l[1],r=void 0===l[3]?U:'"'===l[3]?R:D):r===R||r===D?r=U:r===T||r===k?r=x:(r=U,s=void 0);const d=r===U&&t[e+1].startsWith("/>")?" ":"";n+=r===x?i+C:c>=0?(o.push(a),i.slice(0,c)+"$lit$"+i.slice(c)+$+d):i+$+(-2===c?(o.push(void 0),e):d)}const a=n+(t[i]||"")+(2===e?"":"");if(!Array.isArray(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return[void 0!==b?b.createHTML(a):a,o]})(t,e);if(this.el=H.createElement(l,i),V.currentNode=this.el.content,2===e){const t=this.el.content,e=t.firstChild;e.remove(),t.append(...e.childNodes)}for(;null!==(o=V.nextNode())&&a.length0){o.textContent=y?y.emptyScript:"";for(let i=0;iE(t)||"function"==typeof(null==t?void 0:t[Symbol.iterator]))(t)?this.k(t):this.g(t)}O(t,e=this._$AB){return this._$AA.parentNode.insertBefore(t,e)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}g(t){this._$AH!==O&&S(this._$AH)?this._$AA.nextSibling.data=t:this.T(A.createTextNode(t)),this._$AH=t}$(t){var e;const{values:i,_$litType$:o}=t,s="number"==typeof o?this._$AC(t):(void 0===o.el&&(o.el=H.createElement(o.h,this.options)),o);if((null===(e=this._$AH)||void 0===e?void 0:e._$AD)===s)this._$AH.p(i);else{const t=new L(s,this),e=t.v(this.options);t.p(i),this.T(e),this._$AH=t}}_$AC(t){let e=N.get(t.strings);return void 0===e&&N.set(t.strings,e=new H(t)),e}k(t){E(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let i,o=0;for(const s of t)o===e.length?e.push(i=new j(this.O(I()),this.O(I()),this,this.options)):i=e[o],i._$AI(s),o++;o2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=O}get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}_$AI(t,e=this,i,o){const s=this.strings;let n=!1;if(void 0===s)t=z(this,t,e,0),n=!S(t)||t!==this._$AH&&t!==P,n&&(this._$AH=t);else{const o=t;let r,a;for(t=s[0],r=0;rt}):void 0,w=`lit$${(Math.random()+"").slice(9)}$`,b="?"+w,A=`<${b}>`,C=document,E=(t="")=>C.createComment(t),x=t=>null===t||"object"!=typeof t&&"function"!=typeof t,S=Array.isArray,U=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,I=/-->/g,T=/>/g,D=RegExp(">|[ \t\n\f\r](?:([^\\s\"'>=/]+)([ \t\n\f\r]*=[ \t\n\f\r]*(?:[^ \t\n\f\r\"'`<>=]|(\"|')|))|$)","g"),P=/'/g,k=/"/g,O=/^(?:script|style|textarea|title)$/i,M=(t=>(e,...o)=>({_$litType$:t,strings:e,values:o}))(1),R=Symbol.for("lit-noChange"),N=Symbol.for("lit-nothing"),V=new WeakMap,H=C.createTreeWalker(C,129,null,!1),F=(t,e)=>{const o=t.length-1,i=[];let s,n=2===e?"":"",r=U;for(let e=0;e"===l[0]?(r=null!=s?s:U,c=-1):void 0===l[1]?c=-2:(c=r.lastIndex-l[2].length,a=l[1],r=void 0===l[3]?D:'"'===l[3]?k:P):r===k||r===P?r=D:r===I||r===T?r=U:(r=D,s=void 0);const d=r===D&&t[e+1].startsWith("/>")?" ":"";n+=r===U?o+A:c>=0?(i.push(a),o.slice(0,c)+"$lit$"+o.slice(c)+w+d):o+w+(-2===c?(i.push(void 0),e):d)}const a=n+(t[o]||"")+(2===e?"":"");if(!Array.isArray(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return[void 0!==$?$.createHTML(a):a,i]};class z{constructor({strings:t,_$litType$:e},o){let i;this.parts=[];let s=0,n=0;const r=t.length-1,a=this.parts,[l,c]=F(t,e);if(this.el=z.createElement(l,o),H.currentNode=this.el.content,2===e){const t=this.el.content,e=t.firstChild;e.remove(),t.append(...e.childNodes)}for(;null!==(i=H.nextNode())&&a.length0){i.textContent=y?y.emptyScript:"";for(let o=0;oS(t)||"function"==typeof(null==t?void 0:t[Symbol.iterator]))(t)?this.k(t):this.g(t)}O(t,e=this._$AB){return this._$AA.parentNode.insertBefore(t,e)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}g(t){this._$AH!==N&&x(this._$AH)?this._$AA.nextSibling.data=t:this.T(C.createTextNode(t)),this._$AH=t}$(t){var e;const{values:o,_$litType$:i}=t,s="number"==typeof i?this._$AC(t):(void 0===i.el&&(i.el=z.createElement(i.h,this.options)),i);if((null===(e=this._$AH)||void 0===e?void 0:e._$AD)===s)this._$AH.p(o);else{const t=new j(s,this),e=t.v(this.options);t.p(o),this.T(e),this._$AH=t}}_$AC(t){let e=V.get(t.strings);return void 0===e&&V.set(t.strings,e=new z(t)),e}k(t){S(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let o,i=0;for(const s of t)i===e.length?e.push(o=new B(this.O(E()),this.O(E()),this,this.options)):o=e[i],o._$AI(s),i++;i2||""!==o[0]||""!==o[1]?(this._$AH=Array(o.length-1).fill(new String),this.strings=o):this._$AH=N}get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}_$AI(t,e=this,o,i){const s=this.strings;let n=!1;if(void 0===s)t=L(this,t,e,0),n=!x(t)||t!==this._$AH&&t!==R,n&&(this._$AH=t);else{const i=t;let r,a;for(t=s[0],r=0;r{var o,s;const n=null!==(o=null==i?void 0:i.renderBefore)&&void 0!==o?o:e;let r=n._$litPart$;if(void 0===r){const t=null!==(s=null==i?void 0:i.renderBefore)&&void 0!==s?s:null;n._$litPart$=r=new j(e.insertBefore(I(),t),t,void 0,null!=i?i:{})}return r._$AI(t),r})(e,this.renderRoot,this.renderOptions)}connectedCallback(){var t;super.connectedCallback(),null===(t=this._$Do)||void 0===t||t.setConnected(!0)}disconnectedCallback(){var t;super.disconnectedCallback(),null===(t=this._$Do)||void 0===t||t.setConnected(!1)}render(){return P}}X.finalized=!0,X._$litElement$=!0,null===(J=globalThis.litElementHydrateSupport)||void 0===J||J.call(globalThis,{LitElement:X});const tt=globalThis.litElementPolyfillSupport;null==tt||tt({LitElement:X}),(null!==(Q=globalThis.litElementVersions)&&void 0!==Q?Q:globalThis.litElementVersions=[]).push("3.2.2"); +var Z,Q;class tt extends g{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){var t,e;const o=super.createRenderRoot();return null!==(t=(e=this.renderOptions).renderBefore)&&void 0!==t||(e.renderBefore=o.firstChild),o}update(t){const e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=((t,e,o)=>{var i,s;const n=null!==(i=null==o?void 0:o.renderBefore)&&void 0!==i?i:e;let r=n._$litPart$;if(void 0===r){const t=null!==(s=null==o?void 0:o.renderBefore)&&void 0!==s?s:null;n._$litPart$=r=new B(e.insertBefore(E(),t),t,void 0,null!=o?o:{})}return r._$AI(t),r})(e,this.renderRoot,this.renderOptions)}connectedCallback(){var t;super.connectedCallback(),null===(t=this._$Do)||void 0===t||t.setConnected(!0)}disconnectedCallback(){var t;super.disconnectedCallback(),null===(t=this._$Do)||void 0===t||t.setConnected(!1)}render(){return R}}tt.finalized=!0,tt._$litElement$=!0,null===(Z=globalThis.litElementHydrateSupport)||void 0===Z||Z.call(globalThis,{LitElement:tt});const et=globalThis.litElementPolyfillSupport;null==et||et({LitElement:tt}),(null!==(Q=globalThis.litElementVersions)&&void 0!==Q?Q:globalThis.litElementVersions=[]).push("3.2.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const et=t=>e=>"function"==typeof e?((t,e)=>(customElements.define(t,e),e))(t,e):((t,e)=>{const{kind:i,elements:o}=e;return{kind:i,elements:o,finisher(e){customElements.define(t,e)}}})(t,e) +const ot=t=>e=>"function"==typeof e?((t,e)=>(customElements.define(t,e),e))(t,e):((t,e)=>{const{kind:o,elements:i}=e;return{kind:o,elements:i,finisher(e){customElements.define(t,e)}}})(t,e) /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */,it=(t,e)=>"method"===e.kind&&e.descriptor&&!("value"in e.descriptor)?{...e,finisher(i){i.createProperty(e.key,t)}}:{kind:"field",key:Symbol(),placement:"own",descriptor:{},originalKey:e.key,initializer(){"function"==typeof e.initializer&&(this[e.key]=e.initializer.call(this))},finisher(i){i.createProperty(e.key,t)}};function ot(t){return(e,i)=>void 0!==i?((t,e,i)=>{e.constructor.createProperty(i,t)})(t,e,i):it(t,e) + */,it=(t,e)=>"method"===e.kind&&e.descriptor&&!("value"in e.descriptor)?{...e,finisher(o){o.createProperty(e.key,t)}}:{kind:"field",key:Symbol(),placement:"own",descriptor:{},originalKey:e.key,initializer(){"function"==typeof e.initializer&&(this[e.key]=e.initializer.call(this))},finisher(o){o.createProperty(e.key,t)}};function st(t){return(e,o)=>void 0!==o?((t,e,o)=>{e.constructor.createProperty(o,t)})(t,e,o):it(t,e) /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */}function st(t){return ot({...t,state:!0})} + */}function nt(t){return st({...t,state:!0})} /** * @license * Copyright 2021 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */var nt;null===(nt=window.HTMLSlotElement)||void 0===nt||nt.prototype.assignedElements;var rt,at,lt=function(t,e){return ct(e).format(t)},ct=function(t){return new Intl.DateTimeFormat(t.language,{year:"numeric",month:"long",day:"numeric"})};!function(t){t.language="language",t.system="system",t.comma_decimal="comma_decimal",t.decimal_comma="decimal_comma",t.space_comma="space_comma",t.none="none"}(rt||(rt={})),function(t){t.language="language",t.system="system",t.am_pm="12",t.twenty_four="24"}(at||(at={}));var ht=function(t){if(t.time_format===at.language||t.time_format===at.system){var e=t.time_format===at.language?t.language:void 0,i=(new Date).toLocaleString(e);return i.includes("AM")||i.includes("PM")}return t.time_format===at.am_pm},dt=function(t,e){return ut(e).format(t)},ut=function(t){return new Intl.DateTimeFormat(t.language,{year:"numeric",month:"long",day:"numeric",hour:ht(t)?"numeric":"2-digit",minute:"2-digit",hour12:ht(t)})},pt=function(t,e){return mt(e).format(t)},mt=function(t){return new Intl.DateTimeFormat(t.language,{hour:"numeric",minute:"2-digit",hour12:ht(t)})};function _t(){return(_t=Object.assign||function(t){for(var e=1;e-1?t.split(".")[1].length:0;i.minimumFractionDigits=o,i.maximumFractionDigits=o}return i},yt=function(t,e,i,o){var s=void 0!==o?o:e.state;if("unknown"===s||"unavailable"===s)return t("state.default."+s);if(function(t){return!!t.attributes.unit_of_measurement||!!t.attributes.state_class}(e)){if("monetary"===e.attributes.device_class)try{return gt(s,i,{style:"currency",currency:e.attributes.unit_of_measurement})}catch(t){}return gt(s,i)+(e.attributes.unit_of_measurement?" "+e.attributes.unit_of_measurement:"")}var n=function(t){return ft(t.entity_id)}(e);if("input_datetime"===n){var r;if(void 0===o)return e.attributes.has_date&&e.attributes.has_time?(r=new Date(e.attributes.year,e.attributes.month-1,e.attributes.day,e.attributes.hour,e.attributes.minute),dt(r,i)):e.attributes.has_date?(r=new Date(e.attributes.year,e.attributes.month-1,e.attributes.day),lt(r,i)):e.attributes.has_time?((r=new Date).setHours(e.attributes.hour,e.attributes.minute),pt(r,i)):e.state;try{var a=o.split(" ");if(2===a.length)return dt(new Date(a.join("T")),i);if(1===a.length){if(o.includes("-"))return lt(new Date(o+"T00:00"),i);if(o.includes(":")){var l=new Date;return pt(new Date(l.toISOString().split("T")[0]+"T"+o),i)}}return o}catch(t){return o}}return"humidifier"===n&&"on"===s&&e.attributes.humidity?e.attributes.humidity+" %":"counter"===n||"number"===n||"input_number"===n?gt(s,i):e.attributes.device_class&&t("component."+n+".state."+e.attributes.device_class+"."+s)||t("component."+n+".state._."+s)||s},bt=["closed","locked","off"],$t=function(t,e,i,o){o=o||{},i=null==i?{}:i;var s=new Event(e,{bubbles:void 0===o.bubbles||o.bubbles,cancelable:Boolean(o.cancelable),composed:void 0===o.composed||o.composed});return s.detail=i,t.dispatchEvent(s),s},wt=function(t){$t(window,"haptic",t)},Ct=function(t,e){return function(t,e,i){void 0===i&&(i=!0);var o,s=ft(e),n="group"===s?"homeassistant":s;switch(s){case"lock":o=i?"unlock":"lock";break;case"cover":o=i?"open_cover":"close_cover";break;default:o=i?"turn_on":"turn_off"}return t.callService(n,o,{entity_id:e})}(t,e,bt.includes(t.states[e].state))},At=function(t,e,i,o){if(o||(o={action:"more-info"}),!o.confirmation||o.confirmation.exemptions&&o.confirmation.exemptions.some((function(t){return t.user===e.user.id}))||(wt("warning"),confirm(o.confirmation.text||"Are you sure you want to "+o.action+"?")))switch(o.action){case"more-info":(i.entity||i.camera_image)&&$t(t,"hass-more-info",{entityId:i.entity?i.entity:i.camera_image});break;case"navigate":o.navigation_path&&function(t,e,i){void 0===i&&(i=!1),i?history.replaceState(null,"",e):history.pushState(null,"",e),$t(window,"location-changed",{replace:i})}(0,o.navigation_path);break;case"url":o.url_path&&window.open(o.url_path);break;case"toggle":i.entity&&(Ct(e,i.entity),wt("success"));break;case"call-service":if(!o.service)return void wt("failure");var s=o.service.split(".",2);e.callService(s[0],s[1],o.service_data,o.target),wt("success");break;case"fire-dom-event":$t(t,"ll-custom",o)}};function It(t){return void 0!==t&&"none"!==t.action}const St={required:{icon:"tune",name:"Required",secondary:"Required options for this card to function",show:!0},actions:{icon:"gesture-tap-hold",name:"Actions",secondary:"Perform actions based on tapping/clicking",show:!1,options:{tap:{icon:"gesture-tap",name:"Tap",secondary:"Set the action to perform on tap",show:!1},hold:{icon:"gesture-tap-hold",name:"Hold",secondary:"Set the action to perform on hold",show:!1},double_tap:{icon:"gesture-double-tap",name:"Double Tap",secondary:"Set the action to perform on double tap",show:!1}}},appearance:{icon:"palette",name:"Appearance",secondary:"Customize the name, icon, etc",show:!1}};let Et=class extends X{constructor(){super(...arguments),this._initialized=!1}setConfig(t){this._config=t,this.loadCardHelpers()}shouldUpdate(){return this._initialized||this._initialize(),!0}get _name(){var t;return(null===(t=this._config)||void 0===t?void 0:t.name)||""}get _entity(){var t;return(null===(t=this._config)||void 0===t?void 0:t.entity)||""}get _show_warning(){var t;return(null===(t=this._config)||void 0===t?void 0:t.show_warning)||!1}get _show_error(){var t;return(null===(t=this._config)||void 0===t?void 0:t.show_error)||!1}get _tap_action(){var t;return(null===(t=this._config)||void 0===t?void 0:t.tap_action)||{action:"more-info"}}get _hold_action(){var t;return(null===(t=this._config)||void 0===t?void 0:t.hold_action)||{action:"none"}}get _double_tap_action(){var t;return(null===(t=this._config)||void 0===t?void 0:t.double_tap_action)||{action:"none"}}render(){if(!this.hass||!this._helpers)return F``;this._helpers.importMoreInfoControl("climate");const t=Object.keys(this.hass.states).filter((t=>"sun"===t.substr(0,t.indexOf("."))));return F` + */var rt,at,lt;function ct(){return(ct=Object.assign||function(t){for(var e=1;e"sun"===t.substr(0,t.indexOf("."))));return M`
- -
${St.required.name}
+ +
${mt.required.name}
-
${St.required.secondary}
+
${mt.required.secondary}
- ${St.required.show?F` + ${mt.required.show?M`
e=>"function"==typeof e?((t,e)=>(customElements.define(t,e),e))(t,e) .configValue=${"entity"} > - ${t.map((t=>F` ${t} `))} + ${t.map((t=>M` ${t} `))}
`:""}
- -
${St.actions.name}
+ +
${mt.actions.name}
-
${St.actions.secondary}
+
${mt.actions.secondary}
- ${St.actions.show?F` + ${mt.actions.show?M`
- -
${St.actions.options.tap.name}
+ +
${mt.actions.options.tap.name}
-
${St.actions.options.tap.secondary}
+
${mt.actions.options.tap.secondary}
- ${St.actions.options.tap.show?F` + ${mt.actions.options.tap.show?M`
Action Editors Coming Soon
`:""}
- -
${St.actions.options.hold.name}
+ +
${mt.actions.options.hold.name}
-
${St.actions.options.hold.secondary}
+
${mt.actions.options.hold.secondary}
- ${St.actions.options.hold.show?F` + ${mt.actions.options.hold.show?M`
Action Editors Coming Soon
`:""}
- -
${St.actions.options.double_tap.name}
+ +
${mt.actions.options.double_tap.name}
-
${St.actions.options.double_tap.secondary}
+
${mt.actions.options.double_tap.secondary}
- ${St.actions.options.double_tap.show?F` + ${mt.actions.options.double_tap.show?M`
Action Editors Coming Soon
@@ -112,12 +112,12 @@ const et=t=>e=>"function"==typeof e?((t,e)=>(customElements.define(t,e),e))(t,e) `:""}
- -
${St.appearance.name}
+ +
${mt.appearance.name}
-
${St.appearance.secondary}
+
${mt.appearance.secondary}
- ${St.appearance.show?F` + ${mt.appearance.show?M`
e=>"function"==typeof e?((t,e)=>(customElements.define(t,e),e))(t,e)
`:""}
- `}_initialize(){void 0!==this.hass&&void 0!==this._config&&void 0!==this._helpers&&(this._initialized=!0)}async loadCardHelpers(){this._helpers=await window.loadCardHelpers()}_toggleAction(t){this._toggleThing(t,St.actions.options)}_toggleOption(t){this._toggleThing(t,St)}_toggleThing(t,e){const i=!e[t.target.option].show;for(const[t]of Object.entries(e))e[t].show=!1;e[t.target.option].show=i,this._toggle=!this._toggle}_valueChanged(t){if(!this._config||!this.hass)return;const e=t.target;if(this[`_${e.configValue}`]!==e.value){if(e.configValue)if(""===e.value){const t=Object.assign({},this._config);delete t[e.configValue],this._config=t}else this._config=Object.assign(Object.assign({},this._config),{[e.configValue]:void 0!==e.checked?e.checked:e.value});$t(this,"config-changed",{config:this._config})}}static get styles(){return r` + `}_initialize(){void 0!==this.hass&&void 0!==this._config&&void 0!==this._helpers&&(this._initialized=!0)}async loadCardHelpers(){this._helpers=await window.loadCardHelpers()}_toggleAction(t){this._toggleThing(t,mt.actions.options)}_toggleOption(t){this._toggleThing(t,mt)}_toggleThing(t,e){const o=!e[t.target.option].show;for(const[t]of Object.entries(e))e[t].show=!1;e[t.target.option].show=o,this._toggle=!this._toggle}_valueChanged(t){if(!this._config||!this.hass)return;const e=t.target;if(this[`_${e.configValue}`]!==e.value){if(e.configValue)if(""===e.value){const t=Object.assign({},this._config);delete t[e.configValue],this._config=t}else this._config=Object.assign(Object.assign({},this._config),{[e.configValue]:void 0!==e.checked?e.checked:e.value});dt(this,"config-changed",{config:this._config})}}static get styles(){return r` .option { padding: 4px 0px; cursor: pointer; @@ -171,55 +171,55 @@ const et=t=>e=>"function"==typeof e?((t,e)=>(customElements.define(t,e),e))(t,e) ha-formfield { padding-bottom: 8px; } - `}};t([ot({attribute:!1})],Et.prototype,"hass",void 0),t([st()],Et.prototype,"_config",void 0),t([st()],Et.prototype,"_toggle",void 0),t([st()],Et.prototype,"_helpers",void 0),Et=t([et("rpi-monitor-card-editor")],Et);class xt{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,i){this._$Ct=t,this._$AM=e,this._$Ci=i}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}}const Tt="ontouchstart"in window||navigator.maxTouchPoints>0||navigator.maxTouchPoints>0;class kt extends HTMLElement{constructor(){super(),this.holdTime=500,this.held=!1,this.ripple=document.createElement("mwc-ripple")}connectedCallback(){Object.assign(this.style,{position:"absolute",width:Tt?"100px":"50px",height:Tt?"100px":"50px",transform:"translate(-50%, -50%)",pointerEvents:"none",zIndex:"999"}),this.appendChild(this.ripple),this.ripple.primary=!0,["touchcancel","mouseout","mouseup","touchmove","mousewheel","wheel","scroll"].forEach((t=>{document.addEventListener(t,(()=>{clearTimeout(this.timer),this.stopAnimation(),this.timer=void 0}),{passive:!0})}))}bind(t,e){if(t.actionHandler)return;t.actionHandler=!0,t.addEventListener("contextmenu",(t=>{const e=t||window.event;return e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0,e.returnValue=!1,!1}));const i=t=>{let e,i;this.held=!1,t.touches?(e=t.touches[0].pageX,i=t.touches[0].pageY):(e=t.pageX,i=t.pageY),this.timer=window.setTimeout((()=>{this.startAnimation(e,i),this.held=!0}),this.holdTime)},o=i=>{i.preventDefault(),["touchend","touchcancel"].includes(i.type)&&void 0===this.timer||(clearTimeout(this.timer),this.stopAnimation(),this.timer=void 0,this.held?$t(t,"action",{action:"hold"}):e.hasDoubleClick?"click"===i.type&&i.detail<2||!this.dblClickTimeout?this.dblClickTimeout=window.setTimeout((()=>{this.dblClickTimeout=void 0,$t(t,"action",{action:"tap"})}),250):(clearTimeout(this.dblClickTimeout),this.dblClickTimeout=void 0,$t(t,"action",{action:"double_tap"})):$t(t,"action",{action:"tap"}))};t.addEventListener("touchstart",i,{passive:!0}),t.addEventListener("touchend",o),t.addEventListener("touchcancel",o),t.addEventListener("mousedown",i,{passive:!0}),t.addEventListener("click",o),t.addEventListener("keyup",(t=>{13===t.keyCode&&o(t)}))}startAnimation(t,e){Object.assign(this.style,{left:`${t}px`,top:`${e}px`,display:null}),this.ripple.disabled=!1,this.ripple.active=!0,this.ripple.unbounded=!0}stopAnimation(){this.ripple.active=!1,this.ripple.disabled=!0,this.style.display="none"}}customElements.define("action-handler-rpi-monitor",kt);const Ut=(t,e)=>{const i=(()=>{const t=document.body;if(t.querySelector("action-handler-rpi-monitor"))return t.querySelector("action-handler-rpi-monitor");const e=document.createElement("action-handler-rpi-monitor");return t.appendChild(e),e})();i&&i.bind(t,e)},Dt=(t=>(...e)=>({_$litDirective$:t,values:e}))(class extends xt{update(t,[e]){return Ut(t.element,e),P}render(t){}}),Rt="ifaces",Mt="ux_release",Ft="last_update",Pt="up_time",Ot="fs_total_gb",Nt="fs_free_prcnt",Vt="temperature_c",Ht="show-os-parts",zt="memory_percent";var Lt={version:"Version",invalid_configuration:"Invalid configuration",show_warning:"Show Warning",show_error:"Show Error"},jt={common:Lt},Bt=Object.freeze({__proto__:null,common:Lt,default:jt}),Gt={version:"Versjon",invalid_configuration:"Ikke gyldig konfiguration",show_warning:"Vis advarsel",show_error:"Vis feil"},Kt={common:Gt},qt=Object.freeze({__proto__:null,common:Gt,default:Kt}),Wt={version:"Version",invalid_configuration:"configuración no válida",show_warning:"Mostrar advertencia",show_error:"Mostrar error"},Yt={common:Wt};const Zt={en:Bt,es:Object.freeze({__proto__:null,common:Wt,default:Yt}),nb:qt};function Jt(t,e="",i=""){const o=(localStorage.getItem("selectedLanguage")||"en").replace(/['"]+/g,"").replace("-","_");let s;try{s=t.split(".").reduce(((t,e)=>t[e]),Zt[o])}catch(e){s=t.split(".").reduce(((t,e)=>t[e]),Zt.en)}return void 0===s&&(s=t.split(".").reduce(((t,e)=>t[e]),Zt.en)),""!==e&&""!==i&&(s=s.replace(e,i)),s}console.info(`%c RPI-MONITOR-CARD \n%c ${Jt("common.version")} 1.3.1 `,"color: orange; font-weight: bold; background: black","color: white; font-weight: bold; background: dimgray"),window.customCards=window.customCards||[],window.customCards.push({type:"rpi-monitor-card",name:"RPi Monitor Card",description:"A template custom card for you to create something awesome"});let Qt=class extends X{constructor(){super(...arguments),this._cardSecondsSinceUpdate=0,this._cardUpdateString="",this._firstTime=!0,this._sensorAvailable=!1,this._updateTimerID=void 0,this._configEntityId=void 0,this._hostname="",this._showFullCard=!0,this._useTempsInC=!0,this.kREPLACE_WITH_TEMP_UNITS="replace-with-temp-units",this.kMQTT_DAEMON_RELEASE_URL="https://raw.githubusercontent.com/ironsheep/RPi-Reporter-MQTT2HA-Daemon/master/Release",this.latestDaemonVersions=["v1.7.2","v1.6.1"],this.currentDaemonVersion="",this._showDebug=!1,this._cardFullElements={"Storage Use":Nt,Storage:Ot,"Memory Use":zt,Temperature:Vt,"Up-time":Pt,Updated:Ft,OS:Ht,Model:"rpi_model",Interfaces:Rt},this._cardFullIconNames={Storage:"sd","Storage Use":"file-percent","Memory Use":"memory",Temperature:"thermometer","Up-time":"clock-check-outline",Updated:"update",OS:"linux",Model:"raspberry-pi",Interfaces:""},this.kClassIdIconFSAvail="ico-fs-percent",this.kClassIdIconFSTotal="ico-fs-total",this.kClassIdIconSysTemp="ico-sys-temp",this.kClassIdIconUptime="ico-up-time",this.kClassIdIconUpdated="ico-last-update",this.kClassIdIconOS="ico-*nix",this.kClassIdIconRPiModel="ico-rpi-model",this.kClassIdIconInterfaces="ico-rpi-ifaces",this.kClassIdIconMemoryUsage="ico-memory-percent",this.kClassIdFSAvail="fs-percent",this.kClassIdFSTotal="fs-total",this.kClassIdSysTemp="sys-temp",this.kClassIdUptime="up-time",this.kClassIdUpdated="last-update",this.kClassIdOS="*nix",this.kClassIdRPiModel="rpi-model",this.kClassIdInterfaces="rpi-ifaces",this.kClassIdMemoryUsage="memory-percent",this.kClassIdTempScale="sys-temp-scale",this._cardFullCssIDs={"Storage Use":this.kClassIdFSAvail,Storage:this.kClassIdFSTotal,"Memory Use":this.kClassIdMemoryUsage,Temperature:this.kClassIdSysTemp,"Up-time":this.kClassIdUptime,Updated:this.kClassIdUpdated,OS:this.kClassIdOS,Model:this.kClassIdRPiModel,Interfaces:this.kClassIdInterfaces},this._cardFullIconCssIDs={"Storage Use":this.kClassIdIconFSAvail,Storage:this.kClassIdIconFSTotal,"Memory Use":this.kClassIdIconMemoryUsage,"Up-time":this.kClassIdIconUptime,Updated:this.kClassIdIconUpdated,Temperature:this.kClassIdIconSysTemp,OS:this.kClassIdIconOS,Model:this.kClassIdIconRPiModel,Interfaces:this.kClassIdIconInterfaces},this._cardGlanceElements={"%":Nt,GB:Ot,Mem:zt,"replace-with-temp-units":Vt,UpTime:Pt,Upd:Ft},this._cardGlanceIconNames={"%":"file-percent",GB:"sd",Mem:"memory","replace-with-temp-units":"thermometer",UpTime:"clock-check-outline",Upd:"update"},this._cardGlanceCssIDs={"%":this.kClassIdFSAvail,GB:this.kClassIdFSTotal,Mem:this.kClassIdMemoryUsage,"replace-with-temp-units":this.kClassIdSysTemp,UpTime:this.kClassIdUptime,Upd:this.kClassIdUpdated},this._cardGlanceIconCssIDs={"%":this.kClassIdIconFSAvail,GB:this.kClassIdIconFSTotal,Mem:this.kClassIdIconMemoryUsage,"replace-with-temp-units":this.kClassIdIconSysTemp,UpTime:this.kClassIdIconUptime,Upd:this.kClassIdIconUpdated},this._circleIconsValueByName={"circle-outline":0,"circle-slice-1":13,"circle-slice-2":25,"circle-slice-3":38,"circle-slice-4":50,"circle-slice-5":63,"circle-slice-6":75,"circle-slice-7":88,"circle-slice-8":100},this._colorUsedSpaceDefault=[{color:"default",from:0,to:59},{color:"yellow",from:60,to:84},{color:"red",from:85,to:100}],this._colorTemperatureDefault=[{color:"default",from:0,to:59},{color:"yellow",from:60,to:79},{color:"red",from:85,to:100}],this._colorReportPeriodsAgoDefault=[{color:"default",from:0,to:3},{color:"orange",from:4,to:5},{color:"red",from:6,to:100}],this._colorUsedMemoryDefault=[{color:"red",from:75,to:100},{color:"yellow",from:61,to:74},{color:"default",from:0,to:60}],this._colorReleaseDefault=[{color:"red",os:"stretch"},{color:"red",os:"jessie"},{color:"red",os:"wheezy"}]}static async getConfigElement(){return console.log("- getConfigElement()"),document.createElement("rpi-monitor-card-editor")}static getStubConfig(){return{}}setConfig(t){if(null!=t.show_debug&&(this._showDebug=t.show_debug||this._showDebug),this._showDebug&&console.log("- setConfig()"),!t||t.show_error)throw new Error(Jt("common.invalid_configuration"));if(null!=t.card_style){const e=t.card_style.toLocaleLowerCase();if("full"!=e&&"glance"!=e)throw console.log("Invalid configuration. INVALID card_style = ["+t.card_style+"]"),new Error("Illegal card_style: value (card_style: "+t.card_style+") must be [full or glance]");this._showFullCard="full"===t.card_style.toLocaleLowerCase()}if(null!=t.temp_scale){const e=t.temp_scale.toLocaleLowerCase();if("c"!=e&&"f"!=e)throw console.log("Invalid configuration. INVALID temp_scale = ["+t.temp_scale+"]"),new Error("Illegal temp_scale: value (temp_scale: "+t.temp_scale+") must be [F or C]");this._useTempsInC="c"===t.temp_scale.toLocaleLowerCase()}if(!t.entity)throw console.log("Invalid configuration. If no entity provided, you'll need to provide a remote entity"),new Error("You need to associate an entity");t.test_gui&&function(){var t=document.querySelector("home-assistant");if(t=(t=(t=(t=(t=(t=(t=(t=t&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root")){var e=t.lovelace;return e.current_view=t.___curView,e}return null}().setEditMode(!0),this._config=Object.assign({},t),console.log("- config=["+this._config+"]"),this._configEntityId=null!=this._config.entity?this._config.entity:void 0,this._updateSensorAvailability()}shouldUpdate(t){if(0==this._hostname.length||this._hostname==this._configEntityId){const t=this._getAttributeValueForKey("host_name");t&&t.length>0?this._hostname=t:this._hostname=this._configEntityId?this._configEntityId:"-not-set-"}let e=!0;if(this._updateSensorAvailability(),t.has("_config"))e=!0;else if(this.hass&&this._config){const i=t.get("hass");i&&this._configEntityId&&(e=i.states[this._configEntityId]!==this.hass.states[this._configEntityId])}return e}render(){if(this._showDebug&&console.log("- render("+this._hostname+")"),this._config.show_warning)return this.showWarning(Jt("common.show_warning"));if(this._config.show_error)return this.showError(Jt("common.show_error"));if(this._configEntityId&&!this._sensorAvailable){const t="Entity Unavailable: "+this._configEntityId;return this.showWarning(t)}const t=this._configEntityId?this.hass.states[this._configEntityId]:void 0;if(!this._configEntityId&&!t)return this.showWarning("Entity Unavailable");if(0==this._sensorAvailable)return void console.log("?? Render w/o sensor!! ("+this._hostname+")");let e=F``;this._firstTime&&(this._showDebug&&console.log("- stateObj: ["+t+"]"),this._startCardRefreshTimer(),this._showDebug&&console.log("- 1st-time _config: ["+this._config+"]"),this._firstTime=!1);const i=null==this._config.show_os_age||this._config.show_os_age,o=null==this._config.show_update_age||this._config.show_update_age,s=null==this._config.show_daemon_upd||this._config.show_daemon_upd,n=null==this._config.show_title||this._config.show_title;if(s){const t=this._getAttributeValueForKey("reporter").split(" ");this.currentDaemonVersion=t.length>1?t[1]:"";const e=this._getAttributeValueForKey("reporter_releases");if(e&&e.length>0&&"NOT-LOADED"!=e){const t=e.split(",");this.latestDaemonVersions=t}}const r=this._getAttributeValueForKey("fqdn"),a=1==i?this._getAttributeValueForKey(Mt):"",l=s?this._computeDaemonUpdMessage(this.currentDaemonVersion):"",c=1==o?this._cardUpdateString:"";let h="RPi monitor "+r;h=null!=this._config.name_prefix?this._config.name_prefix+" "+r:h,h=null!=this._config.name?this._config.name:h,0==n&&(h="");const d=0==n?"last-heard-full-notitle":"last-heard-full",u=0==n?"last-heard-notitle":"last-heard",p=0==n?"os-name-full-notitle":"os-name-full",m=0==n?"os-name-notitle":"os-name",_=0==n?"daemon-update-full-notitle":"daemon-update-full",f=0==n?"daemon-update-notitle":"daemon-update";if(this._showFullCard){const t=this._generateFullsizeCardRows();if(0==t.length||!t)return void console.log("ERROR: failed to generate full rows!");e=F` + `}};t([st({attribute:!1})],gt.prototype,"hass",void 0),t([nt()],gt.prototype,"_config",void 0),t([nt()],gt.prototype,"_toggle",void 0),t([nt()],gt.prototype,"_helpers",void 0),gt=t([ot("rpi-monitor-card-editor")],gt);class ft{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,o){this._$Ct=t,this._$AM=e,this._$Ci=o}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}}const vt="ontouchstart"in window||navigator.maxTouchPoints>0||navigator.maxTouchPoints>0;class yt extends HTMLElement{constructor(){super(),this.holdTime=500,this.held=!1,this.ripple=document.createElement("mwc-ripple")}connectedCallback(){Object.assign(this.style,{position:"absolute",width:vt?"100px":"50px",height:vt?"100px":"50px",transform:"translate(-50%, -50%)",pointerEvents:"none",zIndex:"999"}),this.appendChild(this.ripple),this.ripple.primary=!0,["touchcancel","mouseout","mouseup","touchmove","mousewheel","wheel","scroll"].forEach((t=>{document.addEventListener(t,(()=>{clearTimeout(this.timer),this.stopAnimation(),this.timer=void 0}),{passive:!0})}))}bind(t,e){if(t.actionHandler)return;t.actionHandler=!0,t.addEventListener("contextmenu",(t=>{const e=t||window.event;return e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0,e.returnValue=!1,!1}));const o=t=>{let e,o;this.held=!1,t.touches?(e=t.touches[0].pageX,o=t.touches[0].pageY):(e=t.pageX,o=t.pageY),this.timer=window.setTimeout((()=>{this.startAnimation(e,o),this.held=!0}),this.holdTime)},i=o=>{o.preventDefault(),["touchend","touchcancel"].includes(o.type)&&void 0===this.timer||(clearTimeout(this.timer),this.stopAnimation(),this.timer=void 0,this.held?dt(t,"action",{action:"hold"}):e.hasDoubleClick?"click"===o.type&&o.detail<2||!this.dblClickTimeout?this.dblClickTimeout=window.setTimeout((()=>{this.dblClickTimeout=void 0,dt(t,"action",{action:"tap"})}),250):(clearTimeout(this.dblClickTimeout),this.dblClickTimeout=void 0,dt(t,"action",{action:"double_tap"})):dt(t,"action",{action:"tap"}))};t.addEventListener("touchstart",o,{passive:!0}),t.addEventListener("touchend",i),t.addEventListener("touchcancel",i),t.addEventListener("mousedown",o,{passive:!0}),t.addEventListener("click",i),t.addEventListener("keyup",(t=>{13===t.keyCode&&i(t)}))}startAnimation(t,e){Object.assign(this.style,{left:`${t}px`,top:`${e}px`,display:null}),this.ripple.disabled=!1,this.ripple.active=!0,this.ripple.unbounded=!0}stopAnimation(){this.ripple.active=!1,this.ripple.disabled=!0,this.style.display="none"}}customElements.define("action-handler-rpi-monitor",yt);const $t=(t,e)=>{const o=(()=>{const t=document.body;if(t.querySelector("action-handler-rpi-monitor"))return t.querySelector("action-handler-rpi-monitor");const e=document.createElement("action-handler-rpi-monitor");return t.appendChild(e),e})();o&&o.bind(t,e)},wt=(t=>(...e)=>({_$litDirective$:t,values:e}))(class extends ft{update(t,[e]){return $t(t.element,e),R}render(t){}}),bt="ico-fs-percent",At="ico-fs-total",Ct="ico-sys-temp",Et="ico-up-time",xt="ico-last-update",St="ico-memory-percent",Ut="fs-percent",It="fs-total",Tt="sys-temp",Dt="up-time",Pt="last-update",kt="memory-percent",Ot="sys-temp-scale",Mt="ifaces",Rt="ux_release",Nt="last_update",Vt="up_time",Ht="fs_total_gb",Ft="fs_free_prcnt",zt="temperature_c",Lt="show-os-parts",jt="memory_percent";class Bt{constructor(){this._showColorDebug=!1,this._circleIconsValueByName={"circle-outline":0,"circle-slice-1":13,"circle-slice-2":25,"circle-slice-3":38,"circle-slice-4":50,"circle-slice-5":63,"circle-slice-6":75,"circle-slice-7":88,"circle-slice-8":100},this._colorUsedSpaceDefault=[{color:"default",from:0,to:59},{color:"orange",from:60,to:84},{color:"red",from:85,to:100}],this._colorTemperatureDefault=[{color:"default",from:0,to:59},{color:"orange",from:60,to:79},{color:"red",from:85,to:100}],this._colorReportPeriodsAgoDefault=[{color:"default",from:0,to:3},{color:"orange",from:4,to:5},{color:"red",from:6,to:100}],this._colorUsedMemoryDefault=[{color:"red",from:75,to:100},{color:"orange",from:61,to:74},{color:"default",from:0,to:60}],this._colorReleaseDefault=[{color:"red",os:"stretch"},{color:"red",os:"jessie"},{color:"red",os:"wheezy"}]}getIconNameForPercent(t){let e="";for(const o in this._circleIconsValueByName){if(t<=this._circleIconsValueByName[o]){e=o;break}}return e}calculateReporterAgeColor(t){let e;return this._colorReportPeriodsAgoDefault.forEach((o=>{t>=o.from&&t<=o.to&&(e=o.color)})),null!=e&&"default"!=e||(e=""),e}calculateTemperatureColor(t,e){const o=Number(t),i=e||this._colorTemperatureDefault;let s;if(isNaN(o)||i.forEach((e=>{if(o>=e.from&&o<=e.to&&(s=e.color,this._showColorDebug)){const o="_calculateTemperatureColor() - value=["+t+"] matched(from="+e.from+", to="+e.to+", color="+s+")";console.log(o)}})),this._showColorDebug){const e="_calculateTemperatureColor() - value=["+t+"] returns(color="+s+")";console.log(e)}return null!=s&&"default"!=s||(s=""),s}calculateFileSystemUsageColor(t,e){const o=Number(t),i=e||this._colorUsedSpaceDefault;let s;if(isNaN(o)||i.forEach((e=>{if(o>=e.from&&o<=e.to&&(s=e.color,this._showColorDebug)){const o="_calculateFileSystemUsageColor() - value=["+t+"] matched(from="+e.from+", to="+e.to+", color="+s+")";console.log(o)}})),this._showColorDebug){const e="_calculateFileSystemUsageColor() - value=["+t+"] returns(color="+s+")";console.log(e)}return null!=s&&"default"!=s||(s=""),s}calculateMemoryUsageColor(t,e){const o=Number(t),i=e||this._colorUsedMemoryDefault;let s;if(isNaN(o)||i.forEach((e=>{if(o>=e.from&&o<=e.to&&(s=e.color,this._showColorDebug)){const o="_calculateMemoryUsageColor() - value=["+t+"] matched(from="+e.from+", to="+e.to+", color="+s+")";console.log(o)}})),this._showColorDebug){const e="_calculateMemoryUsageColor() - value=["+t+"] returns(color="+s+")";console.log(e)}return null!=s&&"default"!=s||(s=""),s}calculateOsReleaseColor(t,e){const o=e||this._colorReleaseDefault;let i="default";return o.forEach((e=>{t===e.os&&(i=e.color,this._showColorDebug&&console.log("calculateOsReleaseColor() - value=["+t+"] matched(os="+e.os+", color="+i+")"))})),this._showColorDebug&&console.log("calculateOsReleaseColor() - value=["+t+"] returns(color="+i+")"),null!=i&&"default"!=i||(i=""),i}calculateDaemonUpdateVersionColor(t,e){let o;if(o=e.length>0&&""!=t?e[0]==t?"default":e.includes(t)?"orange":"red":"orange",this._showColorDebug){const e="calculateDaemonUpdateVersionColor() - value=["+t+"] returns(color="+o+")";console.log(e)}return null!=o&&"default"!=o||(o=""),o}}var Kt={version:"Version",invalid_configuration:"Invalid configuration",show_warning:"Show Warning",show_error:"Show Error"},Gt={common:Kt},qt=Object.freeze({__proto__:null,common:Kt,default:Gt}),Wt={version:"Versjon",invalid_configuration:"Ikke gyldig konfiguration",show_warning:"Vis advarsel",show_error:"Vis feil"},Xt={common:Wt},Yt=Object.freeze({__proto__:null,common:Wt,default:Xt}),Jt={version:"Version",invalid_configuration:"configuración no válida",show_warning:"Mostrar advertencia",show_error:"Mostrar error"},Zt={common:Jt};const Qt={en:qt,es:Object.freeze({__proto__:null,common:Jt,default:Zt}),nb:Yt};function te(t,e="",o=""){const i=(localStorage.getItem("selectedLanguage")||"en").replace(/['"]+/g,"").replace("-","_");let s;try{s=t.split(".").reduce(((t,e)=>t[e]),Qt[i])}catch(e){s=t.split(".").reduce(((t,e)=>t[e]),Qt.en)}return void 0===s&&(s=t.split(".").reduce(((t,e)=>t[e]),Qt.en)),""!==e&&""!==o&&(s=s.replace(e,o)),s}console.info(`%c RPI-MONITOR-CARD \n%c ${te("common.version")} 1.3.2 `,"color: orange; font-weight: bold; background: black","color: white; font-weight: bold; background: dimgray"),window.customCards=window.customCards||[],window.customCards.push({type:"rpi-monitor-card",name:"RPi Monitor Card",description:"A template custom card for you to create something awesome"});let ee=class extends tt{constructor(){super(...arguments),this._cardMinutesSinceUpdate=0,this._firstTime=!0,this._stateInfoAvailable=!1,this._updateTimerID=void 0,this._configEntityId=void 0,this._hostname="",this._showFullCard=!0,this._useTempsInC=!0,this.kREPLACE_WITH_TEMP_UNITS="replace-with-temp-units",this.latestDaemonVersions=["v1.7.2","v1.6.1"],this.currentDaemonVersion="",this._showOsAge=!0,this._showCardAge=!0,this._showDaemonUpdNeed=!0,this._showCardName=!0,this._showDebug=!1,this.colorHelpers=new Bt,this._cardFullElements={"Storage Use":Ft,Storage:Ht,"Memory Use":jt,Temperature:zt,"Up-time":Vt,Updated:Nt,OS:Lt,Model:"rpi_model",Interfaces:Mt},this._cardFullIconNames={"Storage Use":"file-percent",Storage:"sd","Memory Use":"memory",Temperature:"thermometer","Up-time":"clock-check-outline",Updated:"update",OS:"linux",Model:"raspberry-pi",Interfaces:""},this._cardFullCssIDs={"Storage Use":Ut,Storage:It,"Memory Use":kt,Temperature:Tt,"Up-time":Dt,Updated:Pt,OS:"*nix",Model:"rpi-model",Interfaces:"rpi-ifaces"},this._cardFullIconCssIDs={"Storage Use":bt,Storage:At,"Memory Use":St,Temperature:Ct,"Up-time":Et,Updated:xt,OS:"ico-*nix",Model:"ico-rpi-model",Interfaces:"ico-rpi-ifaces"},this._cardGlanceElements={"%":Ft,GB:Ht,Mem:jt,"replace-with-temp-units":zt,UpTime:Vt,Upd:Nt},this._cardGlanceIconNames={"%":"file-percent",GB:"sd",Mem:"memory","replace-with-temp-units":"thermometer",UpTime:"clock-check-outline",Upd:"update"},this._cardGlanceCssIDs={"%":Ut,GB:It,Mem:kt,"replace-with-temp-units":Tt,UpTime:Dt,Upd:Pt},this._cardGlanceIconCssIDs={"%":bt,GB:At,Mem:St,"replace-with-temp-units":Ct,UpTime:Et,Upd:xt}}static async getConfigElement(){return console.log("- getConfigElement()"),document.createElement("rpi-monitor-card-editor")}static getStubConfig(){return{}}setConfig(t){if(null!=t.show_debug&&(this._showDebug=t.show_debug||this._showDebug),this._showDebug&&console.log("- setConfig()"),!t||t.show_error)throw new Error(te("common.invalid_configuration"));if(!t.entity)throw console.log("Invalid configuration. If no entity provided, you'll need to provide a remote entity"),new Error("You need to associate an entity");if(null!=t.card_style){const e=t.card_style.toLocaleLowerCase();if("full"!=e&&"glance"!=e)throw console.log("Invalid configuration. INVALID card_style = ["+t.card_style+"]"),new Error("Illegal card_style: value (card_style: "+t.card_style+") must be [full or glance]");this._showFullCard="full"===t.card_style.toLocaleLowerCase()}if(null!=t.temp_scale){const e=t.temp_scale.toLocaleLowerCase();if("c"!=e&&"f"!=e)throw console.log("Invalid configuration. INVALID temp_scale = ["+t.temp_scale+"]"),new Error("Illegal temp_scale: value (temp_scale: "+t.temp_scale+") must be [F or C]");this._useTempsInC="c"===t.temp_scale.toLocaleLowerCase()}t.test_gui&&function(){var t=document.querySelector("home-assistant");if(t=(t=(t=(t=(t=(t=(t=(t=t&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root")){var e=t.lovelace;return e.current_view=t.___curView,e}return null}().setEditMode(!0),this._showOsAge=!t.show_os_age||t.show_os_age,this._showCardAge=!t.show_update_age||t.show_update_age,this._showDaemonUpdNeed=!t.show_daemon_upd||t.show_daemon_upd,this._showCardName=!t.show_title||t.show_title,this._config=Object.assign({},t),console.log("- config=["+this._config+"]"),this._configEntityId=null!=this._config.entity?this._config.entity:void 0,this._ensureStateInfoAvail()}shouldUpdate(t){if(this._ensureStateInfoAvail(),this._ensureWeHaveHostName(),this._debugShowProps(t,"shouldUpdate"),!this._config)return console.log(" - SU ABORT, no config"),!1;let e=!1;if(t.has("_config"))console.log(" - SU config present"),e=!0;else if(t.has("_cardMinutesSinceUpdate"))console.log(" - SU card last updated changed"),e=!0;else if(this.hass&&this._config&&t.has("hass")){const o=t.get("hass");o&&this._configEntityId&&(e=o.states[this._configEntityId]!==this.hass.states[this._configEntityId],e?console.log(" - SU hass state changed"):console.log(" - SU !! NO hass state change"))}return console.log("\\---- shouldUpdate("+this._hostname+") - EXIT w/"+e),e}willUpdate(t){this._debugShowProps(t,"willUpdate()")}render(){if(this._showDebug&&console.log("- render("+this._hostname+")"),this._config.show_warning)return this.showWarning(te("common.show_warning"));if(this._config.show_error)return this.showError(te("common.show_error"));if(this._configEntityId&&!this._stateInfoAvailable){const t="Entity Unavailable: "+this._configEntityId;return this.showWarning(t)}const t=this._configEntityId?this.hass.states[this._configEntityId]:void 0;if(!this._configEntityId&&!t)return this.showWarning("Entity Unavailable");if(!this._stateInfoAvailable)return void console.log("?? Render w/o sensor!! ("+this._hostname+")");let e=M``;if(this._firstTime&&(this._showDebug&&console.log("- stateObj: ["+t+"]"),this._startCardRefreshTimer(),this._showDebug&&console.log("- 1st-time _config: ["+this._config+"]"),this._firstTime=!1),this._showDaemonUpdNeed){const t=this._getAttributeValueForKey("reporter").split(" ");this.currentDaemonVersion=t.length>1?t[1]:"";const e=this._getAttributeValueForKey("reporter_releases");if(e&&e.length>0&&"NOT-LOADED"!=e){const t=e.split(",");this.latestDaemonVersions=t}}const o=this._getAttributeValueForKey("fqdn"),i=1==this._showOsAge?this._getAttributeValueForKey(Rt):"",s=this._showDaemonUpdNeed?this._computeDaemonUpdMessage(this.currentDaemonVersion):"";let n="";if(this._showCardAge)if(0==this._cardMinutesSinceUpdate)n="just now";else{const t=1==this._cardMinutesSinceUpdate?"":"s";n=this._cardMinutesSinceUpdate+" min"+t+" ago"}const r=1==this._showCardAge?n:"";let a="RPi monitor "+o;a=null!=this._config.name_prefix?this._config.name_prefix+" "+o:a,a=null!=this._config.name?this._config.name:a,0==this._showCardName&&(a="");const l=0==this._showCardName?"last-heard-full-notitle":"last-heard-full",c=0==this._showCardName?"last-heard-notitle":"last-heard",h=0==this._showCardName?"os-name-full-notitle":"os-name-full",d=0==this._showCardName?"os-name-notitle":"os-name",u=(0==this._showCardName?"daemon-update-full-notitle":"daemon-update-full")+" center",p=(0==this._showCardName?"daemon-update-notitle":"daemon-update")+" center";if(this._showFullCard){const t=this._generateFullsizeCardRows();if(0==t.length||!t)return void console.log("ERROR: failed to generate full rows!");e=M`
${t} -
${c}
-
${a}
-
${l}
+
${r}
+
${i}
+
${s}
- `}else{const t=this._generateGlanceCardRows();if(0==t.length||!t)return void console.log("ERROR: failed to generate glance rows!");e=F` + `}else{const t=this._generateGlanceCardRows();if(0==t.length||!t)return void console.log("ERROR: failed to generate glance rows!");e=M`
${t} -
${c}
-
${a}
-
${l}
+
${r}
+
${i}
+
${s}
- `}return e}updated(t){if(this._showDebug&&console.log("- updated("+this._hostname+")"),this._config){if(this.hass){const e=t.get("hass");(!e||e&&e.themes!==this.hass.themes)&&function(t,e,i,o){void 0===o&&(o=!1),t._themes||(t._themes={});var s=e.default_theme;("default"===i||i&&e.themes[i])&&(s=i);var n=_t({},t._themes);if("default"!==s){var r=e.themes[s];Object.keys(r).forEach((function(e){var i="--"+e;t._themes[i]="",n[i]=r[e]}))}if(t.updateStyles?t.updateStyles(n):window.ShadyCSS&&window.ShadyCSS.styleSubtree(t,n),o){var a=document.querySelector("meta[name=theme-color]");if(a){a.hasAttribute("default-content")||a.setAttribute("default-content",a.getAttribute("content"));var l=n["--primary-color"]||a.getAttribute("default-content");a.setAttribute("content",l)}}}(this,this.hass.themes,this._config.theme)}if(this.hass&&this._configEntityId){this.hass.states[this._configEntityId]||this._stopCardRefreshTimer()}const e=this.shadowRoot;if(this._sensorAvailable){const t=this._getAttributeValueForKey(Mt),i=this._computeOsReleaseColor(t);if(""!=i){e.getElementById("os-name").style.setProperty("color",i)}const o=this._computeDaemonUpdateVersionColor(this.currentDaemonVersion);if(""!=o){e.getElementById("daemon-update").style.setProperty("color",o)}const s=this._computeReporterAgeColor(this._cardSecondsSinceUpdate);if(""!=s&&null!=s){e.getElementById("card-timestamp").style.setProperty("color",s)}if(this._showFullCard)for(const t in this._cardFullCssIDs){const i=this._cardFullCssIDs[t],o=this._cardFullElements[t],s=this._getAttributeValueForKey(o),n=this._getFullCardValueForAttributeKey(o),r=e.getElementById(i);r.textContent=n;const a=this._cardFullIconCssIDs[t],l=e.getElementById(a);if(o==Nt){const t=this._computeFileSystemUsageColor(s);""!=t&&(r.style.setProperty("color",t),l.style.setProperty("color",t))}if(o==zt){const t=this._computeMemoryUsageColor(n.replace(" %",""));""!=t&&(r.style.setProperty("color",t),l.style.setProperty("color",t))}if(o==Vt){const t=this._computeTemperatureColor(s);""!=t&&(r.style.setProperty("color",t),l.style.setProperty("color",t))}}else for(const t in this._cardGlanceCssIDs){const i=this._cardGlanceCssIDs[t],o=this._cardGlanceElements[t],s=this._getAttributeValueForKey(o),n=this._getGlanceCardValueForAttributeKey(o),r=e.getElementById(i);r.textContent=n;const a=this._cardGlanceIconCssIDs[t],l=e.getElementById(a);if(o==Nt){const t=this._computeFileSystemUsageColor(s);""!=t&&(r.style.setProperty("color",t),l.style.setProperty("color",t))}if(o==zt){const t=this._computeMemoryUsageColor(n);""!=t&&(r.style.setProperty("color",t),l.style.setProperty("color",t))}if(o==Vt&&"n/a"!=n){const t=this._computeTemperatureColor(s);""!=t&&(r.style.setProperty("color",t),l.style.setProperty("color",t));e.getElementById(this.kClassIdTempScale).textContent=this._getTemperatureScale()}}}}}_handleAction(t){this.hass&&this._config&&t.detail.action&&function(t,e,i,o){var s;"double_tap"===o&&i.double_tap_action?s=i.double_tap_action:"hold"===o&&i.hold_action?s=i.hold_action:"tap"===o&&i.tap_action&&(s=i.tap_action),At(t,e,i,s)}(this,this.hass,this._config,t.detail.action)}showWarning(t){return F` ${t} `}showError(t){const e=document.createElement("hui-error-card");return e.setConfig({type:"error",error:t,origConfig:this._config}),F` ${e} `}_startCardRefreshTimer(){this._updateTimerID=setInterval((()=>this._handleCardUpdateTimerExpiration()),1e3),this._showDebug&&console.log("TIMER: ("+this._hostname+") started")}_stopCardRefreshTimer(){null!=this._updateTimerID&&(clearInterval(this._updateTimerID),this._updateTimerID=void 0,this._showDebug&&console.log("TIMER: ("+this._hostname+") STOPPED"))}_handleCardUpdateTimerExpiration(){const[t,e]=this._getRelativeTimeSinceUpdate();if(t&&t.length>0){let i=t;t.includes("NaN")&&(console.log(" HCUTE (DBG) ("+this._hostname+") card_timestamp_value=["+t+"]"),i="{bad value}"),this._cardUpdateString!=i&&(this._cardUpdateString=i),this._cardSecondsSinceUpdate!=e&&(this._cardSecondsSinceUpdate=e)}}_logChangeMessage(t){const e="("+this._hostname+"): "+t;this._showDebug&&console.log(e)}_updateSensorAvailability(){let t=!1;if(this.hass&&this._config){const e=this._configEntityId?this.hass.states[this._configEntityId]:void 0;if(this._configEntityId||e){if(this._configEntityId)try{const e="unavailable"!=this.hass.states[this._configEntityId].state;t=this._sensorAvailable!=e,this._sensorAvailable=e}catch(e){this._sensorAvailable=!1,t=!0}}else this._sensorAvailable=!1,t=!0}else this._sensorAvailable=!1,t=!0;t&&this._logChangeMessage("* SENSOR available: "+this._sensorAvailable)}_computeDaemonUpdMessage(t){let e="";return this._showDebug&&(console.log("- RNDR currentDaemonVersion=["+t+"]"),console.log("- RNDR latestDaemonVersions=["+this.latestDaemonVersions+"]")),this.latestDaemonVersions.length>0&&""!=t?t!=this.latestDaemonVersions[0]&&(e=t+" ---\x3e "+this.latestDaemonVersions[0]):e=""!=this.currentDaemonVersion?"{no info avail.}":"v?.?.? {no info avail.}",e}_getRelativeTimeSinceUpdate(){var t;const e=this._configEntityId?this.hass.states[this._configEntityId]:void 0;let i="",o=0,s="";if(this.hass.locale&&e){try{const o=yt(null===(t=this.hass)||void 0===t?void 0:t.localize,e,this.hass.locale),n=void 0===o?"{unknown}":this._formatTimeAgo(o);i=this._sensorAvailable?n:"{unknown}";s=n.split(" ")[0]}catch(t){console.log("GRTSU - exception:"),console.error(t)}o=s.includes("just")||s.includes("unknown")?0:Number(s)}return[i,o]}_formatTimeAgo(t){const e=new Date((t||"").replace(/-/g,"/").replace(/[TZ]/g," ")),i=((new Date).getTime()-e.getTime())/1e3,o=Math.floor(i/86400),s=e.getFullYear(),n=e.getMonth()+1,r=e.getDate();if(isNaN(o)||o<0||o>=31)return s.toString()+"-"+(n<10?"0"+n.toString():n.toString())+"-"+(r<10?"0"+r.toString():r.toString());let a="{unknown}";return 0==o?i<60?a="just now":i<120?a="1 min ago":i<3600?a=Math.floor(i/60)+" mins ago":i<7200?a="1 hr ago":i<86400&&(a=Math.floor(i/3600)+" hrs ago"):1==o?a="Yesterday":o<7?a=o+" days ago":o<31&&(a=Math.ceil(o/7)+" wks ago"),a}_getIconNameForPercent(t){let e="";for(const i in this._circleIconsValueByName){if(t<=this._circleIconsValueByName[i]){e=i;break}}return e}_computeReporterAgeColor(t){let e;return this._colorReportPeriodsAgoDefault.forEach((i=>{t>=i.from&&t<=i.to&&(e=i.color)})),null!=e&&"default"!=e||(e=""),e}_computeTemperatureColor(t){const e=this._config,i=Number(t),o=e.temp_severity?e.temp_severity:this._colorTemperatureDefault;let s;if(isNaN(i)||o.forEach((e=>{if(i>=e.from&&i<=e.to&&(s=e.color,this._showDebug)){const i="_computeTemperatureColor() - value=["+t+"] matched(from="+e.from+", to="+e.to+", color="+s+")";console.log(i)}})),this._showDebug){const e="_computeTemperatureColor() - value=["+t+"] returns(color="+s+")";console.log(e)}return null!=s&&"default"!=s||(s=""),s}_computeFileSystemUsageColor(t){const e=this._config,i=Number(t),o=e.fs_severity?e.fs_severity:this._colorUsedSpaceDefault;let s;if(isNaN(i)||o.forEach((e=>{if(i>=e.from&&i<=e.to&&(s=e.color,this._showDebug)){const i="_computeFileSystemUsageColor() - value=["+t+"] matched(from="+e.from+", to="+e.to+", color="+s+")";console.log(i)}})),this._showDebug){const e="_computeFileSystemUsageColor() - value=["+t+"] returns(color="+s+")";console.log(e)}return null!=s&&"default"!=s||(s=""),s}_computeMemoryUsageColor(t){const e=this._config,i=Number(t),o=e.memory_severity?e.memory_severity:this._colorUsedMemoryDefault;let s;if(isNaN(i)||o.forEach((e=>{if(i>=e.from&&i<=e.to&&(s=e.color,this._showDebug)){const i="_computeMemoryUsageColor() - value=["+t+"] matched(from="+e.from+", to="+e.to+", color="+s+")";console.log(i)}})),this._showDebug){const e="_computeMemoryUsageColor() - value=["+t+"] returns(color="+s+")";console.log(e)}return null!=s&&"default"!=s||(s=""),s}_computeOsReleaseColor(t){const e=this._config,i=e.os_age?e.os_age:this._colorReleaseDefault;let o="default";if(i.forEach((e=>{if(t===e.os&&(o=e.color,this._showDebug)){const i="_computeOsReleaseColor() - value=["+t+"] matched(os="+e.os+", color="+o+")";console.log(i)}})),this._showDebug){const e="_computeOsReleaseColor() - value=["+t+"] returns(color="+o+")";console.log(e)}return null!=o&&"default"!=o||(o=""),o}_computeDaemonUpdateVersionColor(t){let e;if(e=this.latestDaemonVersions.length>0&&""!=t?this.latestDaemonVersions[0]==t?"default":this.latestDaemonVersions.includes(t)?"orange":"red":"orange",this._showDebug){const i="_computeDaemonUpdateVersionColor() - value=["+t+"] returns(color="+e+")";console.log(i)}return null!=e&&"default"!=e||(e=""),e}_filterUptime(t){const e=t.split(" ");let i=t;if(i.includes(":")){for(let t=0;t${t} `}showError(t){const e=document.createElement("hui-error-card");return e.setConfig({type:"error",error:t,origConfig:this._config}),M` ${e} `}_startCardRefreshTimer(){this._updateTimerID=setInterval((()=>this._handleCardUpdateTimerExpiration()),15e3),this._showDebug&&console.log("TIMER: ("+this._hostname+") started")}_stopCardRefreshTimer(){null!=this._updateTimerID&&(clearInterval(this._updateTimerID),this._updateTimerID=void 0,this._showDebug&&console.log("TIMER: ("+this._hostname+") STOPPED"))}_handleCardUpdateTimerExpiration(){const t=this._calculateRelativeMinutesSinceUpdate();this._cardMinutesSinceUpdate!=t&&(this._cardMinutesSinceUpdate=t)}_debugShowProps(t,e){console.log("/ ---- "+e+" "+this._hostname+" ---- :"),console.log(t)}_ensureStateInfoAvail(){if(this._configEntityId&&this.hass){const t=this._configEntityId?this.hass.states[this._configEntityId]:void 0;t?"unavailable"==t.state?this._stateInfoAvailable=!1:this._stateInfoAvailable=!0:this._stateInfoAvailable=!1}}_ensureWeHaveHostName(){if(0==this._hostname.length||this._hostname==this._configEntityId){const t=this._getAttributeValueForKey("host_name");t&&t.length>0?this._hostname=t:this._hostname=this._configEntityId?this._configEntityId:"-not-set-"}}_computeDaemonUpdMessage(t){let e="";return this._showDebug&&(console.log("- RNDR currentDaemonVersion=["+t+"]"),console.log("- RNDR latestDaemonVersions=["+this.latestDaemonVersions+"]")),this.latestDaemonVersions.length>0&&""!=t?t
${e}
-
${o}
+
${i}
- `)}return t}_generateGlanceCardRows(){const t=[];for(const e in this._cardGlanceElements){const i=this._cardGlanceElements[e],o=this._getGlanceCardValueForAttributeKey(i);let s=e;s==this.kREPLACE_WITH_TEMP_UNITS&&(s="n/a"!=o?this._getTemperatureScale():""),i==zt&&(s="% Mem");let n=this._cardGlanceIconNames[e];i==Nt&&(n=this._getIconNameForPercent(o));const r=this._cardGlanceCssIDs[e],a=this._cardGlanceIconCssIDs[e];let l="units";i==Vt&&(l=this.kClassIdTempScale),t.push(F` + `)}return t}_generateGlanceCardRows(){const t=[];for(const e in this._cardGlanceElements){const o=this._cardGlanceElements[e],i=this._getGlanceCardValueForAttributeKey(o);let s=e;s==this.kREPLACE_WITH_TEMP_UNITS&&(s="n/a"!=i?this._getTemperatureScale():""),o==jt&&(s="% Mem");let n=this._cardGlanceIconNames[e];o==Ft&&(n=this.colorHelpers.getIconNameForPercent(i));const r=this._cardGlanceCssIDs[e],a=this._cardGlanceIconCssIDs[e];let l="units";o==zt&&(l=Ot),t.push(M`
-
${o}
+
${i}
${s}
- `)}return t}_getTemperatureScale(){return 1==this._useTempsInC?"ºC":"ºF"}_getScaledTemperatureValue(t){let e=t;return"n/a"!=e&&0==this._useTempsInC&&(e=(9*parseFloat(t)/5+32).toFixed(1)),e}_getFullCardValueForAttributeKey(t){const e=this._getAttributeValueForKey(t);let i=e;if(t==zt)i=this._getPercentMemoryUsed()+" %";else if(t==Ft)i=this._getUIDateForTimestamp(e);else if(t==Vt){if(i=this._getScaledTemperatureValue(e),"n/a"!=i){i=i+" "+this._getTemperatureScale()}}else if(t==Ot)i=e+" GB";else if(t==Nt)i=e+" %";else if(t==Pt)i=this._filterUptime(i);else if(t==Ht){i=this._getAttributeValueForKey(Mt)+" v"+this._getAttributeValueForKey("ux_version")}else if(t==Rt){const t=[];e.includes("e")&&t.push("Ether"),e.includes("w")&&t.push("WiFi"),e.includes("b")&&t.push("Bluetooth"),i=t.join(", ")}return i}_getGlanceCardValueForAttributeKey(t){const e=this._getAttributeValueForKey(t);let i=e;return t==zt?i=this._getPercentMemoryUsed():t==Ft?i=this._getUIDateForTimestamp(e):t==Vt?i=this._getScaledTemperatureValue(e):t==Pt&&(i=this._filterUptime(i)),i}_getUIDateForTimestamp(t){return new Date(t).toLocaleDateString("en-us")}_getPercentMemoryUsed(){const t=this._getAttributeValueForKey("memory"),e=t.size_mb,i=t.free_mb,o=Number(e);return((e-Number(i))/o*100).toFixed(0).toString()}static get styles(){return r` + `)}return t}_getTemperatureScale(){return 1==this._useTempsInC?"ºC":"ºF"}_getScaledTemperatureValue(t){let e=t;return"n/a"!=e&&0==this._useTempsInC&&(e=(9*parseFloat(t)/5+32).toFixed(1)),e}_getFullCardValueForAttributeKey(t){const e=this._getAttributeValueForKey(t);let o=e;if(t==jt)o=this._getPercentMemoryUsed()+" %";else if(t==Nt)o=this._getUIDateForTimestamp(e);else if(t==zt){if(o=this._getScaledTemperatureValue(e),"n/a"!=o){o=o+" "+this._getTemperatureScale()}}else if(t==Ht)o=e+" GB";else if(t==Ft)o=e+" %";else if(t==Vt)o=this._filterUptime(o);else if(t==Lt){o=this._getAttributeValueForKey(Rt)+" v"+this._getAttributeValueForKey("ux_version")}else if(t==Mt){const t=[];e.includes("e")&&t.push("Ether"),e.includes("w")&&t.push("WiFi"),e.includes("b")&&t.push("Bluetooth"),o=t.join(", ")}return o}_getGlanceCardValueForAttributeKey(t){const e=this._getAttributeValueForKey(t);let o=e;return t==jt?o=this._getPercentMemoryUsed():t==Nt?o=this._getUIDateForTimestamp(e):t==zt?o=this._getScaledTemperatureValue(e):t==Vt&&(o=this._filterUptime(o)),o}_getUIDateForTimestamp(t){return new Date(t).toLocaleDateString("en-us")}_getPercentMemoryUsed(){const t=this._getAttributeValueForKey("memory"),e=t.size_mb,o=t.free_mb,i=Number(e);return((e-Number(o))/i*100).toFixed(0).toString()}static get styles(){return r` ha-card { height: 100%; display: flex; @@ -390,4 +390,4 @@ const et=t=>e=>"function"==typeof e?((t,e)=>(customElements.define(t,e),e))(t,e) font-size: 12px; color: var(--primary-text-color); } - `}};t([ot({attribute:!1})],Qt.prototype,"hass",void 0),t([st()],Qt.prototype,"_config",void 0),t([st()],Qt.prototype,"_cardSecondsSinceUpdate",void 0),t([st()],Qt.prototype,"_cardUpdateString",void 0),Qt=t([et("rpi-monitor-card")],Qt);export{Qt as RPiMonitorCard}; + `}};t([st({attribute:!1})],ee.prototype,"hass",void 0),t([nt()],ee.prototype,"_config",void 0),t([nt()],ee.prototype,"_cardMinutesSinceUpdate",void 0),ee=t([ot("rpi-monitor-card")],ee);export{ee as RPiMonitorCard}; diff --git a/package.json b/package.json index 3190472..eae7fb4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rpi-monitor-card", - "version": "1.3.1", + "version": "1.3.2", "description": "Lovelace RPi Monitor Card", "keywords": [ "home-assistant", diff --git a/src/coloring.ts b/src/coloring.ts new file mode 100644 index 0000000..a8d77e9 --- /dev/null +++ b/src/coloring.ts @@ -0,0 +1,305 @@ +import { ColorRange, OsColor } from './types'; + +export class ColorUtils { + // eslint-disable-next-line @typescript-eslint/no-inferrable-types + private _showColorDebug: boolean = false; // REMOVE BEFORE FLIGHT (!set to false before check-in!) + + // space used icon set + private _circleIconsValueByName = { + 'circle-outline': 0, + 'circle-slice-1': 13, + 'circle-slice-2': 25, + 'circle-slice-3': 38, + 'circle-slice-4': 50, + 'circle-slice-5': 63, + 'circle-slice-6': 75, + 'circle-slice-7': 88, + 'circle-slice-8': 100, + }; + + /* + * COLORING Goals (default) + * + * 1) color time since reported: yellow if longer than 1 reporting interval, red if two or more + * 2) color space-used: nothing to 60%, 61-85% yellow, 86%+ red + * 3) color temp: nothing to 59C, 60-79C yellow, 80C+ red + */ + + // DEFAULT coloring for used space + // user sets 'fs_severity' to override + private _colorUsedSpaceDefault = [ + { + color: 'default', + from: 0, + to: 59, + }, + { + color: 'orange', + from: 60, + to: 84, + }, + { + color: 'red', + from: 85, + to: 100, + }, + ]; + + // coloring for temp-in-C + // user sets 'temp_severity' to override + private _colorTemperatureDefault = [ + { + color: 'default', + from: 0, + to: 59, + }, + { + color: 'orange', + from: 60, + to: 79, + }, + { + color: 'red', + from: 85, + to: 100, + }, + ]; + + // coloring for report update age + // no user override for now + private _colorReportPeriodsAgoDefault = [ + { + color: 'default', + from: 0, + to: 3, + }, + { + color: 'orange', + from: 4, + to: 5, + }, + { + color: 'red', + from: 6, + to: 100, + }, + ]; + + // DEFAULT coloring for used memory + // user sets 'memory_severity' to override + private _colorUsedMemoryDefault = [ + { + color: 'red', + from: 75, + to: 100, + }, + { + color: 'orange', + from: 61, + to: 74, + }, + { + color: 'default', + from: 0, + to: 60, + }, + ]; + + // DEFAULT coloring for named releases + // intent is to show which ones are aging and should no longer be used + // user sets 'os_age' to override + // see https://en.wikipedia.org/wiki/Debian_version_history for important dates (e.g., 'Long-term') + // Jessie EOL 30 June 2020 'red' + // Stretch EOL 30 June 2022 'red' + // Buster EOL 30 June 2024: Jun 2023 'orange', Jan 2024 is 'yellow' + // + // TODO: replace color with dates and use days until date to color? + // + // Thinking: past EOL is 'red' + // within 6 mos of EOL is yellow + // within 12 mos of EOL is orange + private _colorReleaseDefault = [ + { + color: 'red', + os: 'stretch', + }, + { + color: 'red', + os: 'jessie', + }, + { + color: 'red', + os: 'wheezy', + }, + ]; + + public getIconNameForPercent(percent: string): string { + // return name of icon we should show for given % + let desiredIconName = ''; + for (const currIconName in this._circleIconsValueByName) { + const currMaxValue = this._circleIconsValueByName[currIconName]; + if (percent <= currMaxValue) { + desiredIconName = currIconName; + break; + } + } + return desiredIconName; + } + + public calculateReporterAgeColor(numberValue: number): string { + const sections = this._colorReportPeriodsAgoDefault; + + //console.log('color-table: sections=[' + sections + ']'); + //return ''; + + let color: undefined | string = undefined; + + sections.forEach((section) => { + if (numberValue >= section.from && numberValue <= section.to) { + color = section.color; + } + }); + + if (color == undefined || color == 'default') color = ''; + return color; + } + + public calculateTemperatureColor(value: string, temp_severity: ColorRange[] | undefined): string { + const numberValue = Number(value); + const sections = temp_severity ? temp_severity : this._colorTemperatureDefault; + + //console.log('color-table: sections=[' + sections + ']'); + //return ''; + + let color: undefined | string; + + if (!isNaN(numberValue)) { + sections.forEach((section) => { + if (numberValue >= section.from && numberValue <= section.to) { + color = section.color; + if (this._showColorDebug) { + const logMessage = + '_calculateTemperatureColor() - value=[' + value + '] matched(from=' + section.from + ', to=' + section.to + ', color=' + color + ')'; + console.log(logMessage); + } + } + }); + } + if (this._showColorDebug) { + const logMessage = '_calculateTemperatureColor() - value=[' + value + '] returns(color=' + color + ')'; + console.log(logMessage); + } + if (color == undefined || color == 'default') color = ''; + return color; + } + + public calculateFileSystemUsageColor(value: string, fs_severity: ColorRange[] | undefined): string { + const numberValue = Number(value); + const sections = fs_severity ? fs_severity : this._colorUsedSpaceDefault; + + //console.log('color-table: sections=[' + _colorUsedMemoryDefault + ']'); + //return ''; + + let color: undefined | string; + + if (!isNaN(numberValue)) { + sections.forEach((section) => { + if (numberValue >= section.from && numberValue <= section.to) { + color = section.color; + if (this._showColorDebug) { + const logMessage = + '_calculateFileSystemUsageColor() - value=[' + value + '] matched(from=' + section.from + ', to=' + section.to + ', color=' + color + ')'; + console.log(logMessage); + } + } + }); + } + if (this._showColorDebug) { + const logMessage = '_calculateFileSystemUsageColor() - value=[' + value + '] returns(color=' + color + ')'; + console.log(logMessage); + } + + if (color == undefined || color == 'default') color = ''; + return color; + } + + public calculateMemoryUsageColor(value: string, memory_severity: ColorRange[] | undefined): string { + const numberValue = Number(value); + const sections = memory_severity ? memory_severity : this._colorUsedMemoryDefault; + + let color: undefined | string; + + if (!isNaN(numberValue)) { + sections.forEach((section) => { + if (numberValue >= section.from && numberValue <= section.to) { + color = section.color; + if (this._showColorDebug) { + const logMessage = + '_calculateMemoryUsageColor() - value=[' + value + '] matched(from=' + section.from + ', to=' + section.to + ', color=' + color + ')'; + console.log(logMessage); + } + } + }); + } + if (this._showColorDebug) { + const logMessage = '_calculateMemoryUsageColor() - value=[' + value + '] returns(color=' + color + ')'; + console.log(logMessage); + } + + if (color == undefined || color == 'default') color = ''; + return color; + } + + public calculateOsReleaseColor(osName: string, os_age: OsColor[] | undefined): string { + const sections = os_age ? os_age : this._colorReleaseDefault; + + //console.log('color-table: sections=[' + sections + ']'); + //return ''; + + let color: undefined | string = 'default'; + + sections.forEach((section) => { + if (osName === section.os) { + color = section.color; + if (this._showColorDebug) { + console.log('calculateOsReleaseColor() - value=[' + osName + '] matched(os=' + section.os + ', color=' + color + ')'); + } + } + }); + if (this._showColorDebug) { + console.log('calculateOsReleaseColor() - value=[' + osName + '] returns(color=' + color + ')'); + } + if (color == undefined || color == 'default') color = ''; + return color; + } + + public calculateDaemonUpdateVersionColor(currentReporterVersion: string, latestDaemonVersions: string[]): string { + //console.log('color-table: sections=[' + sections + ']'); + //return ''; + + let color: undefined | string = undefined; + + if (latestDaemonVersions.length > 0 && currentReporterVersion != '') { + if (latestDaemonVersions[0] == currentReporterVersion) { + // daemon is at latest + color = 'default'; + } else if (latestDaemonVersions.includes(currentReporterVersion)) { + // daemon is recent + color = 'orange'; + } else { + // daemon is old (not even in latest or stable) + color = 'red'; + } + } else { + // daemon values are missing??? + color = 'orange'; + } + if (this._showColorDebug) { + const logMessage = 'calculateDaemonUpdateVersionColor() - value=[' + currentReporterVersion + '] returns(color=' + color + ')'; + console.log(logMessage); + } + + if (color == undefined || color == 'default') color = ''; + return color; + } +} diff --git a/src/const.ts b/src/const.ts index 62531e5..f6b7c60 100644 --- a/src/const.ts +++ b/src/const.ts @@ -1,57 +1,87 @@ -export const CARD_VERSION = '1.3.1'; +export const CARD_VERSION = '1.3.2'; /* -* EXAMPLE attributes ISP-RPi-mqtt-daemon.py v1.5.4 +* EXAMPLE attributes ISP-RPi-mqtt-daemon.py v1.7.2 { "info": { - "timestamp": "2021-05-18T18:17:52-06:00", - "rpi_model": "RPi 2 Model B r1.1", - "ifaces": "e", - "host_name": "pinode1", - "fqdn": "pinode1.home", - "ux_release": "jessie", - "ux_version": "4.9.35-v7+", - "up_time": " 4:55", - "last_update": "2021-05-18T14:39:58-06:00", + "timestamp": "2023-02-11T22:36:15-07:00", + "rpi_model": "RPi 4 Model B r1.5", + "ifaces": "e,w,b", + "host_name": "pip2iotgw", + "fqdn": "pip2iotgw.home", + "ux_release": "bullseye", + "ux_version": "5.15.84-v8+", + "up_time": " 9:41", + "last_update": "2023-02-11T01:18:02-07:00", "fs_total_gb": 32, - "fs_free_prcnt": 19, + "fs_free_prcnt": 18, "networking": { "eth0": { - "mac": "b8:27:eb:b0:9c:3b", - "IP": "192.168.100.42" + "mac": "e4:5f:01:f8:18:01" + }, + "wlan0": { + "IP": "192.168.100.196", + "mac": "e4:5f:01:f8:18:02" } }, "drives": { "root": { "size_gb": 32, - "used_prcnt": 19, + "used_prcnt": 18, "device": "/dev/root", "mount_pt": "/" } }, "memory": { - "size_mb": "923.355", - "free_mb": "795.066" + "size_mb": "1849.246", + "free_mb": "1508.148" }, "cpu": { "hardware": "BCM2835", - "model": "ARMv7 Processor rev 5 (v7l)", + "model": "", "number_cores": 4, - "bogo_mips": "230.40", - "serial": "00000000bab09c3b" + "bogo_mips": "432.00", + "serial": "1000000081ae88c7", + "load_1min_prcnt": 0.2, + "load_5min_prcnt": 0.5, + "load_15min_prcnt": 0 }, "throttle": [ "throttled = 0x0", "Not throttled" ], - "temperature_c": 40.1, - "temp_gpu_c": 40.1, - "temp_cpu_c": 40.1, - "reporter": "ISP-RPi-mqtt-daemon v1.5.4", + "temperature_c": 27.2, + "temp_gpu_c": 27.2, + "temp_cpu_c": 26.3, + "reporter": "ISP-RPi-mqtt-daemon v1.7.2", "reporter_releases": "v1.7.2,v1.6.2", "report_interval": 5 } -}*/ +} +*/ + +// attribute ICON IDs +export const kClassIconFSAvail = 'ico-fs-percent'; +export const kClassIconFSTotal = 'ico-fs-total'; +export const kClassIconSysTemp = 'ico-sys-temp'; +export const kClassIconUptime = 'ico-up-time'; +export const kClassIconUpdated = 'ico-last-update'; +export const kClassIconOS = 'ico-*nix'; +export const kClassIconRPiModel = 'ico-rpi-model'; +export const kClassIconInterfaces = 'ico-rpi-ifaces'; +export const kClassIconMemoryUsage = 'ico-memory-percent'; +// attribute value label IDs +export const kClassIdFSAvail = 'fs-percent'; +export const kClassIdFSTotal = 'fs-total'; +export const kClassIdSysTemp = 'sys-temp'; +export const kClassIdUptime = 'up-time'; +export const kClassIdUpdated = 'last-update'; +export const kClassIdOS = '*nix'; +export const kClassIdRPiModel = 'rpi-model'; +export const kClassIdInterfaces = 'rpi-ifaces'; +export const kClassIdMemoryUsage = 'memory-percent'; +// ond one special for unit +export const kClassIdTempScale = 'sys-temp-scale'; export const RPI_TOP_KEY = 'info'; diff --git a/src/rpi-monitor-card.ts b/src/rpi-monitor-card.ts index e03a0d5..8d32c8c 100644 --- a/src/rpi-monitor-card.ts +++ b/src/rpi-monitor-card.ts @@ -1,10 +1,10 @@ -/* eslint-disable @typescript-eslint/no-inferrable-types */ /* I prefer to learn early when an unexpected type is being assigned */ +/* eslint-disable @typescript-eslint/no-inferrable-types */ +// (I prefer to learn early when an unexpected type is being assigned) import { LitElement, html, TemplateResult, css, PropertyValues, CSSResultGroup } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { HomeAssistant, applyThemesOnElement, - computeStateDisplay, hasAction, ActionHandlerEvent, handleAction, @@ -18,6 +18,7 @@ import './editor'; import { RPiMonitorCardConfig } from './types'; import { actionHandler } from './action-handler-directive'; import * as Constants from './const'; +import { ColorUtils } from './coloring'; import { localize } from './localize/localize'; @@ -55,26 +56,33 @@ export class RPiMonitorCard extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @state() private _config!: RPiMonitorCardConfig; - @state() private _cardSecondsSinceUpdate: number = 0; - @state() private _cardUpdateString: string = ''; + + @state() private _cardMinutesSinceUpdate: number = 0; // and those that don't cause a re-render private _firstTime: boolean = true; - private _sensorAvailable: boolean = false; + private _stateInfoAvailable: boolean = false; private _updateTimerID: NodeJS.Timeout | undefined = undefined; private _configEntityId: string | undefined = undefined; private _hostname: string = ''; private _showFullCard: boolean = true; private _useTempsInC: boolean = true; private kREPLACE_WITH_TEMP_UNITS: string = 'replace-with-temp-units'; - private kMQTT_DAEMON_RELEASE_URL: string = 'https://raw.githubusercontent.com/ironsheep/RPi-Reporter-MQTT2HA-Daemon/master/Release'; private latestDaemonVersions: string[] = ['v1.7.2', 'v1.6.1']; // REMOVE BEFORE FLIGHT (TEST DATA) private currentDaemonVersion: string = ''; + // OS Age is shown (default = True) unless turned off + private _showOsAge: boolean = true; + // Card Update Age is shown (default = True) unless turned off + private _showCardAge: boolean = true; + private _showDaemonUpdNeed: boolean = true; + private _showCardName: boolean = true; + // WARNING set following to false before commit! private _showDebug: boolean = false; // REMOVE BEFORE FLIGHT (!set to false before check-in!) + private colorHelpers: ColorUtils = new ColorUtils(); - // + // ----------------------------------------------------------- // FULL-SIZE CARD tables // private _cardFullElements = { @@ -92,8 +100,8 @@ export class RPiMonitorCard extends LitElement { private _cardFullIconNames = { // top to bottom - Storage: 'sd', 'Storage Use': 'file-percent', + Storage: 'sd', 'Memory Use': 'memory', Temperature: 'thermometer', 'Up-time': 'clock-check-outline', @@ -103,54 +111,32 @@ export class RPiMonitorCard extends LitElement { Interfaces: '', }; - // attribute ICON IDs - private kClassIdIconFSAvail = 'ico-fs-percent'; - private kClassIdIconFSTotal = 'ico-fs-total'; - private kClassIdIconSysTemp = 'ico-sys-temp'; - private kClassIdIconUptime = 'ico-up-time'; - private kClassIdIconUpdated = 'ico-last-update'; - private kClassIdIconOS = 'ico-*nix'; - private kClassIdIconRPiModel = 'ico-rpi-model'; - private kClassIdIconInterfaces = 'ico-rpi-ifaces'; - private kClassIdIconMemoryUsage = 'ico-memory-percent'; - // attribute value label IDs - private kClassIdFSAvail = 'fs-percent'; - private kClassIdFSTotal = 'fs-total'; - private kClassIdSysTemp = 'sys-temp'; - private kClassIdUptime = 'up-time'; - private kClassIdUpdated = 'last-update'; - private kClassIdOS = '*nix'; - private kClassIdRPiModel = 'rpi-model'; - private kClassIdInterfaces = 'rpi-ifaces'; - private kClassIdMemoryUsage = 'memory-percent'; - // ond one special for unit - private kClassIdTempScale = 'sys-temp-scale'; - private _cardFullCssIDs = { // top to bottom - 'Storage Use': this.kClassIdFSAvail, - Storage: this.kClassIdFSTotal, - 'Memory Use': this.kClassIdMemoryUsage, - Temperature: this.kClassIdSysTemp, - 'Up-time': this.kClassIdUptime, - Updated: this.kClassIdUpdated, - OS: this.kClassIdOS, - Model: this.kClassIdRPiModel, - Interfaces: this.kClassIdInterfaces, + 'Storage Use': Constants.kClassIdFSAvail, + Storage: Constants.kClassIdFSTotal, + 'Memory Use': Constants.kClassIdMemoryUsage, + Temperature: Constants.kClassIdSysTemp, + 'Up-time': Constants.kClassIdUptime, + Updated: Constants.kClassIdUpdated, + OS: Constants.kClassIdOS, + Model: Constants.kClassIdRPiModel, + Interfaces: Constants.kClassIdInterfaces, }; private _cardFullIconCssIDs = { // top to bottom - 'Storage Use': this.kClassIdIconFSAvail, - Storage: this.kClassIdIconFSTotal, - 'Memory Use': this.kClassIdIconMemoryUsage, - 'Up-time': this.kClassIdIconUptime, - Updated: this.kClassIdIconUpdated, - Temperature: this.kClassIdIconSysTemp, - OS: this.kClassIdIconOS, - Model: this.kClassIdIconRPiModel, - Interfaces: this.kClassIdIconInterfaces, + 'Storage Use': Constants.kClassIconFSAvail, + Storage: Constants.kClassIconFSTotal, + 'Memory Use': Constants.kClassIconMemoryUsage, + Temperature: Constants.kClassIconSysTemp, + 'Up-time': Constants.kClassIconUptime, + Updated: Constants.kClassIconUpdated, + OS: Constants.kClassIconOS, + Model: Constants.kClassIconRPiModel, + Interfaces: Constants.kClassIconInterfaces, }; - // + + // ----------------------------------------------------------- // GLANCE CARD tables // private _cardGlanceElements = { @@ -174,154 +160,26 @@ export class RPiMonitorCard extends LitElement { private _cardGlanceCssIDs = { // left to right - '%': this.kClassIdFSAvail, - GB: this.kClassIdFSTotal, - Mem: this.kClassIdMemoryUsage, - 'replace-with-temp-units': this.kClassIdSysTemp, - UpTime: this.kClassIdUptime, - Upd: this.kClassIdUpdated, + '%': Constants.kClassIdFSAvail, + GB: Constants.kClassIdFSTotal, + Mem: Constants.kClassIdMemoryUsage, + 'replace-with-temp-units': Constants.kClassIdSysTemp, + UpTime: Constants.kClassIdUptime, + Upd: Constants.kClassIdUpdated, }; private _cardGlanceIconCssIDs = { // left to right - '%': this.kClassIdIconFSAvail, - GB: this.kClassIdIconFSTotal, - Mem: this.kClassIdIconMemoryUsage, - 'replace-with-temp-units': this.kClassIdIconSysTemp, - UpTime: this.kClassIdIconUptime, - Upd: this.kClassIdIconUpdated, - }; - - // space used icon set - private _circleIconsValueByName = { - 'circle-outline': 0, - 'circle-slice-1': 13, - 'circle-slice-2': 25, - 'circle-slice-3': 38, - 'circle-slice-4': 50, - 'circle-slice-5': 63, - 'circle-slice-6': 75, - 'circle-slice-7': 88, - 'circle-slice-8': 100, + '%': Constants.kClassIconFSAvail, + GB: Constants.kClassIconFSTotal, + Mem: Constants.kClassIconMemoryUsage, + 'replace-with-temp-units': Constants.kClassIconSysTemp, + UpTime: Constants.kClassIconUptime, + Upd: Constants.kClassIconUpdated, }; - /* - * COLORING Goals (default) - * - * 1) color time since reported: yellow if longer than 1 reporting interval, red if two or more - * 2) color space-used: nothing to 60%, 61-85% yellow, 86%+ red - * 3) color temp: nothing to 59C, 60-79C yellow, 80C+ red - */ - - // DEFAULT coloring for used space - // user sets 'fs_severity' to override - private _colorUsedSpaceDefault = [ - { - color: 'default', - from: 0, - to: 59, - }, - { - color: 'yellow', - from: 60, - to: 84, - }, - { - color: 'red', - from: 85, - to: 100, - }, - ]; - - // coloring for temp-in-C - // user sets 'temp_severity' to override - private _colorTemperatureDefault = [ - { - color: 'default', - from: 0, - to: 59, - }, - { - color: 'yellow', - from: 60, - to: 79, - }, - { - color: 'red', - from: 85, - to: 100, - }, - ]; - - // coloring for report update age - // no user override for now - private _colorReportPeriodsAgoDefault = [ - { - color: 'default', - from: 0, - to: 3, - }, - { - color: 'orange', - from: 4, - to: 5, - }, - { - color: 'red', - from: 6, - to: 100, - }, - ]; - - // DEFAULT coloring for used memory - // user sets 'memory_severity' to override - private _colorUsedMemoryDefault = [ - { - color: 'red', - from: 75, - to: 100, - }, - { - color: 'yellow', - from: 61, - to: 74, - }, - { - color: 'default', - from: 0, - to: 60, - }, - ]; - - // DEFAULT coloring for named releases - // intent is to show which ones are aging and should no longer be used - // user sets 'os_age' to override - // see https://en.wikipedia.org/wiki/Debian_version_history for important dates (e.g., 'Long-term') - // Jessie EOL 30 June 2020 'red' - // Stretch EOL 30 June 2022 'red' - // Buster EOL 30 June 2024: Jun 2023 'orange', Jan 2024 is 'yellow' - // - // TODO: replace color with dates and use days until date to color? - // - // Thinking: past EOL is 'red' - // within 6 mos of EOL is yellow - // within 12 mos of EOL is orange - private _colorReleaseDefault = [ - { - color: 'red', - os: 'stretch', - }, - { - color: 'red', - os: 'jessie', - }, - { - color: 'red', - os: 'wheezy', - }, - ]; - public setConfig(config: RPiMonitorCardConfig): void { + // https://lit.dev/docs/components/properties/#accessors-custom //console.log('- setConfig() - ENTRY'); // use user debug flag or override with internal flag if set @@ -337,6 +195,11 @@ export class RPiMonitorCard extends LitElement { throw new Error(localize('common.invalid_configuration')); } + if (!config.entity) { + console.log("Invalid configuration. If no entity provided, you'll need to provide a remote entity"); + throw new Error('You need to associate an entity'); + } + if (config.card_style != undefined) { const styleValue: string = config.card_style.toLocaleLowerCase(); if (styleValue != 'full' && styleValue != 'glance') { @@ -355,14 +218,15 @@ export class RPiMonitorCard extends LitElement { this._useTempsInC = config.temp_scale.toLocaleLowerCase() === 'c' ? true : false; } - if (!config.entity) { - console.log("Invalid configuration. If no entity provided, you'll need to provide a remote entity"); - throw new Error('You need to associate an entity'); - } - if (config.test_gui) { getLovelace().setEditMode(true); } + // OS Age is shown (default = True) unless turned off + this._showOsAge = config.show_os_age ? config.show_os_age : true; + // Card Update Age is shown (default = True) unless turned off + this._showCardAge = config.show_update_age ? config.show_update_age : true; + this._showDaemonUpdNeed = config.show_daemon_upd ? config.show_daemon_upd : true; + this._showCardName = config.show_title ? config.show_title : true; this._config = { //name: 'RPi Monitor', (causes name overwrite, don't do this!!!) @@ -373,48 +237,83 @@ export class RPiMonitorCard extends LitElement { this._configEntityId = this._config.entity != undefined ? this._config.entity : undefined; - this._updateSensorAvailability(); - + // set initial state avail. + this._ensureStateInfoAvail(); // request the release info from the DAEMON repository //this.loadDaemonReleases(); //console.log('- setConfig() - EXIT'); } protected shouldUpdate(changedProps: PropertyValues): boolean { + // Called to determine whether an update cycle is required. // https://lit.dev/docs/components/lifecycle/#reactive-update-cycle-performing - //return hasConfigOrEntityChanged(this, changedProps, false); - if (this._hostname.length == 0 || this._hostname == this._configEntityId) { - const tempHostname: string = this._getAttributeValueForKey(Constants.RPI_HOST_NAME_KEY); - if (tempHostname && tempHostname.length > 0) { - this._hostname = tempHostname; - } else { - this._hostname = this._configEntityId ? this._configEntityId : '-not-set-'; - } - } - //console.log('----- shouldUpdate(' + this._hostname + ') - ENTRY'); - let bShouldStatus: boolean = true; + // if we don't yet know our hostname, then get it + + this._ensureStateInfoAvail(); + + // and for debug earliest use: + this._ensureWeHaveHostName(); - this._updateSensorAvailability(); + //console.log('/---- shouldUpdate(' + this._hostname + ') - ENTRY'); + // list our keys + this._debugShowProps(changedProps, 'shouldUpdate'); + + // Opeartional note: + // all the properties will come thru as undefined when page is first loaded + // in this case we say update since the card need to be initially painted + + if (!this._config) { + console.log(' - SU ABORT, no config'); + return false; + } + + // check in order of lightest-weight checks first + let bShouldStatus: boolean = false; if (changedProps.has('_config')) { - //console.log('shouldUpdate(' + this._hostname + ') = [' + true + '] - CONFIG'); + // this will catch our changedProps['_config'] == undefined case in which case we will initially paint our cards + console.log(' - SU config present'); + bShouldStatus = true; + } else if (changedProps.has('_cardMinutesSinceUpdate')) { + console.log(' - SU card last updated changed'); bShouldStatus = true; - } else if (this.hass && this._config) { - const oldHass = changedProps.get('hass') as HomeAssistant | undefined; + } else if (this.hass && this._config && changedProps.has('hass')) { + const oldHass = changedProps.get('hass') as HomeAssistant; if (oldHass && this._configEntityId) { bShouldStatus = oldHass.states[this._configEntityId] !== this.hass.states[this._configEntityId]; - //console.log('shouldUpdate(' + this._hostname + ') = [' + bShouldStatus + '] HASS'); + if (bShouldStatus) { + console.log(' - SU hass state changed'); + } else { + console.log(' - SU !! NO hass state change'); + } } } + /* + else if ( this.hass && this._configEntityId) { + console.log(' - SU NO changes but paint card!'); + // force update so we paint cards early + bShouldStatus = true; + } + */ - //console.log('shouldUpdate(' + this._hostname + ') = [' + true + '] other'); - //console.log('----- shouldUpdate(' + this._hostname + ') - EXIT'); + console.log('\\---- shouldUpdate(' + this._hostname + ') - EXIT w/' + bShouldStatus); return bShouldStatus; } - // https://lit.dev/docs/components/rendering/ + protected willUpdate(changedProps: PropertyValues): void { + // Called before update() (which in-turn calls render()) to compute values needed during the update. + // https://lit.dev/docs/components/lifecycle/#willupdate + //console.log('/---- willUpdate(' + this._hostname + ') - ENTRY'); + // list our keys + this._debugShowProps(changedProps, 'willUpdate()'); + //console.log('\\---- willUpdate(' + this._hostname + ') - EXIT'); + } + protected render(): TemplateResult | void { + // Called by update() and should be implemented to return a renderable result (such as a TemplateResult) used to render the component's DOM. + // https://lit.dev/docs/components/rendering/ + // https://lit.dev/docs/components/lifecycle/#render // Check for stateObj or other necessary things and render a warning if missing if (this._showDebug) { console.log('- render(' + this._hostname + ')'); @@ -427,7 +326,7 @@ export class RPiMonitorCard extends LitElement { return this.showError(localize('common.show_error')); } - if (this._configEntityId && !this._sensorAvailable) { + if (this._configEntityId && !this._stateInfoAvailable) { const warningMessage = 'Entity Unavailable: ' + this._configEntityId; return this.showWarning(warningMessage); } @@ -439,13 +338,13 @@ export class RPiMonitorCard extends LitElement { } // don't let render happen on no-sensor! - if (this._sensorAvailable == false) { + if (!this._stateInfoAvailable) { console.log('?? Render w/o sensor!! (' + this._hostname + ')'); return; } let cardHtml: TemplateResult = html``; - //console.log('----- render(' + this._hostname + ') - ENTRY'); + //console.log('/---- render(' + this._hostname + ') - ENTRY'); if (this._firstTime) { if (this._showDebug) { @@ -462,14 +361,7 @@ export class RPiMonitorCard extends LitElement { this._firstTime = false; } - // OS Age is shown (default = True) unless turned off - const showOsAge = this._config.show_os_age != undefined ? this._config.show_os_age : true; - // Card Update Age is shown (default = True) unless turned off - const showCardAge = this._config.show_update_age != undefined ? this._config.show_update_age : true; - const showDaemonUpdNeed = this._config.show_daemon_upd != undefined ? this._config.show_daemon_upd : true; - const showCardName = this._config.show_title != undefined ? this._config.show_title : true; - - if (showDaemonUpdNeed) { + if (this._showDaemonUpdNeed) { // get Daemon current version const reporter_version: string = this._getAttributeValueForKey(Constants.RPI_SCRIPT_VER_KEY); const reportParts: string[] = reporter_version.split(' '); @@ -486,28 +378,37 @@ export class RPiMonitorCard extends LitElement { } const rpi_fqdn: string = this._getAttributeValueForKey(Constants.RPI_FQDN_KEY); - const ux_release: string = showOsAge == true ? this._getAttributeValueForKey(Constants.RPI_NIX_RELEASE_KEY) : ''; + const ux_release: string = this._showOsAge == true ? this._getAttributeValueForKey(Constants.RPI_NIX_RELEASE_KEY) : ''; - const daemon_update_status: string = showDaemonUpdNeed ? this._computeDaemonUpdMessage(this.currentDaemonVersion) : ''; - const card_timestamp: string = showCardAge == true ? this._cardUpdateString : ''; + const daemon_update_status: string = this._showDaemonUpdNeed ? this._computeDaemonUpdMessage(this.currentDaemonVersion) : ''; + let cardUpdateString: string = ''; + if (this._showCardAge) { + if (this._cardMinutesSinceUpdate == 0) { + cardUpdateString = 'just now'; + } else { + const suffix = this._cardMinutesSinceUpdate == 1 ? '' : 's'; + cardUpdateString = this._cardMinutesSinceUpdate + ' min' + suffix + ' ago'; + } + } + const card_timestamp: string = this._showCardAge == true ? cardUpdateString : ''; //const card_timestamp: string = '{bad value}'; let cardName: string = 'RPi monitor ' + rpi_fqdn; cardName = this._config.name_prefix != undefined ? this._config.name_prefix + ' ' + rpi_fqdn : cardName; cardName = this._config.name != undefined ? this._config.name : cardName; - if (showCardName == false) { + if (this._showCardName == false) { cardName = ''; } - const last_heard_full_class = showCardName == false ? 'last-heard-full-notitle' : 'last-heard-full'; - const last_heard_class = showCardName == false ? 'last-heard-notitle' : 'last-heard'; + const last_heard_full_class = this._showCardName == false ? 'last-heard-full-notitle' : 'last-heard-full'; + const last_heard_class = this._showCardName == false ? 'last-heard-notitle' : 'last-heard'; - const os_name_full_class = showCardName == false ? 'os-name-full-notitle' : 'os-name-full'; - const os_name_class = showCardName == false ? 'os-name-notitle' : 'os-name'; + const os_name_full_class = this._showCardName == false ? 'os-name-full-notitle' : 'os-name-full'; + const os_name_class = this._showCardName == false ? 'os-name-notitle' : 'os-name'; - const daemon_update_full_class = showCardName == false ? 'daemon-update-full-notitle' : 'daemon-update-full'; - const daemon_update_class = showCardName == false ? 'daemon-update-notitle' : 'daemon-update'; + const daemon_update_full_class = (this._showCardName == false ? 'daemon-update-full-notitle' : 'daemon-update-full') + ' center'; + const daemon_update_class = (this._showCardName == false ? 'daemon-update-notitle' : 'daemon-update') + ' center'; if (this._showFullCard) { // our FULL card @@ -532,7 +433,7 @@ export class RPiMonitorCard extends LitElement { ${fullRows}
${card_timestamp}
${ux_release}
-
${daemon_update_status}
+
${daemon_update_status}
`; @@ -559,21 +460,31 @@ export class RPiMonitorCard extends LitElement { ${glanceRows}
${card_timestamp}
${ux_release}
-
${daemon_update_status}
+
${daemon_update_status}
`; } - //console.log('----- render(' + this._hostname + ') - EXIT'); + console.log('/ ---- render() ' + this._hostname + ' ---- :'); + console.log(cardHtml); + //console.log('\\---- render(' + this._hostname + ') - EXIT'); return cardHtml; } - // Here we need to refresh the values after card has been initially rendered protected updated(changedProps: PropertyValues): void { - //console.log('----- updated(' + this._hostname + ') - ENTRY'); + // Called whenever the component’s update finishes and the element's DOM has been updated and rendered. + // NOTE: Implement updated() to perform tasks that use element DOM after an update. For example, + // code that performs animation may need to measure the element DOM. + // https://lit.dev/docs/components/lifecycle/#updated + // Here we need to refresh the values after card has been initially rendered + //console.log('/---- updated(' + this._hostname + ') - ENTRY'); if (this._showDebug) { console.log('- updated(' + this._hostname + ')'); } + + // list our keys + this._debugShowProps(changedProps, 'Updated()'); + if (this._config) { // update cards' theme if changed if (this.hass) { @@ -583,11 +494,10 @@ export class RPiMonitorCard extends LitElement { } } - if (this.hass && this._configEntityId) { - const stateObj = this.hass.states[this._configEntityId]; - if (!stateObj) { - this._stopCardRefreshTimer(); - } + this._ensureStateInfoAvail(); + if (!this._stateInfoAvailable) { + // if we lost our state information, then stop our card timer... + this._stopCardRefreshTimer(); } //console.log('- changed Props: [' + changedProps + ']'); @@ -595,110 +505,113 @@ export class RPiMonitorCard extends LitElement { // eslint-disable-next-line @typescript-eslint/no-explicit-any const root: any = this.shadowRoot; - if (this._sensorAvailable) { - // update common label(s) - const ux_release: string = this._getAttributeValueForKey(Constants.RPI_NIX_RELEASE_KEY); - const rlsNameColor = this._computeOsReleaseColor(ux_release); - if (rlsNameColor != '') { - const labelElement = root.getElementById('os-name'); - labelElement.style.setProperty('color', rlsNameColor); - } - - // apply color if RPi daemon should be updated - const daemonUpdColor = this._computeDaemonUpdateVersionColor(this.currentDaemonVersion); - if (daemonUpdColor != '') { - const labelElement = root.getElementById('daemon-update'); - labelElement.style.setProperty('color', daemonUpdColor); + if (this._stateInfoAvailable) { + if (changedProps.get('_cardMinutesSinceUpdate') != undefined) { + // now apply card age color if our entry is OLD + const intervalColor = this.colorHelpers.calculateReporterAgeColor(this._cardMinutesSinceUpdate); + if (intervalColor != '') { + const labelElement = root.getElementById('card-timestamp'); + labelElement.style.setProperty('color', intervalColor); + } } + if (changedProps.has('hass')) { + // update common label(s) + const ux_release: string = this._getAttributeValueForKey(Constants.RPI_NIX_RELEASE_KEY); + const rlsNameColor = this.colorHelpers.calculateOsReleaseColor(ux_release, this._config.os_age); + if (rlsNameColor != '') { + const labelElement = root.getElementById('os-name'); + labelElement.style.setProperty('color', rlsNameColor); + } - // now apply color if our entry is OLD - const intervalColor = this._computeReporterAgeColor(this._cardSecondsSinceUpdate); - if (intervalColor != '' && intervalColor != undefined) { - const labelElement = root.getElementById('card-timestamp'); - labelElement.style.setProperty('color', intervalColor); - } + // apply color if RPi daemon should be updated + const daemonUpdColor = this.colorHelpers.calculateDaemonUpdateVersionColor(this.currentDaemonVersion, this.latestDaemonVersions); + if (daemonUpdColor != '') { + const labelElement = root.getElementById('daemon-update'); + labelElement.style.setProperty('color', daemonUpdColor); + } - if (this._showFullCard) { - // update our FULL card - for (const currName in this._cardFullCssIDs) { - const currLabelID = this._cardFullCssIDs[currName]; - const currAttrKey = this._cardFullElements[currName]; - const rawValue = this._getAttributeValueForKey(currAttrKey); - const latestValue = this._getFullCardValueForAttributeKey(currAttrKey); - // if (currAttrKey == Constants.RPI_MEMORY_USED_PERCENT_KEY) { - // console.log('- FULL memory latestValue=[' + latestValue + ']'); - // } - const labelElement = root.getElementById(currLabelID); - labelElement.textContent = latestValue; - const currIconCssID = this._cardFullIconCssIDs[currName]; - const iconElement = root.getElementById(currIconCssID); - if (currAttrKey == Constants.RPI_FS_USED_PERCENT_KEY) { - const color = this._computeFileSystemUsageColor(rawValue); - if (color != '') { - labelElement.style.setProperty('color', color); - iconElement.style.setProperty('color', color); - } - } - if (currAttrKey == Constants.RPI_MEMORY_USED_PERCENT_KEY) { - const color = this._computeMemoryUsageColor(latestValue.replace(' %', '')); - if (color != '') { - labelElement.style.setProperty('color', color); - iconElement.style.setProperty('color', color); + if (this._showFullCard) { + // update our FULL card + for (const currName in this._cardFullCssIDs) { + const currLabelID = this._cardFullCssIDs[currName]; + const currAttrKey = this._cardFullElements[currName]; + const rawValue = this._getAttributeValueForKey(currAttrKey); + const latestValue = this._getFullCardValueForAttributeKey(currAttrKey); + // if (currAttrKey == Constants.RPI_MEMORY_USED_PERCENT_KEY) { + // console.log('- FULL memory latestValue=[' + latestValue + ']'); + // } + const labelElement = root.getElementById(currLabelID); + labelElement.textContent = latestValue; + const currIconCssID = this._cardFullIconCssIDs[currName]; + const iconElement = root.getElementById(currIconCssID); + if (currAttrKey == Constants.RPI_FS_USED_PERCENT_KEY) { + const color = this.colorHelpers.calculateFileSystemUsageColor(rawValue, this._config.fs_severity); + if (color != '') { + labelElement.style.setProperty('color', color); + iconElement.style.setProperty('color', color); + } } - } - if (currAttrKey == Constants.RPI_TEMPERATURE_IN_C_KEY) { - const color = this._computeTemperatureColor(rawValue); - if (color != '') { - labelElement.style.setProperty('color', color); - iconElement.style.setProperty('color', color); + if (currAttrKey == Constants.RPI_MEMORY_USED_PERCENT_KEY) { + const color = this.colorHelpers.calculateMemoryUsageColor(latestValue.replace(' %', ''), this._config.memory_severity); + if (color != '') { + labelElement.style.setProperty('color', color); + iconElement.style.setProperty('color', color); + } } - } - } - } else { - // update our GLANCE card - for (const currName in this._cardGlanceCssIDs) { - const currLabelID = this._cardGlanceCssIDs[currName]; - const currAttrKey = this._cardGlanceElements[currName]; - const rawValue = this._getAttributeValueForKey(currAttrKey); - const latestValue = this._getGlanceCardValueForAttributeKey(currAttrKey); - // if (currAttrKey == Constants.RPI_MEMORY_USED_PERCENT_KEY) { - // console.log('- GLNC memory latestValue=[' + latestValue + ']'); - // } - const labelElement = root.getElementById(currLabelID); - labelElement.textContent = latestValue; - const currIconCssID = this._cardGlanceIconCssIDs[currName]; - const iconElement = root.getElementById(currIconCssID); - if (currAttrKey == Constants.RPI_FS_USED_PERCENT_KEY) { - const color = this._computeFileSystemUsageColor(rawValue); - if (color != '') { - labelElement.style.setProperty('color', color); - iconElement.style.setProperty('color', color); + if (currAttrKey == Constants.RPI_TEMPERATURE_IN_C_KEY) { + const color = this.colorHelpers.calculateTemperatureColor(rawValue, this._config.temp_severity); + if (color != '') { + labelElement.style.setProperty('color', color); + iconElement.style.setProperty('color', color); + } } } - if (currAttrKey == Constants.RPI_MEMORY_USED_PERCENT_KEY) { - const color = this._computeMemoryUsageColor(latestValue); - if (color != '') { - labelElement.style.setProperty('color', color); - iconElement.style.setProperty('color', color); + } else { + // update our GLANCE card + for (const currName in this._cardGlanceCssIDs) { + const currLabelID = this._cardGlanceCssIDs[currName]; + const currAttrKey = this._cardGlanceElements[currName]; + const rawValue = this._getAttributeValueForKey(currAttrKey); + const latestValue = this._getGlanceCardValueForAttributeKey(currAttrKey); + // if (currAttrKey == Constants.RPI_MEMORY_USED_PERCENT_KEY) { + // console.log('- GLNC memory latestValue=[' + latestValue + ']'); + // } + const labelElement = root.getElementById(currLabelID); + labelElement.textContent = latestValue; + const currIconCssID = this._cardGlanceIconCssIDs[currName]; + const iconElement = root.getElementById(currIconCssID); + if (currAttrKey == Constants.RPI_FS_USED_PERCENT_KEY) { + const color = this.colorHelpers.calculateFileSystemUsageColor(rawValue, this._config.fs_severity); + if (color != '') { + labelElement.style.setProperty('color', color); + iconElement.style.setProperty('color', color); + } } - } - if (currAttrKey == Constants.RPI_TEMPERATURE_IN_C_KEY) { - // don't place temp scale (C or F) when 'n/a' - if (latestValue != 'n/a') { - const color = this._computeTemperatureColor(rawValue); + if (currAttrKey == Constants.RPI_MEMORY_USED_PERCENT_KEY) { + const color = this.colorHelpers.calculateMemoryUsageColor(latestValue, this._config.memory_severity); if (color != '') { labelElement.style.setProperty('color', color); iconElement.style.setProperty('color', color); } - const scaleLabelElement = root.getElementById(this.kClassIdTempScale); - scaleLabelElement.textContent = this._getTemperatureScale(); + } + if (currAttrKey == Constants.RPI_TEMPERATURE_IN_C_KEY) { + // don't place temp scale (C or F) when 'n/a' + if (latestValue != 'n/a') { + const color = this.colorHelpers.calculateTemperatureColor(rawValue, this._config.temp_severity); + if (color != '') { + labelElement.style.setProperty('color', color); + iconElement.style.setProperty('color', color); + } + const scaleLabelElement = root.getElementById(Constants.kClassIdTempScale); + scaleLabelElement.textContent = this._getTemperatureScale(); + } } } } } } } - //console.log('----- updated(' + this._hostname + ') - EXIT'); + //console.log('\\---- updated(' + this._hostname + ') - EXIT'); } private _handleAction(ev: ActionHandlerEvent): void { @@ -729,7 +642,8 @@ export class RPiMonitorCard extends LitElement { // --------------------------------------------------------------------------- private _startCardRefreshTimer(): void { - this._updateTimerID = setInterval(() => this._handleCardUpdateTimerExpiration(), 1000); + // set timer to refresh every 15 seconds + this._updateTimerID = setInterval(() => this._handleCardUpdateTimerExpiration(), 15 * 1000); if (this._showDebug) { console.log('TIMER: (' + this._hostname + ') started'); } @@ -750,97 +664,47 @@ export class RPiMonitorCard extends LitElement { // timestamp portion of card // //console.log('TIMER: (' + this._hostname + ') timeout ENTRY'); - const [card_timestamp_value, sinceInMinutes] = this._getRelativeTimeSinceUpdate(); - //console.log('-- card_timestamp_value=[' + card_timestamp_value + '] sinceInMinutes=[' + sinceInMinutes + ']'); - if (card_timestamp_value && card_timestamp_value.length > 0) { - let card_timestamp = card_timestamp_value; - //console.log(' HCUTE (' + this._hostname + ') card_timestamp_value=[' + card_timestamp_value + ']'); - // BUGFIX let's NOT show 'in NaN weeks' message on reload... - if (card_timestamp_value.includes('NaN')) { - console.log(' HCUTE (DBG) (' + this._hostname + ') card_timestamp_value=[' + card_timestamp_value + ']'); - //card_timestamp = 'waiting for report...'; - //needCardFlush = true; // we have a system bug causing a mis-fire... don't clear the card... - card_timestamp = '{bad value}'; - } - // set properties which should cause our card update - if (this._cardUpdateString != card_timestamp) { - this._cardUpdateString = card_timestamp; - } - if (this._cardSecondsSinceUpdate != sinceInMinutes) { - this._cardSecondsSinceUpdate = sinceInMinutes; - } + const sinceMinutes = this._calculateRelativeMinutesSinceUpdate(); + // set properties which should cause our card update + if (this._cardMinutesSinceUpdate != sinceMinutes) { + this._cardMinutesSinceUpdate = sinceMinutes; } //console.log('TIMER: (' + this._hostname + ') timeout EXIT'); } - private _logChangeMessage(message: string): void { - const logMessage = '(' + this._hostname + '): ' + message; - if (this._showDebug) { - console.log(logMessage); - } + private _debugShowProps(changedProps: PropertyValues, message: string): void { + console.log('/ ---- ' + message + ' ' + this._hostname + ' ---- :'); + console.log(changedProps); } - private _updateSensorAvailability(): void { - let availChanged: boolean = false; - if (this.hass && this._config) { - const stateObj = this._configEntityId ? this.hass.states[this._configEntityId] : undefined; - - if (!this._configEntityId && !stateObj) { - this._sensorAvailable = false; - availChanged = true; // force output in this case - } else { - if (this._configEntityId) { - try { - const tmpAvail = this.hass.states[this._configEntityId].state != 'unavailable'; - availChanged = this._sensorAvailable != tmpAvail ? true : false; - this._sensorAvailable = tmpAvail; - } catch (error) { - this._sensorAvailable = false; - availChanged = true; // force output in this case - } + private _ensureStateInfoAvail() { + // keep our global status up-to-date + if (this._configEntityId && this.hass) { + const backingState = this._configEntityId ? this.hass.states[this._configEntityId] : undefined; + if (backingState) { + // um, yeah, we have to go one step further so empty card with bad values doesn't display + if (backingState.state == 'unavailable') { + this._stateInfoAvailable = false; // well, not quite yet + } else { + this._stateInfoAvailable = true; // yep!! } + } else { + this._stateInfoAvailable = false; // well, not quite yet } - } else { - this._sensorAvailable = false; - availChanged = true; // force output in this case - } - if (availChanged) { - this._logChangeMessage('* SENSOR available: ' + this._sensorAvailable); } } - /* - private async loadDaemonReleases(): Promise { - this.latestDaemonVersions = await fetch(this.kMQTT_DAEMON_RELEASE_URL).then((response) => response.text().then(this._loadDaemonReleaseInfo)); - console.log('LDR (' + this._hostname + ') latestDaemonVersions=[' + this.latestDaemonVersions + '](' + this.latestDaemonVersions.length + ')'); - } - - private _loadDaemonReleaseInfo(retrievedText: string): string[] { - //console.log('LDRI retrievedText=[' + retrievedText + ']'); - let foundVersions: string[] = []; - if (retrievedText) { - foundVersions = []; // silence FALSE! compiler-detect error - const lines: string[] = retrievedText.split('\n'); - //console.log('FAR lines=[' + lines + '](' + lines.length + ')'); - for (let index: number = 0; index < lines.length; index++) { - const currLine: string = lines[index]; - //console.log('FAR currLine=[' + currLine + '](' + currLine.length + ')'); - if (currLine.length > 0) { - const lineParts: string[] = currLine.split(' '); - if (lineParts.length > 0) { - //console.log('FAR lineParts(' + index + ')=[' + lineParts + '](' + lineParts.length + ')'); - if (!foundVersions.includes(lineParts[0])) { - // add only non-duplicates - foundVersions.push(lineParts[0]); - } - } - } + private _ensureWeHaveHostName() { + // as soon as we get our real hostname post it globally + if (this._hostname.length == 0 || this._hostname == this._configEntityId) { + const tempHostname: string = this._getAttributeValueForKey(Constants.RPI_HOST_NAME_KEY); + if (tempHostname && tempHostname.length > 0) { + this._hostname = tempHostname; + } else { + this._hostname = this._configEntityId ? this._configEntityId : '-not-set-'; } } - //console.log('* foundVersions=[' + foundVersions + ']'); - return foundVersions; } - */ private _computeDaemonUpdMessage(currentReporterVersion: string): string { let updateStatusMessage: string = ''; @@ -849,7 +713,16 @@ export class RPiMonitorCard extends LitElement { console.log('- RNDR latestDaemonVersions=[' + this.latestDaemonVersions + ']'); } if (this.latestDaemonVersions.length > 0 && currentReporterVersion != '') { - if (currentReporterVersion != this.latestDaemonVersions[0]) { + if (currentReporterVersion < this.latestDaemonVersions[0]) { + // test code + /* + if (currentReporterVersion > this.latestDaemonVersions[0]) { + console.log(currentReporterVersion + ' is > than ' + this.latestDaemonVersions[0]); + } else { + console.log(currentReporterVersion + ' is < than ' + this.latestDaemonVersions[0]); + } + */ + // test code // reporter version is not latest updateStatusMessage = currentReporterVersion + ' ---> ' + this.latestDaemonVersions[0]; } @@ -863,243 +736,23 @@ export class RPiMonitorCard extends LitElement { return updateStatusMessage; } - private _getRelativeTimeSinceUpdate(): [string, number] { - const stateObj = this._configEntityId ? this.hass.states[this._configEntityId] : undefined; - let desiredValue: string = ''; + private _calculateRelativeMinutesSinceUpdate(): number { let desiredMinutes: number = 0; - let minutesValue: string = ''; - if (this.hass.locale && stateObj) { - try { - const stateStrInterp = computeStateDisplay(this.hass?.localize, stateObj, this.hass.locale); - // console.log('- grtsu card stateStrInterp=[' + stateStrInterp + ']'); - const relativeInterp = stateStrInterp === undefined ? '{unknown}' : this._formatTimeAgo(stateStrInterp); - // console.log(' relativeInterp=[' + relativeInterp + ']'); - desiredValue = this._sensorAvailable ? relativeInterp : '{unknown}'; - // console.log(' desiredValue=[' + desiredValue + ']'); - const lineParts: string[] = relativeInterp.split(' '); - minutesValue = lineParts[0]; - } catch (error) { - console.log('GRTSU - exception:'); - console.error(error); - } - - if (minutesValue.includes('just') || minutesValue.includes('unknown')) { - desiredMinutes = 0; - } else { - desiredMinutes = Number(minutesValue); - } - } - return [desiredValue, desiredMinutes]; - } - - private _formatTimeAgo(time: string): string { - const date: Date = new Date((time || '').replace(/-/g, '/').replace(/[TZ]/g, ' ')); - const diff: number = (new Date().getTime() - date.getTime()) / 1000; - const day_diff: number = Math.floor(diff / 86400); - const year: number = date.getFullYear(); - const month: number = date.getMonth() + 1; - const day: number = date.getDate(); - - if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) - return year.toString() + '-' + (month < 10 ? '0' + month.toString() : month.toString()) + '-' + (day < 10 ? '0' + day.toString() : day.toString()); - - let rslt: string = '{unknown}'; - if (day_diff == 0) { - if (diff < 60) { - rslt = 'just now'; - } else if (diff < 120) { - rslt = '1 min ago'; - } else if (diff < 3600) { - rslt = Math.floor(diff / 60) + ' mins ago'; - } else if (diff < 7200) { - rslt = '1 hr ago'; - } else if (diff < 86400) { - rslt = Math.floor(diff / 3600) + ' hrs ago'; - } - } else if (day_diff == 1) { - rslt = 'Yesterday'; - } else if (day_diff < 7) { - rslt = day_diff + ' days ago'; - } else if (day_diff < 31) { - rslt = Math.ceil(day_diff / 7) + ' wks ago'; - } - return rslt; - } - - private _getIconNameForPercent(percent: string): string { - // return name of icon we should show for given % - let desiredIconName = ''; - for (const currIconName in this._circleIconsValueByName) { - const currMaxValue = this._circleIconsValueByName[currIconName]; - if (percent <= currMaxValue) { - desiredIconName = currIconName; - break; - } - } - return desiredIconName; - } - - private _computeReporterAgeColor(numberValue: number): string { - const sections = this._colorReportPeriodsAgoDefault; - - //console.log('color-table: sections=[' + sections + ']'); - //return ''; - - let color: undefined | string = undefined; - - sections.forEach((section) => { - if (numberValue >= section.from && numberValue <= section.to) { - color = section.color; - } - }); - - if (color == undefined || color == 'default') color = ''; - return color; - } - - private _computeTemperatureColor(value: string): string { - const config = this._config; - const numberValue = Number(value); - const sections = config.temp_severity ? config.temp_severity : this._colorTemperatureDefault; - - //console.log('color-table: sections=[' + sections + ']'); - //return ''; - - let color: undefined | string; - - if (!isNaN(numberValue)) { - sections.forEach((section) => { - if (numberValue >= section.from && numberValue <= section.to) { - color = section.color; - if (this._showDebug) { - const logMessage = - '_computeTemperatureColor() - value=[' + value + '] matched(from=' + section.from + ', to=' + section.to + ', color=' + color + ')'; - console.log(logMessage); - } - } - }); - } - if (this._showDebug) { - const logMessage = '_computeTemperatureColor() - value=[' + value + '] returns(color=' + color + ')'; - console.log(logMessage); - } - if (color == undefined || color == 'default') color = ''; - return color; - } - - private _computeFileSystemUsageColor(value: string): string { - const config = this._config; - const numberValue = Number(value); - const sections = config.fs_severity ? config.fs_severity : this._colorUsedSpaceDefault; - - //console.log('color-table: sections=[' + _colorUsedMemoryDefault + ']'); - //return ''; - - let color: undefined | string; - - if (!isNaN(numberValue)) { - sections.forEach((section) => { - if (numberValue >= section.from && numberValue <= section.to) { - color = section.color; - if (this._showDebug) { - const logMessage = - '_computeFileSystemUsageColor() - value=[' + value + '] matched(from=' + section.from + ', to=' + section.to + ', color=' + color + ')'; - console.log(logMessage); - } - } - }); - } - if (this._showDebug) { - const logMessage = '_computeFileSystemUsageColor() - value=[' + value + '] returns(color=' + color + ')'; - console.log(logMessage); - } - - if (color == undefined || color == 'default') color = ''; - return color; - } - - private _computeMemoryUsageColor(value: string): string { - const config = this._config; - const numberValue = Number(value); - const sections = config.memory_severity ? config.memory_severity : this._colorUsedMemoryDefault; - - let color: undefined | string; - - if (!isNaN(numberValue)) { - sections.forEach((section) => { - if (numberValue >= section.from && numberValue <= section.to) { - color = section.color; - if (this._showDebug) { - const logMessage = - '_computeMemoryUsageColor() - value=[' + value + '] matched(from=' + section.from + ', to=' + section.to + ', color=' + color + ')'; - console.log(logMessage); - } - } - }); - } - if (this._showDebug) { - const logMessage = '_computeMemoryUsageColor() - value=[' + value + '] returns(color=' + color + ')'; - console.log(logMessage); + const backingState = this._configEntityId ? this.hass.states[this._configEntityId] : undefined; + // publish so we don't check this again + this._stateInfoAvailable = backingState ? true : false; + if (backingState) { + const stateTime: string = backingState.state; + //console.log('state:' + stateTime + ', chg:' + stateLastChangedTime + ', upd:' + stateLastUpdatedTime); + const stateDate: Date = new Date(stateTime); + const stateSeconds = Math.round(stateDate.getTime() / 1000); + const currSeconds: number = Math.round(new Date().getTime() / 1000); + //if (this._hostname == 'pip2iotgw') { + // console.log('- GRSSU (' + this._hostname + ') stateSec:' + (currSeconds - stateSeconds)); + //} + desiredMinutes = Math.round((currSeconds - stateSeconds) / 60); } - - if (color == undefined || color == 'default') color = ''; - return color; - } - - private _computeOsReleaseColor(osName: string): string { - const config = this._config; - const sections = config.os_age ? config.os_age : this._colorReleaseDefault; - - //console.log('color-table: sections=[' + sections + ']'); - //return ''; - - let color: undefined | string = 'default'; - - sections.forEach((section) => { - if (osName === section.os) { - color = section.color; - if (this._showDebug) { - const logMessage = '_computeOsReleaseColor() - value=[' + osName + '] matched(os=' + section.os + ', color=' + color + ')'; - console.log(logMessage); - } - } - }); - if (this._showDebug) { - const logMessage = '_computeOsReleaseColor() - value=[' + osName + '] returns(color=' + color + ')'; - console.log(logMessage); - } - if (color == undefined || color == 'default') color = ''; - return color; - } - - private _computeDaemonUpdateVersionColor(currentReporterVersion: string): string { - //console.log('color-table: sections=[' + sections + ']'); - //return ''; - - let color: undefined | string = undefined; - - if (this.latestDaemonVersions.length > 0 && currentReporterVersion != '') { - if (this.latestDaemonVersions[0] == currentReporterVersion) { - // daemon is at latest - color = 'default'; - } else if (this.latestDaemonVersions.includes(currentReporterVersion)) { - // daemon is recent - color = 'orange'; - } else { - // daemon is old (not even in latest or stable) - color = 'red'; - } - } else { - // daemon values are missing??? - color = 'orange'; - } - if (this._showDebug) { - const logMessage = '_computeDaemonUpdateVersionColor() - value=[' + currentReporterVersion + '] returns(color=' + color + ')'; - console.log(logMessage); - } - - if (color == undefined || color == 'default') color = ''; - return color; + return desiredMinutes; } private _filterUptime(uptimeRaw: string): string { @@ -1142,34 +795,6 @@ export class RPiMonitorCard extends LitElement { return desiredValue; } - private _emptyCardValuesWhileWaitingForSensor(): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const root: any = this.shadowRoot; - - if (this._sensorAvailable) { - if (this._showFullCard) { - // clear values for our FULL card - for (const currName in this._cardFullCssIDs) { - const currLabelID = this._cardFullCssIDs[currName]; - const labelElement = root.getElementById(currLabelID); - labelElement.textContent = ''; - } - } else { - // clear values for our GLANCE card - for (const currName in this._cardGlanceCssIDs) { - const currLabelID = this._cardGlanceCssIDs[currName]; - const currAttrKey = this._cardGlanceElements[currName]; - const labelElement = root.getElementById(currLabelID); - labelElement.textContent = ''; - if (currAttrKey == Constants.RPI_TEMPERATURE_IN_C_KEY) { - const scaleLabelElement = root.getElementById(this.kClassIdTempScale); - scaleLabelElement.textContent = this._getTemperatureScale(); - } - } - } - } - } - private _generateFullsizeCardRows(): TemplateResult[] { // create the rows for the GLANCE card const rowsArray: TemplateResult[] = []; @@ -1183,7 +808,7 @@ export class RPiMonitorCard extends LitElement { let currIconName = this._cardFullIconNames[currName]; if (currAttributeKey == Constants.RPI_FS_USED_PERCENT_KEY) { const latestRawValue = this._getAttributeValueForKey(currAttributeKey); - currIconName = this._getIconNameForPercent(latestRawValue); + currIconName = this.colorHelpers.getIconNameForPercent(latestRawValue); } const currIconCssID = this._cardFullIconCssIDs[currName]; // get ID for values that need updating @@ -1233,14 +858,14 @@ export class RPiMonitorCard extends LitElement { } let currIconName = this._cardGlanceIconNames[currName]; if (currAttributeKey == Constants.RPI_FS_USED_PERCENT_KEY) { - currIconName = this._getIconNameForPercent(interpValue); + currIconName = this.colorHelpers.getIconNameForPercent(interpValue); } const currLabelCssID = this._cardGlanceCssIDs[currName]; const currIconCssID = this._cardGlanceIconCssIDs[currName]; let scaleCssID = 'units'; if (currAttributeKey == Constants.RPI_TEMPERATURE_IN_C_KEY) { - scaleCssID = this.kClassIdTempScale; + scaleCssID = Constants.kClassIdTempScale; } columnsArray.push(html`