iphong
(Phong Vu)
May 8, 2020, 4:00pm
1
I think the new lovelace ui along with home assistant cast has lots of potential. And i’m thinking of creating a lovelace card builder so people can create custom cards and import designs created in Sketch or Illustrator. And a easy to use GUI editor for mapping states and attaching actions.
My approach is to break down the card into 3 parts.
Use any SVG or HTML file as the source of content
Define data bindings to elements in the UI
Attach actions on any element in the UI
This way you can have a designer work solely on the visual part. The best part is it allows to update the design of your card later on by just simply import a svg or html file.
Here is a demo of what I have so far
Import design into existing card
Take full advantage of HA event bus for updating states and calling services
And this is how the configuration looks like
So i need more input on this. What do you guys think, should I continue with this, or is it something that has been done?
10 Likes
Jas39
(Anders)
May 14, 2020, 8:48pm
2
That looks super interesting to me and I would love to try it out for a custom card of mine.
how is this different from layout-card paired with all of thomasloven’s other custom cards?
1 Like
Jas39
(Anders)
May 14, 2020, 9:13pm
4
I cant really answer that, I’m relative new to hass and currently working on a first custom integration to which I would like to make a lovelace-card-gui.combining html, css with events and data. This looked to be the cook book for it. But please advice if there’s better path to take as I haven’t gone through all the beutiful cards from Thomas yet.
iphong
(Phong Vu)
May 15, 2020, 2:26am
5
I was focusing on fullscreen card and take advantage of SVG scaling capability. Imagine something was designed for 720p screen and displaying theme on a 4K screen. It scales out beautifully.
I have lots of designer friends and they can produce beautiful designs, and their outputs are SVG, my card is a bridge to bring their designs to lovelace UI, that’s all.
1 Like
iphong
(Phong Vu)
May 15, 2020, 2:32am
6
By the way, my card is available to try in repo. Just include the script, and the card will show up in new card selection modal.
class ExampleCardConfigEditor extends HTMLElement {
constructor() {
super()
console.log('editor: new instance')
}
setConfig(config) {
this.config = config
this.innerHTML = this.render(config)
}
handleChange(e) {
const event = new Event('config-changed', {
bubbles: true,
composed: true
})
event.detail = {
config: {
...this.config,
[e.target.id]: e.target.value
This file has been truncated. show original
if the code is being share. I would also love to test it
iphong
(Phong Vu)
May 15, 2020, 3:22am
8
These are some of the yaml config as seen in the video
cards:
- actions:
- call: entity.toggle()
selector: '#light'
type: click
bindings:
- bind: return Math.round((attr.brightness || 0) / 255 * 100) || '--'
selector: '#light-value'
type: html
- bind: 'return Math.round(hass.states["sensor.balcony_temperature"].state)'
selector: '#temp-value'
type: html
- bind: 'return hass.states["sensor.balcony_humidity"].state'
selector: '#humid-value'
type: html
- bind: 'return state == "on" ? "orange" : "gray"'
selector: '#light circle'
type: stroke
- bind: 'return state == "on" ? "#ff98001a" : "#2196f317"'
selector: '#background'
type: fill
- bind: return (attr.brightness || 0) / 255 * 0.8 + 0.2
selector: '#light circle'
type: opacity
content: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 180 110\">\n<style type=\"text/css\">\n\t.st1{fill:none;stroke-width:2;}\n\t.st2{fill:#919DA9;}\n\t.st4{font-size:18px;}\n\t.st5{font-size:6px;}\n\t.st6{font-size:4px;}\n\ttext { text-anchor: middle; alignment-baseline: middle; }\n</style>\n<rect id=\"background\" class=\"st0\" width=\"180\" height=\"110\" fill=\"transparent\"/>\n<g id=\"temp\" transform=\"translate(20.000000, 55.000000)\">\n\t<circle stroke=\"#D2D8DE\" id=\"circle\" class=\"st1\" cx=\"20\" cy=\"20\" r=\"21\"/>\n\t<text x=\"20\" y=\"8\" class=\"st2 st3 st6\">TEMP</text>\n\t<text x=\"20\" y=\"32\" class=\"st2 st3 st5\">ºC</text>\n\t<text id=\"temp-value\" x=\"20\" y=\"21\" class=\"st2 st3 st4\">0</text>\n</g>\n<g id=\"humid\" transform=\"translate(65.000000, 15.000000)\">\n\t<circle stroke=\"#D2D8DE\" id=\"circle_1_\" class=\"st1\" cx=\"20\" cy=\"20\" r=\"20\"/>\n\t<text x=\"20\" y=\"8\" class=\"st2 st3 st6\">HUMID</text>\n\t<text x=\"20\" y=\"32\" class=\"st2 st3 st5\">%</text>\n\t<text id=\"humid-value\" x=\"20\" y=\"21\" class=\"st2 st3 st4\">0</text>\n</g>\n<g id=\"light\" transform=\"translate(120.000000, 45.000000)\">\n\t<circle id=\"circle_2_\" class=\"st1\" cx=\"20\" cy=\"20\" r=\"30\"/>\n\t<text x=\"20\" y=\"8\" class=\"st2 st3 st6\">LIGHT</text>\n\t<text x=\"20\" y=\"32\" class=\"st2 st3 st5\">%</text>\n\t<text id=\"light-value\" x=\"20\" y=\"21\" class=\"st2 st3 st4\">0</text>\n</g>\n</svg>"
entity: light.bedroom_light
type: 'custom:example-card'
- entity: light.bedroom_light
type: light
- actions:
- call: entity.toggle()
selector: '#light'
type: click
bindings:
- bind: return Math.round((attr.brightness || 0) / 255 * 100) || '--'
selector: '#light-value'
type: html
- bind: 'return Math.round(hass.states["sensor.balcony_temperature"].state)'
selector: '#temp-value'
type: html
- bind: 'return hass.states["sensor.balcony_humidity"].state'
selector: '#humid-value'
type: html
- bind: 'return state == "on" ? "lightseagreen" : "gray"'
selector: '#light circle'
type: stroke
- bind: 'return state == "on" ? "#ff98001a" : "#2196f317"'
selector: '#background'
type: fill
- bind: return (attr.brightness || 0) / 255 * 0.8 + 0.2
selector: '#light circle'
type: opacity
content: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 180 110\">\n<style type=\"text/css\">\n\t.st1{fill:none;stroke-width:2;}\n\t.st2{fill:#919DA9;}\n\t.st4{font-size:18px;}\n\t.st5{font-size:6px;}\n\t.st6{font-size:4px;}\n\ttext { text-anchor: middle; alignment-baseline: middle; }\n</style>\n<rect id=\"background\" class=\"st0\" width=\"180\" height=\"110\" fill=\"transparent\"/>\n<g id=\"temp\" transform=\"translate(20.000000, 35.000000)\">\n\t<circle stroke=\"#D2D8DE\" id=\"circle\" class=\"st1\" cx=\"20\" cy=\"20\" r=\"21\"/>\n\t<text x=\"20\" y=\"8\" class=\"st2 st3 st6\">TEMP</text>\n\t<text x=\"20\" y=\"32\" class=\"st2 st3 st5\">ºC</text>\n\t<text id=\"temp-value\" x=\"20\" y=\"21\" class=\"st2 st3 st4\">0</text>\n</g>\n<g id=\"humid\" transform=\"translate(70.000000, 35.000000)\">\n\t<circle stroke=\"#D2D8DE\" id=\"circle_1_\" class=\"st1\" cx=\"20\" cy=\"20\" r=\"20\"/>\n\t<text x=\"20\" y=\"8\" class=\"st2 st3 st6\">HUMID</text>\n\t<text x=\"20\" y=\"32\" class=\"st2 st3 st5\">%</text>\n\t<text id=\"humid-value\" x=\"20\" y=\"21\" class=\"st2 st3 st4\">0</text>\n</g>\n<g id=\"light\" transform=\"translate(120.000000, 35.000000)\">\n\t<circle id=\"circle_2_\" class=\"st1\" cx=\"20\" cy=\"20\" r=\"21\"/>\n\t<text x=\"20\" y=\"8\" class=\"st2 st3 st6\">LIGHT</text>\n\t<text x=\"20\" y=\"32\" class=\"st2 st3 st5\">%</text>\n\t<text id=\"light-value\" x=\"20\" y=\"21\" class=\"st2 st3 st4\">0</text>\n</g>\n</svg>"
entity: light.bathroom_light
type: 'custom:example-card'
panel: false
path: test-2
title: Demo
cards:
- actions:
- call: entity.toggle()
selector: button
type: click
- call: >-
this.value == 0 ? entity.turn_off() : entity.turn_on({ brightness:
this.value })
selector: input
type: change
bindings:
- bind: return attr.brightness || 0
selector: input
type: value
- bind: return attr.color_temp || 0
selector: span
type: text
content: |-
<section>
<h3>Custom design card</h3>
<button>Click me</button>
<input disable />
<span style="font-size: 20px; font-weight: bold;"></span>
</section>
entity: light.bedroom_light
type: 'custom:example-card'
- actions:
- call: entity.toggle()
selector: button
type: click
- call: >-
this.value == 0 ? entity.turn_off() : entity.turn_on({ brightness:
this.value })
selector: input
type: change
bindings:
- bind: return attr.brightness || 0
selector: input
type: value
- bind: return attr.color_temp || 0
selector: span
type: text
content: |-
<section>
<h3>Custom design card</h3>
<button>Click me</button>
<input disable />
<span style="font-size: 20px; font-weight: bold;"></span>
</section>
entity: light.balcony_light
type: 'custom:example-card'
- actions:
- call: 'this.checked ? entity.turn_on() : entity.turn_off()'
selector: '#t1'
type: change
bindings:
- bind: 'return state === "on" ? true : false'
selector: '#t1'
type: checked
valueMap:
'off': false
'on': true
content: |-
<ha-card header="Another custom card">
<div style="padding: 10px;">
<ha-switch id="t1">Toogle 1</ha-switch>
</div>
<div style="padding: 10px;">
<ha-switch id="t2">Toogle 2</ha-switch>
</div>
</ha-card>
entity: light.bedroom_light
type: 'custom:example-card'
- cards:
- actions:
- call: 'entity.turn_on({ brightness: this.value })'
selector: .slider
type: change
bindings:
- bind: return attr.brightness
selector: .slider
type: value
- bind: return attr.brightness
selector: .slider
type: 'value:text'
content: >-
<ui-round-slider track:color="lightcoral" class="slider"
max="255"></ui-round-slider>
entity: light.bedroom_light
type: 'custom:example-card'
- actions: []
bindings:
- bind: 'return state === "on" ? 1 : 0'
selector: .slider
type: value
- bind: return state
selector: .slider
type: valueText
content: >-
<ui-round-slider class="slider" track:color="orange"
max="1"></ui-round-slider>
entity: light.balcony_light
type: 'custom:example-card'
- actions: []
bindings:
- bind: 'return state === "on" ? 1 : 0'
selector: .slider
type: value
content: >-
<ui-round-slider class="slider" track:color="lightseagreen"
max="1"></ui-round-slider>
entity: light.bathroom_light
type: 'custom:example-card'
type: horizontal-stack
- cards:
- entity: light.bedroom_light
type: light
- entity: light.balcony_light
type: light
type: horizontal-stack
1 Like
iphong
(Phong Vu)
May 15, 2020, 5:49am
9
Designs like these, which is very hard to do using default lovelace cards, can be made possible. Just import the SVG and link all the parameters.
2 Likes
marrewijk
(Marrewijk)
August 23, 2022, 4:06pm
10
I like your idea!
The low amount of replies tell me that another way to make custom cards is existing.
If some else bumps on this thread you may find these link interesting
Wer eine individuelle Tankkarte haben möchte, für den eignet sich dieser Beitrag! Hier wird Schritt-für-Schritt gezeigt, wie man mit der Erstellung einer Karte anfängt. Der Vorteil einer custom:button-card: "es lassen sich so gut wie alle anderen...