├── example.png ├── tracker.json ├── LICENSE ├── README.md └── attribute-entity-row.js /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benct/lovelace-attribute-entity-row/HEAD/example.png -------------------------------------------------------------------------------- /tracker.json: -------------------------------------------------------------------------------- 1 | { 2 | "attribute-entity-row": { 3 | "updated_at": "2020-01-13", 4 | "version": "1.1.2", 5 | "remote_location": "https://raw.githubusercontent.com/benct/lovelace-attribute-entity-row/master/attribute-entity-row.js", 6 | "visit_repo": "https://github.com/benct/lovelace-attribute-entity-row", 7 | "changelog": "https://github.com/benct/lovelace-attribute-entity-row" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ben Tomlin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # attribute-entity-row 2 | Show entity attribute value(s) on entity rows in Home Assistant's Lovelace UI. 3 | 4 | [![GH-release](https://img.shields.io/badge/version-1.1.2-red.svg?style=flat-square)](https://raw.githubusercontent.com/benct/lovelace-attribute-entity-row/master/attribute-entity-row.js) 5 | [![GH-last-commit](https://img.shields.io/github/last-commit/benct/lovelace-attribute-entity-row.svg?style=flat-square)](https://github.com/benct/lovelace-attribute-entity-row/commits/master) 6 | [![GH-code-size](https://img.shields.io/github/languages/code-size/benct/lovelace-attribute-entity-row.svg?style=flat-square)](https://github.com/benct/lovelace-attribute-entity-row) 7 | 8 | **Note:** Semi-deprecated in favor of [multiple-entity-row](https://github.com/benct/lovelace-multiple-entity-row) card, so this card will most likely not be further worked upon. 9 | 10 | ## Setup 11 | 12 | Add [attribute-entity-row.js](https://raw.githubusercontent.com/benct/lovelace-attribute-entity-row/master/attribute-entity-row.js) to your `/www/` folder. Add the following to your `ui-lovelace.yaml` file: 13 | 14 | ```yaml 15 | resources: 16 | - url: /local/attribute-entity-row.js?v=1.1.2 17 | type: js 18 | ``` 19 | 20 | ## Options 21 | 22 | | Name | Type | Default | Description 23 | | ---- | ---- | ------- | ----------- 24 | | type | string | **Required** | `custom:attribute-entity-row` 25 | | entity | string | **Required** | `sensor.my_sensor` 26 | | name | string | | Override entity name / friendly_name 27 | | name_attribute | string | | Use an attribute as the entity name 28 | | unit | string | | Override state unit_of_measurement 29 | | toggle | bool | `false` | Display a toogle instead of state 30 | | hide_state | bool | `false` | Hide the entity state 31 | | primary | object | *see below* | Primary attribute object 32 | | secondary | object | *see below* | Secondary attribute object 33 | 34 | ### Primary/secondary object 35 | 36 | | Name | Type | Default | Description 37 | | ---- | ---- | ------- | ----------- 38 | | key | string | **Required** | A valid attribute key within the entity 39 | | name | string | | Name / prefix for attribute 40 | | unit | string | | Unit / postfix for attribute 41 | | entity | string | | Use attribute from another entity 42 | 43 | ## Example 44 | 45 | ![attribute-entity-row](https://raw.githubusercontent.com/benct/lovelace-attribute-entity-row/master/example.png) 46 | 47 | ```yaml 48 | type: entities 49 | title: attribute-entity-row 50 | show_header_toggle: false 51 | entities: 52 | - type: section 53 | label: Primary attribute 54 | 55 | - entity: sensor.smoke_sensor_livingroom_temperature 56 | type: custom:attribute-entity-row 57 | primary: 58 | key: battery_level 59 | name: Battery 60 | unit: '%' 61 | - entity: light.living_room 62 | type: custom:attribute-entity-row 63 | primary: 64 | key: min_mireds 65 | name: 'Attribute:' 66 | - entity: media_player.spotify 67 | type: custom:attribute-entity-row 68 | primary: 69 | key: media_title 70 | 71 | - type: section 72 | label: Toggle 73 | 74 | - entity: light.living_room 75 | type: custom:attribute-entity-row 76 | name: Light with Toggle 77 | toggle: true 78 | primary: 79 | key: min_mireds 80 | name: Mireds 81 | - entity: switch.power_office_pc 82 | type: custom:attribute-entity-row 83 | toggle: true 84 | primary: 85 | key: friendly_name 86 | 87 | - type: section 88 | label: Customization 89 | 90 | - entity: sensor.smoke_sensor_livingroom_temperature 91 | type: custom:attribute-entity-row 92 | name: Custom Name 93 | primary: 94 | key: battery_level 95 | name: Battery 96 | unit: '%' 97 | - entity: sensor.motion_hall_temperature 98 | type: custom:attribute-entity-row 99 | name: Sensor 100 | primary: 101 | key: battery_level 102 | name: 'Value:' 103 | unit: units 104 | - entity: sensor.motion_hall_temperature 105 | type: custom:attribute-entity-row 106 | name: Sensor 107 | unit: Unit 108 | primary: 109 | key: battery_level 110 | name: Battery 111 | unit: '%' 112 | 113 | - type: section 114 | label: Secondary attribute 115 | 116 | - entity: sensor.magnet_door_main_temperature 117 | type: custom:attribute-entity-row 118 | secondary: 119 | key: battery_level 120 | name: Battery 121 | unit: '%' 122 | - entity: vacuum.xiaomi_vacuum_cleaner 123 | type: custom:attribute-entity-row 124 | primary: 125 | key: battery_level 126 | name: Battery 127 | unit: '%' 128 | secondary: 129 | key: status 130 | - entity: vacuum.xiaomi_vacuum_cleaner 131 | type: custom:attribute-entity-row 132 | primary: 133 | key: status 134 | name: 'Status:' 135 | secondary: 136 | key: battery_level 137 | name: Battery 138 | unit: '%' 139 | 140 | - type: section 141 | label: Alternative entity 142 | 143 | - entity: sensor.smoke_sensor_livingroom_temperature 144 | type: 'custom:attribute-entity-row' 145 | primary: 146 | key: fan_speed 147 | name: 'Vacuum fan:' 148 | entity: vacuum.xiaomi_vacuum_cleaner 149 | - entity: sensor.template_smoke_sensor_livingroom 150 | type: custom:attribute-entity-row 151 | primary: 152 | key: battery_level 153 | name: Other entity attribute 154 | entity: sensor.smoke_sensor_livingroom_temperature 155 | secondary: 156 | key: status 157 | name: Another entity - 158 | entity: vacuum.xiaomi_vacuum_cleaner 159 | 160 | - type: section 161 | label: Hide State 162 | 163 | - entity: sensor.smoke_sensor_livingroom_temperature 164 | type: custom:attribute-entity-row 165 | hide_state: true 166 | primary: 167 | key: battery_level 168 | name: Battery 169 | unit: '%' 170 | - entity: sensor.smoke_sensor_livingroom_temperature 171 | type: custom:attribute-entity-row 172 | name: With secondary 173 | hide_state: true 174 | primary: 175 | key: battery_level 176 | name: Battery 177 | unit: '%' 178 | secondary: 179 | key: status 180 | entity: vacuum.xiaomi_vacuum_cleaner 181 | ``` 182 | 183 | Partially based on @thomasloven's [slider-entity-row](https://github.com/thomasloven/lovelace-slider-entity-row) lovelace card. 184 | 185 | ## My cards 186 | 187 | [xiaomi-vacuum-card](https://github.com/benct/lovelace-xiaomi-vacuum-card) | 188 | [github-entity-row](https://github.com/benct/lovelace-github-entity-row) | 189 | [multiple-entity-row](https://github.com/benct/lovelace-multiple-entity-row) | 190 | [~~attribute-entity-row~~](https://github.com/benct/lovelace-attribute-entity-row) 191 | 192 | [![BMC](https://www.buymeacoffee.com/assets/img/custom_images/white_img.png)](https://www.buymeacoff.ee/benct) 193 | -------------------------------------------------------------------------------- /attribute-entity-row.js: -------------------------------------------------------------------------------- 1 | class AttributeEntityRow extends Polymer.Element { 2 | 3 | static get template() { 4 | return Polymer.html` 5 | 45 |
46 | 47 |
48 |
49 | [[name]] 50 |
51 | [[attributeString(stateObj, primary)]] 52 |
53 |
54 |
55 |
56 | [[attributeString(stateObj, secondary)]] 57 |
58 | 63 | 68 |
69 | `; 70 | } 71 | 72 | setConfig(config) { 73 | if (!config.entity) throw new Error('Please define an entity.'); 74 | if (config.primary && !config.primary.key) throw new Error('Please define a primary attribute key.'); 75 | if (config.secondary && !config.secondary.key) throw new Error('Please define a secondary attribute key.'); 76 | 77 | const controllers = { 78 | light: { 79 | string: (stateObj, i18n) => { 80 | if (stateObj.state === 'off') return i18n['state.default.off']; 81 | return `${stateObj.state === 'on' ? Math.ceil(stateObj.attributes.brightness * 100.0 / 255) : 0} %`; 82 | }, 83 | toggle: true, 84 | }, 85 | media_player: { 86 | string: stateObj => { 87 | if (stateObj.attributes.is_volume_muted) return '-'; 88 | return `${stateObj.attributes.is_volume_muted ? 0 : Math.ceil(stateObj.attributes.volume_level * 100.0)} %`; 89 | }, 90 | toggle: false, 91 | }, 92 | switch: { 93 | string: stateObj => stateObj.state, 94 | toggle: true, 95 | }, 96 | default: { 97 | string: stateObj => this.stateValue(stateObj, this._config.unit), 98 | toggle: false, 99 | } 100 | }; 101 | 102 | this._config = config; 103 | this.stateObj = null; 104 | const domain = config.entity.split('.')[0]; 105 | this.controller = controllers[domain] || controllers.default; 106 | 107 | this.displayToggle = config.toggle && this.controller.toggle; 108 | this.displayValue = !this.displayToggle && !config.hide_state; 109 | } 110 | 111 | stateString(stateObj) { 112 | let i18n = this._hass.resources[this._hass.language]; 113 | if (!stateObj) return i18n['state.default.unavailable']; 114 | return this.controller.string(stateObj, i18n); 115 | } 116 | 117 | attributeString(stateObj, attribute) { 118 | if (!stateObj || !attribute || !attribute.key) return null; 119 | if (attribute.entity) { 120 | stateObj = attribute.entity in this._hass.states ? this._hass.states[attribute.entity] : null; 121 | if (!stateObj) return null; 122 | } 123 | let i18n = this._hass.resources[this._hass.language]; 124 | const value = (attribute.key in stateObj.attributes ? stateObj.attributes[attribute.key] : i18n['state.default.unavailable']); 125 | return (attribute.name ? `${attribute.name} ` : '') + value + (attribute.unit ? ` ${attribute.unit}` : ''); 126 | } 127 | 128 | stateValue(stateObj, unit) { 129 | let display; 130 | const domain = stateObj.entity_id.substr(0, stateObj.entity_id.indexOf(".")); 131 | 132 | if (domain === "binary_sensor") { 133 | if (stateObj.attributes.device_class) { 134 | display = this._hass.localize(`state.${domain}.${stateObj.attributes.device_class}.${stateObj.state}`); 135 | } 136 | if (!display) { 137 | display = this._hass.localize(`state.${domain}.default.${stateObj.state}`); 138 | } 139 | } else if (unit !== false && (unit || stateObj.attributes.unit_of_measurement) && !["unknown", "unavailable"].includes(stateObj.state)) { 140 | display = `${stateObj.state} ${unit || stateObj.attributes.unit_of_measurement}`; 141 | } else if (domain === "zwave") { 142 | display = ["initializing", "dead"].includes(stateObj.state) 143 | ? this._hass.localize(`state.zwave.query_stage.${stateObj.state}`, 'query_stage', stateObj.attributes.query_stage) 144 | : this._hass.localize(`state.zwave.default.${stateObj.state}`); 145 | } else { 146 | display = this._hass.localize(`state.${domain}.${stateObj.state}`); 147 | } 148 | 149 | return display || 150 | this._hass.localize(`state.default.${stateObj.state}`) || 151 | this._hass.localize(`component.${domain}.state.${stateObj.state}`) || 152 | stateObj.state; 153 | } 154 | 155 | set hass(hass) { 156 | this._hass = hass; 157 | 158 | if (hass && this._config) { 159 | this.stateObj = this._config.entity in hass.states ? hass.states[this._config.entity] : null; 160 | if (this.stateObj) { 161 | this.primary = this._config.primary; 162 | this.secondary = this._config.secondary; 163 | this.name = this._config.name || this.stateObj.attributes.friendly_name; 164 | if (this._config.name_attribute && this._config.name_attribute in this.stateObj.attributes) { 165 | this.name = this.stateObj.attributes[this._config.name_attribute]; 166 | } 167 | } 168 | } 169 | } 170 | } 171 | 172 | customElements.define('attribute-entity-row', AttributeEntityRow); 173 | --------------------------------------------------------------------------------