tap_action instead of action, deprecation of color_off and style in state support (#84)
* Support for style definition in state * Update documentation * Deprecate color_off and action replaced by tap_action * Fix documentation * Fixing documentation * Fix #71 * Add support for navigation * Fix documentation * Fix #71 - better solution * Default color when off is var(--disabled-text-color) * location action example * Fix documentation * Some bugfix * Fix documentation * Disable click when not needed * Linting and some code fix requested * Some fix * renamed location to navigate * Missing break in switch case * remove inexisting variable reference * Fixing button size and font to match default * Fixing button size on firefox * Use default entity icon if undefined and add show_icon, Fix #53 * Fix documentation * Replace default colors to match hass default * Updating documentation * Fix isClickable * Some refactoring * Blink animation support
This commit is contained in:
parent
416fb899a9
commit
11b87a5a50
219
README.md
219
README.md
|
@ -16,43 +16,75 @@ Lovelace Button card for your entities.
|
|||
## Features
|
||||
|
||||
- works with any toggleable entity
|
||||
- 3 actions on tap `toggle`, `more_info` and `service`
|
||||
- 3 actions on tap `none`, `toggle`, `more-info` and `call-service`
|
||||
- state display (optional)
|
||||
- custom color for `on` and `off` state (optional)
|
||||
- custom state definition with customizable color (optional)
|
||||
- custom color (optional), or based on light rgb value
|
||||
- custom state definition with customizable color, icon and style (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`
|
||||
- support unit of measurement
|
||||
- blank card and label card (for organization)
|
||||
- [blink](#blink) animation support
|
||||
- support for [custom_updater](https://github.com/custom-components/custom_updater)
|
||||
|
||||
## Options
|
||||
## Configuration
|
||||
### Main Options
|
||||
|
||||
| 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` \| `attribute` | Icon to display in place of the state. Will be overriden by the icon defined defined in a state (if present). If you use keywork `attribute` it will fetch the icon configured on the entity (overrides all icons defined). |
|
||||
| color_type | string | `icon` | `icon` \| `card` \| `blank-card` \| `label-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. Additional color-type options `blank-card` and `label-card` can be used for organisation (see examples). |
|
||||
| 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` \| `service` | Define the type of action |
|
||||
| service | Object | optional | See [example section](#Examples) | Service to call and service data when action is set to `service` |
|
||||
| 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 |
|
||||
| state | list | optional | See [state example section](#Configuration-with-states) | State to use for the color of the button. Multiple states can be defined |
|
||||
| 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 | `attribute` | `mdi:air-conditioner` \| `attribute` | Icon to display in place of the state. Will be overriden by the icon defined in a state (if present). If you use keyword `attribute` it will fetch the icon configured on the entity. |
|
||||
| `color_type` | string | `icon` | `icon` \| `card` \| `blank-card` \| `label-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. Additional color-type options `blank-card` and `label-card` can be used for organisation (see examples). |
|
||||
| `color` | string | optional | `auto` \| `rgb(28, 128, 199)` | Color of the icon/card. `auto` sets the color based on the color of a light. By default, if the entity state is `off`, the color will be `var(--paper-item-icon-active-color)`, for `on` it will be `var(--paper-item-icon-color)` and for any other state it will be `var(--primary-text-color)`. You can redefine each colors using `state` |
|
||||
| `size` | string | `40%` | `20px` | Size of the icon. Can be percentage or pixel |
|
||||
| `tap_action` | object | optional | See [Service](#Action) | Define the type of action, if undefined, toggle will be used. |
|
||||
| `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 |
|
||||
| `show_icon` | boolean | `true` | `true` \| `false` | Wether to show the icon or not. Unless redefined in `icon`, uses the default entity icon from hass |
|
||||
| `style` | object list | optional | `- text-transform: none` | Define a list of css attribute and their value to apply to the card |
|
||||
| `state` | object list | optional | See [State](#State) | State to use for the color, icon and style of the button. Multiple states can be defined |
|
||||
|
||||
## Installaion
|
||||
### Action
|
||||
|
||||
| Name | Type | Default | Supported options | Description |
|
||||
| ----------------- | ------ | -------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
||||
| `action` | string | `toggle` | `more-info`, `toggle`, `call-service`, `none`, `navigate` | Action to perform |
|
||||
| `navigation_path` | string | none | Eg: `/lovelace/0/` | Path to navigate to (e.g. `/lovelace/0/`) when action defined as navigate |
|
||||
| `service` | string | none | Any service | Service to call (e.g. `media_player.media_play_pause`) when `action` defined as `call-service` |
|
||||
| `service_data` | object | none | Any service data | Service data to include (e.g. `entity_id: media_player.bedroom`) when `action` defined as `call-service` |
|
||||
|
||||
|
||||
### State
|
||||
|
||||
| Name | Type | Default | Supported options | Description |
|
||||
| ---------- | ------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `operator` | string | `==` | See [Available Operators](#Available-operators) | The operator used to compare the current state against the `value` |
|
||||
| `value` | string/number | **required** (unless operator is `default`) | If your entity is a sensor with numbers, use a number directly, else use a string | The value which will be compared against the current state of the entity |
|
||||
| `icon` | string | optional | `mdi:battery`, `attribute` | The icon to display for this state. If `attribute` is used, the icon of the entity will be used |
|
||||
| `color` | string | `var(--primary-text-color)` | Any color, eg: `rgb(28, 128, 199)` or `blue` | The color of the icon (if `color_type: icon`) or the background (if `color_type: card`) |
|
||||
| `style` | string | optional | Any CSS style. If nothing is specified, the main style is used unless undefined. If you want to override the default style of the main part of the config, use `style: []` | Define a list of css attribute and their value to apply to the card |
|
||||
|
||||
### Available operators
|
||||
|
||||
| Operator | `value` example | Description |
|
||||
| :-------: | --------------- | -------------------------------------------------------------------------------------------------------- |
|
||||
| `<` | `5` | Current state is inferior to `value` |
|
||||
| `<=` | `4` | Current state is inferior or equal to `value` |
|
||||
| `==` | `42` or `'on'` | **This is the default if no operator is specified.** Current state is equal (`==` javascript) to `value` |
|
||||
| `>=` | `32` | Current state is superior or equal to `value` |
|
||||
| `>` | `12` | Current state is superior to `value` |
|
||||
| `!=` | `'normal'` | Current state is not equal (`!=` javascript) to `value` |
|
||||
| `regex` | `'^norm.*$'` | `value` regex applied to current state does match |
|
||||
| `default` | N/A | If nothing matches, this is used |
|
||||
|
||||
|
||||
## Installation
|
||||
### Manual Installation
|
||||
|
||||
1. Download the [button-card](https://raw.githubusercontent.com/custom-cards/button-card/master/button-card.js)
|
||||
|
@ -84,10 +116,7 @@ resources:
|
|||
|
||||
## Examples
|
||||
|
||||
|
||||
More examples in [here](./examples)
|
||||
|
||||
Show a button for the air conditioner (blue when on):
|
||||
Show a button for the air conditioner (blue when on, `var(--disabled-text-color)` when off):
|
||||
|
||||
![ac](examples/ac.png)
|
||||
|
||||
|
@ -97,6 +126,18 @@ Show a button for the air conditioner (blue when on):
|
|||
icon: mdi:air-conditioner
|
||||
color: rgb(28, 128, 199)
|
||||
```
|
||||
|
||||
Redefine the color when the state if off to red:
|
||||
```yaml
|
||||
- type: "custom:button-card"
|
||||
entity: switch.ac
|
||||
icon: mdi:air-conditioner
|
||||
color: rgb(28, 128, 199)
|
||||
state:
|
||||
- value: 'off'
|
||||
color: rgb(255, 0, 0)
|
||||
```
|
||||
|
||||
---------
|
||||
|
||||
Show an ON/OFF button for the home_lights group:
|
||||
|
@ -121,7 +162,8 @@ Light entity with custom icon and "more info" pop-in:
|
|||
entity: light.living_room_lights
|
||||
icon: mdi:sofa
|
||||
color: auto
|
||||
action: more_info
|
||||
tap_action:
|
||||
action: more-info
|
||||
```
|
||||
|
||||
|
||||
|
@ -138,8 +180,8 @@ Light card with card color type, name, and automatic color:
|
|||
icon: mdi:home
|
||||
color: auto
|
||||
color_type: card
|
||||
default_color: rgb(255, 233, 155)
|
||||
action: more_info
|
||||
tap_action:
|
||||
action: more-info
|
||||
name: Home
|
||||
style:
|
||||
- font-size: 12px
|
||||
|
@ -168,21 +210,19 @@ Horizontal stack with :
|
|||
color_type: card
|
||||
color: rgb(223, 255, 97)
|
||||
icon: mdi:volume-plus
|
||||
action: service
|
||||
service:
|
||||
domain: media_player
|
||||
action: volume_up
|
||||
data:
|
||||
tap_action:
|
||||
action: service
|
||||
service: media_player.volume_up
|
||||
service_data:
|
||||
entity_id: media_player.livimg_room_speaker
|
||||
- type: "custom:button-card"
|
||||
color_type: card
|
||||
color: rgb(223, 255, 97)
|
||||
icon: mdi:volume-minus
|
||||
action: service
|
||||
service:
|
||||
domain: media_player
|
||||
action: volume_down
|
||||
data:
|
||||
tap_action:
|
||||
action: service
|
||||
service: media_player.volume_down
|
||||
service_data:
|
||||
entity_id: media_player.livimg_room_speaker
|
||||
- type: "custom:button-card"
|
||||
color_type: blank-card
|
||||
|
@ -247,55 +287,76 @@ Input select card with select next service and custom color and icon for states.
|
|||
![cube](examples/cube.png)
|
||||
|
||||
#### Default behavior
|
||||
If you don't specify any operator, `==` will be used to match the current state against the `value`
|
||||
```yaml
|
||||
- type: "custom:button-card"
|
||||
entity: input_select.cube_mode
|
||||
icon: mdi:cube
|
||||
action: service
|
||||
show_state: true
|
||||
state:
|
||||
- value: 'sleeping'
|
||||
color: var(--disabled-text-color)
|
||||
icon: mdi:cube-outline
|
||||
- value: 'media'
|
||||
color: rgb(5, 147, 255)
|
||||
- value: 'light'
|
||||
color: rgb(189, 255, 5)
|
||||
- type: "custom:button-card"
|
||||
entity: input_select.cube_mode
|
||||
icon: mdi:cube
|
||||
tap_action:
|
||||
action: toggle
|
||||
show_state: true
|
||||
state:
|
||||
- value: 'sleeping'
|
||||
color: var(--disabled-text-color)
|
||||
icon: mdi:cube-outline
|
||||
- value: 'media'
|
||||
color: rgb(5, 147, 255)
|
||||
- value: 'light'
|
||||
color: rgb(189, 255, 5)
|
||||
```
|
||||
|
||||
#### With Operator on state
|
||||
The definition order matters, the first item to match will be the one selected.
|
||||
```yaml
|
||||
- type: "custom:button-card"
|
||||
entity: sensor.temperature
|
||||
show_state: true
|
||||
state:
|
||||
- value: 15
|
||||
operator: '<='
|
||||
color: blue
|
||||
icon: mdi:thermometer-minus
|
||||
- value: 25
|
||||
operator: '>='
|
||||
color: red
|
||||
icon: mdi:thermometer-plus
|
||||
- operator: 'default' # used if nothing matches
|
||||
color: yellow
|
||||
icon: mdi: thermometer
|
||||
- type: "custom:button-card"
|
||||
entity: sensor.temperature
|
||||
show_state: true
|
||||
state:
|
||||
- value: 15
|
||||
operator: '<='
|
||||
color: blue
|
||||
icon: mdi:thermometer-minus
|
||||
- value: 25
|
||||
operator: '>='
|
||||
color: red
|
||||
icon: mdi:thermometer-plus
|
||||
- operator: 'default' # used if nothing matches
|
||||
color: yellow
|
||||
icon: mdi: thermometer
|
||||
style:
|
||||
- opacity: 0.5
|
||||
```
|
||||
|
||||
Available operators:
|
||||
|
||||
| Operator | `value` example | Description |
|
||||
| :-------: | --------------- | ----------------------------------------------- |
|
||||
| `<` | `5` | State is inferior to `value` |
|
||||
| `<=` | `4` | State is inferior or equal to `value` |
|
||||
| `==` | `42` | State is equal (`==` javascript) to `value` |
|
||||
| `>=` | `32` | State is superior or equal to `value` |
|
||||
| `>` | `12` | State is superior to `value` |
|
||||
| `!=` | `normal` | State is not equal (`!=` javascript) to `value` |
|
||||
| `regex` | `'^norm.*$'` | `value` regex applied to State does match |
|
||||
| `default` | N/A | If nothing matches, this is used |
|
||||
#### `tap_action` Location
|
||||
For example, you can swith panel with the `location` action:
|
||||
```yaml
|
||||
- type: "custom:button-card"
|
||||
color_type: label-card
|
||||
icon: mdi:home
|
||||
name: Go To Home
|
||||
tap_action:
|
||||
action: location
|
||||
navigation_path: /lovelace/0
|
||||
```
|
||||
|
||||
#### blink
|
||||
You can make the whole button blink:
|
||||
![blink-animation](examples/blink-animation.gif)
|
||||
```yaml
|
||||
- type: "custom:button-card"
|
||||
color_type: card
|
||||
entity: binary_sensor.intruder
|
||||
name: Intruder Alert
|
||||
state:
|
||||
- value: 'on'
|
||||
color: red
|
||||
icon: mdi:alert
|
||||
style:
|
||||
- animation: blink 2s ease infinite
|
||||
- operator: default
|
||||
color: green
|
||||
icon: mdi:shield-check
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
|
|
433
button-card.js
433
button-card.js
|
@ -1,3 +1,107 @@
|
|||
/**
|
||||
* Return the icon to be used for a domain.
|
||||
*
|
||||
* Optionally pass in a state to influence the domain icon.
|
||||
*/
|
||||
export const DEFAULT_DOMAIN_ICON = "hass:bookmark";
|
||||
|
||||
const fixedIcons = {
|
||||
alert: "hass:alert",
|
||||
automation: "hass:playlist-play",
|
||||
calendar: "hass:calendar",
|
||||
camera: "hass:video",
|
||||
climate: "hass:thermostat",
|
||||
configurator: "hass:settings",
|
||||
conversation: "hass:text-to-speech",
|
||||
device_tracker: "hass:account",
|
||||
fan: "hass:fan",
|
||||
group: "hass:google-circles-communities",
|
||||
history_graph: "hass:chart-line",
|
||||
homeassistant: "hass:home-assistant",
|
||||
homekit: "hass:home-automation",
|
||||
image_processing: "hass:image-filter-frames",
|
||||
input_boolean: "hass:drawing",
|
||||
input_datetime: "hass:calendar-clock",
|
||||
input_number: "hass:ray-vertex",
|
||||
input_select: "hass:format-list-bulleted",
|
||||
input_text: "hass:textbox",
|
||||
light: "hass:lightbulb",
|
||||
mailbox: "hass:mailbox",
|
||||
notify: "hass:comment-alert",
|
||||
person: "hass:account",
|
||||
plant: "hass:flower",
|
||||
proximity: "hass:apple-safari",
|
||||
remote: "hass:remote",
|
||||
scene: "hass:google-pages",
|
||||
script: "hass:file-document",
|
||||
sensor: "hass:eye",
|
||||
simple_alarm: "hass:bell",
|
||||
sun: "hass:white-balance-sunny",
|
||||
switch: "hass:flash",
|
||||
timer: "hass:timer",
|
||||
updater: "hass:cloud-upload",
|
||||
vacuum: "hass:robot-vacuum",
|
||||
water_heater: "hass:thermometer",
|
||||
weblink: "hass:open-in-new",
|
||||
};
|
||||
|
||||
export default function domainIcon(domain, state) {
|
||||
if (domain in fixedIcons) {
|
||||
return fixedIcons[domain];
|
||||
}
|
||||
|
||||
switch (domain) {
|
||||
case "alarm_control_panel":
|
||||
switch (state) {
|
||||
case "armed_home":
|
||||
return "hass:bell-plus";
|
||||
case "armed_night":
|
||||
return "hass:bell-sleep";
|
||||
case "disarmed":
|
||||
return "hass:bell-outline";
|
||||
case "triggered":
|
||||
return "hass:bell-ring";
|
||||
default:
|
||||
return "hass:bell";
|
||||
}
|
||||
|
||||
case "binary_sensor":
|
||||
return state && state === "off"
|
||||
? "hass:radiobox-blank"
|
||||
: "hass:checkbox-marked-circle";
|
||||
|
||||
case "cover":
|
||||
return state === "closed" ? "hass:window-closed" : "hass:window-open";
|
||||
|
||||
case "lock":
|
||||
return state && state === "unlocked" ? "hass:lock-open" : "hass:lock";
|
||||
|
||||
case "media_player":
|
||||
return state && state !== "off" && state !== "idle"
|
||||
? "hass:cast-connected"
|
||||
: "hass:cast";
|
||||
|
||||
case "zwave":
|
||||
switch (state) {
|
||||
case "dead":
|
||||
return "hass:emoticon-dead";
|
||||
case "sleeping":
|
||||
return "hass:sleep";
|
||||
case "initializing":
|
||||
return "hass:timer-sand";
|
||||
default:
|
||||
return "hass:z-wave";
|
||||
}
|
||||
|
||||
default:
|
||||
// tslint:disable-next-line
|
||||
console.warn(
|
||||
"Unable to find icon for domain " + domain + " (" + state + ")"
|
||||
);
|
||||
return DEFAULT_DOMAIN_ICON;
|
||||
}
|
||||
}
|
||||
|
||||
((LitElement, ButtonBase) => {
|
||||
var html = LitElement.prototype.html;
|
||||
var css = LitElement.prototype.css;
|
||||
|
@ -37,33 +141,54 @@
|
|||
margin: auto;
|
||||
text-align: center;
|
||||
}
|
||||
button-card-button div {
|
||||
padding: 4%;
|
||||
button-card-button.disabled {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
button-card-button div.main {
|
||||
padding: 4% 0px;
|
||||
text-transform: none;
|
||||
font-weight: 400;
|
||||
font-size: 1.2rem;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
letter-spacing: normal;
|
||||
width: 100%;
|
||||
}
|
||||
@keyframes blink{
|
||||
0%{opacity:0;}
|
||||
50%{opacity:1;}
|
||||
100%{opacity:0;}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
render() {
|
||||
const state = this.__hass.states[this.config.entity];
|
||||
const configState = this.testConfigState(state, this.config)
|
||||
switch (this.config.color_type) {
|
||||
case 'blank-card':
|
||||
return this.blankCardColoredHtml(state, this.config);
|
||||
return this.blankCardColoredHtml(state, this.config, configState);
|
||||
case 'label-card':
|
||||
return this.labelCardColoredHtml(state, this.config);
|
||||
return this.labelCardColoredHtml(state, this.config, configState);
|
||||
case 'card':
|
||||
return this.cardColoredHtml(state, this.config);
|
||||
return this.cardColoredHtml(state, this.config, configState);
|
||||
case 'icon':
|
||||
default:
|
||||
return this.iconColoredHtml(state, this.config);
|
||||
return this.iconColoredHtml(state, this.config, configState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
getFontColorBasedOnBackgroundColor(backgroundColor) {
|
||||
const parsedRgbColor = backgroundColor.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i);
|
||||
const parsedBackgroundColor = parsedRgbColor ? parsedRgbColor : this.hexToRgb(backgroundColor.substring(1));
|
||||
let parsedBackgroundColor = null;
|
||||
if (backgroundColor.substring(0, 3) === "var") {
|
||||
let rgb = getComputedStyle(this.parentNode).getPropertyValue(backgroundColor.substring(4).slice(0, -1)).trim();
|
||||
parsedBackgroundColor = this.hexToRgb(rgb.substring(1));
|
||||
} else {
|
||||
const parsedRgbColor = backgroundColor.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i);
|
||||
parsedBackgroundColor = parsedRgbColor ? parsedRgbColor : this.hexToRgb(backgroundColor.substring(1));
|
||||
}
|
||||
let fontColor = ''; // don't override by default
|
||||
if (parsedBackgroundColor) {
|
||||
// Counting the perceptive luminance - human eye favors green color...
|
||||
|
@ -111,7 +236,7 @@
|
|||
def = elt;
|
||||
}
|
||||
} else {
|
||||
return (elt.value === state.state)
|
||||
return (elt.value == state.state)
|
||||
}
|
||||
})
|
||||
if (!retval)
|
||||
|
@ -121,119 +246,195 @@
|
|||
return retval;
|
||||
}
|
||||
|
||||
buildCssColorAttribute(state, config) {
|
||||
let color = config.color;
|
||||
if (state) {
|
||||
let configState = this.testConfigState(state, config);
|
||||
if (configState) {
|
||||
color = configState.color ? configState.color : config.color_off;
|
||||
if (configState.color === 'auto') {
|
||||
color = state.attributes.rgb_color ? `rgb(${state.attributes.rgb_color.join(',')})` : configState.default_color;
|
||||
getDefaultColorForState(state) {
|
||||
switch (state.state) {
|
||||
case 'on':
|
||||
return this.config.color_on;
|
||||
case 'off':
|
||||
return this.config.color_off;
|
||||
default:
|
||||
return this.config.default_color;
|
||||
}
|
||||
}
|
||||
|
||||
buildCssColorAttribute(state, config, configState) {
|
||||
let colorValue = null;
|
||||
let color = null;
|
||||
if (configState && configState.color) {
|
||||
colorValue = configState.color;
|
||||
} else {
|
||||
if (config.color != 'auto' && state && state.state == 'off') {
|
||||
colorValue = config.color_off;
|
||||
} else {
|
||||
colorValue = config.color;
|
||||
}
|
||||
}
|
||||
if (colorValue == 'auto') {
|
||||
if (state) {
|
||||
if (state.attributes.rgb_color) {
|
||||
color = `rgb(${state.attributes.rgb_color.join(',')})`
|
||||
} else {
|
||||
color = this.getDefaultColorForState(state)
|
||||
}
|
||||
} else {
|
||||
if (config.color === 'auto') {
|
||||
color = state.attributes.rgb_color ? `rgb(${state.attributes.rgb_color.join(',')})` : config.default_color;
|
||||
color = config.default_color;
|
||||
}
|
||||
} else {
|
||||
if (!colorValue) {
|
||||
if (state) {
|
||||
color = this.getDefaultColorForState(state)
|
||||
} else {
|
||||
color = config.default_color;
|
||||
}
|
||||
color = state.state === 'on' ? color : config.color_off;
|
||||
} else {
|
||||
color = colorValue;
|
||||
}
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
buildIcon(state, config) {
|
||||
let iconOff = config.icon;
|
||||
if (config.icon == 'attribute') {
|
||||
if (state) {
|
||||
const icon = state.attributes.icon;
|
||||
return icon;
|
||||
}
|
||||
return iconOff;
|
||||
}
|
||||
let configState = this.testConfigState(state, config);
|
||||
buildIcon(state, config, configState) {
|
||||
let iconValue = null;
|
||||
let icon = null;
|
||||
if (configState && configState.icon) {
|
||||
const icon = configState.icon;
|
||||
return icon;
|
||||
iconValue = configState.icon;
|
||||
} else {
|
||||
iconValue = config.icon;
|
||||
}
|
||||
return iconOff;
|
||||
if (iconValue == 'attribute') {
|
||||
if (state) {
|
||||
icon = state.attributes.icon ?
|
||||
state.attributes.icon :
|
||||
domainIcon(state.entity_id.split('.', 2)[0], state.state);
|
||||
} else {
|
||||
icon = undefined;
|
||||
}
|
||||
} else {
|
||||
icon = iconValue;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
blankCardColoredHtml(state, config) {
|
||||
buildStyle(state, config, configState) {
|
||||
let cardStyle = '';
|
||||
let styleArray = undefined;
|
||||
if (state) {
|
||||
if (configState && configState.style) {
|
||||
styleArray = configState.style;
|
||||
} else if (config.style) {
|
||||
styleArray = config.style;
|
||||
}
|
||||
} else {
|
||||
if (config.style)
|
||||
styleArray = config.style;
|
||||
}
|
||||
if (styleArray) {
|
||||
styleArray.forEach((cssObject) => {
|
||||
const attribute = Object.keys(cssObject)[0];
|
||||
const value = cssObject[attribute];
|
||||
cardStyle += `${attribute}: ${value};\n`;
|
||||
});
|
||||
}
|
||||
return cardStyle;
|
||||
}
|
||||
|
||||
isClickable(state, config) {
|
||||
let clickable = true;
|
||||
if (config.tap_action.action == 'toggle') {
|
||||
if (state) {
|
||||
switch (state.entity_id.split('.', 2)[0]) {
|
||||
case 'sensor':
|
||||
case 'binary_sensor':
|
||||
clickable = false
|
||||
break;
|
||||
default:
|
||||
clickable = true
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
clickable = false
|
||||
}
|
||||
} else {
|
||||
clickable = !(config.tap_action.action == 'none')
|
||||
}
|
||||
return clickable;
|
||||
}
|
||||
|
||||
|
||||
blankCardColoredHtml(state, config, configState) {
|
||||
const color = this.buildCssColorAttribute(state, config);
|
||||
const fontColor = this.getFontColorBasedOnBackgroundColor(color);
|
||||
return html`
|
||||
<ha-card style="color: ${fontColor}; background-color: ${color}; ${config.card_style}" on-tap="${ev => this._toggle(state, config)}">
|
||||
<ha-card class="disabled" style="color: ${fontColor}; background-color: ${color}; position: relative;">
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
labelCardColoredHtml(state, config) {
|
||||
const color = this.buildCssColorAttribute(state, config);
|
||||
labelCardColoredHtml(state, config, configState) {
|
||||
const color = this.buildCssColorAttribute(state, config, configState);
|
||||
const fontColor = this.getFontColorBasedOnBackgroundColor(color);
|
||||
const icon = this.buildIcon(state, config, configState);
|
||||
const style = this.buildStyle(state, config, configState);
|
||||
return html`
|
||||
<ha-card style="color: ${fontColor};">
|
||||
<button-card-button noink style="background-color: ${color}">
|
||||
<div style="${config.card_style}">
|
||||
${config.icon ? html`<ha-icon style="width: ${config.size}; height: ${config.size};" icon="${config.icon}"></ha-icon>` : ''}
|
||||
${config.name ? html`<span>${config.name}</span>` : ''}
|
||||
</div>
|
||||
<ha-card style="color: ${fontColor}; position: relative;" @tap="${ev => this._handleTap(state, config)}">
|
||||
<button-card-button class="${this.isClickable(state, config) ? '' : "disabled"}" style="background-color: ${color}">
|
||||
<div class="main" style="${style}">
|
||||
${config.show_icon && icon ? html`<ha-icon style="width: ${config.size}; height: auto;" icon="${icon}"></ha-icon>` : ''}
|
||||
${config.name ? html`<div>${config.name}</div>` : ''}
|
||||
</div>
|
||||
</button-card-button>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
cardColoredHtml(state, config) {
|
||||
const color = this.buildCssColorAttribute(state, config);
|
||||
cardColoredHtml(state, config, configState) {
|
||||
const color = this.buildCssColorAttribute(state, config, configState);
|
||||
const fontColor = this.getFontColorBasedOnBackgroundColor(color);
|
||||
const icon = this.buildIcon(state, config);
|
||||
const icon = this.buildIcon(state, config, configState);
|
||||
const style = this.buildStyle(state, config, configState);
|
||||
return html`
|
||||
<ha-card style="color: ${fontColor};" @tap="${ev => this._toggle(state, config)}">
|
||||
<button-card-button style="background-color: ${color}; ${config.card_style}">
|
||||
<div style="${config.card_style}">
|
||||
${config.icon || icon ? html`<ha-icon style="width: ${config.size}; height: ${config.size};" icon="${icon}"></ha-icon>` : ''}
|
||||
${config.name ? html`<span>${config.name}</span>` : ''}
|
||||
${config.show_state ? html`<span>${state.state} ${state.attributes.unit_of_measurement ? state.attributes.unit_of_measurement : ''}</span>` : ''}
|
||||
</div>
|
||||
<ha-card style="color: ${fontColor}; position: relative;" @tap="${ev => this._handleTap(state, config)}">
|
||||
<button-card-button class="${this.isClickable(state, config) ? '' : "disabled"}" style="background-color: ${color};">
|
||||
<div class="main" style="${style}">
|
||||
${config.show_icon && icon ? html`<ha-icon style="width: ${config.size}; height: auto;" icon="${icon}"></ha-icon>` : ''}
|
||||
${config.name ? html`<div>${config.name}</div>` : ''}
|
||||
${config.show_state ? html`<div>${state.state} ${state.attributes.unit_of_measurement ? state.attributes.unit_of_measurement : ''}</div>` : ''}
|
||||
</div>
|
||||
</button-card-button>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
iconColoredHtml(state, config) {
|
||||
const color = this.buildCssColorAttribute(state, config);
|
||||
const icon = this.buildIcon(state, config);
|
||||
iconColoredHtml(state, config, configState) {
|
||||
const color = this.buildCssColorAttribute(state, config, configState);
|
||||
const icon = this.buildIcon(state, config, configState);
|
||||
const style = this.buildStyle(state, config, configState);
|
||||
return html`
|
||||
<ha-card @tap="${ev => this._toggle(state, config)}">
|
||||
<button-card-button style="${config.card_style}">
|
||||
<div style="${config.card_style}">
|
||||
${config.icon || icon ? html`<ha-icon style="color: ${color}; width: ${config.size}; height: ${config.size};" icon="${icon}"></ha-icon>` : ''}
|
||||
${config.name ? html`<div>${config.name}</div>` : ''}
|
||||
${config.show_state ? html`<div>${state.state} ${state.attributes.unit_of_measurement ? state.attributes.unit_of_measurement : ''}</div>` : ''}
|
||||
</div>
|
||||
<ha-card style="position: relative;" @tap="${ev => this._handleTap(state, config)}">
|
||||
<button-card-button class="${this.isClickable(state, config) ? '' : "disabled"}">
|
||||
<div class="main" style="${style}">
|
||||
${config.show_icon && icon ? html`<ha-icon style="color: ${color}; width: ${config.size}; height: auto;" icon="${icon}"></ha-icon>` : ''}
|
||||
${config.name ? html`<div>${config.name}</div>` : ''}
|
||||
${config.show_state ? html`<div>${state.state} ${state.attributes.unit_of_measurement ? state.attributes.unit_of_measurement : ''}</div>` : ''}
|
||||
</div>
|
||||
</button-card-button>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
setConfig(config) {
|
||||
// if (!config.entity) {
|
||||
// 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 cardStyle = '';
|
||||
if (config.style) {
|
||||
config.style.forEach((cssObject) => {
|
||||
const attribute = Object.keys(cssObject)[0];
|
||||
const value = cssObject[attribute];
|
||||
cardStyle += `${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 = cardStyle;
|
||||
this.config.name = config.name ? config.name : '';
|
||||
this.config = {
|
||||
tap_action: { action: "toggle" },
|
||||
size: '40%',
|
||||
color_type: 'icon',
|
||||
default_color: 'var(--primary-text-color)',
|
||||
name: '',
|
||||
icon: 'attribute',
|
||||
show_icon: true,
|
||||
...config
|
||||
};
|
||||
this.config.color_off = 'var(--paper-item-icon-color)';
|
||||
this.config.color_on = 'var(--paper-item-icon-active-color)';
|
||||
}
|
||||
|
||||
// The height of your card. Home Assistant uses this to automatically
|
||||
|
@ -242,34 +443,48 @@
|
|||
return 3;
|
||||
}
|
||||
|
||||
_toggle(state, config) {
|
||||
switch (config.action) {
|
||||
case 'toggle':
|
||||
this.hass.callService('homeassistant', 'toggle', {
|
||||
entity_id: state.entity_id,
|
||||
});
|
||||
break;
|
||||
case 'more_info': {
|
||||
const node = this.shadowRoot;
|
||||
const options = {};
|
||||
const detail = { entityId: state.entity_id };
|
||||
const event = new Event('hass-more-info', {
|
||||
bubbles: options.bubbles === undefined ? true : options.bubbles,
|
||||
cancelable: Boolean(options.cancelable),
|
||||
composed: options.composed === undefined ? true : options.composed,
|
||||
});
|
||||
event.detail = detail;
|
||||
node.dispatchEvent(event);
|
||||
return event;
|
||||
_handleTap(state, config) {
|
||||
if (config.tap_action) {
|
||||
let event;
|
||||
switch (config.tap_action.action) {
|
||||
case 'none':
|
||||
break;
|
||||
case 'more-info':
|
||||
case 'more_info':
|
||||
event = new Event('hass-more-info', {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
composed: true,
|
||||
});
|
||||
event.detail = { entityId: state.entity_id };
|
||||
this.shadowRoot.dispatchEvent(event);
|
||||
break;
|
||||
case 'navigate':
|
||||
if (!config.tap_action.navigation_path) break;
|
||||
history.pushState(null, "", config.tap_action.navigation_path);
|
||||
event = new Event('location-changed', {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
composed: true,
|
||||
});
|
||||
event.detail = {};
|
||||
this.shadowRoot.dispatchEvent(event);
|
||||
break;
|
||||
case 'service':
|
||||
case 'call-service':
|
||||
if (!config.tap_action.service) {
|
||||
return;
|
||||
}
|
||||
const [domain, service] = config.tap_action.service.split('.', 2);
|
||||
this.hass.callService(domain, service, config.tap_action.service_data);
|
||||
break;
|
||||
case 'toggle':
|
||||
default:
|
||||
this.hass.callService('homeassistant', 'toggle', {
|
||||
entity_id: state.entity_id,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'service':
|
||||
this.hass.callService(config.service.domain, config.service.action, config.service.data);
|
||||
break;
|
||||
default:
|
||||
this.hass.callService('homeassistant', 'toggle', {
|
||||
entity_id: state.entity_id,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 210 KiB |
Loading…
Reference in New Issue