Custom Lovelace Card - Control lights better on tablets

On the forum someone asked how to get homekit like or atmos like slider on a card to control your lights on a tablet. Custom light slider/dimmer

So i made the card for him and i like to share it here maybe other people can also use it.
You can find it over here: https://github.com/DBuit/hass-smart-home-panel-card

Screenshot:

8 Likes

Nice, This look very good.
Can You share the rest of you Ui.
I like to look at how you implemented this in the whole picture?

Hello,

The card is best used with panel:true settings which makes it fill up the whole page.

This is a photo from someone using it on a tablet the colors are now different but you can see hoe it looks

1 Like

Here is another photo of this with the latest version…

1 Like

switchWidth and switchHeight don’t seem to change anything for me. Stuck with big switches. Am I doing something wrong here?

image

Realizing this is probably the toggle button, not switch…

Hello @stingray072 the switchWidth and Height is not used for the button below the slider.
When you have a light which without brightness the brightness slider changes to a switch and this switch uses the switchWidth and Height.

But what are you trying to do? maybe i can make some changes so you can accomplish what you want.

Yeah I finally figured that out. I’ve been messing around with the actual .js to try and get what I’m trying to do. Still obviously have a lot to figure out…

For the setup I’m using right now, I actually am trying to just use the sliders/switches on a transparent background without sidebar/counter/icon.

This is what I have so far:
image

As you can see there are a few funky things going on-I have to resize the buttons on the bottom, just probably have to do half-height, and also have a white bar on the bottom, can’t tell if that’s just a vestige from the return home button I tried to get rid of, or from the tabs that are supposed to be on the sliders that I have misplaced somewhere…

You can see what I’ve butchered of the code trying to delete parts… (go easy on me-remember I have no real html/css skills )

import {
    LitElement,
    html,
    css
} from "https://unpkg.com/[email protected]/lit-element.js?module";
class CustomSmartHomePanelCard extends LitElement {
  
  static get properties() {
    return {
      hass: {},
      config: {},
      active: {}
    };
  }
  
  constructor() {
    super();
  }
  
  render() {
    var brightnessWidth = this.config.brightnessWidth ? this.config.brightnessWidth : "60px";
    var brightnessHeight = this.config.brightnessHeight ? this.config.brightnessHeight : "120px";
    var switchWidth = this.config.switchWidth ? this.config.switchWidth : "60px";
    var switchHeight = this.config.switchHeight ? this.config.switchHeight : "90px";
    
    var countText = this.config.countText ? this.config.countText : "lights on";
    var entityCounter = 0;
    
    var showButton = this.config.showButton == "show" ? true : false;
    var buttonText = this.config.buttonText ? this.config.buttonText : "Home";
    var buttonPath = this.config.buttonPath ? this.config.buttonPath : "/lovelace/0";
    var background = this.config.background ? this.config.background : "transparent";
    
    return html`
        <div class="page" style="background:${background};">
          <div class="side">
            <div class="header">
              
            </div>
            <div class="center">
              <div class="icon">
                <ha-icon icon="${this.config.icon}" />
              </div>
              <h1>${this.config.title}</h1>
              <h3>${this._stateCount()} ${countText}</h3>
            </div>
            <div class="bottom">
                ${showButton ? html`<button class="back-btn" @click=${e => this._navigate(buttonPath)}>${buttonText}</button>` : html``}
            </div>
          </div>
          
          <div class="main">
            <div class="inner-main" style="width:${this.config.entities.length * 90}px;">
            ${this.config.entities.map(ent => {
                entityCounter++;
                var switchValue = 0;
                const stateObj = this.hass.states[ent.entity];
                switch(stateObj.state) {
                    case 'on':
                        switchValue = 1;
                        break;
                    case 'off':
                        switchValue = 0;
                        break;
                    default:
                        switchValue = 0;
                }
                return stateObj ? html`
                    <div class="light">
                      <div class="light-slider">
                        <h2>${ent.name || stateObj.attributes.friendly_name}</h2>
                        ${stateObj.attributes.supported_features > 9 ? html`
                            <h4 class="brightness">${stateObj.state === "off" ? 0 : Math.round(stateObj.attributes.brightness/2.55)}</h4>
                            <div class="range-holder" style="--slider-height: ${brightnessHeight};">
                              <input type="range" class="${stateObj.state}" style="--slider-width: ${brightnessWidth};--slider-height: ${brightnessHeight};" .value="${stateObj.state === "off" ? 0 : Math.round(stateObj.attributes.brightness/2.55)}" @change=${e => this._setBrightness(stateObj, e.target.value)}>
                            </div>
                        ` : html`
                            <h4>${stateObj.state}</h4>
                            <div class="switch-holder" style="--switch-height: ${switchHeight}">
                              <input type="range" class="${stateObj.state}" style="--switch-width: ${switchWidth};--switch-height: ${switchHeight};" value="0" min="0" max="1" .value="${switchValue}" @change=${e => this._switch(stateObj)}>
                            </div>
                        `}
                      </div>
                      <div class="toggle">
                        <input ?checked=${stateObj.state == "on"} type="checkbox" id='toggle${entityCounter}' class='toggle-btn' @change=${e => this._switch(stateObj)} />
                        <label for='toggle${entityCounter}'><span></span></label>
                      </div>  
                    </div>
                `: html``;
            })}
            </div>
          </div>
        </div>
    `;
  }
    
