diff --git a/CHANGELOG.md b/CHANGELOG.md index 3df7bd6..52829a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG.md +## 1.1.0 + +### Features + +- **Language Localization Support:** Added comprehensive support for localization across the card, enabling users to see translated strings based on their selected language. + ## [1.0.7](https://github.com/ngocjohn/vehicle-info-card/releases/tag/v1.0.7) (2024-07-25) ### Features diff --git a/README.md b/README.md index ef075b4..5e43fe9 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ Below is the basic configuration for the custom card: | `name` | string | Optional | The name to be displayed on the card. Default is vehicle model name. | | `device_tracker` | string | Optional | The entity ID of the device tracker for map display. | | `google_api_key` | string | Optional | Google Maps API key for generating address from coordinates. Default is using OpenStreetMap service. | +| `selected_language` | string | Optional | Language options. Default `en` | | `show_slides` | boolean | Optional | Set to `true` to enable slideshow of car images. Default is `false`. | | `show_map` | boolean | Optional | Set to `true` to display the car's position on a map. Default is `false`. | | `show_buttons` | boolean | Optional | Set to `true` to show the buttons. Default is `true`. | diff --git a/dist/vehicle-info-card.js b/dist/vehicle-info-card.js index a85d66d..dedbc34 100644 --- a/dist/vehicle-info-card.js +++ b/dist/vehicle-info-card.js @@ -17,7 +17,7 @@ function t(t,e,i,a){var s,n=arguments.length,r=n<3?e:null===a?a=Object.getOwnPro * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */}console.groupCollapsed("%c VEHICLE-INFO-CARD \n%c v1.0.7 ","color: orange; font-weight: bold; background: black","color: white; font-weight: bold; background: dimgray"),console.info("Lovelace custom card for displaying vehicle information from Mercedes Component integration"),console.info("Github: https://github.com/ngocjohn/vehicle-info-card"),console.info("If you like the card, consider supporting the developer: https://github.com/sponsors/ngocjohn"),console.groupEnd();const e=globalThis,i=e.ShadowRoot&&(void 0===e.ShadyCSS||e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,a=Symbol(),s=new WeakMap;class n{constructor(t,e,i){if(this._$cssResult$=!0,i!==a)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=>new n("string"==typeof t?t:t+"",void 0,a),o=(t,...e)=>{const i=1===t.length?t[0]:e.reduce(((e,i,a)=>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[a+1]),t[0]);return new n(i,t,a)},l=(t,a)=>{if(i)t.adoptedStyleSheets=a.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet));else for(const i of a){const a=document.createElement("style"),s=e.litNonce;void 0!==s&&a.setAttribute("nonce",s),a.textContent=i.cssText,t.appendChild(a)}},c=i?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return r(e)})(t):t + */}console.groupCollapsed("%c VEHICLE-INFO-CARD \n%c v1.1.0-alpha ","color: orange; font-weight: bold; background: black","color: white; font-weight: bold; background: dimgray"),console.info("Lovelace custom card for displaying vehicle information from Mercedes Component integration"),console.info("Github: https://github.com/ngocjohn/vehicle-info-card"),console.info("If you like the card, consider supporting the developer: https://github.com/sponsors/ngocjohn"),console.groupEnd();const e=globalThis,i=e.ShadowRoot&&(void 0===e.ShadyCSS||e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,a=Symbol(),s=new WeakMap;class n{constructor(t,e,i){if(this._$cssResult$=!0,i!==a)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=>new n("string"==typeof t?t:t+"",void 0,a),o=(t,...e)=>{const i=1===t.length?t[0]:e.reduce(((e,i,a)=>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[a+1]),t[0]);return new n(i,t,a)},l=(t,a)=>{if(i)t.adoptedStyleSheets=a.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet));else for(const i of a){const a=document.createElement("style"),s=e.litNonce;void 0!==s&&a.setAttribute("nonce",s),a.textContent=i.cssText,t.appendChild(a)}},c=i?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const i of t.cssRules)e+=i.cssText;return r(e)})(t):t /** * @license * Copyright 2017 Google LLC @@ -2690,7 +2690,7 @@ function(){function t(t){t.remember("_draggable",this),this.el=t}t.prototype.ini
${Object.entries(i).map((([t,e])=>this._renderServiceBtn(t,e)))}
- `}saveConfigChange(t){switch(t){case"preheat_start_departure_time":const e={time:Ys(this.preheatConfig.data.time.hour,this.preheatConfig.data.time.minute)};this.callService(t,e);break;case"auxheat_configure":const{items:i,time_selection:a}=this.auxheatConfig.data,s=Object.entries(i).reduce(((t,[e,i])=>{const{hour:a,minute:s}=i;return t[e]=Ys(a,s),t}),{}),n=Object.assign({time_selection:a},s);this.callService(t,n);break;case"battery_max_soc_configure":const r={charge_program:this.chargeConfig.data.selected_program,max_soc:this.chargeConfig.data.max_soc.value};this.callService(t,r);break;case"charge_program_configure":const o={charge_program:this.chargeConfig.data.selected_program};this.callService(t,o);break;case"windows_move":const l=Object.entries(this.windowsConfig.data.positions).reduce(((t,[e,i])=>{const{value:a}=i;return t[e]=a,t}),{});this.callService(t,l);break;case"send_route":const c=Object.entries(this.sendRouteConfig.data).reduce(((t,[e,i])=>{const{value:a}=i;return t[e]=a,t}),{});this.callService(t,c)}}handleSendRouteChange(t,e){const i=e.target.value;this.sendRouteConfig.data[t].value=i,this.requestUpdate()}handleChargeProgramChange(t,e){const i=e.target.value;"max_soc"===t?this.chargeConfig.data[t].value=parseInt(i,10):this.chargeConfig.data[t]=parseInt(i,10),this.requestUpdate()}handlePreheatTimeChange(t){const e=t.target,i=e.value,a=e.configValue,s=this.preheatConfig.data.time;let n;"_hours"===a?(n=parseInt(i,10),s.hour=n):"_mins"===a&&(n=parseInt(i,10),s.minute=n),this.requestUpdate()}handleAuxheatChange(t,e,i){const a=i.target,s=a.value,n=a.configValue,r=this.auxheatConfig.data;let o;"time_selection"===t?r.time_selection=parseInt(s,10):"_hours"===n?(o=parseInt(s,10),r.items[e].hour=o):"_mins"===n&&(o=parseInt(s,10),r.items[e].minute=o),this.requestUpdate()}handleWindowsChange(t,e){this.windowsConfig.data.positions[t].value=e.detail.value,this.requestUpdate()}_handleSubCardClick(t){qt("light"),this.subcardType=this.subcardType===t?null:t,setTimeout((()=>{var t;const e=null===(t=this.shadowRoot)||void 0===t?void 0:t.querySelectorAll(".control-btn-rounded:not(.active).click-shrink");null==e||e.forEach((t=>{t.classList.remove("fade-in","fade-out","hidden"),null===this.subcardType?(t.classList.add("fade-in"),t.classList.remove("hidden")):(t.classList.add("fade-out"),t.addEventListener("animationend",(()=>{t.classList.add("hidden")}),{once:!0}))}))}),0)}lockMoreInfo(){It(this,"hass-more-info",{entityId:this.carLockEntity})}callService(t,e){qt("success"),this.hass.callService("mbapi2020",t,Object.assign({vin:this.carVin},e)),this.launchToast()}launchToast(){var t;const e=null===(t=this.shadowRoot)||void 0===t?void 0:t.getElementById("toast");e&&(e.classList.add("show"),setTimeout((()=>{e.classList.remove("show")}),3e3))}};t([mt({attribute:!1})],Js.prototype,"hass",void 0),t([mt({type:Object})],Js.prototype,"servicesConfig",void 0),t([mt({type:String})],Js.prototype,"carVin",void 0),t([mt({type:String})],Js.prototype,"carLockEntity",void 0),t([mt({type:String})],Js.prototype,"selectedLanguage",void 0),t([vt()],Js.prototype,"subcardType",void 0),t([vt()],Js.prototype,"serviceData",void 0),Js=t([pt("remote-control")],Js);var _s="1.0.7";const $s=_s,tn={lock:{prefix:"lock",suffix:"_lock"},parkBrake:{suffix:"_parkbrakestatus"},liquidRangeCritical:{suffix:"_liquidrangecritical"},lowBrakeFluid:{suffix:"_warningbrakefluid"},lowWashWater:{suffix:"_warningwashwater"},lowCoolantLevel:{suffix:"_warningcoolantlevellow"},engineLight:{suffix:"_warningenginelight"},windowsClosed:{suffix:"_windowstatusoverall"},tirePressureWarning:{suffix:"_tirewarninglamp"},remoteStartActive:{suffix:"_remotestartactive"},engineState:{suffix:"_enginestate"},chargeFlapACStatus:{suffix:"_chargeflapacstatus"}},en={lockSensor:{prefix:"sensor.",suffix:"_lock"},averageSpeedReset:{suffix:"_averagespeedreset"},averageSpeedStart:{suffix:"_averagespeedstart"},distanceReset:{suffix:"_distancereset"},distanceStart:{suffix:"_distancestart"},liquidConsumptionReset:{suffix:"_liquidconsumptionreset"},liquidConsumptionStart:{suffix:"_liquidconsumptionstart"},electricConsumptionReset:{suffix:"_electricconsumptionreset"},electricConsumptionStart:{suffix:"_electricconsumptionstart"},odometer:{suffix:"_odometer"},rangeLiquid:{suffix:"_rangeliquid"},rangeElectric:{suffix:"_rangeelectrickm"},fuelLevel:{suffix:"_tanklevelpercent"},adBlueLevel:{suffix:"_tankleveladblue"},ecoScoreTotal:{suffix:"_ecoscoretotal"},ecoScoreFreeWheel:{suffix:"_ecoscorefreewhl"},ecoScoreBonusRange:{suffix:"_ecoscorebonusrange"},ecoScoreConstant:{suffix:"_ecoscoreconst"},ecoScoreAcceleraion:{suffix:"_ecoscoreaccel"},starterBatteryState:{suffix:"_starterbatterystate"},ignitionState:{suffix:"_ignitionstate"},tirePressureRearLeft:{suffix:"_tirepressurerearleft"},tirePressureRearRight:{suffix:"_tirepressurerearright"},tirePressureFrontLeft:{suffix:"_tirepressurefrontleft"},tirePressureFrontRight:{suffix:"_tirepressurefrontright"},maxSoc:{prefix:"sensor.",suffix:"_max_state_of_charge"},soc:{prefix:"sensor.",suffix:"soc"},chargingPower:{suffix:"_chargingpowerkw"},iginitionState:{suffix:"_ignitionstate"}},an=Object.assign(Object.assign({},tn),en);async function sn(t,e){const i=await t.callWS({type:"config/entity_registry/list"}),a=i.find((t=>t.entity_id===e.entity));if(!a)return{};const s=i.filter((t=>t.device_id===a.device_id)),n={};for(const t of Object.keys(an)){const{prefix:e,suffix:i}=an[t];if("soc"===t||"maxSoc"===t){const e="soc"===t?"State of Charge":"Max State of Charge",i=s.find((t=>t.original_name===e));i&&(n[t]={entity_id:i.entity_id,original_name:i.original_name});continue}const a=s.find((t=>e?t.entity_id.startsWith(e)&&t.entity_id.endsWith(i):t.unique_id.endsWith(i)));a&&(n[t]={entity_id:a.entity_id,original_name:a.original_name})}return n}function nn(t,e){if(!t)return;let i=null,a=null,s=null,n=null,r=!1;const o=e=>{e.stopImmediatePropagation(),e instanceof TouchEvent?(i=e.touches[0].clientX,a=e.touches[0].clientY):e instanceof MouseEvent&&(i=e.clientX,a=e.clientY),["touchmove","mousemove"].forEach((e=>{t.addEventListener(e,l)})),["touchend","mouseup"].forEach((e=>{t.addEventListener(e,c)}))},l=t=>{null!==i&&null!==a&&(t instanceof TouchEvent?(s=i-t.touches[0].clientX,n=a-t.touches[0].clientY):t instanceof MouseEvent&&(s=i-t.clientX,n=a-t.clientY),null!==s&&null!==n&&Math.abs(s)>1&&Math.abs(n)>1&&(r=!0))},c=o=>{o.stopImmediatePropagation(),["touchmove","mousemove"].forEach((e=>{t.removeEventListener(e,l)})),["touchend","mouseup"].forEach((e=>{t.removeEventListener(e,c)}));const h=t.clientWidth;r&&null!==s&&null!==n&&(Math.abs(s)>Math.abs(n)&&Math.abs(s)>h/3&&(s>0?(t.classList.add("swiping-left"),setTimeout((()=>{e("next"),t.classList.remove("swiping-left")}),300)):(t.classList.add("swiping-right"),setTimeout((()=>{e("prev"),t.classList.remove("swiping-right")}),300))),s=n=i=a=null,r=!1)};["touchstart","mousedown"].forEach((e=>{t.addEventListener(e,o)}))}const rn=window.loadCardHelpers?window.loadCardHelpers():void 0;let on=class extends dt{constructor(){super(...arguments),this.selectedLanguage="en",this.vehicleEntities={},this.additionalCards={},this.activeCardType=null,this.localize=(t,e="",i="")=>Qe(t,this.selectedLanguage,e,i),this.getEntityInfoByKey=({key:t,name:e,icon:i,state:a,unit:s})=>{const n=this.vehicleEntities[t];if(!n)return this.getFallbackEntityInfo({key:t,name:e,icon:i,state:a,unit:s});const r=this.getDefaultEntityInfo({key:t,name:e,icon:i,state:a,unit:s},n);switch(t){case"soc":return this.getSocInfo(r,n);case"maxSoc":return this.getMaxSocInfo(r,n);case"chargingPower":return this.getChargingPowerInfo(r,n);case"parkBrake":return this.getParkBrakeInfo(r,n);case"windowsClosed":return this.getWindowsClosedInfo(r,n);case"ignitionState":return this.getIgnitionStateInfo(r,n);case"lockSensor":return this.getLockSensorInfo(r,n);case"starterBatteryState":return this.getStarterBatteryInfo(r,n);default:return this.getWarningOrDefaultInfo(r,t,n)}},this.getFallbackEntityInfo=({key:t,name:e,icon:i,state:a,unit:s})=>{var n,r,o;const l=this.selectedLanguage;if("selectedProgram"===t)return{key:t,name:e,icon:i,state:yi(l)[this.getEntityAttribute(null===(n=this.vehicleEntities.rangeElectric)||void 0===n?void 0:n.entity_id,"selectedChargeProgram")],unit:s};if("doorStatusOverall"===t){const a=this.getEntityAttribute(null===(r=this.vehicleEntities.lockSensor)||void 0===r?void 0:r.entity_id,"doorStatusOverall");return{key:t,name:e,icon:i,state:vi(l)[a]||"Unknown",active:"1"===a,unit:s}}if("drivenTimeReset"===t||"drivenTimeStart"===t){const a="drivenTimeReset"===t?"distanceReset":"distanceStart",n=this.getEntityAttribute(null===(o=this.vehicleEntities[a])||void 0===o?void 0:o.entity_id,t);return{key:t,name:e,icon:i,state:n?Hs(parseInt(n)):"",unit:s}}return{key:t,name:e,icon:i,state:a,unit:s}},this.getDefaultEntityInfo=({key:t,name:e,icon:i,state:a,unit:s},n)=>({key:t,name:null!=e?e:n.original_name,icon:null!=i?i:this.getEntityAttribute(n.entity_id,"icon"),state:null!=a?a:this.getStateDisplay(n.entity_id),unit:null!=s?s:this.getEntityAttribute(n.entity_id,"unit_of_measurement")}),this.getSocInfo=(t,e)=>{const i=this.getEntityState(e.entity_id),a=i?parseFloat(i):0;let s;return s=a<35?"mdi:battery-charging-low":a<70?"mdi:battery-charging-medium":"mdi:battery-charging-high",Object.assign(Object.assign({},t),{icon:s})},this.getMaxSocInfo=(t,e)=>{const i=this.getEntityState(e.entity_id),a=i?parseFloat(i):0,s=`mdi:battery-charging-${10*Math.round(a/10)}`;return Object.assign(Object.assign({},t),{icon:s})},this.getChargingPowerInfo=(t,e)=>{const i=this.getEntityState(e.entity_id),a=i?parseFloat(i):0,s=this.getEntityAttribute(e.entity_id,"unit_of_measurement")||"kW",n=Lt(a,this.hass.locale)+" "+s;return Object.assign(Object.assign({},t),{state:n})},this.getParkBrakeInfo=(t,e)=>{const i=this.getBooleanState(e.entity_id),a=this.localize("common.stateParkBrakeOff"),s=this.localize("common.stateParkBrakeOn");return Object.assign(Object.assign({},t),{state:i?s:a,active:i})},this.getWindowsClosedInfo=(t,e)=>{let i;const a=this.selectedLanguage,s=this.getBooleanState(e.entity_id);if(s)i=this.localize("common.stateClosed");else{const t={};Object.keys(wi(a)).forEach((i=>{const a=this.getEntityAttribute(e.entity_id,i);null!=a&&(t[i]=a)}));i=`${Object.keys(t).filter((e=>"0"===t[e])).length} ${this.localize("common.stateOpen")}`}return Object.assign(Object.assign({},t),{state:i,active:s})},this.getIgnitionStateInfo=(t,e)=>{const i=this.getEntityAttribute(e.entity_id,"value_short"),a=this.getEntityState(e.entity_id),s="0"===a||"1"===a;return Object.assign(Object.assign({},t),{state:i||"Unknown",active:s})},this.getLockSensorInfo=(t,e)=>{const i=this.selectedLanguage,a=this.getEntityState(e.entity_id),s=xi(i)[a]||xi[4],n="2"===a||"1"===a?"mdi:lock":"mdi:lock-open";return Object.assign(Object.assign({},t),{icon:n,state:s,active:"2"===a||"1"===a})},this.getStarterBatteryInfo=(t,e)=>{const i=this.getEntityState(e.entity_id),a=Ai[i]||"Unknown";return Object.assign(Object.assign({},t),{state:a})},this.getWarningOrDefaultInfo=(t,e,i)=>{const a=this.selectedLanguage;if(ai(a).map((t=>t.key)).includes(e)){const e=this.getBooleanState(i.entity_id);return Object.assign(Object.assign({},t),{state:e?"Problem":"Ok",active:e})}return t}}static async getConfigElement(){return await Promise.resolve().then((function(){return Mc})),document.createElement("vehicle-info-card-editor")}get isCharging(){var t;return this.getEntityAttribute(null===(t=this.vehicleEntities.rangeElectric)||void 0===t?void 0:t.entity_id,"chargingactive")}get carVinNumber(){return this.config.entity?this.getEntityAttribute(this.config.entity,"vin"):""}get isDark(){var t,e,i,a;return"dark"===(null===(e=null===(t=this.config)||void 0===t?void 0:t.selected_theme)||void 0===e?void 0:e.mode)||"light"!==(null===(a=null===(i=this.config)||void 0===i?void 0:i.selected_theme)||void 0===a?void 0:a.mode)&&this.hass.themes.darkMode}static get styles(){return Si}async setConfig(t){if(!t)throw new Error("Invalid configuration");this.config=Object.assign({},t),this.selectedLanguage=this.config.selected_language||localStorage.getItem("selectedLanguage")||"en";const e=this.selectedLanguage;for(const t of _e(e))this.config[t.config]&&this.createCards(this.config[t.config],t.type);if(this.config.device_tracker){const{default_zoom:t,hours_to_show:e,theme_mode:i}=this.config.map_popup_config,a={type:"map",default_zoom:t,hours_to_show:e,theme_mode:i,entities:[{entity:this.config.device_tracker}]};this.createCards([a],"mapDialog")}this.config.selected_theme&&this.applyTheme(this.config.selected_theme.theme)}getCardSize(){return 5}firstUpdated(t){super.firstUpdated(t),this.configureAsync(),this.config.selected_theme&&this.applyTheme(this.config.selected_theme.theme)}async configureAsync(){this.vehicleEntities=await sn(this.hass,this.config),this.requestUpdate()}connectedCallback(){super.connectedCallback(),this._editorEventsHandler=this._editorEventsHandler.bind(this),window.addEventListener("editor-event",this._editorEventsHandler)}disconnectedCallback(){window.removeEventListener("editor-event",this._editorEventsHandler),super.disconnectedCallback()}async createCards(t,e){if(rn){const i=await rn,a=await Promise.all(t.map((async t=>{const e=await i.createCardElement(t);return e.hass=this.hass,e})));this.additionalCards[e]=a}}updated(t){var e;if(super.updated(t),t.has("activeCardType")&&"mapDialog"!==this.activeCardType){const t=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector(".card-element");if(!t)return;nn(t,this.toggleCard.bind(this))}}shouldUpdate(t){return!(!this.config||!this.hass)&&(!(!t.has("hass")&&!t.has("config"))||Bt(this,t,!1))}render(){if(!this.config||!this.hass)return Z``;const t=this.config.name||"";return Z` + `}saveConfigChange(t){switch(t){case"preheat_start_departure_time":const e={time:Ys(this.preheatConfig.data.time.hour,this.preheatConfig.data.time.minute)};this.callService(t,e);break;case"auxheat_configure":const{items:i,time_selection:a}=this.auxheatConfig.data,s=Object.entries(i).reduce(((t,[e,i])=>{const{hour:a,minute:s}=i;return t[e]=Ys(a,s),t}),{}),n=Object.assign({time_selection:a},s);this.callService(t,n);break;case"battery_max_soc_configure":const r={charge_program:this.chargeConfig.data.selected_program,max_soc:this.chargeConfig.data.max_soc.value};this.callService(t,r);break;case"charge_program_configure":const o={charge_program:this.chargeConfig.data.selected_program};this.callService(t,o);break;case"windows_move":const l=Object.entries(this.windowsConfig.data.positions).reduce(((t,[e,i])=>{const{value:a}=i;return t[e]=a,t}),{});this.callService(t,l);break;case"send_route":const c=Object.entries(this.sendRouteConfig.data).reduce(((t,[e,i])=>{const{value:a}=i;return t[e]=a,t}),{});this.callService(t,c)}}handleSendRouteChange(t,e){const i=e.target.value;this.sendRouteConfig.data[t].value=i,this.requestUpdate()}handleChargeProgramChange(t,e){const i=e.target.value;"max_soc"===t?this.chargeConfig.data[t].value=parseInt(i,10):this.chargeConfig.data[t]=parseInt(i,10),this.requestUpdate()}handlePreheatTimeChange(t){const e=t.target,i=e.value,a=e.configValue,s=this.preheatConfig.data.time;let n;"_hours"===a?(n=parseInt(i,10),s.hour=n):"_mins"===a&&(n=parseInt(i,10),s.minute=n),this.requestUpdate()}handleAuxheatChange(t,e,i){const a=i.target,s=a.value,n=a.configValue,r=this.auxheatConfig.data;let o;"time_selection"===t?r.time_selection=parseInt(s,10):"_hours"===n?(o=parseInt(s,10),r.items[e].hour=o):"_mins"===n&&(o=parseInt(s,10),r.items[e].minute=o),this.requestUpdate()}handleWindowsChange(t,e){this.windowsConfig.data.positions[t].value=e.detail.value,this.requestUpdate()}_handleSubCardClick(t){qt("light"),this.subcardType=this.subcardType===t?null:t,setTimeout((()=>{var t;const e=null===(t=this.shadowRoot)||void 0===t?void 0:t.querySelectorAll(".control-btn-rounded:not(.active).click-shrink");null==e||e.forEach((t=>{t.classList.remove("fade-in","fade-out","hidden"),null===this.subcardType?(t.classList.add("fade-in"),t.classList.remove("hidden")):(t.classList.add("fade-out"),t.addEventListener("animationend",(()=>{t.classList.add("hidden")}),{once:!0}))}))}),0)}lockMoreInfo(){It(this,"hass-more-info",{entityId:this.carLockEntity})}callService(t,e){qt("success"),this.hass.callService("mbapi2020",t,Object.assign({vin:this.carVin},e)),this.launchToast()}launchToast(){var t;const e=null===(t=this.shadowRoot)||void 0===t?void 0:t.getElementById("toast");e&&(e.classList.add("show"),setTimeout((()=>{e.classList.remove("show")}),3e3))}};t([mt({attribute:!1})],Js.prototype,"hass",void 0),t([mt({type:Object})],Js.prototype,"servicesConfig",void 0),t([mt({type:String})],Js.prototype,"carVin",void 0),t([mt({type:String})],Js.prototype,"carLockEntity",void 0),t([mt({type:String})],Js.prototype,"selectedLanguage",void 0),t([vt()],Js.prototype,"subcardType",void 0),t([vt()],Js.prototype,"serviceData",void 0),Js=t([pt("remote-control")],Js);var _s="1.1.0-alpha";const $s=_s,tn={lock:{prefix:"lock",suffix:"_lock"},parkBrake:{suffix:"_parkbrakestatus"},liquidRangeCritical:{suffix:"_liquidrangecritical"},lowBrakeFluid:{suffix:"_warningbrakefluid"},lowWashWater:{suffix:"_warningwashwater"},lowCoolantLevel:{suffix:"_warningcoolantlevellow"},engineLight:{suffix:"_warningenginelight"},windowsClosed:{suffix:"_windowstatusoverall"},tirePressureWarning:{suffix:"_tirewarninglamp"},remoteStartActive:{suffix:"_remotestartactive"},engineState:{suffix:"_enginestate"},chargeFlapACStatus:{suffix:"_chargeflapacstatus"}},en={lockSensor:{prefix:"sensor.",suffix:"_lock"},averageSpeedReset:{suffix:"_averagespeedreset"},averageSpeedStart:{suffix:"_averagespeedstart"},distanceReset:{suffix:"_distancereset"},distanceStart:{suffix:"_distancestart"},liquidConsumptionReset:{suffix:"_liquidconsumptionreset"},liquidConsumptionStart:{suffix:"_liquidconsumptionstart"},electricConsumptionReset:{suffix:"_electricconsumptionreset"},electricConsumptionStart:{suffix:"_electricconsumptionstart"},odometer:{suffix:"_odometer"},rangeLiquid:{suffix:"_rangeliquid"},rangeElectric:{suffix:"_rangeelectrickm"},fuelLevel:{suffix:"_tanklevelpercent"},adBlueLevel:{suffix:"_tankleveladblue"},ecoScoreTotal:{suffix:"_ecoscoretotal"},ecoScoreFreeWheel:{suffix:"_ecoscorefreewhl"},ecoScoreBonusRange:{suffix:"_ecoscorebonusrange"},ecoScoreConstant:{suffix:"_ecoscoreconst"},ecoScoreAcceleraion:{suffix:"_ecoscoreaccel"},starterBatteryState:{suffix:"_starterbatterystate"},ignitionState:{suffix:"_ignitionstate"},tirePressureRearLeft:{suffix:"_tirepressurerearleft"},tirePressureRearRight:{suffix:"_tirepressurerearright"},tirePressureFrontLeft:{suffix:"_tirepressurefrontleft"},tirePressureFrontRight:{suffix:"_tirepressurefrontright"},maxSoc:{prefix:"sensor.",suffix:"_max_state_of_charge"},soc:{prefix:"sensor.",suffix:"soc"},chargingPower:{suffix:"_chargingpowerkw"},iginitionState:{suffix:"_ignitionstate"}},an=Object.assign(Object.assign({},tn),en);async function sn(t,e){const i=await t.callWS({type:"config/entity_registry/list"}),a=i.find((t=>t.entity_id===e.entity));if(!a)return{};const s=i.filter((t=>t.device_id===a.device_id)),n={};for(const t of Object.keys(an)){const{prefix:e,suffix:i}=an[t];if("soc"===t||"maxSoc"===t){const e="soc"===t?"State of Charge":"Max State of Charge",i=s.find((t=>t.original_name===e));i&&(n[t]={entity_id:i.entity_id,original_name:i.original_name});continue}const a=s.find((t=>e?t.entity_id.startsWith(e)&&t.entity_id.endsWith(i):t.unique_id.endsWith(i)));a&&(n[t]={entity_id:a.entity_id,original_name:a.original_name})}return n}function nn(t,e){if(!t)return;let i=null,a=null,s=null,n=null,r=!1;const o=e=>{e.stopImmediatePropagation(),e instanceof TouchEvent?(i=e.touches[0].clientX,a=e.touches[0].clientY):e instanceof MouseEvent&&(i=e.clientX,a=e.clientY),["touchmove","mousemove"].forEach((e=>{t.addEventListener(e,l)})),["touchend","mouseup"].forEach((e=>{t.addEventListener(e,c)}))},l=t=>{null!==i&&null!==a&&(t instanceof TouchEvent?(s=i-t.touches[0].clientX,n=a-t.touches[0].clientY):t instanceof MouseEvent&&(s=i-t.clientX,n=a-t.clientY),null!==s&&null!==n&&Math.abs(s)>1&&Math.abs(n)>1&&(r=!0))},c=o=>{o.stopImmediatePropagation(),["touchmove","mousemove"].forEach((e=>{t.removeEventListener(e,l)})),["touchend","mouseup"].forEach((e=>{t.removeEventListener(e,c)}));const h=t.clientWidth;r&&null!==s&&null!==n&&(Math.abs(s)>Math.abs(n)&&Math.abs(s)>h/3&&(s>0?(t.classList.add("swiping-left"),setTimeout((()=>{e("next"),t.classList.remove("swiping-left")}),300)):(t.classList.add("swiping-right"),setTimeout((()=>{e("prev"),t.classList.remove("swiping-right")}),300))),s=n=i=a=null,r=!1)};["touchstart","mousedown"].forEach((e=>{t.addEventListener(e,o)}))}const rn=window.loadCardHelpers?window.loadCardHelpers():void 0;let on=class extends dt{constructor(){super(...arguments),this.selectedLanguage="en",this.vehicleEntities={},this.additionalCards={},this.activeCardType=null,this.localize=(t,e="",i="")=>Qe(t,this.selectedLanguage,e,i),this.getEntityInfoByKey=({key:t,name:e,icon:i,state:a,unit:s})=>{const n=this.vehicleEntities[t];if(!n)return this.getFallbackEntityInfo({key:t,name:e,icon:i,state:a,unit:s});const r=this.getDefaultEntityInfo({key:t,name:e,icon:i,state:a,unit:s},n);switch(t){case"soc":return this.getSocInfo(r,n);case"maxSoc":return this.getMaxSocInfo(r,n);case"chargingPower":return this.getChargingPowerInfo(r,n);case"parkBrake":return this.getParkBrakeInfo(r,n);case"windowsClosed":return this.getWindowsClosedInfo(r,n);case"ignitionState":return this.getIgnitionStateInfo(r,n);case"lockSensor":return this.getLockSensorInfo(r,n);case"starterBatteryState":return this.getStarterBatteryInfo(r,n);default:return this.getWarningOrDefaultInfo(r,t,n)}},this.getFallbackEntityInfo=({key:t,name:e,icon:i,state:a,unit:s})=>{var n,r,o;const l=this.selectedLanguage;if("selectedProgram"===t)return{key:t,name:e,icon:i,state:yi(l)[this.getEntityAttribute(null===(n=this.vehicleEntities.rangeElectric)||void 0===n?void 0:n.entity_id,"selectedChargeProgram")],unit:s};if("doorStatusOverall"===t){const a=this.getEntityAttribute(null===(r=this.vehicleEntities.lockSensor)||void 0===r?void 0:r.entity_id,"doorStatusOverall");return{key:t,name:e,icon:i,state:vi(l)[a]||"Unknown",active:"1"===a,unit:s}}if("drivenTimeReset"===t||"drivenTimeStart"===t){const a="drivenTimeReset"===t?"distanceReset":"distanceStart",n=this.getEntityAttribute(null===(o=this.vehicleEntities[a])||void 0===o?void 0:o.entity_id,t);return{key:t,name:e,icon:i,state:n?Hs(parseInt(n)):"",unit:s}}return{key:t,name:e,icon:i,state:a,unit:s}},this.getDefaultEntityInfo=({key:t,name:e,icon:i,state:a,unit:s},n)=>({key:t,name:null!=e?e:n.original_name,icon:null!=i?i:this.getEntityAttribute(n.entity_id,"icon"),state:null!=a?a:this.getStateDisplay(n.entity_id),unit:null!=s?s:this.getEntityAttribute(n.entity_id,"unit_of_measurement")}),this.getSocInfo=(t,e)=>{const i=this.getEntityState(e.entity_id),a=i?parseFloat(i):0;let s;return s=a<35?"mdi:battery-charging-low":a<70?"mdi:battery-charging-medium":"mdi:battery-charging-high",Object.assign(Object.assign({},t),{icon:s})},this.getMaxSocInfo=(t,e)=>{const i=this.getEntityState(e.entity_id),a=i?parseFloat(i):0,s=`mdi:battery-charging-${10*Math.round(a/10)}`;return Object.assign(Object.assign({},t),{icon:s})},this.getChargingPowerInfo=(t,e)=>{const i=this.getEntityState(e.entity_id),a=i?parseFloat(i):0,s=this.getEntityAttribute(e.entity_id,"unit_of_measurement")||"kW",n=Lt(a,this.hass.locale)+" "+s;return Object.assign(Object.assign({},t),{state:n})},this.getParkBrakeInfo=(t,e)=>{const i=this.getBooleanState(e.entity_id),a=this.localize("common.stateParkBrakeOff"),s=this.localize("common.stateParkBrakeOn");return Object.assign(Object.assign({},t),{state:i?s:a,active:i})},this.getWindowsClosedInfo=(t,e)=>{let i;const a=this.selectedLanguage,s=this.getBooleanState(e.entity_id);if(s)i=this.localize("common.stateClosed");else{const t={};Object.keys(wi(a)).forEach((i=>{const a=this.getEntityAttribute(e.entity_id,i);null!=a&&(t[i]=a)}));i=`${Object.keys(t).filter((e=>"0"===t[e])).length} ${this.localize("common.stateOpen")}`}return Object.assign(Object.assign({},t),{state:i,active:s})},this.getIgnitionStateInfo=(t,e)=>{const i=this.getEntityAttribute(e.entity_id,"value_short"),a=this.getEntityState(e.entity_id),s="0"===a||"1"===a;return Object.assign(Object.assign({},t),{state:i||"Unknown",active:s})},this.getLockSensorInfo=(t,e)=>{const i=this.selectedLanguage,a=this.getEntityState(e.entity_id),s=xi(i)[a]||xi[4],n="2"===a||"1"===a?"mdi:lock":"mdi:lock-open";return Object.assign(Object.assign({},t),{icon:n,state:s,active:"2"===a||"1"===a})},this.getStarterBatteryInfo=(t,e)=>{const i=this.getEntityState(e.entity_id),a=Ai[i]||"Unknown";return Object.assign(Object.assign({},t),{state:a})},this.getWarningOrDefaultInfo=(t,e,i)=>{const a=this.selectedLanguage;if(ai(a).map((t=>t.key)).includes(e)){const e=this.getBooleanState(i.entity_id);return Object.assign(Object.assign({},t),{state:e?"Problem":"Ok",active:e})}return t}}static async getConfigElement(){return await Promise.resolve().then((function(){return Mc})),document.createElement("vehicle-info-card-editor")}get isCharging(){var t;return this.getEntityAttribute(null===(t=this.vehicleEntities.rangeElectric)||void 0===t?void 0:t.entity_id,"chargingactive")}get carVinNumber(){return this.config.entity?this.getEntityAttribute(this.config.entity,"vin"):""}get isDark(){var t,e,i,a;return"dark"===(null===(e=null===(t=this.config)||void 0===t?void 0:t.selected_theme)||void 0===e?void 0:e.mode)||"light"!==(null===(a=null===(i=this.config)||void 0===i?void 0:i.selected_theme)||void 0===a?void 0:a.mode)&&this.hass.themes.darkMode}static get styles(){return Si}async setConfig(t){if(!t)throw new Error("Invalid configuration");this.config=Object.assign({},t),this.selectedLanguage=this.config.selected_language||localStorage.getItem("selectedLanguage")||"en";const e=this.selectedLanguage;for(const t of _e(e))this.config[t.config]&&this.createCards(this.config[t.config],t.type);if(this.config.device_tracker){const{default_zoom:t,hours_to_show:e,theme_mode:i}=this.config.map_popup_config,a={type:"map",default_zoom:t,hours_to_show:e,theme_mode:i,entities:[{entity:this.config.device_tracker}]};this.createCards([a],"mapDialog")}this.config.selected_theme&&this.applyTheme(this.config.selected_theme.theme)}getCardSize(){return 5}firstUpdated(t){super.firstUpdated(t),this.configureAsync(),this.config.selected_theme&&this.applyTheme(this.config.selected_theme.theme)}async configureAsync(){this.vehicleEntities=await sn(this.hass,this.config),this.requestUpdate()}connectedCallback(){super.connectedCallback(),this._editorEventsHandler=this._editorEventsHandler.bind(this),window.addEventListener("editor-event",this._editorEventsHandler)}disconnectedCallback(){window.removeEventListener("editor-event",this._editorEventsHandler),super.disconnectedCallback()}async createCards(t,e){if(rn){const i=await rn,a=await Promise.all(t.map((async t=>{const e=await i.createCardElement(t);return e.hass=this.hass,e})));this.additionalCards[e]=a}}updated(t){var e;if(super.updated(t),t.has("activeCardType")&&"mapDialog"!==this.activeCardType){const t=null===(e=this.shadowRoot)||void 0===e?void 0:e.querySelector(".card-element");if(!t)return;nn(t,this.toggleCard.bind(this))}}shouldUpdate(t){return!(!this.config||!this.hass)&&(!(!t.has("hass")&&!t.has("config"))||Bt(this,t,!1))}render(){if(!this.config||!this.hass)return Z``;const t=this.config.name||"";return Z` ${this._renderHeaderBackground()}
diff --git a/package.json b/package.json index 4682c74..2f99340 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vehicle-info-card", - "version": "1.0.7", + "version": "1.1.0-alpha", "description": "Lovelace custom card for displaying vehicle information from Mercedes Component integration", "keywords": [ "home-assistant",