diff --git a/README.md b/README.md index 85bbf8f..fc3f33d 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,39 @@ # Button card -Simple button card for your entities. +Lovelace Button card for your entities. -![all](all.png) +![all](all.gif) ## Features - works with any toggleable entity - 2 actions on tap `toggle` and `more_info` (more to come) - - shows state if no icon specified for a very simple on/off button - - custom color for `on` state - - custom size - - custom icon - - icon automagically takes the color of light entities if rgb attribute is present + - state display (optional) + - custom color for `on` and `off` state (optional) + - custom size (optional) + - custom icon (optional) + - custom css style (optional) + - automatic color for light (optional) + - custom default color for lights (when color cannot be determined) (optional) + - 2 color types + - `icon` : apply color settings to the icon only + - `card` : apply color settings to the card only + - automatic font color if color_type is set to `card` ## Options -| Name | Type | Default | Example | Description +| Name | Type | Default | Supported options | Description | ---- | ---- | ------- | --------- | ----------- | type | string | **Required** | `custom:button-card` | Type of the card | entity | string | **Required** | `switch.ac` | entity_id | icon | string | optional | `mdi:air-conditioner` | Icon to display in place of the state -| color | string | `var(--primary-text-color)` | `rgb(28, 128, 199)` | Color of the icon when state is `on`. Can be any html color +| color_type | string | `icon` | `icon` \| `card` | Color either the background of the card or the icon inside the card. Setting this to `card` enable automatic `font` and `icon` color. This allows the text/icon to be readable even if the background color is bright/dark. +| color | string | `var(--primary-text-color)` | `auto` \| `rgb(28, 128, 199)` | Color of the icon/card when state is `on`. `auto` sets the color based on the color of a light. +| color_off | string | `var(--disabled-text-color)` | `rgb(28, 128, 199)` | Color of the icon/card when state is `off`. | size | string | `40%` | `20px` | Size of the icon. Can be percentage or pixel | action | string | `toggle` | `toggle` \| `more_info` | Define the type of action | name | string | optional | `Air conditioner` | Define an optional text to show below the icon +| show_state | boolean | `false` | `true` \| `false` | Show the state on the card. defaults to false if not set | style | object | optional | `- text-transform: none` | Define a list of css attribute and their value to apply to the card ## Instructions @@ -44,47 +53,70 @@ resources: Show a button for the air conditioner (blue when on): + +![ac](ac.png) + ```yaml - type: "custom:button-card" entity: switch.ac icon: mdi:air-conditioner color: rgb(28, 128, 199) ``` -![ac](ac.png) +--------- Show an ON/OFF button for the home_lights group: + +![no-icon](no_icon.png) + ```yaml - type: "custom:button-card" entity: group.home_lights + show_state: true ``` -![no-icon](no_icon.png) -Light entity with custom icon and "more info" pop-in + +---------------- + +Light entity with custom icon and "more info" pop-in:6 + +![sofa](sofa.png) + ```yaml - type: "custom:button-card" entity: light.living_room_lights icon: mdi:sofa + color: auto action: more_info ``` -![sofa](sofa.png) -Light card with text + +------------------------- + +Light card with text: + +![text](text.png) ```yaml - type: "custom:button-card" entity: light.living_room_lights icon: mdi:sofa + color: auto name: Living room ``` -![text](text.png) -Light card with text and custom style + +------------- + +Light card with text and custom style: + +![home-custom](home-custom.png) ```yaml - type: "custom:button-card" entity: light._ icon: mdi:home + color: auto action: more_info name: Home style: @@ -93,7 +125,79 @@ Light card with text and custom style - font-weight: bold ``` -![home-custom](home-custom.png) + +----- + +Light card with card color type, name, and automatic color: + +![color](color.gif) + +```yaml +- type: "custom:button-card" + entity: light._ + icon: mdi:home + color: auto + color_type: card + default_color: rgb(255, 233, 155) + action: more_info + name: Home + style: + - font-size: 12px + - font-weight: bold +``` + +--------------- + +Home + all rooms in an horizontal stack + +![all-home](all-home.png) + + +```yaml +- type: horizontal-stack + cards: + - type: "custom:button-card" + entity: light.living_room_lights + icon: mdi:sofa + color: auto + action: more_info + default_color: rgb(255, 233, 155) + color_type: card + name: Living room + style: + - font-size: 12px + - font-weight: bold + - type: "custom:button-card" + entity: light.harry + color: auto + icon: mdi:ceiling-light + action: more_info + name: Ceiling + style: + - font-size: 12px + - font-weight: bold + - type: "custom:button-card" + entity: light.ron + color: auto + icon: mdi:lamp + action: more_info + name: TV + style: + - font-size: 12px + - font-weight: bold + - type: "custom:button-card" + entity: light.snape + icon: mdi:floor-lamp + color: auto + action: more_info + name: Floor + style: + - font-size: 12px + - font-weight: bold +``` + + + ## Credits diff --git a/all-home.png b/all-home.png new file mode 100644 index 0000000..175f724 Binary files /dev/null and b/all-home.png differ diff --git a/all.gif b/all.gif new file mode 100644 index 0000000..c3534f7 Binary files /dev/null and b/all.gif differ diff --git a/all.png b/all.png index aed8dde..3292aa2 100644 Binary files a/all.png and b/all.png differ diff --git a/button-card.js b/button-card.js index e16520a..412444d 100644 --- a/button-card.js +++ b/button-card.js @@ -7,66 +7,96 @@ class ButtonCard extends LitElement { static get properties() { return { hass: Object, - config: Object, + config: Object } } _render({ hass, config }) { const state = hass.states[config.entity]; - if (config.icon) { - return this.icon(state, config); + switch (config.color_type) { + case "card": + return this.card_colored_html(state, config); + break; + case "icon": + default: + return this.icon_colored_html(state, config); + break; + } + } + + + get_font_color_based_on_background_color(background_color) { + background_color = background_color.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i); + let fontColor = ""; // don't override by default + if (background_color) { + // Counting the perceptive luminance - human eye favors green color... + const luminance = (0.299 * background_color[1] + 0.587 * background_color[2] + 0.114 * background_color[3]) / 255; + if (luminance > 0.5) { + fontColor = "rgb(62, 62, 62)"; // bright colors - black font + } else { + fontColor = "rgb(234, 234, 234)"// dark colors - white font + } } - return this.no_icon(state, config); + return fontColor; } + build_css_color_attribute(state, config) { + let color_on = config.color; + if (config.color == "auto") { + color_on = state.attributes.rgb_color ? `rgb(${state.attributes.rgb_color.join(',')})` : config.default_color; + } + let color = state.state === 'on' ? color_on : config.color_off; + return color; + } - no_icon(state, config) { + card_colored_html(state, config) { + const color = this.build_css_color_attribute(state, config); + const fontColor = this.get_font_color_based_on_background_color(color); return html` - - - ${state.state} + + +
+ ${config.icon ? html`` : ''} + ${config.name ? html`${config.name}` : ''} + ${config.show_state ? html`${state.state}` : ''} +
`; } - icon(state, config) { - const color = state.attributes.rgb_color ? `rgb(${state.attributes.rgb_color.join(',')})` : ( - config.color ? config.color : "var(--primary-text-color)" - ) - const color_on = state.state === 'on' ? color : "var(--disabled-text-color)"; - let card_style = ''; - if (config.style){ - config.style.forEach( cssObject => { - const attribute = Object.keys(cssObject)[0] - const value = cssObject[attribute] - card_style += `${attribute}: ${value};\n` - }) - } - + icon_colored_html(state, config) { + const color = this.build_css_color_attribute(state, config); return html` - - - - ${config.name ? config.name : ""} + + +
+ ${config.icon ? html`` : ''} + ${config.name ? html`${config.name}` : ''} + ${config.show_state ? html`${state.state}` : ''} +
`; @@ -77,6 +107,21 @@ class ButtonCard extends LitElement { throw new Error('You need to define entity'); } this.config = config; + this.config.color = config.color ? config.color : "var(--primary-text-color)"; + this.config.size = config.size ? config.size : "40%"; + let card_style = ''; + if (config.style) { + config.style.forEach(cssObject => { + const attribute = Object.keys(cssObject)[0] + const value = cssObject[attribute] + card_style += `${attribute}: ${value};\n` + }) + } + this.config.color_type = config.color_type ? config.color_type : "icon"; + this.config.color_off = config.color_off ? config.color_off : "var(--disabled-text-color)"; + this.config.default_color = config.default_color ? config.default_color : "var(--primary-text-color)"; + this.config.card_style = card_style; + this.config.name = config.name ? config.name : ""; } // The height of your card. Home Assistant uses this to automatically diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..8ca571b --- /dev/null +++ b/changelog.md @@ -0,0 +1,21 @@ +## 0.0.1 +Initial release that supports versioning + +### New features : + + - Color on off state + - Default color on light (when color set to `auto` and detection fails) + - Background color card + - Boolean to show/hide state + - Automatic font color based on card color (for readability) + +### Changed features : + + - Automatic color mode for lights now has to be enabled via `color: auto` + - State display has to be enabled explicity via `show_state: true` and is not enabled by default when an icon is not set + +### Other + + - Lots of refactoring + - Versionning + diff --git a/color.gif b/color.gif new file mode 100644 index 0000000..c779d3f Binary files /dev/null and b/color.gif differ