  updated() {}
  
  _setBrightness(state, value) {
    this.hass.callService("homeassistant", "turn_on", {
        entity_id: state.entity_id,
        brightness: value * 2.55
    });
  }
  
  _stateCount() {
      let count = 0;
      this.config.entities.map(ent => {
          const stateObj = this.hass.states[ent.entity];
          if(stateObj.state === "on") {
              count++;
          }
      })
      return count;
  }
  
  _switch(state) {
      this.hass.callService("homeassistant", "toggle", {
        entity_id: state.entity_id    
      });
  }
  
  _navigate(path) {
      window.location.href = path;
  }
  
  setConfig(config) {
    if (!config.entities) {
      throw new Error("You need to define entities");
    }
    if (!config.title) {
      throw new Error("You need to define a title");
    }
    if (!config.icon) {
      throw new Error("You need to define a icon");
    }
    this.config = config;
  }

  getCardSize() {
    return this.config.entities.length + 1;
  }
  
  static get styles() {
    return css`
        :host {
            
        }
        .page {
          width:100%;
          height:100%;
          display:flex;
          flex-direction: row;
        }
        .page > .side {
          padding: 0px;
          width: 0%;
          display:flex;
          flex-direction:column;
          background: rgb(1,180,217);
          background: linear-gradient(235deg, rgba(1,180,217,1) 0%, rgba(1,180,217,1) 90%);
          justify-content:space-between
        }
        .side .header {
          
        }
        .side .center {
          display:flex;
          flex-direction:column;
          
        }
        .side .center .icon {
          display:block;
          overflow:hidden;
        }
        .side .center .icon ha-icon {
          width: 0px;
          height: 0px;
        }
        .side .center  h1 {
          //color:#FFF;
          margin:0px 0 0 0;
          font-weight:400;
          font-family: Roboto
          font-size: 0px;
          line-height: 14px;
        }
        .side .center  h3 {
          //color:#FFF;
          margin:0px 0 0 0;
          font-size: 0px;
          font-weight: 400;
         margin: 0;
        }
        
        .side .bottom {
            background:transparent;
        }
        

        
        .page > .main {
          width: 100%;
          overflow-x:scroll;
        }
        .page > .main > .inner-main {
            display:flex;
            flex-direction:row;
            align-items:center;
            height:100%;
            margin:auto;
            //background: rgb(1,180,217);
            background:transparent;
            border-radius:8px;
        }

        h2 {
          color: #FFF;
          display: block;
          font-weight: 450;
          margin-bottom: 5px;
          text-align: center;
          font-size:14px;
          margin-top:15px;
        }
        h4 {
          color: #FFF;
          display: block;
          font-weight: 450;
          margin-bottom: 5px;
          text-align: center;
          font-size:10px;
          margin-top:0;
        }
        h4.brightness:after {
          content: "%";
          padding-left: 2px;
        }
        
        .range-holder {
          height: var(--slider-height);
          position:relative;
          display: block;
        }
        .range-holder input[type="range"] {
          outline: 0;
          border: 0;
          border-radius: 8px;
          width: var(--slider-height);
          margin: 0;
          transition: box-shadow 0.2s ease-in-out;
          -webkit-transform:rotate(270deg);
          -moz-transform:rotate(270deg);
          -o-transform:rotate(270deg);
          -ms-transform:rotate(270deg);
          transform:rotate(270deg);
          overflow: hidden;
          height: var(--slider-width);
          -webkit-appearance: none;
          background-color: #4d4d4d;
          position: absolute;
          top: calc(50% - (var(--slider-width) / 2));
          right: calc(50% - (var(--slider-height) / 2));
        }
        .range-holder input[type="range"]::-webkit-slider-runnable-track {
          height: var(--slider-width);
          -webkit-appearance: none;
          color: #636363;
          margin-top: -1px;
          transition: box-shadow 0.2s ease-in-out;
        }
        .range-holder input[type="range"]::-webkit-slider-thumb {
          width: 25px;
          border-right:10px solid #636363;
          border-left:10px solid #636363;
          border-top:20px solid #636363;
          border-bottom:20px solid #636363;
          -webkit-appearance: none;
          height: 80px;
          cursor: ew-resize;
          background: #636363;
          box-shadow: -350x 0 0 350px #636363, inset 0 0 0 80px #969696;
          border-radius: 0;
          transition: box-shadow 0.2s ease-in-out;
          position: relative;
          top: calc((var(--slider-width) - 80px) / 2);
        }
        // .range-holder input[type="range"].on::-webkit-slider-thumb {
        //     border-color: #1c7ae2;
        //     box-shadow: -350px 0 0 350px #1c7ae2, inset 0 0 0 80px #FFF;
        // }
        
        .switch-holder {
          height: var(--switch-height);
          position:relative;
          display: block;
        }
        .switch-holder input[type="range"] {
          outline: 0;
          border: 0;
          border-radius: 4px;
          width: calc(var(--switch-height) - 60px);
          margin: 0;
          transition: box-shadow 0.2s ease-in-out;
          -webkit-transform: rotate(270deg);
          -moz-transform: rotate(270deg);
          -o-transform: rotate(270deg);
          -ms-transform: rotate(270deg);
          transform: rotate(270deg);
          overflow: hidden;
          height: calc(var(--switch-width) - 120px);
          -webkit-appearance: none;
          background-color: #4d4d4d;
          padding: 10px;
          position: absolute;
          top: calc(50% - (var(--switch-width) / 2));
          right: calc(50% - (var(--switch-height) / 2));
        }
        .switch-holder input[type="range"]::-webkit-slider-runnable-track {
          height: calc(var(--switch-width) - 20px);
          -webkit-appearance: none;
          color: #636363;
          margin-top: -1px;
          transition: box-shadow 0.2s ease-in-out;
        }
        .switch-holder input[type="range"]::-webkit-slider-thumb {
          width: calc(var(--switch-height) / 2);
          -webkit-appearance: none;
          height: calc(var(--switch-width) - 20px);
          cursor: ew-resize;
          background: #636363;
          transition: box-shadow 0.2s ease-in-out;
          box-shadow: -80px 0 0 90px #4d4d4d, inset 0 0 0 80px #969696;
          position: relative;
          top: 0;
          border-radius: 4px;
        }
        // .switch-holder input[type="range"].on::-webkit-slider-thumb {
        //     box-shadow: -340px 0 0 350px #4d4d4d, inset 0 0 0 80px #1c7ae2;
        // }
        
        .toggle {
          margin-top:15px;
          margin-bottom:5px;
          display:flex;
          align-items:center;
          justify-content:center;
        }
        .toggle > input.toggle-btn {
          display: none;
        }
        .toggle > input.toggle-btn + label {
          border: 1px solid #FFF;
          background: transparent;
          width:60px;
          height:60px;
          text-align:center;
          line-height:30px;
          cursor: pointer;
          border-radius: 4px;
          color:#FFF;
          display:block;
          font-size:12px;
          font-weight: 450;
        }
        .toggle > input.toggle-btn:not(:checked) + label > span:before {
          content: 'Off';
        }
        .toggle > input.toggle-btn + label:active,
        .toggle > input.toggle-btn:checked + label {
          background: rgb(40,180,140);
          border-color: rgb(40,180,140);;
        }
        .toggle > input.toggle-btn:checked + label > span:before {
          content: 'On';
        }
    `;
  }  
  
}

customElements.define('custom-smart-home-panel-card', CustomSmartHomePanelCard);

Hey man,

can’t say what the white bar is but in the html you should just delete the part that starts with class=“side”.

The button size is this part in the css .toggle > input.toggle-btn + label

How do you install?

Awesome job! @DBuit :sunglasses:
I converted this to a popup for my mobile setup and I was able to get the buttons to change colors with my themes, but having no luck whatsoever with the slider colors. Not sure if it’s because of the custom named themed variables I’m using or not, but what applies the color for the part that slides up and down?
Here is what I have so far:


Thanks!

I’m afraid you can’t, it’s an input[type=range] and if I’m correct, that it’s pretty impossible to style (or at best, very badly supported by browsers)… :confused:

1 Like

@Dino-Tech Hey man, cool nice work! So in the css of the card you will find a part “input[type=“range”]::-webkit-slider-thumb” this is the part you wanna color.

The box-shadow part makes the part that is filled the light gray color and i think the border color that makes the part around the light gray line the right color.

1 Like

Got it working! Thank you for inspiration!!! @DBuit @woodmoose

3 Likes

How would I go about adding buttons above the dimmers that would open up a color wheel?

Thanks for the code, I have been customizing it a bit, to remove the left size etc.!

I was wondering if you could help me out so I could replace the On/Off button with a light bulp icon?

