├── .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 | [](https://www.home-assistant.io)
4 | [](https://github.com/hacs/integration)
5 | [](https://github.com/pmazz/ps_hassio_entities/releases)
6 | [](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 | 
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
--------------------------------------------------------------------------------