From 98ef9fed054fa4e71899a0e62ce7f8350a912ab7 Mon Sep 17 00:00:00 2001 From: Johan Frick Date: Fri, 13 Oct 2023 08:12:11 +0200 Subject: [PATCH] Add options for all areas (#52) Area identifier `_` sets the options for all areas. Options for a specific area can still be overridden like before. Also the HA area-card is added to use as a strategy area-card. --------- Co-authored-by: DigiLive --- README.md | 35 +++++++++++++---- dist/mushroom-strategy.js | 2 +- src/cards/AreaCard.js | 6 +++ src/cards/HaAreaCard.js | 47 +++++++++++++++++++++++ src/cards/typedefs.js | 7 ++++ src/mushroom-strategy.js | 15 ++++---- src/typedefs.js | 1 + src/views/HomeView.js | 81 +++++++++++++++++++++++++++------------ 8 files changed, 152 insertions(+), 42 deletions(-) create mode 100644 src/cards/HaAreaCard.js diff --git a/README.md b/README.md index d7ada87..903c1b7 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ All the rounded cards can be configured using the Dashboard UI editor. ```yaml strategy: type: custom:mushroom-strategy -views: [ ] +views: [] ``` ### Hidding specific entities @@ -133,7 +133,7 @@ strategy: name: Family Room icon: mdi:sofa icon_color: green -views: [ ] +views: [] ``` ### Area Object @@ -161,6 +161,7 @@ at the top of the area subview. | `hidden` | boolean | false | Set to `true` to exclude the area from the dashboard and views. | | `order` | number | Infinity | Ordering position of the area in the list of available areas. | | `extra_cards` | array of cards | unset or empty | A list of cards to show on the top of the area subview. | +| `type` | string | `default` | Set to a type of area card. (Currently supported: `default` & `HaAreaCard` | *) `more-info` `toggle` `call-service` `navigate` `url` `none` @@ -191,7 +192,9 @@ strategy: order: 2 garage_id: hidden: true -views: [ ] + hallway_id: + type: HaAreaCard +views: [] ``` #### Undisclosed Area @@ -202,6 +205,22 @@ This area is enabled by default and includes the entities that aren't linked to The area can be configured like any other area as described above. To exclude this area from the dashboard and views, set its property `hidden` to `true`. +#### Setting options for all areas + +Use `_` as an identifier to set the options for all areas. + +The following example sets the type of all area-cards to Home Assistant's area card: + +```yaml +strategy: + type: custom:mushroom-strategy + options: + areas: + _: + type: HaAreaCard +views: [] +``` + ### Card Options The `card_options` entry enables you to specify a card type for an entity or to hide the card from the dashboard. @@ -222,7 +241,7 @@ strategy: 077ba0492c9bb3b31ffac34f1f3a626a: hidden: true -views: [ ] +views: [] ``` ### Pre-built views @@ -230,7 +249,7 @@ views: [ ] ![Light Views](./docs/light_view.png) Mushroom strategy includes pre-built views to control/view specific domains. -All devices that are in an area where `hidden` is set to false/undefined are shown. +All devices that are in an area where `hidden` is set to false/undefined are shown. By default, all pre-built views below are shown: @@ -270,7 +289,7 @@ strategy: order: 1 hidden: true icon: mdi:toggle-switch -views: [ ] +views: [] ``` ### Supported domains @@ -312,7 +331,7 @@ strategy: showControls: false default: hidden: true -views: [ ] +views: [] ``` ### Chips @@ -475,7 +494,7 @@ strategy: title: cool view path: cool-view icon: mdi:emoticon-cool - badges: [ ] + badges: [] cards: - type: markdown content: I am cool diff --git a/dist/mushroom-strategy.js b/dist/mushroom-strategy.js index 6a055f3..df2ee0e 100644 --- a/dist/mushroom-strategy.js +++ b/dist/mushroom-strategy.js @@ -1 +1 @@ -(()=>{var t,e,i={84:(t,e,i)=>{"use strict";i.d(e,{W:()=>a});const s={home:{order:1,hidden:!1},light:{order:2,hidden:!1},fan:{order:3,hidden:!1},cover:{order:4,hidden:!1},switch:{order:5,hidden:!1},climate:{order:6,hidden:!1},camera:{order:7,hidden:!1}},r={aliases:[],area_id:null,name:"Undisclosed",picture:null,hidden:!1},o={default:{title:"Miscellaneous",showControls:!1,hidden:!1},light:{title:"Lights",showControls:!0,iconOn:"mdi:lightbulb",iconOff:"mdi:lightbulb-off",onService:"light.turn_on",offService:"light.turn_off",hidden:!1},fan:{title:"Fans",showControls:!0,iconOn:"mdi:fan",iconOff:"mdi:fan-off",onService:"fan.turn_on",offService:"fan.turn_off",hidden:!1},cover:{title:"Covers",showControls:!0,iconOn:"mdi:arrow-up",iconOff:"mdi:arrow-down",onService:"cover.open_cover",offService:"cover.close_cover",hidden:!1},switch:{title:"Switches",showControls:!0,iconOn:"mdi:power-plug",iconOff:"mdi:power-plug-off",onService:"switch.turn_on",offService:"switch.turn_off",hidden:!1},camera:{title:"Cameras",showControls:!1,hidden:!1},lock:{title:"Locks",showControls:!1,hidden:!1},climate:{title:"Climates",showControls:!1,hidden:!1},media_player:{title:"Media Players",showControls:!1,hidden:!1},sensor:{title:"Sensors",showControls:!1,hidden:!1},binary_sensor:{title:"Binary Sensors",showControls:!1,hidden:!1}};class a{static#t;static#e;static#i=[];static#s;static#r=!1;static#o={};static debug=false;constructor(){throw new Error("This class should be invoked with method initialize() instead of using the keyword new!")}static get strategyOptions(){return this.#o}static get areas(){return this.#i}static get devices(){return this.#e}static get entities(){return this.#t}static get debug(){return this.debug}static async initialize(t){this.#s=t.hass.states;try{[this.#t,this.#e,this.#i]=await Promise.all([t.hass.callWS({type:"config/entity_registry/list"}),t.hass.callWS({type:"config/device_registry/list"}),t.hass.callWS({type:"config/area_registry/list"})])}catch(t){console.error(a.debug?t:"An error occurred while querying Home assistant's registries!")}this.#o=structuredClone(t.config.strategy.options||{}),this.debug=this.#o.debug,this.#o.areas=this.#o.areas??{},this.#o.views=this.#o.views??{},this.#o.domains=this.#o.domains??{},this.#o.areas.undisclosed?.hidden||(this.#o.areas.undisclosed={...r,...this.#o.areas.undisclosed},this.#o.areas.undisclosed.area_id=null,this.#i.push(this.#o.areas.undisclosed)),this.#i=a.areas.map((t=>({...t,...this.#o.areas[t.area_id??"undisclosed"]}))),this.#i.sort(((t,e)=>(t.order??1/0)-(e.order??1/0)||t.name.localeCompare(e.name)));for(const t of Object.keys(s))this.#o.views[t]={...s[t],...this.#o.views[t]};this.#o.views=Object.fromEntries(Object.entries(this.#o.views).sort((([,t],[,e])=>(t.order??1/0)-(e.order??1/0)||t.title?.localeCompare(e.title))));for(const t of Object.keys(o))this.#o.domains[t]={...o[t],...this.#o.domains[t]};this.#o.domains=Object.fromEntries(Object.entries(this.#o.domains).sort((([,t],[,e])=>(t.order??1/0)-(e.order??1/0)||t.title?.localeCompare(e.title)))),this.#r=!0}static isInitialized(){return this.#r}static getCountTemplate(t,e,i){const s=[];this.isInitialized()||console.warn("Helper class should be initialized before calling this method!");for(const e of this.#i){const i=this.#e.filter((t=>t.area_id===e.area_id)).map((t=>t.id)),r=this.#t.filter(this.#a,{area:e,domain:t,areaDeviceIds:i}).map((t=>`states['${t.entity_id}']`));s.push(...r)}return`{% set entities = [${s}] %} {{ entities | selectattr('state','${e}','${i}') | list | count }}`}static#a(t){return(this.area.area_id?this.areaDeviceIds.includes(t.device_id)||t.area_id===this.area.area_id:(this.areaDeviceIds.includes(t.device_id)||!t.device_id)&&!t.area_id)&&t.entity_id.startsWith(`${this.domain}.`)&&null==t.hidden_by&&null==t.disabled_by}static getDeviceEntities(t,e){this.isInitialized()||console.warn("Helper class should be initialized before calling this method!");const i=this.#e.filter((e=>e.area_id===t.area_id)).map((t=>t.id));return this.#t.filter(this.#a,{area:t,domain:e,areaDeviceIds:i}).sort(((t,e)=>t.original_name?.localeCompare(e.original_name)))}static getStateEntities(t,e){this.isInitialized()||console.warn("Helper class should be initialized before calling this method!");const i=[],s=Object.fromEntries(this.#t.map((t=>[t.entity_id,t]))),r=Object.fromEntries(this.#e.map((t=>[t.id,t]))),o=Object.values(this.#s).filter((t=>t.entity_id.startsWith(`${e}.`)));for(const e of o){const o=s[e.entity_id],a=r[o?.device_id];(o?.area_id===t.area_id||a&&a.area_id===t.area_id)&&i.push(e)}return i}static sanitizeClassName(t){return(t=t.charAt(0).toUpperCase()+t.slice(1)).replace(/([-_][a-z])/g,(t=>t.toUpperCase().replace("-","").replace("_","")))}static#n(t,e,i){const s=[];for(const r of Object.keys(t))t[r][e]===i&&s.push(r);return s}static getExposedViewIds(){return this.isInitialized()||console.warn("Helper class should be initialized before calling this method!"),this.#n(this.#o.views,"hidden",!1)}static getExposedDomainIds(){return this.isInitialized()||console.warn("Helper class should be initialized before calling this method!"),this.#n(this.#o.domains,"hidden",!1)}}},981:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AbstractCard:()=>r});var s=i(84);class r{entity;options={type:"custom:mushroom-entity-card",icon:"mdi:help-circle",double_tap_action:{action:null}};constructor(t){if(this.constructor===r)throw new Error("Abstract classes can't be instantiated.");if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.entity=t}mergeOptions(t,e){this.options={...this.options,...t,...e};try{this.options.double_tap_action.target.entity_id=this.entity.entity_id}catch{}}getCard(){return{entity:this.entity.entity_id,...this.options}}}},138:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AreaCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-template-card",primary:void 0,icon:"mdi:texture-box",icon_color:"blue",tap_action:{action:"navigate",navigation_path:void 0},hold_action:{action:"none"}};constructor(t,e={}){super(t),this.#c.primary=t.name,this.#c.tap_action.navigation_path=t.area_id??t.name,this.mergeOptions(this.#c,e),!e.primary&&e.name&&(this.options.primary=e.name)}}},917:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BinarySensorCard:()=>r});var s=i(408);class r extends s.SensorCard{#c={type:"custom:mushroom-entity-card",icon:"mdi:power-cycle",icon_color:"green"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},497:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CameraCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"picture-entity",show_name:!1,show_state:!1,camera_view:"live"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},898:(t,e,i)=>{"use strict";i.r(e),i.d(e,{ClimateCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-climate-card",icon:void 0,hvac_modes:["off","cool","heat","fan_only"],show_temperature_control:!0};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},499:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CoverCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-cover-card",icon:void 0,show_buttons_control:!0,show_position_control:!0,show_tilt_position_control:!0};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},297:(t,e,i)=>{"use strict";i.r(e),i.d(e,{FanCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-fan-card",icon:void 0,show_percentage_control:!0,show_oscillate_control:!0,icon_animation:!0};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},698:(t,e,i)=>{"use strict";i.r(e),i.d(e,{LightCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-light-card",icon:void 0,show_brightness_control:!0,show_color_control:!0,use_light_color:!0,double_tap_action:{target:{entity_id:void 0},action:"call-service",service:"light.turn_on",data:{rgb_color:[255,255,255]}}};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},315:(t,e,i)=>{"use strict";i.r(e),i.d(e,{LockCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-lock-card",icon:void 0};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},568:(t,e,i)=>{"use strict";i.r(e),i.d(e,{MediaPlayerCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-media-player-card",icon:void 0,use_media_info:!0,media_controls:["on_off","play_pause_stop"],show_volume_level:!0,volume_controls:["volume_mute","volume_set","volume_buttons"]};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},190:(t,e,i)=>{"use strict";i.r(e),i.d(e,{MiscellaneousCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-entity-card",icon_color:"blue-grey"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},543:(t,e,i)=>{"use strict";i.r(e),i.d(e,{PersonCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-person-card",layout:"vertical",primary_info:"none",secondary_info:"none",icon_type:"entity-picture"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},408:(t,e,i)=>{"use strict";i.r(e),i.d(e,{SensorCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-entity-card",icon:"mdi:information",animate:!0,line_color:"green"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},177:(t,e,i)=>{"use strict";i.r(e),i.d(e,{SwitchCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-entity-card",icon:void 0,tap_action:{action:"toggle"}};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},402:(t,e,i)=>{"use strict";i.r(e),i.d(e,{TitleCard:()=>s});class s{#d;#l={title:void 0,subtitle:void 0,showControls:!0,iconOn:"mdi:power-on",iconOff:"mdi:power-off",onService:"none",offService:"none"};constructor(t,e={}){this.#d=t.map((t=>t.area_id)).filter((t=>t)),this.#l={...this.#l,...e}}createCard(){const t=[{type:"custom:mushroom-title-card",title:this.#l.title,subtitle:this.#l.subtitle}];return this.#l.showControls&&t.push({type:"horizontal-stack",cards:[{type:"custom:mushroom-template-card",icon:this.#l.iconOff,layout:"vertical",icon_color:"red",tap_action:{action:"call-service",service:this.#l.offService,target:{area_id:this.#d},data:{}}},{type:"custom:mushroom-template-card",icon:this.#l.iconOn,layout:"vertical",icon_color:"amber",tap_action:{action:"call-service",service:this.#l.onService,target:{area_id:this.#d},data:{}}}]}),{type:"horizontal-stack",cards:t}}}},244:()=>{},175:(t,e,i)=>{var s={"./AbstractCard":[981,9],"./AbstractCard.js":[981,9],"./AreaCard":[138,9,179],"./AreaCard.js":[138,9,179],"./BinarySensorCard":[917,9,179],"./BinarySensorCard.js":[917,9,179],"./CameraCard":[497,9,179],"./CameraCard.js":[497,9,179],"./ClimateCard":[898,9,179],"./ClimateCard.js":[898,9,179],"./CoverCard":[499,9,179],"./CoverCard.js":[499,9,179],"./FanCard":[297,9,179],"./FanCard.js":[297,9,179],"./LightCard":[698,9,179],"./LightCard.js":[698,9,179],"./LockCard":[315,9,179],"./LockCard.js":[315,9,179],"./MediaPlayerCard":[568,9,179],"./MediaPlayerCard.js":[568,9,179],"./MiscellaneousCard":[190,9,179],"./MiscellaneousCard.js":[190,9,179],"./PersonCard":[543,9,179],"./PersonCard.js":[543,9,179],"./SensorCard":[408,9],"./SensorCard.js":[408,9],"./SwitchCard":[177,9,179],"./SwitchCard.js":[177,9,179],"./TitleCard":[402,9],"./TitleCard.js":[402,9],"./typedefs":[244,7,179],"./typedefs.js":[244,7,179]};function r(t){if(!i.o(s,t))return Promise.resolve().then((()=>{var e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}));var e=s[t],r=e[0];return Promise.all(e.slice(2).map(i.e)).then((()=>i.t(r,16|e[1])))}r.keys=()=>Object.keys(s),r.id=175,t.exports=r},354:(t,e,i)=>{"use strict";i.r(e),i.d(e,{ClimateChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:thermostat",icon_color:"orange",content:s.W.getCountTemplate("climate","ne","off"),tap_action:{action:"navigate",navigation_path:"climates"},hold_action:{action:"navigate",navigation_path:"climates"}}}}},454:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CoverChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:window-open",icon_color:"cyan",content:s.W.getCountTemplate("cover","eq","open"),tap_action:{action:"navigate",navigation_path:"covers"}}}}},955:(t,e,i)=>{"use strict";i.r(e),i.d(e,{FanChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:fan",icon_color:"green",content:s.W.getCountTemplate("fan","eq","on"),tap_action:{action:"call-service",service:"fan.turn_off",target:{area_id:this.#d},data:{}},hold_action:{action:"navigate",navigation_path:"fans"}}}}},980:(t,e,i)=>{"use strict";i.r(e),i.d(e,{LightChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:lightbulb-group",icon_color:"amber",content:s.W.getCountTemplate("light","eq","on"),tap_action:{action:"call-service",service:"light.turn_off",target:{area_id:this.#d},data:{}},hold_action:{action:"navigate",navigation_path:"lights"}}}}},25:(t,e,i)=>{"use strict";i.r(e),i.d(e,{SwitchChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:dip-switch",icon_color:"blue",content:s.W.getCountTemplate("switch","eq","on"),tap_action:{action:"call-service",service:"switch.turn_off",target:{area_id:this.#d},data:{}},hold_action:{action:"navigate",navigation_path:"switches"}}}}},369:(t,e,i)=>{"use strict";i.r(e),i.d(e,{WeatherChip:()=>s});class s{#h;#l={show_temperature:!0,show_conditions:!0};constructor(t,e={}){this.#h=t,this.#l={...this.#l,...e}}getChip(){return{type:"weather",entity:this.#h,...this.#l}}}},837:(t,e,i)=>{var s={"./ClimateChip":[354,179],"./ClimateChip.js":[354,179],"./CoverChip":[454,179],"./CoverChip.js":[454,179],"./FanChip":[955,179],"./FanChip.js":[955,179],"./LightChip":[980,179],"./LightChip.js":[980,179],"./SwitchChip":[25,179],"./SwitchChip.js":[25,179],"./WeatherChip":[369,179],"./WeatherChip.js":[369,179]};function r(t){if(!i.o(s,t))return Promise.resolve().then((()=>{var e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}));var e=s[t],r=e[0];return i.e(e[1]).then((()=>i(r)))}r.keys=()=>Object.keys(s),r.id=837,t.exports=r},721:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AbstractView:()=>o});var s=i(84),r=i(402);class o{options={title:null,path:null,icon:"mdi:view-dashboard",subview:!1};viewTitleCard;constructor(){if(this.constructor===o)throw new Error("Abstract classes can't be instantiated.");if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.")}mergeOptions(t,e){this.options={...t,...e}}async createViewCards(){const t=[];for(const e of s.W.areas){const o=[],a=s.W.getDeviceEntities(e,this.domain),n=s.W.sanitizeClassName(this.domain+"Card"),c=await i(175)(`./${n}`);for(const t of a){let e=s.W.strategyOptions.card_options?.[t.entity_id]??{},i=s.W.strategyOptions.card_options?.[t.device_id]??{};e.hidden||i.hidden||o.push(new c[n](t,e).getCard())}o.length&&(o.unshift(new r.TitleCard([e],{title:e.name,...this.options.titleCard},this.domain).createCard()),t.push({type:"vertical-stack",cards:o}))}return t.unshift(t.length?this.viewTitleCard:{type:"custom:mushroom-title-card",title:"No Entities Available",subtitle:"They're either hidden by the configuration or by Home Assistant."}),t}async getView(){return{...this.options,cards:await this.createViewCards()}}}},458:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CameraView:()=>a});var s=i(84),r=i(402),o=i(721);class a extends o.AbstractView{#p="camera";#c={title:"Cameras",path:"cameras",icon:"mdi:cctv",subview:!1,titleCard:{showControls:!1}};#u={title:"All Cameras",...this.options.titleCard};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},310:(t,e,i)=>{"use strict";i.r(e),i.d(e,{ClimateView:()=>a});var s=i(84),r=i(402),o=i(721);class a extends o.AbstractView{#p="climate";#c={title:"Climates",path:"climates",icon:"mdi:thermostat",subview:!1,titleCard:{showControls:!1}};#u={title:"All Climates",subtitle:s.W.getCountTemplate(this.domain,"ne","off")+" climates on",...this.options.titleCard};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},401:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CoverView:()=>a});var s=i(84),r=i(402),o=i(721);class a extends o.AbstractView{#p="cover";#c={title:"Covers",path:"covers",icon:"mdi:window-open",subview:!1,titleCard:{iconOn:"mdi:arrow-up",iconOff:"mdi:arrow-down",onService:"cover.open_cover",offService:"cover.close_cover"}};#u={title:"All Covers",subtitle:s.W.getCountTemplate(this.domain,"eq","open")+" covers open"};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},902:(t,e,i)=>{"use strict";i.r(e),i.d(e,{FanView:()=>a});var s=i(84),r=i(402),o=i(721);class a extends o.AbstractView{#p="fan";#c={title:"Fans",path:"fans",icon:"mdi:fan",subview:!1,titleCard:{iconOn:"mdi:fan",iconOff:"mdi:fan-off",onService:"fan.turn_on",offService:"fan.turn_off"}};#u={title:"All Fans",subtitle:s.W.getCountTemplate(this.domain,"eq","on")+" fans on"};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},530:(t,e,i)=>{"use strict";i.r(e),i.d(e,{HomeView:()=>o});var s=i(84),r=i(721);class o extends r.AbstractView{#c={title:"Home",path:"home",subview:!1};constructor(t={}){super(),this.mergeOptions(this.#c,t)}async createViewCards(){return await Promise.all([this.#m(),this.#f(),this.#g()]).then((([t,e,i])=>{const r=s.W.strategyOptions,o=[{type:"custom:mushroom-chips-card",alignment:"center",chips:t},{type:"horizontal-stack",cards:e},{type:"custom:mushroom-template-card",primary:"{% set time = now().hour %} {% if (time >= 18) %} Good Evening, {{user}}! {% elif (time >= 12) %} Good Afternoon, {{user}}! {% elif (time >= 5) %} Good Morning, {{user}}! {% else %} Hello, {{user}}! {% endif %}",icon:"mdi:hand-wave",icon_color:"orange",tap_action:{action:"none"},double_tap_action:{action:"none"},hold_action:{action:"none"}}];return r.quick_access_cards&&o.push(...r.quick_access_cards),o.push({type:"vertical-stack",cards:i}),r.extra_cards&&o.push(...r.extra_cards),o}))}async#m(){const t=[],e=s.W.strategyOptions.chips,r=["light","fan","cover","switch","climate"],o=s.W.areas.map((t=>t.area_id));let a;const n=e?.weather_entity??s.W.entities.find((t=>t.entity_id.startsWith("weather.")&&null==t.disabled_by&&null==t.hidden_by))?.entity_id;if(n)try{a=await Promise.resolve().then(i.bind(i,369));const e=new a.WeatherChip(n);t.push(e.getChip())}catch(t){console.error(s.W.debug?t:"An error occurred while creating the weather chip!")}for(let n of r)if(e?.[`${n}_count`]??1){const e=s.W.sanitizeClassName(n+"Chip");try{a=await i(837)(`./${e}`);const s=new a[e](o);t.push(s.getChip())}catch(t){console.error(s.W.debug?t:`An error occurred while creating the ${n} chip!`)}}return e?.extra_chips&&t.push(...e.extra_chips),t}#f(){const t=[];return Promise.resolve().then(i.bind(i,543)).then((e=>{for(const i of s.W.entities.filter((t=>t.entity_id.startsWith("person.")&&null==t.hidden_by&&null==t.disabled_by)))t.push(new e.PersonCard(i).getCard())})),t}#g(){const t=[{type:"custom:mushroom-title-card",title:"Areas"}];return Promise.resolve().then(i.bind(i,138)).then((e=>{const i=[];for(const t of s.W.areas)s.W.strategyOptions.areas[t.area_id]?.hidden||i.push(new e.AreaCard(t,s.W.strategyOptions.areas[t.area_id??"undisclosed"]).getCard());for(let e=0;e{"use strict";i.r(e),i.d(e,{LightView:()=>a});var s=i(84),r=i(402),o=i(721);class a extends o.AbstractView{#p="light";#c={title:"Lights",path:"lights",icon:"mdi:lightbulb-group",subview:!1,titleCard:{iconOn:"mdi:lightbulb",iconOff:"mdi:lightbulb-off",onService:"light.turn_on",offService:"light.turn_off"}};#u={title:"All Lights",subtitle:s.W.getCountTemplate(this.domain,"eq","on")+" lights on"};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},133:(t,e,i)=>{"use strict";i.r(e),i.d(e,{SwitchView:()=>a});var s=i(84),r=i(402),o=i(721);class a extends o.AbstractView{#p="switch";#c={title:"Switches",path:"switches",icon:"mdi:dip-switch",subview:!1,titleCard:{iconOn:"mdi:power-plug",iconOff:"mdi:power-plug-off",onService:"switch.turn_on",offService:"switch.turn_off"}};#u={title:"All Switches",subtitle:s.W.getCountTemplate(this.domain,"eq","on")+" switches on"};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},654:(t,e,i)=>{"use strict";i.r(e)},968:(t,e,i)=>{var s={"./AbstractView":[721,179],"./AbstractView.js":[721,179],"./CameraView":[458,179],"./CameraView.js":[458,179],"./ClimateView":[310,179],"./ClimateView.js":[310,179],"./CoverView":[401,179],"./CoverView.js":[401,179],"./FanView":[902,179],"./FanView.js":[902,179],"./HomeView":[530,179],"./HomeView.js":[530,179],"./LightView":[587,179],"./LightView.js":[587,179],"./SwitchView":[133,179],"./SwitchView.js":[133,179],"./typedefs":[654,179],"./typedefs.js":[654,179]};function r(t){if(!i.o(s,t))return Promise.resolve().then((()=>{var e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}));var e=s[t],r=e[0];return i.e(e[1]).then((()=>i(r)))}r.keys=()=>Object.keys(s),r.id=968,t.exports=r}},s={};function r(t){var e=s[t];if(void 0!==e)return e.exports;var o=s[t]={exports:{}};return i[t](o,o.exports,r),o.exports}e=Object.getPrototypeOf?t=>Object.getPrototypeOf(t):t=>t.__proto__,r.t=function(i,s){if(1&s&&(i=this(i)),8&s)return i;if("object"==typeof i&&i){if(4&s&&i.__esModule)return i;if(16&s&&"function"==typeof i.then)return i}var o=Object.create(null);r.r(o);var a={};t=t||[null,e({}),e([]),e(e)];for(var n=2&s&&i;"object"==typeof n&&!~t.indexOf(n);n=e(n))Object.getOwnPropertyNames(n).forEach((t=>a[t]=()=>i[t]));return a.default=()=>i,r.d(o,a),o},r.d=(t,e)=>{for(var i in e)r.o(e,i)&&!r.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},r.e=()=>Promise.resolve(),r.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},(()=>{"use strict";var t=r(84),e=r(408),i=r(402);customElements.define("ll-strategy-mushroom-strategy",class{static async generateDashboard(e){await t.W.initialize(e);const i=[];let s;for(let e of t.W.getExposedViewIds())try{const o=t.W.sanitizeClassName(e+"View");s=await r(968)(`./${o}`);const a=await new s[o](t.W.strategyOptions.views[e]).getView();i.push(a)}catch(i){console.error(t.W.debug?i:`View '${e}' couldn't be loaded!`)}for(let e of t.W.areas)e.hidden||i.push({title:e.name,path:e.area_id??e.name,subview:!0,strategy:{type:"custom:mushroom-strategy",options:{area:e}}});return t.W.strategyOptions.extra_views&&i.push(...t.W.strategyOptions.extra_views),{views:i}}static async generateView(s){const o=t.W.getExposedDomainIds(),a=s.view.strategy.options.area,n=[...a.extra_cards??[]];for(const s of o){if("default"===s)continue;const o=t.W.sanitizeClassName(s+"Card");let c=[];try{c=await r(175)(`./${o}`).then((r=>{let n=[];const c=t.W.getDeviceEntities(a,s);if(c.length){const d=new i.TitleCard([a],t.W.strategyOptions.domains[s]).createCard();if("sensor"===s){const i=t.W.getStateEntities(a,"sensor"),s=[];for(const r of c){const o=i.find((t=>t.entity_id===r.entity_id));let a=t.W.strategyOptions.card_options?.[r.entity_id]??{},n=t.W.strategyOptions.card_options?.[r.device_id]??{};a.hidden||n.hidden||(o?.attributes.unit_of_measurement&&(a={type:"custom:mini-graph-card",entities:[r.entity_id],...a}),s.push(new e.SensorCard(r,a).getCard()))}return s.length&&(n.push({type:"vertical-stack",cards:s}),n.unshift(d)),n}for(const e of c){let i=t.W.strategyOptions.card_options?.[e.entity_id]??{},s=t.W.strategyOptions.card_options?.[e.device_id]??{};i.hidden||s.hidden||n.push(new r[o](e,i).getCard())}if("binary_sensor"===s){const t=[];for(let e=0;et.area_id===a.area_id)).map((t=>t.id)),s=t.W.entities.filter((t=>(e.includes(t.device_id)||t.area_id===a.area_id)&&null==t.hidden_by&&null==t.disabled_by&&!o.includes(t.entity_id.split(".",1)[0])));if(s.length){let e=[];try{e=await Promise.resolve().then(r.bind(r,190)).then((e=>{const r=[new i.TitleCard([a],t.W.strategyOptions.domains.default).createCard()];for(const i of s){let s=t.W.strategyOptions.card_options?.[i.entity_id]??{},o=t.W.strategyOptions.card_options?.[i.device_id]??{};s.hidden||o.hidden||r.push(new e.MiscellaneousCard(i,s).getCard())}return r}))}catch(e){console.error(t.W.debug?e:"An error occurred while creating the domain cards!")}n.push({type:"vertical-stack",cards:e})}}return{cards:n}}})})()})(); \ No newline at end of file +(()=>{var t,e,i={84:(t,e,i)=>{"use strict";i.d(e,{W:()=>o});const s={home:{order:1,hidden:!1},light:{order:2,hidden:!1},fan:{order:3,hidden:!1},cover:{order:4,hidden:!1},switch:{order:5,hidden:!1},climate:{order:6,hidden:!1},camera:{order:7,hidden:!1}},r={aliases:[],area_id:null,name:"Undisclosed",picture:null,hidden:!1},a={default:{title:"Miscellaneous",showControls:!1,hidden:!1},light:{title:"Lights",showControls:!0,iconOn:"mdi:lightbulb",iconOff:"mdi:lightbulb-off",onService:"light.turn_on",offService:"light.turn_off",hidden:!1},fan:{title:"Fans",showControls:!0,iconOn:"mdi:fan",iconOff:"mdi:fan-off",onService:"fan.turn_on",offService:"fan.turn_off",hidden:!1},cover:{title:"Covers",showControls:!0,iconOn:"mdi:arrow-up",iconOff:"mdi:arrow-down",onService:"cover.open_cover",offService:"cover.close_cover",hidden:!1},switch:{title:"Switches",showControls:!0,iconOn:"mdi:power-plug",iconOff:"mdi:power-plug-off",onService:"switch.turn_on",offService:"switch.turn_off",hidden:!1},camera:{title:"Cameras",showControls:!1,hidden:!1},lock:{title:"Locks",showControls:!1,hidden:!1},climate:{title:"Climates",showControls:!1,hidden:!1},media_player:{title:"Media Players",showControls:!1,hidden:!1},sensor:{title:"Sensors",showControls:!1,hidden:!1},binary_sensor:{title:"Binary Sensors",showControls:!1,hidden:!1}};class o{static#t;static#e;static#i=[];static#s;static#r=!1;static#a={};static debug=false;constructor(){throw new Error("This class should be invoked with method initialize() instead of using the keyword new!")}static get strategyOptions(){return this.#a}static get areas(){return this.#i}static get devices(){return this.#e}static get entities(){return this.#t}static get debug(){return this.debug}static async initialize(t){this.#s=t.hass.states;try{[this.#t,this.#e,this.#i]=await Promise.all([t.hass.callWS({type:"config/entity_registry/list"}),t.hass.callWS({type:"config/device_registry/list"}),t.hass.callWS({type:"config/area_registry/list"})])}catch(t){console.error(o.debug?t:"An error occurred while querying Home assistant's registries!")}this.#a=structuredClone(t.config.strategy.options||{}),this.debug=this.#a.debug,this.#a.areas=this.#a.areas??{},this.#a.views=this.#a.views??{},this.#a.domains=this.#a.domains??{},this.#a.areas.undisclosed?.hidden||(this.#a.areas.undisclosed={...r,...this.#a.areas.undisclosed},this.#a.areas.undisclosed.area_id=null,this.#i.push(this.#a.areas.undisclosed)),this.#i=o.areas.map((t=>({...t,...this.#a.areas[t.area_id??"undisclosed"]}))),this.#i.sort(((t,e)=>(t.order??1/0)-(e.order??1/0)||t.name.localeCompare(e.name)));for(const t of Object.keys(s))this.#a.views[t]={...s[t],...this.#a.views[t]};this.#a.views=Object.fromEntries(Object.entries(this.#a.views).sort((([,t],[,e])=>(t.order??1/0)-(e.order??1/0)||t.title?.localeCompare(e.title))));for(const t of Object.keys(a))this.#a.domains[t]={...a[t],...this.#a.domains[t]};this.#a.domains=Object.fromEntries(Object.entries(this.#a.domains).sort((([,t],[,e])=>(t.order??1/0)-(e.order??1/0)||t.title?.localeCompare(e.title)))),this.#r=!0}static isInitialized(){return this.#r}static getCountTemplate(t,e,i){const s=[];this.isInitialized()||console.warn("Helper class should be initialized before calling this method!");for(const e of this.#i){const i=this.#e.filter((t=>t.area_id===e.area_id)).map((t=>t.id)),r=this.#t.filter(this.#o,{area:e,domain:t,areaDeviceIds:i}).map((t=>`states['${t.entity_id}']`));s.push(...r)}return`{% set entities = [${s}] %} {{ entities | selectattr('state','${e}','${i}') | list | count }}`}static#o(t){return(this.area.area_id?this.areaDeviceIds.includes(t.device_id)||t.area_id===this.area.area_id:(this.areaDeviceIds.includes(t.device_id)||!t.device_id)&&!t.area_id)&&t.entity_id.startsWith(`${this.domain}.`)&&null==t.hidden_by&&null==t.disabled_by}static getDeviceEntities(t,e){this.isInitialized()||console.warn("Helper class should be initialized before calling this method!");const i=this.#e.filter((e=>e.area_id===t.area_id)).map((t=>t.id));return this.#t.filter(this.#o,{area:t,domain:e,areaDeviceIds:i}).sort(((t,e)=>t.original_name?.localeCompare(e.original_name)))}static getStateEntities(t,e){this.isInitialized()||console.warn("Helper class should be initialized before calling this method!");const i=[],s=Object.fromEntries(this.#t.map((t=>[t.entity_id,t]))),r=Object.fromEntries(this.#e.map((t=>[t.id,t]))),a=Object.values(this.#s).filter((t=>t.entity_id.startsWith(`${e}.`)));for(const e of a){const a=s[e.entity_id],o=r[a?.device_id];(a?.area_id===t.area_id||o&&o.area_id===t.area_id)&&i.push(e)}return i}static sanitizeClassName(t){return(t=t.charAt(0).toUpperCase()+t.slice(1)).replace(/([-_][a-z])/g,(t=>t.toUpperCase().replace("-","").replace("_","")))}static#n(t,e,i){const s=[];for(const r of Object.keys(t))t[r][e]===i&&s.push(r);return s}static getExposedViewIds(){return this.isInitialized()||console.warn("Helper class should be initialized before calling this method!"),this.#n(this.#a.views,"hidden",!1)}static getExposedDomainIds(){return this.isInitialized()||console.warn("Helper class should be initialized before calling this method!"),this.#n(this.#a.domains,"hidden",!1)}}},981:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AbstractCard:()=>r});var s=i(84);class r{entity;options={type:"custom:mushroom-entity-card",icon:"mdi:help-circle",double_tap_action:{action:null}};constructor(t){if(this.constructor===r)throw new Error("Abstract classes can't be instantiated.");if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.entity=t}mergeOptions(t,e){this.options={...this.options,...t,...e};try{this.options.double_tap_action.target.entity_id=this.entity.entity_id}catch{}}getCard(){return{entity:this.entity.entity_id,...this.options}}}},138:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AreaCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-template-card",primary:void 0,icon:"mdi:texture-box",icon_color:"blue",tap_action:{action:"navigate",navigation_path:void 0},hold_action:{action:"none"}};constructor(t,e={}){super(t),this.#c.primary=t.name,this.#c.tap_action.navigation_path=t.area_id??t.name,"default"===e.type&&(e.type=this.#c.type),this.mergeOptions(this.#c,e),!e.primary&&e.name&&(this.options.primary=e.name)}}},917:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BinarySensorCard:()=>r});var s=i(408);class r extends s.SensorCard{#c={type:"custom:mushroom-entity-card",icon:"mdi:power-cycle",icon_color:"green"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},497:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CameraCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"picture-entity",show_name:!1,show_state:!1,camera_view:"live"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},898:(t,e,i)=>{"use strict";i.r(e),i.d(e,{ClimateCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-climate-card",icon:void 0,hvac_modes:["off","cool","heat","fan_only"],show_temperature_control:!0};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},499:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CoverCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-cover-card",icon:void 0,show_buttons_control:!0,show_position_control:!0,show_tilt_position_control:!0};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},297:(t,e,i)=>{"use strict";i.r(e),i.d(e,{FanCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-fan-card",icon:void 0,show_percentage_control:!0,show_oscillate_control:!0,icon_animation:!0};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},194:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AreaCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"area",area:void 0,navigation_path:void 0};constructor(t,e={}){super(t),this.#c.area=t.area_id??t.name,this.#c.navigation_path=t.area_id??t.name,e.type=this.#c.type,this.mergeOptions(this.#c,e)}}},698:(t,e,i)=>{"use strict";i.r(e),i.d(e,{LightCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-light-card",icon:void 0,show_brightness_control:!0,show_color_control:!0,use_light_color:!0,double_tap_action:{target:{entity_id:void 0},action:"call-service",service:"light.turn_on",data:{rgb_color:[255,255,255]}}};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},315:(t,e,i)=>{"use strict";i.r(e),i.d(e,{LockCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-lock-card",icon:void 0};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},568:(t,e,i)=>{"use strict";i.r(e),i.d(e,{MediaPlayerCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-media-player-card",icon:void 0,use_media_info:!0,media_controls:["on_off","play_pause_stop"],show_volume_level:!0,volume_controls:["volume_mute","volume_set","volume_buttons"]};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},190:(t,e,i)=>{"use strict";i.r(e),i.d(e,{MiscellaneousCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-entity-card",icon_color:"blue-grey"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},543:(t,e,i)=>{"use strict";i.r(e),i.d(e,{PersonCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-person-card",layout:"vertical",primary_info:"none",secondary_info:"none",icon_type:"entity-picture"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},408:(t,e,i)=>{"use strict";i.r(e),i.d(e,{SensorCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-entity-card",icon:"mdi:information",animate:!0,line_color:"green"};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},177:(t,e,i)=>{"use strict";i.r(e),i.d(e,{SwitchCard:()=>r});var s=i(981);class r extends s.AbstractCard{#c={type:"custom:mushroom-entity-card",icon:void 0,tap_action:{action:"toggle"}};constructor(t,e={}){super(t),this.mergeOptions(this.#c,e)}}},402:(t,e,i)=>{"use strict";i.r(e),i.d(e,{TitleCard:()=>s});class s{#d;#l={title:void 0,subtitle:void 0,showControls:!0,iconOn:"mdi:power-on",iconOff:"mdi:power-off",onService:"none",offService:"none"};constructor(t,e={}){this.#d=t.map((t=>t.area_id)).filter((t=>t)),this.#l={...this.#l,...e}}createCard(){const t=[{type:"custom:mushroom-title-card",title:this.#l.title,subtitle:this.#l.subtitle}];return this.#l.showControls&&t.push({type:"horizontal-stack",cards:[{type:"custom:mushroom-template-card",icon:this.#l.iconOff,layout:"vertical",icon_color:"red",tap_action:{action:"call-service",service:this.#l.offService,target:{area_id:this.#d},data:{}}},{type:"custom:mushroom-template-card",icon:this.#l.iconOn,layout:"vertical",icon_color:"amber",tap_action:{action:"call-service",service:this.#l.onService,target:{area_id:this.#d},data:{}}}]}),{type:"horizontal-stack",cards:t}}}},244:()=>{},175:(t,e,i)=>{var s={"./AbstractCard":[981,9],"./AbstractCard.js":[981,9],"./AreaCard":[138,9,179],"./AreaCard.js":[138,9,179],"./BinarySensorCard":[917,9,179],"./BinarySensorCard.js":[917,9,179],"./CameraCard":[497,9,179],"./CameraCard.js":[497,9,179],"./ClimateCard":[898,9,179],"./ClimateCard.js":[898,9,179],"./CoverCard":[499,9,179],"./CoverCard.js":[499,9,179],"./FanCard":[297,9,179],"./FanCard.js":[297,9,179],"./HaAreaCard":[194,9,179],"./HaAreaCard.js":[194,9,179],"./LightCard":[698,9,179],"./LightCard.js":[698,9,179],"./LockCard":[315,9,179],"./LockCard.js":[315,9,179],"./MediaPlayerCard":[568,9,179],"./MediaPlayerCard.js":[568,9,179],"./MiscellaneousCard":[190,9,179],"./MiscellaneousCard.js":[190,9,179],"./PersonCard":[543,9,179],"./PersonCard.js":[543,9,179],"./SensorCard":[408,9],"./SensorCard.js":[408,9],"./SwitchCard":[177,9,179],"./SwitchCard.js":[177,9,179],"./TitleCard":[402,9],"./TitleCard.js":[402,9],"./typedefs":[244,7,179],"./typedefs.js":[244,7,179]};function r(t){if(!i.o(s,t))return Promise.resolve().then((()=>{var e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}));var e=s[t],r=e[0];return Promise.all(e.slice(2).map(i.e)).then((()=>i.t(r,16|e[1])))}r.keys=()=>Object.keys(s),r.id=175,t.exports=r},354:(t,e,i)=>{"use strict";i.r(e),i.d(e,{ClimateChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:thermostat",icon_color:"orange",content:s.W.getCountTemplate("climate","ne","off"),tap_action:{action:"navigate",navigation_path:"climates"},hold_action:{action:"navigate",navigation_path:"climates"}}}}},454:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CoverChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:window-open",icon_color:"cyan",content:s.W.getCountTemplate("cover","eq","open"),tap_action:{action:"navigate",navigation_path:"covers"}}}}},955:(t,e,i)=>{"use strict";i.r(e),i.d(e,{FanChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:fan",icon_color:"green",content:s.W.getCountTemplate("fan","eq","on"),tap_action:{action:"call-service",service:"fan.turn_off",target:{area_id:this.#d},data:{}},hold_action:{action:"navigate",navigation_path:"fans"}}}}},980:(t,e,i)=>{"use strict";i.r(e),i.d(e,{LightChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:lightbulb-group",icon_color:"amber",content:s.W.getCountTemplate("light","eq","on"),tap_action:{action:"call-service",service:"light.turn_off",target:{area_id:this.#d},data:{}},hold_action:{action:"navigate",navigation_path:"lights"}}}}},25:(t,e,i)=>{"use strict";i.r(e),i.d(e,{SwitchChip:()=>r});var s=i(84);class r{#d;#l={};constructor(t,e={}){if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.");this.#d=t.filter((t=>t)),this.#l={...this.#l,...e}}getChip(){return{type:"template",icon:"mdi:dip-switch",icon_color:"blue",content:s.W.getCountTemplate("switch","eq","on"),tap_action:{action:"call-service",service:"switch.turn_off",target:{area_id:this.#d},data:{}},hold_action:{action:"navigate",navigation_path:"switches"}}}}},369:(t,e,i)=>{"use strict";i.r(e),i.d(e,{WeatherChip:()=>s});class s{#h;#l={show_temperature:!0,show_conditions:!0};constructor(t,e={}){this.#h=t,this.#l={...this.#l,...e}}getChip(){return{type:"weather",entity:this.#h,...this.#l}}}},837:(t,e,i)=>{var s={"./ClimateChip":[354,179],"./ClimateChip.js":[354,179],"./CoverChip":[454,179],"./CoverChip.js":[454,179],"./FanChip":[955,179],"./FanChip.js":[955,179],"./LightChip":[980,179],"./LightChip.js":[980,179],"./SwitchChip":[25,179],"./SwitchChip.js":[25,179],"./WeatherChip":[369,179],"./WeatherChip.js":[369,179]};function r(t){if(!i.o(s,t))return Promise.resolve().then((()=>{var e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}));var e=s[t],r=e[0];return i.e(e[1]).then((()=>i(r)))}r.keys=()=>Object.keys(s),r.id=837,t.exports=r},721:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AbstractView:()=>a});var s=i(84),r=i(402);class a{options={title:null,path:null,icon:"mdi:view-dashboard",subview:!1};viewTitleCard;constructor(){if(this.constructor===a)throw new Error("Abstract classes can't be instantiated.");if(!s.W.isInitialized())throw new Error("The Helper module must be initialized before using this one.")}mergeOptions(t,e){this.options={...t,...e}}async createViewCards(){const t=[];for(const e of s.W.areas){const a=[],o=s.W.getDeviceEntities(e,this.domain),n=s.W.sanitizeClassName(this.domain+"Card"),c=await i(175)(`./${n}`);for(const t of o){let e=s.W.strategyOptions.card_options?.[t.entity_id]??{},i=s.W.strategyOptions.card_options?.[t.device_id]??{};e.hidden||i.hidden||a.push(new c[n](t,e).getCard())}a.length&&(a.unshift(new r.TitleCard([e],{title:e.name,...this.options.titleCard},this.domain).createCard()),t.push({type:"vertical-stack",cards:a}))}return t.unshift(t.length?this.viewTitleCard:{type:"custom:mushroom-title-card",title:"No Entities Available",subtitle:"They're either hidden by the configuration or by Home Assistant."}),t}async getView(){return{...this.options,cards:await this.createViewCards()}}}},458:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CameraView:()=>o});var s=i(84),r=i(402),a=i(721);class o extends a.AbstractView{#p="camera";#c={title:"Cameras",path:"cameras",icon:"mdi:cctv",subview:!1,titleCard:{showControls:!1}};#u={title:"All Cameras",...this.options.titleCard};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},310:(t,e,i)=>{"use strict";i.r(e),i.d(e,{ClimateView:()=>o});var s=i(84),r=i(402),a=i(721);class o extends a.AbstractView{#p="climate";#c={title:"Climates",path:"climates",icon:"mdi:thermostat",subview:!1,titleCard:{showControls:!1}};#u={title:"All Climates",subtitle:s.W.getCountTemplate(this.domain,"ne","off")+" climates on",...this.options.titleCard};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},401:(t,e,i)=>{"use strict";i.r(e),i.d(e,{CoverView:()=>o});var s=i(84),r=i(402),a=i(721);class o extends a.AbstractView{#p="cover";#c={title:"Covers",path:"covers",icon:"mdi:window-open",subview:!1,titleCard:{iconOn:"mdi:arrow-up",iconOff:"mdi:arrow-down",onService:"cover.open_cover",offService:"cover.close_cover"}};#u={title:"All Covers",subtitle:s.W.getCountTemplate(this.domain,"eq","open")+" covers open"};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},902:(t,e,i)=>{"use strict";i.r(e),i.d(e,{FanView:()=>o});var s=i(84),r=i(402),a=i(721);class o extends a.AbstractView{#p="fan";#c={title:"Fans",path:"fans",icon:"mdi:fan",subview:!1,titleCard:{iconOn:"mdi:fan",iconOff:"mdi:fan-off",onService:"fan.turn_on",offService:"fan.turn_off"}};#u={title:"All Fans",subtitle:s.W.getCountTemplate(this.domain,"eq","on")+" fans on"};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},530:(t,e,i)=>{"use strict";i.r(e),i.d(e,{HomeView:()=>a});var s=i(84),r=i(721);class a extends r.AbstractView{#c={title:"Home",path:"home",subview:!1};constructor(t={}){super(),this.mergeOptions(this.#c,t)}async createViewCards(){return await Promise.all([this.#m(),this.#f(),this.#g()]).then((([t,e,i])=>{const r=s.W.strategyOptions,a=[{type:"custom:mushroom-chips-card",alignment:"center",chips:t},{type:"horizontal-stack",cards:e},{type:"custom:mushroom-template-card",primary:"{% set time = now().hour %} {% if (time >= 18) %} Good Evening, {{user}}! {% elif (time >= 12) %} Good Afternoon, {{user}}! {% elif (time >= 5) %} Good Morning, {{user}}! {% else %} Hello, {{user}}! {% endif %}",icon:"mdi:hand-wave",icon_color:"orange",tap_action:{action:"none"},double_tap_action:{action:"none"},hold_action:{action:"none"}}];return r.quick_access_cards&&a.push(...r.quick_access_cards),a.push({type:"vertical-stack",cards:i}),r.extra_cards&&a.push(...r.extra_cards),a}))}async#m(){const t=[],e=s.W.strategyOptions.chips,r=["light","fan","cover","switch","climate"],a=s.W.areas.map((t=>t.area_id));let o;const n=e?.weather_entity??s.W.entities.find((t=>t.entity_id.startsWith("weather.")&&null==t.disabled_by&&null==t.hidden_by))?.entity_id;if(n)try{o=await Promise.resolve().then(i.bind(i,369));const e=new o.WeatherChip(n);t.push(e.getChip())}catch(t){console.error(s.W.debug?t:"An error occurred while creating the weather chip!")}for(let n of r)if(e?.[`${n}_count`]??1){const e=s.W.sanitizeClassName(n+"Chip");try{o=await i(837)(`./${e}`);const s=new o[e](a);t.push(s.getChip())}catch(t){console.error(s.W.debug?t:`An error occurred while creating the ${n} chip!`)}}return e?.extra_chips&&t.push(...e.extra_chips),t}#f(){const t=[];return Promise.resolve().then(i.bind(i,543)).then((e=>{for(const i of s.W.entities.filter((t=>t.entity_id.startsWith("person.")&&null==t.hidden_by&&null==t.disabled_by)))t.push(new e.PersonCard(i).getCard())})),t}async#g(){const t=[{type:"custom:mushroom-title-card",title:"Areas"}];let e=[];for(const[r,a]of s.W.areas.entries()){let o,n=s.W.strategyOptions.areas[a.area_id??"undisclosed"]?.type??s.W.strategyOptions.areas._?.type??"default";try{o=await i(175)(`./${n}`)}catch(t){o=await Promise.resolve().then(i.bind(i,138)),s.W.strategyOptions.debug&&"default"!==n&&console.error(t)}if(!s.W.strategyOptions.areas[a.area_id]?.hidden){let t={...s.W.strategyOptions.areas._,...s.W.strategyOptions.areas[a.area_id??"undisclosed"]};e.push(new o.AreaCard(a,t).getCard())}if(r===s.W.areas.length-1)for(let i=0;i{"use strict";i.r(e),i.d(e,{LightView:()=>o});var s=i(84),r=i(402),a=i(721);class o extends a.AbstractView{#p="light";#c={title:"Lights",path:"lights",icon:"mdi:lightbulb-group",subview:!1,titleCard:{iconOn:"mdi:lightbulb",iconOff:"mdi:lightbulb-off",onService:"light.turn_on",offService:"light.turn_off"}};#u={title:"All Lights",subtitle:s.W.getCountTemplate(this.domain,"eq","on")+" lights on"};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},133:(t,e,i)=>{"use strict";i.r(e),i.d(e,{SwitchView:()=>o});var s=i(84),r=i(402),a=i(721);class o extends a.AbstractView{#p="switch";#c={title:"Switches",path:"switches",icon:"mdi:dip-switch",subview:!1,titleCard:{iconOn:"mdi:power-plug",iconOff:"mdi:power-plug-off",onService:"switch.turn_on",offService:"switch.turn_off"}};#u={title:"All Switches",subtitle:s.W.getCountTemplate(this.domain,"eq","on")+" switches on"};constructor(t={}){super(),this.mergeOptions(this.#c,t),this.viewTitleCard=new r.TitleCard(s.W.areas,{...this.#u,...this.options.titleCard}).createCard()}get domain(){return this.#p}}},654:(t,e,i)=>{"use strict";i.r(e)},968:(t,e,i)=>{var s={"./AbstractView":[721,179],"./AbstractView.js":[721,179],"./CameraView":[458,179],"./CameraView.js":[458,179],"./ClimateView":[310,179],"./ClimateView.js":[310,179],"./CoverView":[401,179],"./CoverView.js":[401,179],"./FanView":[902,179],"./FanView.js":[902,179],"./HomeView":[530,179],"./HomeView.js":[530,179],"./LightView":[587,179],"./LightView.js":[587,179],"./SwitchView":[133,179],"./SwitchView.js":[133,179],"./typedefs":[654,179],"./typedefs.js":[654,179]};function r(t){if(!i.o(s,t))return Promise.resolve().then((()=>{var e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}));var e=s[t],r=e[0];return i.e(e[1]).then((()=>i(r)))}r.keys=()=>Object.keys(s),r.id=968,t.exports=r}},s={};function r(t){var e=s[t];if(void 0!==e)return e.exports;var a=s[t]={exports:{}};return i[t](a,a.exports,r),a.exports}e=Object.getPrototypeOf?t=>Object.getPrototypeOf(t):t=>t.__proto__,r.t=function(i,s){if(1&s&&(i=this(i)),8&s)return i;if("object"==typeof i&&i){if(4&s&&i.__esModule)return i;if(16&s&&"function"==typeof i.then)return i}var a=Object.create(null);r.r(a);var o={};t=t||[null,e({}),e([]),e(e)];for(var n=2&s&&i;"object"==typeof n&&!~t.indexOf(n);n=e(n))Object.getOwnPropertyNames(n).forEach((t=>o[t]=()=>i[t]));return o.default=()=>i,r.d(a,o),a},r.d=(t,e)=>{for(var i in e)r.o(e,i)&&!r.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},r.e=()=>Promise.resolve(),r.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},(()=>{"use strict";var t=r(84),e=r(408),i=r(402);customElements.define("ll-strategy-mushroom-strategy",class{static async generateDashboard(e){await t.W.initialize(e);const i=[];let s;for(let e of t.W.getExposedViewIds())try{const a=t.W.sanitizeClassName(e+"View");s=await r(968)(`./${a}`);const o=await new s[a](t.W.strategyOptions.views[e]).getView();i.push(o)}catch(i){console.error(t.W.debug?i:`View '${e}' couldn't be loaded!`)}for(let e of t.W.areas)e.hidden||i.push({title:e.name,path:e.area_id??e.name,subview:!0,strategy:{type:"custom:mushroom-strategy",options:{area:e}}});return t.W.strategyOptions.extra_views&&i.push(...t.W.strategyOptions.extra_views),{views:i}}static async generateView(s){const a=t.W.getExposedDomainIds(),o=s.view.strategy.options.area,n=[...o.extra_cards??[]];for(const s of a){if("default"===s)continue;const a=t.W.sanitizeClassName(s+"Card");let c=[];try{c=await r(175)(`./${a}`).then((r=>{let n=[];const c=t.W.getDeviceEntities(o,s);if(c.length){const d=new i.TitleCard([o],t.W.strategyOptions.domains[s]).createCard();if("sensor"===s){const i=t.W.getStateEntities(o,"sensor"),s=[];for(const r of c){const a=i.find((t=>t.entity_id===r.entity_id));let o=t.W.strategyOptions.card_options?.[r.entity_id]??{},n=t.W.strategyOptions.card_options?.[r.device_id]??{};o.hidden||n.hidden||(a?.attributes.unit_of_measurement&&(o={type:"custom:mini-graph-card",entities:[r.entity_id],...o}),s.push(new e.SensorCard(r,o).getCard()))}return s.length&&(n.push({type:"vertical-stack",cards:s}),n.unshift(d)),n}for(const e of c){let i=t.W.strategyOptions.card_options?.[e.entity_id]??{},s=t.W.strategyOptions.card_options?.[e.device_id]??{};i.hidden||s.hidden||n.push(new r[a](e,i).getCard())}if("binary_sensor"===s){const t=[];for(let e=0;et.area_id===o.area_id)).map((t=>t.id)),s=t.W.entities.filter((t=>(e.includes(t.device_id)||t.area_id===o.area_id)&&null==t.hidden_by&&null==t.disabled_by&&!a.includes(t.entity_id.split(".",1)[0])));if(s.length){let e=[];try{e=await Promise.resolve().then(r.bind(r,190)).then((e=>{const r=[new i.TitleCard([o],t.W.strategyOptions.domains.default).createCard()];for(const i of s){let s=t.W.strategyOptions.card_options?.[i.entity_id]??{},a=t.W.strategyOptions.card_options?.[i.device_id]??{};s.hidden||a.hidden||r.push(new e.MiscellaneousCard(i,s).getCard())}return r}))}catch(e){console.error(t.W.debug?e:"An error occurred while creating the domain cards!")}n.push({type:"vertical-stack",cards:e})}}return{cards:n}}})})()})(); \ No newline at end of file diff --git a/src/cards/AreaCard.js b/src/cards/AreaCard.js index cf43671..16b4212 100644 --- a/src/cards/AreaCard.js +++ b/src/cards/AreaCard.js @@ -38,9 +38,15 @@ class AreaCard extends AbstractCard { */ constructor(area, options = {}) { super(area); + this.#defaultOptions.primary = area.name; this.#defaultOptions.tap_action.navigation_path = area.area_id ?? area.name; + // Set card type to default if a type "default" is given in strategy options. + if (options.type === "default") { + options.type = this.#defaultOptions.type; + } + this.mergeOptions( this.#defaultOptions, options, diff --git a/src/cards/HaAreaCard.js b/src/cards/HaAreaCard.js new file mode 100644 index 0000000..bf4c921 --- /dev/null +++ b/src/cards/HaAreaCard.js @@ -0,0 +1,47 @@ +import {AbstractCard} from "./AbstractCard"; + +/** + * HA Area Card Class + * + * Used to create a card for an entity of the area domain using the built in type 'area'. + * + * @class + * @extends AbstractCard + */ +class AreaCard extends AbstractCard { + /** + * Default options of the card. + * + * @type {HaAreaCardOptions} + * @private + */ + #defaultOptions = { + type: "area", + area: undefined, + navigation_path: undefined, + }; + + /** + * Class constructor. + * + * @param {areaEntity} area The area entity to create a card for. + * @param {HaAreaCardOptions} [options={}] Options for the card. + * @throws {Error} If the Helper module isn't initialized. + */ + + constructor(area, options = {}) { + super(area); + this.#defaultOptions.area = area.area_id ?? area.name; + this.#defaultOptions.navigation_path = area.area_id ?? area.name; + + // Enforce the card type. + options.type = this.#defaultOptions.type; + + this.mergeOptions( + this.#defaultOptions, + options, + ); + } +} + +export {AreaCard}; diff --git a/src/cards/typedefs.js b/src/cards/typedefs.js index 3312c14..bb031cb 100644 --- a/src/cards/typedefs.js +++ b/src/cards/typedefs.js @@ -112,6 +112,13 @@ * @memberOf typedefs.cards */ +/** + * @typedef {abstractOptions & Object} HaAreaCardOptions HA Area Card options. + * @property {string} area The id of the area. + * @property {string} navigation_path The id of the area to navigate to. + * @memberOf typedefs.cards + */ + /** * @typedef {abstractOptions & Object} mediaPlayerCardOptions Media Player Card options. * @property {boolean} [use_media_info=true] Use media info instead of name, state, and icon when a media is playing diff --git a/src/mushroom-strategy.js b/src/mushroom-strategy.js index a6fdbb4..770dcf2 100644 --- a/src/mushroom-strategy.js +++ b/src/mushroom-strategy.js @@ -191,12 +191,11 @@ class MushroomStrategy { } if (!Helper.strategyOptions.domains.default.hidden) { - // TODO: Check if default is hidden // Create cards for any other domain. // Collect device entities of the current area. const areaDevices = Helper.devices.filter(device => device.area_id === area.area_id) .map(device => device.id); - + // Collect the remaining entities of which all conditions below are met: // 1. The entity is linked to a device which is linked to the current area, // or the entity itself is linked to the current area. @@ -207,33 +206,33 @@ class MushroomStrategy { && entity.disabled_by == null && !exposedDomainIds.includes(entity.entity_id.split(".", 1)[0]); }); - + // Create a column of miscellaneous entity cards. if (miscellaneousEntities.length) { let miscellaneousCards = []; - + try { miscellaneousCards = await import("./cards/MiscellaneousCard").then(cardModule => { /** @type Object[] */ const miscellaneousCards = [ new TitleCard([area], Helper.strategyOptions.domains.default).createCard(), ]; - + for (const entity of miscellaneousEntities) { let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id] ?? {}; let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id] ?? {}; - + if (!cardOptions.hidden && !deviceOptions.hidden) { miscellaneousCards.push(new cardModule.MiscellaneousCard(entity, cardOptions).getCard()); } } - + return miscellaneousCards; }); } catch (e) { console.error(Helper.debug ? e : "An error occurred while creating the domain cards!"); } - + viewCards.push({ type: "vertical-stack", cards: miscellaneousCards, diff --git a/src/typedefs.js b/src/typedefs.js index 46944e1..04408a7 100644 --- a/src/typedefs.js +++ b/src/typedefs.js @@ -35,6 +35,7 @@ * @property {Object[]} [extra_cards] An array of card configurations. * The configured cards are added to the dashboard. * This property is added by the custom strategy. + * @property {boolean} [use_ha_area_card] Set to true to use ha area card instead of mushroom. * @memberOf typedefs.generic */ diff --git a/src/views/HomeView.js b/src/views/HomeView.js index df4edbf..c24c178 100644 --- a/src/views/HomeView.js +++ b/src/views/HomeView.js @@ -82,9 +82,9 @@ class HomeView extends AbstractView { // Add area cards. homeViewCards.push({ - type: "vertical-stack", - cards: areaCards, - }); + type: "vertical-stack", + cards: areaCards, + }); // Add custom cards. if (options.extra_cards) { @@ -158,10 +158,10 @@ class HomeView extends AbstractView { import("../cards/PersonCard").then(personModule => { for (const person of Helper.entities.filter(entity => { - return entity.entity_id.startsWith("person.") - && entity.hidden_by == null - && entity.disabled_by == null - })) { + return entity.entity_id.startsWith("person.") + && entity.hidden_by == null + && entity.disabled_by == null; + })) { cards.push(new personModule.PersonCard(person).getCard()); } }); @@ -176,30 +176,61 @@ class HomeView extends AbstractView { * * @return {Object[]} A card object array. */ - #createAreaCards() { - const groupedCards = [{ - type: "custom:mushroom-title-card", - title: "Areas", - }]; + async #createAreaCards() { + /** + * Cards to be stacked vertically. + * + * Contains a Title card and horizontal stacks of Area cards. + * + * @type {[{}]} + */ + const groupedCards = [ + { + type: "custom:mushroom-title-card", + title: "Areas", + }, + ]; + let areaCards = []; - import("../cards/AreaCard").then(areaModule => { - const areaCards = []; + for (const [i, area] of Helper.areas.entries()) { + let module; + let moduleName = + Helper.strategyOptions.areas[area.area_id ?? "undisclosed"]?.type ?? + Helper.strategyOptions.areas["_"]?.type ?? + "default"; - for (const area of Helper.areas) { - if (!Helper.strategyOptions.areas[area.area_id]?.hidden) { - areaCards.push( - new areaModule.AreaCard(area, Helper.strategyOptions.areas[area.area_id ?? "undisclosed"]).getCard()); + // Load module by type in strategy options. + try { + module = await import((`../cards/${moduleName}`)); + } catch (e) { + // Fallback to the default strategy card. + module = await import("../cards/AreaCard"); + + if (Helper.strategyOptions.debug && moduleName !== "default") { + console.error(e); } } - // Horizontally group every two area cards. - for (let i = 0; i < areaCards.length; i += 2) { - groupedCards.push({ - type: "horizontal-stack", - cards: areaCards.slice(i, i + 2), - }); + // Get a card for the area. + if (!Helper.strategyOptions.areas[area.area_id]?.hidden) { + let options = { + ...Helper.strategyOptions.areas["_"], + ...Helper.strategyOptions.areas[area.area_id ?? "undisclosed"], + }; + + areaCards.push(new module.AreaCard(area, options).getCard()); } - }); + + // Horizontally group every two area cards if all cards are created. + if (i === Helper.areas.length - 1) { + for (let i = 0; i < areaCards.length; i += 2) { + groupedCards.push({ + type: "horizontal-stack", + cards: areaCards.slice(i, i + 2), + }); + } + } + } return groupedCards; }