Here is my code:

import {
    LitElement,
    html,
    css
} from "https://unpkg.com/[email protected]/lit-element.js?module";
class CustomSmartHomePanelCard extends LitElement {
  
  static get properties() {
    return {
      hass: {},
      config: {},
      active: {}
    };
  }
  
  constructor() {
    super();
  }
  
  render() {
    var brightnessWidth = this.config.brightnessWidth ? this.config.brightnessWidth : "100px";
    var brightnessHeight = this.config.brightnessHeight ? this.config.brightnessHeight : "300px";
    var toggleHeight = this.config.toggleHeight ? this.config.toggleHeight : "60px";
    var toggleWidth = this.config.toggleWidth ? this.config.toggleWidth : "60px";
    var switchWidth = this.config.switchWidth ? this.config.switchWidth : "100px";
    var switchHeight = this.config.switchHeight ? this.config.switchHeight : "300px";
    
    var countText = this.config.countText ? this.config.countText : "lights on";
    var entityCounter = 0;
    
    var showButton = this.config.showButton == "show" ? true : false;
    var buttonText = this.config.buttonText ? this.config.buttonText : "Home";
    var buttonPath = this.config.buttonPath ? this.config.buttonPath : "/lovelace/0";
    var background = this.config.background ? this.config.background : "transparent";
    
    return html`
        <div class="page" style="background:${background};">
          <div class="main">
            <div class="inner-main" style="width:${this.config.entities.length * 150}px;">
            ${this.config.entities.map(ent => {
                entityCounter++;
                var switchValue = 0;
                const stateObj = this.hass.states[ent.entity];
                switch(stateObj.state) {
                    case 'on':
                        switchValue = 1;
                        break;
                    case 'off':
                        switchValue = 0;
                        break;
                    default:
                        switchValue = 0;
                }
                return stateObj ? html`
                    <div class="light">
                      <div class="light-slider">
                        <h2>${ent.name || stateObj.attributes.friendly_name}</h2>
                        ${stateObj.attributes.supported_features > 9 ? html`
                            <h4 class="brightness">${stateObj.state === "off" ? 0 : Math.round(stateObj.attributes.brightness/2.55)}</h4>
                            <div class="range-holder" style="--slider-height: ${brightnessHeight};">
                              <input type="range" class="${stateObj.state}" style="--slider-width: ${brightnessWidth};--slider-height: ${brightnessHeight};" .value="${stateObj.state === "off" ? 0 : Math.round(stateObj.attributes.brightness/2.55)}" @change=${e => this._setBrightness(stateObj, e.target.value)}>
                            </div>
                        ` : html`
                            <h4>${stateObj.state}</h4>
                            <div class="switch-holder" style="--switch-height: ${switchHeight}">
                              <input type="range" class="${stateObj.state}" style="--switch-width: ${switchWidth};--switch-height: ${switchHeight};" value="0" min="0" max="1" .value="${switchValue}" @change=${e => this._switch(stateObj)}>
                            </div>
                        `}
                      </div>
                      <div class="toggle" style="--toggle-width: ${toggleWidth};--toggle-height: ${toggleHeight};--toggle-line-height: ${toggleHeight};">
                        <input ?checked=${stateObj.state == "on"} type="checkbox" id='toggle${entityCounter}' class='toggle-btn' @change=${e => this._switch(stateObj)} />
                        <label for='toggle${entityCounter}'><span></span></label>
                      </div>  
                    </div>
                `: html``;
            })}
            </div>
          </div>
        </div>
    `;
  }
    
