Skip to content

Commit 8992274

Browse files
committed
v0.7.1
1 parent f7c1be7 commit 8992274

File tree

8 files changed

+84
-41
lines changed

8 files changed

+84
-41
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.7.1] - 2025-03-16
9+
10+
### Changed
11+
12+
- Http request responses are now also used for the media_title attribute of the associated request method's media player entity. This allows you to add a media player widget to an activity and see the response within an activity because you can't add sensors to activities as there's no widget for them.
13+
814
## [0.7.0] - 2025-03-08
915

1016
### Added

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ Using [uc-integration-api](https://github.com/aitatoi/integration-python-library
1717
- [1 - Wake-on-lan](#1---wake-on-lan)
1818
- [Supported parameters](#supported-parameters)
1919
- [2 - HTTP requests](#2---http-requests)
20-
- [Expected http request server response](#expected-http-request-server-response)
21-
- [Server response sensor entity](#server-response-sensor-entity)
20+
- [Expected http request server response code](#expected-http-request-server-response-code)
2221
- [Additional command parameters](#additional-command-parameters)
2322
- [SSL verification \& Fire and forget mode](#ssl-verification--fire-and-forget-mode)
2423
- [Use case examples](#use-case-examples)
24+
- [Show (parts) of the server response text in the remote ui](#show-parts-of-the-server-response-text-in-the-remote-ui)
2525
- [Legacy syntax](#legacy-syntax)
2626
- [3 - Text over TCP](#3---text-over-tcp)
2727
- [Control characters](#control-characters)
@@ -92,16 +92,12 @@ All parameters from [pywakeonlan](https://github.com/remcohaszing/pywakeonlan) a
9292

9393
Enter the desired url (including http(s)://). Additional parameters can be added (see below).
9494

95-
#### Expected http request server response
95+
#### Expected http request server response code
9696

9797
Your server needs to respond with a *200 OK* status or any other informational or redirection http status code (100s, 200s or 300s). If the server's response content is not empty it will be shown in the integration log. In case of a client or server error (400s or 500s) the command will fail on the remote and the error message and status code will be shown in the integration log.
9898

9999
If you activate the fire and forget mode the remote will always receive a *200 OK* status code (see below).
100100

101-
#### Server response sensor entity
102-
103-
The integration also exposes a sensor entity that shows the server response from the last executed http request command. The output can be parsed to only show a specific part of the response message using regular expressions. These can be configured in the advanced setup. Sites like [regex101.com](https://regex101.com) can help you with finding matching expressions. By default the complete response message will be used if no regular expression has been set or no matches have been found.
104-
105101
#### Additional command parameters
106102

107103
Almost all parameters from the Python requests module like `timeout`, `verify`, `data`, `json` or `headers` are supported (see [Python requests module parameters](https://requests.readthedocs.io/en/latest/api/#requests.request)) although not all of them have been tested with this integration. Simply separate them with a comma.
@@ -125,6 +121,12 @@ If you activate the option to ignore HTTP requests errors in the integration set
125121
| Adding json payload data (content type is set automatically) | `json` | `url="https://httpbin.org/post", json="{'key1':'value1','key2':'value2'}"` |
126122
| Adding xml payload data | `data` and `headers` | `url="https://httpbin.org/post", data="<Tests Id='01'><Test TestId='01'><Name>Command name</Name></Test></Tests>", headers="{'Content-Type':'application/xml'}"` |
127123

124+
#### Show (parts) of the server response text in the remote ui
125+
126+
The integration exposes a sensor entity that shows the text of the response body from the last executed http request command. Responses are also used for the media_title attribute of the associated request method's media player entity. This allows you to add a media player widget to an activity and see the response within an activity because you can't add sensors to activities as there's no widget for them.
127+
128+
The output can be parsed to only show a specific part of the response message using regular expressions. These can be configured in the advanced setup. Sites like [regex101.com](https://regex101.com) or the AI model of your choice can help you with finding matching expressions. By default the complete response message will be used if no regular expression has been set or no matches have been found.
129+
128130
#### Legacy syntax
129131

130132
⚠️ Used before v0.6.0 and support will be removed in a future version

driver.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"driver_id": "requests",
3-
"version": "0.7.0",
4-
"release_date": "2025-03-08",
3+
"version": "0.7.1",
4+
"release_date": "2025-03-16",
55
"min_core_api": "0.24.3",
66
"name": {
77
"en": "HTTP requests, WoL & text over TCP",

intg-requests/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class Setup:
6262
@staticmethod
6363
def get(key):
6464
"""Get the value from the specified key in __conf"""
65-
if Setup.__conf[key] == "" and key is not "rq_response_regex": #rq_response_regex can be empty
65+
if Setup.__conf[key] == "" and key != "rq_response_regex": #rq_response_regex can be empty
6666
raise ValueError("Got empty value for " + key + " from config storage")
6767
return Setup.__conf[key]
6868

@@ -179,7 +179,7 @@ def load():
179179
else:
180180
_LOG.info("Using the default http requests syntax as it has not been changed during setup. \
181181
The Default value " + str(Setup.get("rq_legacy")) + " will be used")
182-
182+
183183
if "rq_response_regex" in configfile:
184184
Setup.__conf["rq_response_regex"] = configfile["rq_response_regex"]
185185
_LOG.info("Loaded rq_response_regex: " + str(configfile["rq_response_regex"]) + " flag into runtime storage from " + Setup.__conf["cfg_path"])

intg-requests/driver.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ async def add_mp(entity_id: str, entity_name: str):
4949
definition = ucapi.MediaPlayer(
5050
entity_id,
5151
entity_name,
52-
[ucapi.media_player.Features.SELECT_SOURCE],
52+
[
53+
ucapi.media_player.Features.SELECT_SOURCE, \
54+
ucapi.media_player.Features.MEDIA_TITLE
55+
],
5356
attributes={ucapi.media_player.Attributes.STATE: ucapi.media_player.States.ON},
5457
cmd_handler=mp_cmd_handler
5558
)
@@ -171,6 +174,7 @@ def setup_logger():
171174
logging.getLogger("ucapi.entity").setLevel(level)
172175
logging.getLogger("driver").setLevel(level)
173176
logging.getLogger("media_player").setLevel(level)
177+
logging.getLogger("sensor").setLevel(level)
174178
logging.getLogger("setup").setLevel(level)
175179
logging.getLogger("config").setLevel(level)
176180
logging.getLogger("getmac").setLevel(level)

intg-requests/media_player.py

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import ast
1111
import shlex
1212

13-
from re import sub, match, IGNORECASE
13+
from re import sub, match, search, IGNORECASE
1414
from ipaddress import ip_address, IPv4Address, IPv6Address, AddressValueError
1515
import urllib3 #Needed to optionally deactivate requests ssl verify warning message
1616

@@ -23,6 +23,7 @@
2323

2424
import config
2525
import sensor
26+
import driver
2627

2728
_LOG = logging.getLogger(__name__)
2829

@@ -128,6 +129,57 @@ def replace_control_hex(match):
128129
return data
129130

130131

132+
def parse_rq_response(response: str):
133+
"""Parse http request response with configured regular expression"""
134+
135+
regex = config.Setup.get("rq_response_regex")
136+
137+
if regex == "":
138+
parsed_response = response
139+
_LOG.debug("No regular expression set for the http request response sensor. The complete response will be used")
140+
else:
141+
match = search(regex, response)
142+
if match:
143+
parsed_response = match.group(1)
144+
_LOG.debug("Parsed response from configured regex: " + parsed_response)
145+
else:
146+
parsed_response = response
147+
_LOG.warning("No matches found in the http request response for the regular expression " + regex + ". \
148+
The complete response will be used")
149+
150+
return parsed_response
151+
152+
153+
154+
def update_response(method:str, response: str):
155+
"""Update the response in the sensor entity and media player widget"""
156+
157+
entity_id = "http-" + method
158+
159+
parsed_response = parse_rq_response(response)
160+
161+
sensor.update_rq_sensor(config.Setup.get("id-rq-sensor"), parsed_response)
162+
163+
update_rq_media_widget(entity_id, parsed_response)
164+
165+
166+
167+
def update_rq_media_widget(entity_id:str, response: str):
168+
"""Update the response in the media player widget"""
169+
170+
attributes_to_send = {ucapi.media_player.Attributes.MEDIA_TITLE: response}
171+
172+
try:
173+
api_update_attributes = driver.api.configured_entities.update_attributes(entity_id, attributes_to_send)
174+
except Exception as e:
175+
raise Exception("Error while updating attributes for entity id " + entity_id) from e
176+
177+
if not api_update_attributes:
178+
raise Exception("Entity " + entity_id + " not found. Please make sure it's added as a configured entity on the remote")
179+
else:
180+
_LOG.info("Updated entity attribute(s) " + str(attributes_to_send) + " for " + entity_id)
181+
182+
131183

132184
def rq_cmd(method: str, cmd_param: str=None) -> int:
133185
"""Send a requests command to the passed url with the passed data and return the status code"""
@@ -262,7 +314,7 @@ def rq_cmd(method: str, cmd_param: str=None) -> int:
262314
_LOG.info("Sent http-" + method + " request to: " + url)
263315
if response.text != "":
264316
_LOG.info("Server response: " + response.text)
265-
sensor.update_rq_sensor(config.Setup.get("id-rq-sensor"), response.text)
317+
update_response(method, response.text)
266318
else:
267319
_LOG.debug("Received 200 - OK status code")
268320
return ucapi.StatusCodes.OK
@@ -276,7 +328,7 @@ def rq_cmd(method: str, cmd_param: str=None) -> int:
276328
if response.status_code == 404:
277329
if response.text != "":
278330
_LOG.info("Server response: " + response.text)
279-
sensor.update_rq_sensor(config.Setup.get("id-rq-sensor"), response.text)
331+
update_response(method, response.text)
280332
return ucapi.StatusCodes.NOT_FOUND
281333
return ucapi.StatusCodes.BAD_REQUEST
282334
return ucapi.StatusCodes.SERVER_ERROR
@@ -285,7 +337,7 @@ def rq_cmd(method: str, cmd_param: str=None) -> int:
285337
_LOG.info("Received informational or redirection http status code: " + str(response.status_code))
286338
if response.text != "":
287339
_LOG.info("Server response: " + response)
288-
sensor.update_rq_sensor(config.Setup.get("id-rq-sensor"), response.text)
340+
update_response(method, response.text)
289341
return ucapi.StatusCodes.OK
290342

291343

intg-requests/sensor.py

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33
"""Module that includes functions to add a http request response sensor entity"""
44

55
import logging
6-
76
import ucapi
8-
from re import search
9-
10-
import config
117
import driver
128

139
_LOG = logging.getLogger(__name__)
1410

1511
#TODO Add possibility to add additional sensor entities in advanced setup. Each sensor then can be linked to a specific http request command by using a special command parameter
16-
12+
#TODO Use media player title, artist, album or media type to also show the response because sensors cant be added to activities and have no widgets
1713

1814

1915
async def add_rq_sensor(ent_id: str, name: str):
@@ -37,24 +33,7 @@ async def add_rq_sensor(ent_id: str, name: str):
3733
def update_rq_sensor(entity_id: str, response: str):
3834
"""Parse http request response with configured regular expression and update sensor entity value"""
3935

40-
regex = config.Setup.get("rq_response_regex")
41-
42-
if regex == "":
43-
parsed_response = response
44-
_LOG.debug("No regular expression set for the http request response sensor. The complete response will be sent to the http request response sensor")
45-
else:
46-
match = search(regex, response)
47-
if match:
48-
parsed_response = match.group(1)
49-
_LOG.debug("Parsed response: " + parsed_response)
50-
else:
51-
parsed_response = response
52-
_LOG.warning("No matches found in the http request response for the regular expression " + regex + ". \
53-
The complete response will be sent to the http request response sensor")
54-
55-
value = parsed_response
56-
57-
attributes_to_send = {ucapi.sensor.Attributes.STATE: ucapi.sensor.States.ON, ucapi.sensor.Attributes.VALUE: value}
36+
attributes_to_send = {ucapi.sensor.Attributes.STATE: ucapi.sensor.States.ON, ucapi.sensor.Attributes.VALUE: response}
5837

5938
try:
6039
api_update_attributes = driver.api.configured_entities.update_attributes(entity_id, attributes_to_send)
@@ -65,4 +44,4 @@ def update_rq_sensor(entity_id: str, response: str):
6544
if not api_update_attributes:
6645
raise Exception("Sensor entity " + entity_id + " not found. Please make sure it's added as a configured entity on the remote")
6746

68-
_LOG.info("Updated http request response sensor value to " + value)
47+
_LOG.info("Updated http request response sensor value to " + response)

intg-requests/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ async def handle_driver_setup(msg: ucapi.DriverSetupRequest,) -> ucapi.SetupActi
111111
"id": "tcp_text_timeout",
112112
"label": {
113113
"en": "Timeout for Text over TCP (max. 30 seconds):",
114-
"de": "Timeout für Text over TCP (max. 30 Sekunden):"
114+
"de": "Timeout für Text über TCP (max. 30 Sekunden):"
115115
},
116116
"field": {"number": {
117117
"value": tcp_text_timeout,

0 commit comments

Comments
 (0)