├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md ├── LICENSE ├── README.md ├── hacs.json ├── python_scripts └── hass_entities.py └── sample.gif /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help improve the script 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior. 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **YAML configuration** 20 | ```yaml 21 | # paste your configuration here 22 | ``` 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Version** 28 | What is the version of the script? 29 | 30 | **Additional information** 31 | Add any other information about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for the script 4 | title: "[FEATURE REQ]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Additional information** 17 | Add any other information or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask for help if the script doesn't work as expected 4 | title: "[QUESTION] " 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What is your question** 11 | A clear and concise question here. 12 | 13 | **YAML configuration** 14 | ```yaml 15 | # paste your configuration here 16 | ``` 17 | 18 | **Screenshots** 19 | If applicable, add your screenshots here. 20 | 21 | **Version** 22 | What is the version of the script? 23 | 24 | **Additional information** 25 | Add any other relevant additional information here. 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ian Richardson 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 | # Home Assistant Entities Script 2 | 3 | [![hass_badge](https://img.shields.io/badge/Platform-Home%20Assistant-blue.svg)](https://www.home-assistant.io) 4 | [![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg)](https://github.com/hacs/integration) 5 | [![GitHub Release](https://img.shields.io/github/release/pmazz/ps_hassio_entities.svg)](https://github.com/pmazz/ps_hassio_entities/releases) 6 | [![GitHub Last Commit](https://img.shields.io/github/last-commit/pmazz/ps_hassio_entities.svg)](https://github.com/pmazz/ps_hassio_entities/commits) 7 | 8 | Python script for Home Assistant to handle state and attributes of existing sensors and entities. 9 | Useful if you need to change a sensor's state or attribute from whithin a script, an automation, or your Lovelace UI. 10 | 11 | ## Installation 12 | 13 | You can install this script via [HACS](https://hacs.xyz) or just download `hass_entities.py` file and save it in your `/config/python_scripts` folder. 14 | 15 | This script use Home Assistant [python_script](https://www.home-assistant.io/integrations/python_script) component and you have to add it to your `configuration.yaml` file. 16 | 17 | ## Usage 18 | 19 | ### 1. Set both state and attributes 20 | 21 | | Name | Type | Required | Description | 22 | | ---- | :--: | :------: | ----------- | 23 | | action | string | Yes | `set_state_attributes`
Allows to set both state and attributes. | 24 | | entity_id | string | Yes | Entity ID of the sensor to be set. | 25 | | state | string | Yes | The state to be set. | 26 | | attributes | list | Yes | List of attributes to be set (the actual list of attributes depends on the referred entity). | 27 | | log_enabled | bool | No | Indicates whether to log system messages to the Home Assistant log (see [Logging](#logging) for further details). | 28 | 29 | #### 1.1. Automation Sample 30 | 31 | ```yaml 32 | - alias: paolo_home_since 33 | trigger: 34 | - platform: state 35 | entity_id: device_tracker.paolo 36 | from: "not_home" 37 | to: "home" 38 | action: 39 | - service: python_script.hass_entities 40 | data: 41 | action: set_state_attributes 42 | entity_id: sensor.paolo_home_from 43 | state: "{{ 'At home since '~ now().strftime('%H.%M') }}" 44 | attributes: 45 | - icon: mdi:home 46 | ``` 47 | 48 | #### 1.2. Script Sample 49 | 50 | ```yaml 51 | turn_on_switch: 52 | sequence: 53 | - service: switch.turn_on 54 | data: 55 | entity_id: switch.plug_1 56 | - service: python_script.hass_entities 57 | data: 58 | action: set_state_attributes 59 | entity_id: sensor.plug_1_status 60 | state: "{{ 'Switched on at '~ now().strftime('%H.%M') }}" 61 | attributes: 62 | - icon: mdi:toggle-switch 63 | ``` 64 | 65 | #### 1.3. Lovelace Sample 66 | 67 | ```yaml 68 | - type: entities 69 | entities: 70 | - sensor.mysensor 71 | - type: section 72 | - type: call-service 73 | name: "Set Windy" 74 | service: python_script.hass_entities 75 | service_data: 76 | action: set_state_attributes 77 | entity_id: sensor.mysensor 78 | state: "3.02" 79 | attributes: 80 | - icon: mdi:weather-windy 81 | - friendly_name: Windy 82 | - unit_of_measurement: m/s 83 | log_enabled: True 84 | - type: call-service 85 | name: "Set Rainy" 86 | service: python_script.hass_entities 87 | service_data: 88 | action: set_state_attributes 89 | entity_id: sensor.mysensor 90 | state: 30 91 | attributes: 92 | - icon: mdi:weather-rainy 93 | - friendly_name: Rainy 94 | - unit_of_measurement: mm/h 95 | log_enabled: True 96 | ``` 97 | 98 | ![Sample](sample.gif) 99 | 100 | ### 2. Set state only 101 | 102 | | Name | Type | Required | Description | 103 | | ---- | :--: | :------: | ----------- | 104 | | action | string | Yes | `set_state`
Allows to set a sensor state only. | 105 | | entity_id | string | Yes | Entity ID of the sensor to be set. | 106 | | state | string | Yes | The state to be set. | 107 | | log_enabled | bool | No | Indicates whether to log system messages to the Home Assistant log (see [Logging](#logging) for further details). | 108 | 109 | #### 2.1. Automation Sample 110 | 111 | ```yaml 112 | - alias: paolo_home_since 113 | trigger: 114 | - platform: state 115 | entity_id: device_tracker.paolo 116 | from: "not_home" 117 | to: "home" 118 | action: 119 | - service: python_script.hass_entities 120 | data: 121 | action: set_state 122 | entity_id: sensor.paolo_home_from 123 | state: "{{ 'At home since '~ now().strftime('%H.%M') }}" 124 | ``` 125 | 126 | #### 2.2. Script Sample 127 | 128 | ```yaml 129 | turn_on_switch: 130 | sequence: 131 | - service: switch.turn_on 132 | data: 133 | entity_id: switch.plug_1 134 | - service: python_script.hass_entities 135 | data: 136 | action: set_state 137 | entity_id: sensor.plug_1_status 138 | state: "{{ 'Switched on at '~ now().strftime('%H.%M') }}" 139 | ``` 140 | 141 | #### 2.3. Lovelace Sample 142 | 143 | ```yaml 144 | - type: entities 145 | entities: 146 | - sensor.mysensor 147 | - type: section 148 | - type: call-service 149 | name: "Set Windy State" 150 | service: python_script.hass_entities 151 | service_data: 152 | action: set_state 153 | entity_id: sensor.mysensor 154 | state: "3.02" 155 | log_enabled: True 156 | - type: call-service 157 | name: "Set Rainy State" 158 | service: python_script.hass_entities 159 | service_data: 160 | action: set_state 161 | entity_id: sensor.mysensor 162 | state: 30 163 | log_enabled: True 164 | ``` 165 | 166 | ### 3. Set attributes only 167 | 168 | | Name | Type | Required | Description | 169 | | ---- | :--: | :------: | ----------- | 170 | | action | string | Yes | `set_attributes`
Allows to set a sensor attributes only. | 171 | | entity_id | string | Yes | Entity ID of the sensor to be set. | 172 | | attributes | list | Yes | List of attributes to be set (the actual list of attributes depends on the referred entity). | 173 | | log_enabled | bool | No | Indicates whether to log system messages to the Home Assistant log (see [Logging](#logging) for further details). | 174 | 175 | #### 3.1. Automation Sample 176 | 177 | ```yaml 178 | - alias: paolo_home_since 179 | trigger: 180 | - platform: state 181 | entity_id: device_tracker.paolo 182 | from: "not_home" 183 | to: "home" 184 | action: 185 | - service: python_script.hass_entities 186 | data: 187 | action: set_attributes 188 | entity_id: sensor.paolo_home_from 189 | attributes: 190 | - icon: mdi:home 191 | - time: "{{ now().strftime('%H.%M') }}" 192 | ``` 193 | 194 | #### 3.2. Script Sample 195 | 196 | ```yaml 197 | turn_on_switch: 198 | sequence: 199 | - service: switch.turn_on 200 | data: 201 | entity_id: switch.plug_1 202 | - service: python_script.hass_entities 203 | data: 204 | action: set_attributes 205 | entity_id: sensor.plug_1_status 206 | attributes: 207 | - icon: mdi:toggle-switch 208 | - time: "{{ now().strftime('%H.%M') }}" 209 | ``` 210 | 211 | #### 3.3. Lovelace Sample 212 | 213 | ```yaml 214 | - type: entities 215 | entities: 216 | - sensor.mysensor 217 | - type: section 218 | - type: call-service 219 | name: "Set Windy Icon" 220 | service: python_script.hass_entities 221 | service_data: 222 | action: set_attributes 223 | entity_id: sensor.mysensor 224 | attributes: 225 | - icon: mdi:weather-windy 226 | log_enabled: True 227 | - type: call-service 228 | name: "Set Rainy Icon" 229 | service: python_script.hass_entities 230 | service_data: 231 | action: set_attributes 232 | entity_id: sensor.mysensor 233 | attributes: 234 | - icon: mdi:weather-rainy 235 | log_enabled: True 236 | ``` 237 | 238 | ### 4. Delete an existing attribute 239 | 240 | | Name | Type | Required | Description | 241 | | ---- | :--: | :------: | ----------- | 242 | | action | string | Yes | `delete_attribute`
Delete an existing attribute. | 243 | | entity_id | string | Yes | Entity ID of the sensor to be set. | 244 | | attribute | string | Yes | Attribute to be deleted from the sensor definition. | 245 | | log_enabled | bool | No | Indicates whether to log system messages to the Home Assistant log (see [Logging](#logging) for further details). | 246 | 247 | #### 4.1. Automation Sample 248 | 249 | ```yaml 250 | - alias: paolo_not_home 251 | trigger: 252 | - platform: state 253 | entity_id: device_tracker.paolo 254 | from: "home" 255 | to: "not_home" 256 | action: 257 | - service: python_script.hass_entities 258 | data: 259 | action: delete_attribute 260 | entity_id: sensor.paolo_home_from 261 | attribute: time 262 | ``` 263 | 264 | #### 4.2. Script Sample 265 | 266 | ```yaml 267 | turn_on_switch: 268 | sequence: 269 | - service: python_script.hass_entities 270 | data: 271 | action: delete_attribute 272 | entity_id: sensor.plug_1_status 273 | attribute: icon 274 | ``` 275 | 276 | #### 4.3. Lovelace Sample 277 | 278 | ```yaml 279 | - type: entities 280 | entities: 281 | - sensor.mysensor 282 | - type: section 283 | - type: call-service 284 | name: "Set Windy Icon" 285 | service: python_script.hass_entities 286 | service_data: 287 | action: delete_attribute 288 | entity_id: sensor.mysensor 289 | attribute: icon 290 | log_enabled: True 291 | ``` 292 | 293 | ## Logging 294 | 295 | **Important**: In addition to the `log_enabled` parameter, make sure the [Logger](https://www.home-assistant.io/components/logger) component has been configured in your `configuration.yaml` (log level must be at least `debug`). 296 | 297 | ```yaml 298 | logger: 299 | logs: 300 | homeassistant.components.python_script: debug 301 | ``` 302 | -------------------------------------------------------------------------------- /hacs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Entities Script", 3 | "render_readme": "true" 4 | } 5 | -------------------------------------------------------------------------------- /python_scripts/hass_entities.py: -------------------------------------------------------------------------------- 1 | def log_info(logger, data, msg): 2 | log_enabled = str(data.get("log_enabled", "false")) 3 | if log_enabled.lower() == "true": 4 | logger.debug(msg) 5 | 6 | 7 | def log_error(logger, msg): 8 | logger.error(msg) 9 | #Notify the error via persistent_notification 10 | domain = "persistent_notification" 11 | service = "create" 12 | service_data = {} 13 | service_data["notification_id"] = "hass_entities_error" 14 | service_data["title"] = "\U000026A0 hass_entities error" 15 | service_data["message"] = "{}".format(msg) 16 | hass.services.call(domain, service, service_data, False) 17 | 18 | 19 | try: 20 | #Execute requested action 21 | script_name = "hass_entities.py" 22 | action = data.get("action", "") 23 | 24 | #Log start action execution 25 | log_info(logger, data, "Python Script: {} -> START of action: {}".format(script_name, action)) 26 | 27 | if action == "": 28 | log_error(logger, "**Required parameter 'action' is missing.**\n\nScript NOT executed.") 29 | 30 | elif action.lower() == "set_state": 31 | #Parameter -> action: set_state (string, required) 32 | #Parameter -> entity_id (string, required) 33 | #Parameter -> state (string, required) 34 | #Parameter -> log_enabled (bool) 35 | 36 | #Getting entity 37 | entity_id = data.get("entity_id", "") 38 | if entity_id == "": 39 | log_error(logger, "**Required parameter 'entity_id' is missing.**\n\nAction '{}' NOT executed.".format(action.lower())) 40 | else: 41 | #Getting original state and attributes 42 | entity = hass.states.get(entity_id) 43 | if entity is None: 44 | log_error(logger, "**Cannot find entity '{}'.**\n\nAction '{}' NOT executed.".format(entity_id, action.lower())) 45 | else: 46 | attributes = {} 47 | for attr in entity.attributes: 48 | attributes[attr] = entity.attributes.get(attr) 49 | #Getting new state 50 | new_state = data.get("state", "") 51 | if new_state is None or new_state == "": 52 | log_error(logger, "**Required parameter 'state' is missing.**\n\nAction '{}' NOT executed.".format(action.lower())) 53 | else: 54 | #Setting new state 55 | log_info(logger, data, " Entity: '{}' -> New state: '{}'".format(entity_id, new_state)) 56 | hass.states.set(entity_id, new_state, attributes) 57 | log_info(logger, data, " DONE -> State set for entity '{}'".format(entity_id)) 58 | 59 | elif action.lower() == "set_attributes": 60 | #Parameter -> action: set_attributes (string, required) 61 | #Parameter -> entity_id (string, required) 62 | #Parameter -> attributes (list, required) 63 | #Parameter -> log_enabled (bool) 64 | 65 | #Getting entity 66 | entity_id = data.get("entity_id", "") 67 | if entity_id == "": 68 | log_error(logger, "**Required parameter 'entity_id' is missing.**\n\nAction '{}' NOT executed.".format(action.lower())) 69 | else: 70 | #Getting original state and attributes 71 | entity = hass.states.get(entity_id) 72 | if entity is None: 73 | log_error(logger, "**Cannot find entity '{}'.**\n\nAction '{}' NOT executed.".format(entity_id, action.lower())) 74 | else: 75 | state = entity.state 76 | attributes = {} 77 | for attr in entity.attributes: 78 | attributes[attr] = entity.attributes.get(attr) 79 | #Getting new attributes 80 | new_attributes = data.get("attributes", "") 81 | if new_attributes is None or new_attributes == "": 82 | log_error(logger, "**Required parameter 'attributes' is missing.**\n\nAction '{}' NOT executed.".format(action.lower())) 83 | else: 84 | #Setting new attributes 85 | for new_attr in new_attributes: 86 | for k,v in new_attr.items(): #This should iterate just once 87 | log_info(logger, data, " Entity: '{}' -> New attribute '{}': '{}'".format(entity_id, k, v)) 88 | attributes[k] = v 89 | hass.states.set(entity_id, state, attributes) 90 | log_info(logger, data, " DONE -> Attributes set for entity '{}'".format(entity_id)) 91 | 92 | elif action.lower() == "set_state_attributes": 93 | #Parameter -> action: set_state_attributes (string, required) 94 | #Parameter -> entity_id (string, required) 95 | #Parameter -> state (string, required) 96 | #Parameter -> attributes (list, required) 97 | #Parameter -> log_enabled (bool) 98 | 99 | #Getting entity 100 | entity_id = data.get("entity_id", "") 101 | if entity_id == "": 102 | log_error(logger, "**Required parameter 'entity_id' is missing.**\n\nAction '{}' NOT executed.".format(action.lower())) 103 | else: 104 | #Getting original state and attributes 105 | entity = hass.states.get(entity_id) 106 | if entity is None: 107 | log_error(logger, "**Cannot find entity '{}'.**\n\nAction '{}' NOT executed.".format(entity_id, action.lower())) 108 | else: 109 | state = entity.state 110 | attributes = {} 111 | for attr in entity.attributes: 112 | attributes[attr] = entity.attributes.get(attr) 113 | #Getting new state 114 | new_state = data.get("state", "") 115 | if new_state is None or new_state == "": 116 | log_error(logger, "**Required parameter 'state' is missing.**\n\nAction '{}' NOT executed.".format(action.lower())) 117 | else: 118 | state = new_state 119 | #Setting new state 120 | log_info(logger, data, " Entity: '{}' -> New state: '{}'".format(entity_id, new_state)) 121 | #Getting new attributes 122 | new_attributes = data.get("attributes", "") 123 | if new_attributes is None or new_attributes == "": 124 | log_error(logger, "**Required parameter 'attributes' is missing.**\n\nAction '{}' NOT executed.".format(action.lower())) 125 | else: 126 | #Setting new attributes 127 | for new_attr in new_attributes: 128 | for k,v in new_attr.items(): #This should iterate just once 129 | log_info(logger, data, " Entity: '{}' -> New attribute '{}': '{}'".format(entity_id, k, v)) 130 | attributes[k] = v 131 | hass.states.set(entity_id, state, attributes) 132 | log_info(logger, data, " DONE -> State & attributes set for entity '{}'".format(entity_id)) 133 | 134 | elif action.lower() == "delete_attribute": 135 | #Parameter -> action: delete_attribute (string, required) 136 | #Parameter -> entity_id (string, required) 137 | #Parameter -> attribute (string, required) 138 | #Parameter -> log_enabled (bool) 139 | 140 | #Getting entity 141 | entity_id = data.get("entity_id", "") 142 | if entity_id == "": 143 | log_error(logger, "**Required parameter 'entity_id' is missing.**\n\nAction '{}' NOT executed.".format(action.lower())) 144 | else: 145 | #Getting original state and attributes 146 | entity = hass.states.get(entity_id) 147 | if entity is None: 148 | log_error(logger, "**Cannot find entity '{}'.**\n\nAction '{}' NOT executed.".format(entity_id, action.lower())) 149 | else: 150 | state = entity.state 151 | attributes = {} 152 | #Getting attribute to delete 153 | del_attribute = data.get("attribute", "") 154 | if del_attribute == "": 155 | log_error(logger, "**Required parameter 'attribute' is missing.**\n\nAction '{}' NOT executed.".format(action.lower())) 156 | else: 157 | for attr in entity.attributes: 158 | if attr != del_attribute: 159 | attributes[attr] = entity.attributes.get(attr) 160 | #Setting attributes 161 | hass.states.set(entity_id, state, attributes) 162 | log_info(logger, data, " DONE -> Attribute '{}' deleted from entity '{}'".format(del_attribute, entity_id)) 163 | 164 | else: 165 | log_error(logger, "**Invalid action provided ('{}').**\n\nExpected: 'set_state', 'set_attributes', 'set_state_attributes', 'delete_attribute'.".format(action)) 166 | 167 | #Log end action execution 168 | log_info(logger, data, "Python Script: {} -> END of action: {}".format(script_name, action)) 169 | 170 | except Exception as e: 171 | log_error(logger, "**An unhandled error has occurred.**\n\n{}".format(e)) 172 | -------------------------------------------------------------------------------- /sample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmazz/ps_hassio_entities/5a14ea2019434f35f57cfc5ddaf1881f6ff5931c/sample.gif --------------------------------------------------------------------------------