  updated() {}
  
  _setBrightness(state, value) {
    this.hass.callService("homeassistant", "turn_on", {
        entity_id: state.entity_id,
        brightness: value * 2.55
    });
  }
  
  _stateCount() {
      let count = 0;
      this.config.entities.map(ent => {
          const stateObj = this.hass.states[ent.entity];
          if(stateObj.state === "on") {
              count++;
          }
      })
      return count;
  }
  
  _switch(state) {
      this.hass.callService("homeassistant", "toggle", {
        entity_id: state.entity_id    
      });
  }
  
  _navigate(path) {
      window.location.href = path;
  }
  
  setConfig(config) {
    if (!config.entities) {
      throw new Error("You need to define entities");
    }
    if (!config.title) {
      throw new Error("You need to define a title");
    }
    if (!config.icon) {
      throw new Error("You need to define a icon");
    }
    this.config = config;
  }

  getCardSize() {
    return this.config.entities.length + 1;
  }
  
  static get styles() {
    return css`
        :host {
            
        }
        .page {
          width:100%;
          height:100%;
          display:flex;
          flex-direction: row;
        }
                
        .back-btn {
          border:2px solid #FFF;
          color:#FFF;
          background:transparent;
          font-size:24px;
          border-radius:4px;
          width:100%;
          display:block;
          padding: 10px 0;
        }
        
        .page > .main {
          width:70%;
          //overflow-x:hidden;
        }
        .page > .main > .inner-main {
            display:flex;
            flex-direction:row;
            align-items:center;
            height:100%;
            margin:auto;
        }
        .page > .main > .inner-main > .light {
          width:150px;
          display:inline-block;
        }
        
        .light .icon {
          margin: 0 auto;
          text-align:center;
          display:block;
          height: 40px;
          width: 40px;
          color: rgba(255,255,255,0.3);
          font-size: 30px;
          padding-top:5px;
        }
        .light .icon ha-icon {
          width:30px;
          height:30px;
        }
        .light .icon.on ha-icon {
          fill: #f7d959;
        }
        h2 {
          color: #212121;
          font-family: Roboto,noto,sans-serif;
          display: block;
          font-weight: 300;
          margin-bottom: 10px;
          text-align: center;
          font-size:20px;
          margin-top:0;
        }
        h4 {
          color: #FFF;
          display: block;
          font-weight: 300;
          margin-bottom: 30px;
          text-align: center;
          font-size:16px;
          margin-top:0;
        }
        h4.brightness:after {
          content: "%";
          padding-left: 1px;
        }
        
        .range-holder {
          height: var(--slider-height);
          position:relative;
          display: block;
        }
        .range-holder input[type="range"] {
          outline: 0;
          border: 1px solid #c3c5c9;
          border-radius: 4px;
          width: var(--slider-height);
          margin: 0;
          transition: box-shadow 0.2s ease-in-out;
          -webkit-transform:rotate(270deg);
          -moz-transform:rotate(270deg);
          -o-transform:rotate(270deg);
          -ms-transform:rotate(270deg);
          transform:rotate(270deg);
          overflow: hidden;
          height: var(--slider-width);
          -webkit-appearance: none;
          background-color: #bdbdbd;
          position: absolute;
          top: calc(50% - (var(--slider-width) / 2));
          right: calc(50% - (var(--slider-height) / 2));
        }
        .range-holder input[type="range"]::-webkit-slider-runnable-track {
          height: var(--slider-width);
          -webkit-appearance: none;
          color: #03a9f4;
          margin-top: -1px;
          transition: box-shadow 0.2s ease-in-out;
        }
        .range-holder input[type="range"]::-webkit-slider-thumb {
          width: 25px;
          border-right:10px solid #03a9f4;
          border-left:10px solid #03a9f4;
          border-top:20px solid #03a9f4;
          border-bottom:20px solid #03a9f4;
          -webkit-appearance: none;
          height: 80px;
          cursor: ew-resize;
          background: #03a9f4;
          box-shadow: -350px 0 0 350px #03a9f4, inset 0 0 0 80px #969696;
          border-radius: 0;
          transition: box-shadow 0.2s ease-in-out;
          position: relative;
          top: calc((var(--slider-width) - 80px) / 2);
        }
        // .range-holder input[type="range"].on::-webkit-slider-thumb {
        //     border-color: #1c7ae2;
        //     box-shadow: -350px 0 0 350px #1c7ae2, inset 0 0 0 80px #FFF;
        // }
        
        .switch-holder {
          height: var(--switch-height);
          position:relative;
          display: block;
        }
        .switch-holder input[type="range"] {
          outline: 0;
          border: 0;
          border-radius: 4px;
          width: calc(var(--switch-height) - 20px);
          margin: 0;
          transition: box-shadow 0.2s ease-in-out;
          -webkit-transform: rotate(270deg);
          -moz-transform: rotate(270deg);
          -o-transform: rotate(270deg);
          -ms-transform: rotate(270deg);
          transform: rotate(270deg);
          overflow: hidden;
          height: calc(var(--switch-width) - 20px);
          -webkit-appearance: none;
          background-color: #4d4d4d;
          padding: 10px;
          position: absolute;
          top: calc(50% - (var(--switch-width) / 2));
          right: calc(50% - (var(--switch-height) / 2));
        }
        .switch-holder input[type="range"]::-webkit-slider-runnable-track {
          height: calc(var(--switch-width) - 20px);
          -webkit-appearance: none;
          color: #03a9f4;
          margin-top: -1px;
          transition: box-shadow 0.2s ease-in-out;
        }
        .switch-holder input[type="range"]::-webkit-slider-thumb {
          width: calc(var(--switch-height) / 2);
          -webkit-appearance: none;
          height: calc(var(--switch-width) - 20px);
          cursor: ew-resize;
          background: #636363;
          transition: box-shadow 0.2s ease-in-out;
          box-shadow: -340px 0 0 350px #4d4d4d, inset 0 0 0 80px #969696;
          position: relative;
          top: 0;
          border-radius: 4px;
        }
        // .switch-holder input[type="range"].on::-webkit-slider-thumb {
        //     box-shadow: -340px 0 0 350px #4d4d4d, inset 0 0 0 80px #1c7ae2;
        // }
        
        .toggle {
          margin-top:30px;
          display:flex;
          align-items:center;
          justify-content:center;
        }
        .toggle > input.toggle-btn {
          display: none;
        }
        .toggle > input.toggle-btn + label {
          border: 1px solid #c3c5c9;
          background: transparent;
          width:var(--toggle-width); //width:60px;
          height:var(--toggle-height); //height:60px;
          text-align:center;
          line-height:var(--toggle-line-height);//100px;
          cursor: pointer;
          border-radius: 4px;
          color:#212121;
          font-family: Roboto,noto,sans-serif;
          display:block;
          font-size:22px;
        }
        .toggle > input.toggle-btn:not(:checked) + label > span:before {
          content: 'Off';
        }
        .toggle > input.toggle-btn + label:active,
        .toggle > input.toggle-btn:checked + label {
          background: #1c7ae2;
          border-color: #c3c5c9;
        }
        .toggle > input.toggle-btn:checked + label > span:before {
          content: 'On';
        }
    `;
  }  
  
}

customElements.define('custom-smart-home-panel-card', CustomSmartHomePanelCard);

Summary

This text will be hidden

Hello.

I downloaded the js file from your github.

Added it to my www folder

Added this to my config:

  - url: /local/custom-smart-home-panel-card.js
    type: js
  
  

added this to my lovelaceui


    - type: "custom:custom-smart-home-panel-card"
      title: Test
      icon: mdi:floor-lamp
      showButton: "show"
      buttonText: "Test"
      buttonPath: "/lovelace/0"
      background: "#1c1d1f"
      entities:
        - entity: light.hue_filament_bulb_1
        - entity: light.hue_filament_bulb_2
        - entity: light.hue_filament_bulb_3        
        - entity: switch.plug_1
        - entity: switch.plug_1


restarted everything but get the error “Custom element doesn’t exist: custom-smart-home-panel-card”

worked it out, needs to be module not js.

Looking at the size of the card I dont think this will work for what I want, but its nice

Where do I add - url: /local/custom-smart-home-panel-card.js
type: js

So… you planning on just rubbing it in our face with your picture or you going to share the code?

2 Likes