diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f8285d..b0f9525 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.6.0] - 2025-01-04
+
+### Breaking changes
+
+- HTTP requests entities can now be used with most parameters and the same syntax as the Python Requests module. This simplifies the usage and adds the possibility of e.g. adding more complex json payload or custom headers (e.g. for server authentication). More infos and examples can be found here: [Additional http requests parameters](/README.md#additional-command-parameters)
+ - The previous syntax by using separator characters (§, | etc) is now called legacy syntax and can still be used by activating the legacy syntax option in the advanced setup which is off by default. Please keep in mind that the use of the legacy syntax will be removed in a future version
+
+### Added
+
+- The global settings for Fire and forget mode and timeouts for HTTP requests can now be overwritten as a parameter in each http request command. E.g. use ffg=True to only activate fire and forget for a specific command.
+
## [0.5.2] - 2024-12-25
### Fixed
diff --git a/README.md b/README.md
index 645cc4d..56ff64a 100755
--- a/README.md
+++ b/README.md
@@ -10,13 +10,18 @@ Integration for Unfolded Circle Remote Devices running [Unfolded OS](https://www
Using [uc-integration-api](https://github.com/aitatoi/integration-python-library), [requests](https://github.com/psf/requests), [pywakeonlan](https://github.com/remcohaszing/pywakeonlan) and [getmac](https://github.com/GhostofGoes/getmac).
+- [Supported entity features](#supported-entity-features)
+- [Planned features](#planned-features)
- [Configuration](#configuration)
- [Usage](#usage)
- [1 - Wake-on-lan](#1---wake-on-lan)
- [Supported parameters](#supported-parameters)
- [2 - HTTP requests](#2---http-requests)
- [Expected http request server response](#expected-http-request-server-response)
- - [Adding payload data](#adding-payload-data)
+ - [Additional command parameters](#additional-command-parameters)
+ - [SSL verification \& Fire and forget mode](#ssl-verification--fire-and-forget-mode)
+ - [Use case examples](#use-case-examples)
+ - [Legacy syntax used before v0.6.0 (⚠️ Will be removed in a future version)](#legacy-syntax-used-before-v060-️-will-be-removed-in-a-future-version)
- [Only one payload type per requests is supported](#only-one-payload-type-per-requests-is-supported)
- [3 - Text over TCP](#3---text-over-tcp)
- [Control characters](#control-characters)
@@ -42,22 +47,23 @@ Using [uc-integration-api](https://github.com/aitatoi/integration-python-library
- [Contributions](#contributions)
- [License](#license)
-### Supported features
+## Supported entity features
- Send http get, post, patch, put, delete & head requests to a specified url
- - Add form, json or xml payload (see [adding payload data](#adding-payload-data))
- - Define a global custom timeout (default is 2 seconds)
- - Deactivate ssl/tls verification for self signed certificates
- - Option to ignore HTTP requests errors and always return a OK/200 status code to the remote. Helpful if the server doesn't send any response or closes the connection after a command is received (fire and forget). The error message will still be logged but at debug instead of error level
-- Send wake-on-lan magic packets to a specified mac address, ip (v4/v6) or hostname (ipv4 only)
- - Discover the mac address from an ip address or a hostname is not supported when running the integration on the remote due to sandbox limitations and may not work on all systems. Please refer to the [getmac supported platforms](https://github.com/GhostofGoes/getmac?tab=readme-ov-file#platforms-currently-supported)
+ - Add [additional command parameters]((#additional-command-parameters))
+ - Option to ignore HTTP requests errors and always return a OK/200 status code to the remote
+ - Helpful if the server doesn't send any response or closes the connection after a command is received (fire and forget). The error message will still be logged but at debug instead of error level
+- Send wake-on-lan magic packets to one or more mac addresses, ips (v4/v6) or hostnames (ipv4 only)
+ - [Supported parameters](#supported-parameters)
+ - Discover the mac address from an ip address or a hostname
+ - Not supported when running the integration on the remote due to sandbox limitations and may not work on all systems. Please refer to the [getmac supported platforms](https://github.com/GhostofGoes/getmac?tab=readme-ov-file#platforms-currently-supported)
- Send text over TCP
- This protocol is used by some home automation systems or tools like [win-remote-control](https://github.com/moefh/win-remote-control)
+ - Support for c++ and hex style control characters
- The default timeout can be changed in the advanced setup settings
-### Planned features
+## Planned features
-- Support for custom http headers
- SSH client entity
Additional smaller planned improvements or changes are labeled with #TODO in the code
@@ -66,6 +72,8 @@ Additional smaller planned improvements or changes are labeled with #TODO in the
During the integration setup you can turn on the advanced settings to change various timeouts and others entity related settings (see [Usage](#usage)). You can run the setup process again in the integration settings to change these settings after adding entities to the remote.
+For http requests it's also possible to temporally overwrite one or more settings for a specific command by adding [additional command parameters](#additional-command-parameters).
+
## Usage
The integration exposes a media player entity for each supported command. These entities only support the source feature. Just enter the needed string needed for the chosen entity in the source field when you configure your activity/macro sequences or activity ui.
@@ -82,17 +90,40 @@ All parameters from [pywakeonlan](https://github.com/remcohaszing/pywakeonlan) a
### 2 - HTTP requests
-Enter the desired url (including http(s)://) in the source field when you configure your activity/macro sequences or activity ui. Additional payload data can be added (see below).
+Enter the desired url (including http(s)://) in the source field when you configure your activity/macro sequences or activity ui. Additional parameters can be added (see below).
#### Expected http request server response
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.
-If you activate the option to ignore HTTP requests errors in the integration setup a OK/200 status code will always be returned to the remote (fire and forget). This can be helpful if the requested server/device needs longer than the set timeout to wake up from deep sleep, generally doesn't send any response at all or closes the connection after a command is received. The error message will still be logged but at debug instead of error level.
+If you activate the fire and forget mode the remote will always receive a *200 OK* status code (see below).
+
+#### Additional command parameters
+
+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.
+
+When using one or more parameters you need to use the `url` parameter for the url itself as well. If a parameter value contains commas, equal signs or quotes put it in double quotes and use single quotes inside (see examples below).
+
+#### SSL verification & Fire and forget mode
+
+When using a self signed ssl certificate you can globally deactivate ssl cert verification in the advanced setup or temporally for specific commands by using `verify=False` as a command parameter.
+
+If you activate the option to ignore HTTP requests errors in the integration setup or by adding `ffg=True` as a command parameter a OK/200 status code will always be returned to the remote (fire and forget). This can be helpful if the requested server/device needs longer than the set timeout to wake up from deep sleep, generally doesn't send any response at all or closes the connection after a command is received. The error message will still be logged but at debug instead of error level.
+
+#### Use case examples
+
+| Use Case | Parameters | Example |
+|-----------------------------------|---------------|--------------------------------------------------------------|
+| Temporally use a different timeout and activate fire and forget mode | `timeout` and `ffg` | `url="https://httpbin.org/get", timeout=5, ffg=True` |
+| Adding form payload data` | `data` | `url="https://httpbin.org/post", data="key1=value1,key2=value2"` |
+| Adding json payload data (content type is set automatically) | `json` | `url="https://httpbin.org/post", json="{'key1':'value1','key2':'value2'}"` |
+| Adding xml payload data | `data` and `headers` | `url="https://httpbin.org/post", data="Command name", headers="{'Content-Type':'application/xml'}"` |
-#### Adding payload data
+#### Legacy syntax used before v0.6.0 (⚠️ Will be removed in a future version)
+
+Legacy syntax
-Optional payload data can be added to the request body with a specific separator charter
+Optional payload data can be added to the request body with a specific separator character:
| Content type | Separator | Example | Notes |
|-----------------------------------|---------------|--------------------------------------------------------------|-------|
@@ -103,6 +134,7 @@ Optional payload data can be added to the request body with a specific separator
#### Only one payload type per requests is supported
If your actual url contains one or more of the above separators or other special characters that are not url reserved control characters you need to url-encode them first (e.g. with )
+
### 3 - Text over TCP
diff --git a/driver.json b/driver.json
index 5335bcb..9954a1a 100755
--- a/driver.json
+++ b/driver.json
@@ -1,7 +1,7 @@
{
"driver_id": "requests",
- "version": "0.5.2",
- "release_date": "2024-12-25",
+ "version": "0.6.0",
+ "release_date": "2025-01-04",
"min_core_api": "0.24.3",
"name": {
"en": "HTTP requests, WoL & text over TCP",
diff --git a/intg-requests/config.py b/intg-requests/config.py
index ac9d2e4..818a4de 100644
--- a/intg-requests/config.py
+++ b/intg-requests/config.py
@@ -23,6 +23,7 @@ class Setup:
"rq_ssl_verify": True,
"rq_user_agent": "uc-intg-requests",
"rq_fire_and_forget": False,
+ "rq_legacy": False,
"id-get": "http-get",
"name-get": "HTTP Get",
"id-post": "http-post",
@@ -40,8 +41,10 @@ class Setup:
"id-tcp-text": "tcp-text",
"name-tcp-text": "Text over TCP"
}
- __setters = ["standby", "setup_complete", "setup_reconfigure", "tcp_text_timeout", "rq_timeout", "rq_user_agent", "rq_ssl_verify", "rq_fire_and_forget", "bundle_mode", "cfg_path"]
- __storers = ["setup_complete", "tcp_text_timeout", "rq_timeout", "rq_user_agent", "rq_ssl_verify", "rq_fire_and_forget"] #Skip runtime only related values in config file
+ __setters = ["standby", "setup_complete", "setup_reconfigure", "tcp_text_timeout", "rq_timeout", "rq_user_agent", "rq_ssl_verify", "rq_fire_and_forget", "rq_legacy",\
+ "bundle_mode", "cfg_path"]
+ #Skip runtime only related values in config file
+ __storers = ["setup_complete", "tcp_text_timeout", "rq_timeout", "rq_user_agent", "rq_ssl_verify", "rq_fire_and_forget", "rq_legacy"]
all_cmds = ["get", "post", "patch", "put", "delete", "head", "wol", "tcp-text"]
rq_ids = [__conf["id-get"], __conf["id-post"], __conf["id-patch"], __conf["id-put"], __conf["id-delete"], __conf["id-head"]]
@@ -127,11 +130,12 @@ def load():
else:
if "tcp_text_timeout" in configfile:
Setup.__conf["tcp_text_timeout"] = configfile["tcp_text_timeout"]
- _LOG.info("Loaded custom text over tcp timeout of " + str(configfile["tcp_text_timeout"]) + " seconds into runtime storage from " + Setup.__conf["cfg_path"])
+ _LOG.info("Loaded custom text over tcp timeout of " + str(configfile["tcp_text_timeout"]) + " seconds \
+into runtime storage from " + Setup.__conf["cfg_path"])
else:
_LOG.info("Skip loading custom text over tcp timeout as it has not been changed during setup. \
The Default value of " + str(Setup.get("tcp_text_timeout")) + " seconds will be used")
-
+
if "rq_user_agent" in configfile:
Setup.__conf["rq_user_agent"] = configfile["rq_user_agent"]
_LOG.info("Loaded custom http requests user agent " + str(configfile["rq_user_agent"]) + " into runtime storage from " + Setup.__conf["cfg_path"])
@@ -160,5 +164,12 @@ def load():
_LOG.info("Skip loading fire_and_forget as it has not been changed during setup. \
The Default value " + str(Setup.get("rq_fire_and_forget")) + " will be used")
+ if "rq_legacy" in configfile:
+ Setup.__conf["rq_legacy"] = configfile["rq_legacy"]
+ _LOG.info("Loaded rq_legacy: " + str(configfile["rq_legacy"]) + " flag into runtime storage from " + Setup.__conf["cfg_path"])
+ else:
+ _LOG.info("Using current http requests syntax as it has not been changed during setup. \
+The Default value " + str(Setup.get("rq_legacy")) + " will be used")
+
else:
_LOG.info(Setup.__conf["cfg_path"] + " does not exist (yet). Please start the setup process")
diff --git a/intg-requests/driver.py b/intg-requests/driver.py
index 3bcb6cb..28d9e52 100755
--- a/intg-requests/driver.py
+++ b/intg-requests/driver.py
@@ -19,6 +19,8 @@
loop = asyncio.get_event_loop()
api = ucapi.IntegrationAPI(loop)
+#TODO Change icon in driver.json from uc:integration to uc:webhook once the new configurator that includes this icon is out of beta
+
async def startcheck():
diff --git a/intg-requests/media_player.py b/intg-requests/media_player.py
index b677ea6..d5ce26a 100644
--- a/intg-requests/media_player.py
+++ b/intg-requests/media_player.py
@@ -7,18 +7,15 @@
import json
from json import JSONDecodeError
from typing import Any
+import ast
+import shlex
from re import sub, match, IGNORECASE
from ipaddress import ip_address, IPv4Address, IPv6Address, AddressValueError
import urllib3 #Needed to optionally deactivate requests ssl verify warning message
import ucapi
-from requests import get as rq_get
-from requests import put as rq_put
-from requests import patch as rq_patch
-from requests import post as rq_post
-from requests import delete as rq_delete
-from requests import head as rq_head
+from requests import request
from requests import codes as http_codes
from requests import exceptions as rq_exceptions
from wakeonlan import send_magic_packet
@@ -104,50 +101,166 @@ def get_mac(param: str):
-def rq_cmd(rq_cmd_name: str, url: str, data: str = None, xml: bool = False):
+def tcp_text_process_control_data(data):
+ """
+ - Hex style control characters such as "0x09" are processed and can be be escaped with a leading "0\\\" (e.g. 0\\\x09)
+ - C++ control characters such as "\n", "\t" are also processed and can be escaped with a leading single additional backslash (e.g. \\n)
+ """
+
+ # Search for hex style escape characters (starting with \\)
+ def replace_literal_hex(match):
+ return match.group(1)
+
+ # replace \\0xHH (with a double backslash) through string/literal value
+ data = sub(r"\\\\(0x[0-9A-Fa-f]{2})", replace_literal_hex, data)
+
+ # Match real hex style control characters (0xHH)
+ def replace_control_hex(match):
+ return chr(int(match.group(1), 16))
+
+ # Replace 0xHH with the corresponding control character
+ data = sub(r"(? int:
"""Send a requests command to the passed url with the passed data and return the status code"""
- rq_timeout = config.Setup.get("rq_timeout")
+
rq_ssl_verify = config.Setup.get("rq_ssl_verify")
rq_fire_and_forget = config.Setup.get("rq_fire_and_forget")
+ rq_timeout = config.Setup.get("rq_timeout")
+ rq_user_agent = config.Setup.get("rq_user_agent")
+
+ params = {}
- user_agent = config.Setup.get("rq_user_agent")
- headers = {"User-Agent" : user_agent}
- if xml is True:
- headers.update({"Content-Type" : "application/xml"})
+ #TODO Remove legacy syntax in a future version
+ if config.Setup.get("rq_legacy"):
+ _LOG.warning("You are using the legacy http requests syntax. Please update your configuration to use the new syntax as described in the documentation. \
+The legacy syntax will be removed in a future version")
- _LOG.debug("rq_cmd_name: " + rq_cmd_name + ", rq_timeout: " + str(rq_timeout) + ", rq_ssl_verify: " + str(rq_ssl_verify) + \
-", rq_fire_and_forget: " + str(rq_fire_and_forget))
+ if "§" in cmd_param:
+ _LOG.info("Passed parameter contains form data")
+ url, form_string = cmd_param.split("§")
+ #Convert passed string input into Python dict for requests
+ params["data"] = dict(pair.split("=") for pair in form_string.split(","))
+
+ elif "|" in cmd_param:
+ _LOG.info("Passed parameter contains json data")
+ url, json_string = cmd_param.split("|")
+ try:
+ params["json"] = json.loads(json_string)
+ except JSONDecodeError as e:
+ _LOG.error("JSONDecodeError: " + str(e))
+ return ucapi.StatusCodes.CONFLICT
- if rq_ssl_verify is False:
- #Deactivate SSL verify warning message
- urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
+ elif "^" in cmd_param:
+ _LOG.info("Passed parameter contains xml data")
+ url, params["data"] = cmd_param.split("^")
+ params["headers"] = {"Content-Type" : "application/xml"}
+
+ else:
+ url = cmd_param
+
+ else:
+ if cmd_param.startswith(("http://", "https://")):
+ url = cmd_param
+ else:
+ lexer = shlex.shlex(cmd_param, posix=True) # Use shlex to handle command argument like parameters
+ lexer.whitespace_split = True
+ lexer.whitespace = "," #Use comma as separator
+ lexer.quotes = '"' #Handle everything in double quotes as one value
+
+ #Parse the cmd_param string into a dictionary of parameters
+ for param in lexer:
+ try:
+ key, value = param.split("=", 1)
+ except ValueError:
+ if key is None or "":
+ key = "Unknown key"
+ _LOG.error("The parameter key is incorrectly formatted. Please use a syntax like key=\"value\" in the source parameter")
+ _LOG.error("The parameter value for \"" + key + " \" is not in the correct format. \
+Please put it in double quotes and use single quotes inside when the value itself contains double quotes")
+ return ucapi.StatusCodes.BAD_REQUEST
+
+ #Prevent boolean values from being passed as strings
+ if value.lower() == "true":
+ value = True
+ elif value.lower() == "false":
+ value = False
+
+ try:
+ value = ast.literal_eval(value) #Try to convert value to Python data type (e.g. dicts)
+ except (ValueError, SyntaxError):
+ #Use value as string if ast.literal_eval fails
+ pass
+
+ params[key.strip()] = value
+
+ url = params.pop("url", None)
+ if not url:
+ _LOG.error("A url is required. Please use a syntax like url=\"http://example.com\" in the source parameter")
+ return ucapi.StatusCodes.BAD_REQUEST
+
+ if "ffg" in params:
+ rq_fire_and_forget = params.pop("ffg")
+ _LOG.debug("Custom fire and forget setting " + str(rq_fire_and_forget) + " defined with 'ffg' command parameter. \
+Ignoring global setting: " + str(config.Setup.get("rq_fire_and_forget")))
+
+ if "headers" in params:
+ if "User-Agent" not in params["headers"]:
+ params["headers"].update({"User-Agent": rq_user_agent})
+ else:
+ _LOG.info("Custom user agent defined in headers command parameter. Ignoring global http requests user agent: " + rq_user_agent)
+ else:
+ params["headers"] = {"User-Agent": rq_user_agent}
+
+ if "timeout" in params:
+ _LOG.info("Custom timeout of " + str(params["timeout"]) + " seconds defined with 'timeout' command parameter. \
+Ignoring global http requests timeout of " + str(rq_timeout) + " seconds")
+ else:
+ params["timeout"] = rq_timeout
+
+ if "verify" in params:
+ _LOG.info("Custom SSL verification setting " + str(params["verify"]) + " defined with 'verify' command parameter. \
+Ignoring global ssl verification setting: " + str(rq_ssl_verify))
+ if not params["verify"]:
+ #Deactivate SSL verify warning message
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
+ else:
+ params["verify"] = rq_ssl_verify
+ if not rq_ssl_verify:
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
+
+ _LOG.debug("method: " + method + ", fire_and_forget: " + str(rq_fire_and_forget) + ", url: " + url + ", params: " + str(params))
try:
- #Utilise globals()[] to be able to use a variable as a function name, save server response in a variable and catch exceptions
- response = globals()[rq_cmd_name](url, data=data, headers=headers, timeout=rq_timeout, verify=rq_ssl_verify)
+ response = request(method, url, **params)
except rq_exceptions.Timeout as t:
- if rq_fire_and_forget is True:
+ if rq_fire_and_forget:
_LOG.info("Got a timeout error but fire and forget mode is active. Return 200/OK status code to the remote")
_LOG.debug("Ignored error: " + str(t))
return ucapi.StatusCodes.OK
- else:
- _LOG.error("Got a timeout error from Python requests module:")
- _LOG.error(t)
- return ucapi.StatusCodes.TIMEOUT
+ _LOG.error("Got a timeout error from Python requests module:")
+ _LOG.error(t)
+ return ucapi.StatusCodes.TIMEOUT
except Exception as e:
- if rq_fire_and_forget is True:
+ if rq_fire_and_forget:
_LOG.info("Got a requests error but fire and forget mode is active. Return 200/OK status code to the remote")
_LOG.debug("Ignored error: " + str(e))
return ucapi.StatusCodes.OK
- else:
- _LOG.error("Got error message from Python requests module:")
- _LOG.error(e)
- return ucapi.StatusCodes.CONFLICT
+ _LOG.error("Got error message from Python requests module:")
+ _LOG.error(e)
+ return ucapi.StatusCodes.CONFLICT
if response.status_code == http_codes.ok:
- _LOG.info("Sent " + rq_cmd_name + " request to: " + url)
+ _LOG.info("Sent http-" + method + " request to: " + url)
if response.text != "":
- _LOG.debug("Server response: " + response.text)
+ _LOG.info("Server response: " + response.text)
else:
_LOG.debug("Received 200 - OK status code")
return ucapi.StatusCodes.OK
@@ -160,7 +273,7 @@ def rq_cmd(rq_cmd_name: str, url: str, data: str = None, xml: bool = False):
if 400 <= response.status_code <= 499:
if response.status_code == 404:
if response.text != "":
- _LOG.debug("Server response: " + response.text)
+ _LOG.info("Server response: " + response.text)
return ucapi.StatusCodes.NOT_FOUND
return ucapi.StatusCodes.BAD_REQUEST
return ucapi.StatusCodes.SERVER_ERROR
@@ -168,38 +281,11 @@ def rq_cmd(rq_cmd_name: str, url: str, data: str = None, xml: bool = False):
if response.raise_for_status() is None:
_LOG.info("Received informational or redirection http status code: " + str(response.status_code))
if response.text != "":
- _LOG.debug("Server response: " + response.text)
+ _LOG.info("Server response: " + response.text)
return ucapi.StatusCodes.OK
-def tcp_text_process_control_data(data):
- """
- - Hex style control characters such as "0x09" are processed and can be be escaped with a leading "0\\\" (e.g. 0\\\x09)
- - C++ control characters such as "\n", "\t" are also processed and can be escaped with a leading single additional backslash (e.g. \\n)
- """
-
- # Search for hex style escape characters (starting with \\)
- def replace_literal_hex(match):
- return match.group(1)
-
- # replace \\0xHH (with a double backslash) through string/literal value
- data = sub(r"\\\\(0x[0-9A-Fa-f]{2})", replace_literal_hex, data)
-
- # Match real hex style control characters (0xHH)
- def replace_control_hex(match):
- return chr(int(match.group(1), 16))
-
- # Replace 0xHH with the corresponding control character
- data = sub(r"(? str:
"""Send a text over tcp command to the passed address and return the status code"""
address, data =cmd_param.split(",", 1) #Split only at the 1st comma to ignore all others that may be included in the text to be send
@@ -244,40 +330,15 @@ async def mp_cmd_assigner(entity_id: str, cmd_name: str, params: dict[str, Any]
_LOG.error("Source parameter empty")
return ucapi.StatusCodes.BAD_REQUEST
+
+
if entity_id in config.Setup.rq_ids:
if cmd_name == ucapi.media_player.Commands.SELECT_SOURCE:
- #Needed as hyphens can not be used in function and variable names and also to keep the existing entity IDs to prevent activity/macro reconfiguration.
- rq_cmd_name = entity_id.replace("http-", "rq_")
-
- #TODO Try to use the same syntax as requests module. Experiment with split parameters (e.g. just use first n appearances of a character)
- if "§" in cmd_param:
- _LOG.info("Passed parameter contains form data")
- url, form_string = cmd_param.split("§")
- #Convert passed string input into Python dict for requests
- form_dict = dict(pair.split("=") for pair in form_string.split(",")) #TODO Support multiple values for a single key. Will probably require a syntax change
- #Use asyncio.gather() to run the function in a separate thread and use asyncio.sleep(0) to prevent blocking the event loop
- cmd_status = await asyncio.gather(asyncio.to_thread(rq_cmd, rq_cmd_name, url, data=form_dict), asyncio.sleep(0))
- return cmd_status[0] #Return the return value of rq_cmd which is the first command in asyncio.gather()
-
- if "|" in cmd_param:
- _LOG.info("Passed parameter contains json data")
- url, json_string = cmd_param.split("|")
- try:
- json_dict = json.loads(json_string)
- except JSONDecodeError as e:
- _LOG.error("JSONDecodeError: " + str(e))
- return ucapi.StatusCodes.CONFLICT
- cmd_status = await asyncio.gather(asyncio.to_thread(rq_cmd, rq_cmd_name, url, data=json_dict), asyncio.sleep(0))
- return cmd_status[0]
-
- if "^" in cmd_param:
- _LOG.info("Passed parameter contains xml data")
- url, xml_string = cmd_param.split("^")
- cmd_status = await asyncio.gather(asyncio.to_thread(rq_cmd, rq_cmd_name, url, data=xml_string, xml=True), asyncio.sleep(0))
- return cmd_status[0]
+ method = entity_id.replace("http-", "")
- url = cmd_param
- cmd_status = await asyncio.gather(asyncio.to_thread(rq_cmd, rq_cmd_name, url), asyncio.sleep(0))
+ #Use asyncio.gather() to run the function in a separate thread and use asyncio.sleep(0) to prevent blocking the event loop
+ cmd_status = await asyncio.gather(asyncio.to_thread(rq_cmd, method, cmd_param), asyncio.sleep(0))
+ #Return the return value of rq_cmd which is the first command in asyncio.gather()
return cmd_status[0]
_LOG.error("Command not implemented: " + cmd_name)
diff --git a/intg-requests/setup.py b/intg-requests/setup.py
index 13f19f7..32817be 100644
--- a/intg-requests/setup.py
+++ b/intg-requests/setup.py
@@ -83,11 +83,12 @@ async def handle_driver_setup(msg: ucapi.DriverSetupRequest,) -> ucapi.SetupActi
rq_ssl_verify = config.Setup.get("rq_ssl_verify")
rq_fire_and_forget = config.Setup.get("rq_fire_and_forget")
rq_user_agent = config.Setup.get("rq_user_agent")
+ rq_legacy = config.Setup.get("rq_legacy")
except ValueError as v:
_LOG.error(v)
_LOG.debug("Currently stored - tcp_text_timeout: " + str(tcp_text_timeout) + " , rq_timeout: " + str(rq_timeout) + " , rq_ssl_verify: "\
-+ str(rq_ssl_verify) + " , rq_fire_and_forget: " + str(rq_fire_and_forget) + ", rq_user_agent: " + str(rq_user_agent))
++ str(rq_ssl_verify) + " , rq_fire_and_forget: " + str(rq_fire_and_forget) + ", rq_user_agent: " + str(rq_user_agent) + ", rq_legacy: " + str(rq_legacy))
return ucapi.RequestUserInput(
{
@@ -167,7 +168,7 @@ async def handle_driver_setup(msg: ucapi.DriverSetupRequest,) -> ucapi.SetupActi
}
},
},
- {
+ {
"id": "rq_fire_and_forget",
"label": {
"en": "Ignore HTTP requests errors (fire and forget):",
@@ -178,6 +179,17 @@ async def handle_driver_setup(msg: ucapi.DriverSetupRequest,) -> ucapi.SetupActi
}
},
},
+ {
+ "id": "rq_legacy",
+ "label": {
+ "en": "Use http requests legacy syntax:",
+ "de": "Legacy-Syntax für HTTP-Anfragen verwenden:"
+ },
+ "field": {"checkbox": {
+ "value": rq_legacy
+ }
+ },
+ },
],
)
@@ -207,6 +219,7 @@ async def handle_user_data_response(msg: ucapi.UserDataResponse) -> ucapi.Setup
rq_ssl_verify = msg.input_values["rq_ssl_verify"]
rq_fire_and_forget = msg.input_values["rq_fire_and_forget"]
rq_user_agent = msg.input_values["rq_user_agent"]
+ rq_legacy = msg.input_values["rq_legacy"]
rq_timeout = int(rq_timeout)
tcp_text_timeout = int(tcp_text_timeout)
@@ -267,6 +280,24 @@ async def handle_user_data_response(msg: ucapi.UserDataResponse) -> ucapi.Setup
_LOG.error(e)
config.Setup.set("setup_complete", False)
return ucapi.SetupError()
+ _LOG.info("Fire and forget mode deactivated. Return the actual status code")
+
+ if rq_legacy == "true": #Boolean in quotes as all values are returned as strings
+ try:
+ config.Setup.set("rq_legacy", True)
+ except Exception as e:
+ _LOG.error(e)
+ config.Setup.set("setup_complete", False)
+ return ucapi.SetupError()
+ _LOG.info("Legacy syntax activated")
+ else:
+ try:
+ config.Setup.set("rq_legacy", False)
+ except Exception as e:
+ _LOG.error(e)
+ config.Setup.set("setup_complete", False)
+ return ucapi.SetupError()
+ _LOG.info("Legacy syntax deactivated")
if not config.Setup.get("setup_reconfigure"):
for cmd in config.Setup.all_cmds: