Add initial rest query params (#42198)

* add initial rest query params

* of course I didn't run black

* fix tests

* fix tests

* add test

* reformat

* add binary sensor test

* fix tests

* add one more test and fix switch

* should not have touched that

* if you don't pay attention once
This commit is contained in:
Moritz Schmitz von Hülst 2020-11-11 20:03:55 +01:00 committed by GitHub
parent 6a7b71e8fb
commit 434d39a5ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 106 additions and 6 deletions

View file

@ -53,7 +53,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
verify_ssl = DEFAULT_VERIFY_SSL
headers = {"X-Pvoutput-Apikey": api_key, "X-Pvoutput-SystemId": system_id}
rest = RestData(method, _ENDPOINT, auth, headers, payload, verify_ssl)
rest = RestData(method, _ENDPOINT, auth, headers, None, payload, verify_ssl)
await rest.async_update()
if rest.data is None:

View file

@ -14,6 +14,7 @@ from homeassistant.const import (
CONF_HEADERS,
CONF_METHOD,
CONF_NAME,
CONF_PARAMS,
CONF_PASSWORD,
CONF_PAYLOAD,
CONF_RESOURCE,
@ -45,6 +46,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
[HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]
),
vol.Optional(CONF_HEADERS): {cv.string: cv.string},
vol.Optional(CONF_PARAMS): {cv.string: cv.string},
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(["POST", "GET"]),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
@ -78,6 +80,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
headers = config.get(CONF_HEADERS)
params = config.get(CONF_PARAMS)
device_class = config.get(CONF_DEVICE_CLASS)
value_template = config.get(CONF_VALUE_TEMPLATE)
force_update = config.get(CONF_FORCE_UPDATE)
@ -97,7 +100,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
else:
auth = None
rest = RestData(method, resource, auth, headers, payload, verify_ssl, timeout)
rest = RestData(
method, resource, auth, headers, params, payload, verify_ssl, timeout
)
await rest.async_update()
if rest.data is None:
raise PlatformNotReady

View file

@ -17,6 +17,7 @@ class RestData:
resource,
auth,
headers,
params,
data,
verify_ssl,
timeout=DEFAULT_TIMEOUT,
@ -26,6 +27,7 @@ class RestData:
self._resource = resource
self._auth = auth
self._headers = headers
self._params = params
self._request_data = data
self._timeout = timeout
self._verify_ssl = verify_ssl
@ -53,6 +55,7 @@ class RestData:
self._method,
self._resource,
headers=self._headers,
params=self._params,
auth=self._auth,
data=self._request_data,
timeout=self._timeout,

View file

@ -17,6 +17,7 @@ from homeassistant.const import (
CONF_HEADERS,
CONF_METHOD,
CONF_NAME,
CONF_PARAMS,
CONF_PASSWORD,
CONF_RESOURCE,
CONF_USERNAME,
@ -51,6 +52,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
["POST", "GET", "POST_JSON"]
),
vol.Optional(CONF_HEADERS): vol.Schema({cv.string: cv.string}),
vol.Optional(CONF_PARAMS): vol.Schema({cv.string: cv.string}),
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_TARGET_PARAMETER_NAME): cv.string,
vol.Optional(CONF_TITLE_PARAMETER_NAME): cv.string,
@ -75,6 +77,7 @@ def get_service(hass, config, discovery_info=None):
resource = config.get(CONF_RESOURCE)
method = config.get(CONF_METHOD)
headers = config.get(CONF_HEADERS)
params = config.get(CONF_PARAMS)
message_param_name = config.get(CONF_MESSAGE_PARAMETER_NAME)
title_param_name = config.get(CONF_TITLE_PARAMETER_NAME)
target_param_name = config.get(CONF_TARGET_PARAMETER_NAME)
@ -97,6 +100,7 @@ def get_service(hass, config, discovery_info=None):
resource,
method,
headers,
params,
message_param_name,
title_param_name,
target_param_name,
@ -116,6 +120,7 @@ class RestNotificationService(BaseNotificationService):
resource,
method,
headers,
params,
message_param_name,
title_param_name,
target_param_name,
@ -129,6 +134,7 @@ class RestNotificationService(BaseNotificationService):
self._hass = hass
self._method = method.upper()
self._headers = headers
self._params = params
self._message_param_name = message_param_name
self._title_param_name = title_param_name
self._target_param_name = target_param_name
@ -171,6 +177,7 @@ class RestNotificationService(BaseNotificationService):
response = requests.post(
self._resource,
headers=self._headers,
params=self._params,
data=data,
timeout=10,
auth=self._auth,
@ -180,6 +187,7 @@ class RestNotificationService(BaseNotificationService):
response = requests.post(
self._resource,
headers=self._headers,
params=self._params,
json=data,
timeout=10,
auth=self._auth,
@ -189,7 +197,7 @@ class RestNotificationService(BaseNotificationService):
response = requests.get(
self._resource,
headers=self._headers,
params=data,
params=self._params.update(data),
timeout=10,
auth=self._auth,
verify=self._verify_ssl,

View file

@ -16,6 +16,7 @@ from homeassistant.const import (
CONF_HEADERS,
CONF_METHOD,
CONF_NAME,
CONF_PARAMS,
CONF_PASSWORD,
CONF_PAYLOAD,
CONF_RESOURCE,
@ -56,6 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
[HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]
),
vol.Optional(CONF_HEADERS): vol.Schema({cv.string: cv.string}),
vol.Optional(CONF_PARAMS): vol.Schema({cv.string: cv.string}),
vol.Optional(CONF_JSON_ATTRS, default=[]): cv.ensure_list_csv,
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(METHODS),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
@ -90,6 +92,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
headers = config.get(CONF_HEADERS)
params = config.get(CONF_PARAMS)
unit = config.get(CONF_UNIT_OF_MEASUREMENT)
device_class = config.get(CONF_DEVICE_CLASS)
value_template = config.get(CONF_VALUE_TEMPLATE)
@ -112,7 +115,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
auth = (username, password)
else:
auth = None
rest = RestData(method, resource, auth, headers, payload, verify_ssl, timeout)
rest = RestData(
method, resource, auth, headers, params, payload, verify_ssl, timeout
)
await rest.async_update()
if rest.data is None:

View file

@ -11,6 +11,7 @@ from homeassistant.const import (
CONF_HEADERS,
CONF_METHOD,
CONF_NAME,
CONF_PARAMS,
CONF_PASSWORD,
CONF_RESOURCE,
CONF_TIMEOUT,
@ -46,6 +47,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
vol.Required(CONF_RESOURCE): cv.url,
vol.Optional(CONF_STATE_RESOURCE): cv.url,
vol.Optional(CONF_HEADERS): {cv.string: cv.string},
vol.Optional(CONF_PARAMS): {cv.string: cv.string},
vol.Optional(CONF_BODY_OFF, default=DEFAULT_BODY_OFF): cv.template,
vol.Optional(CONF_BODY_ON, default=DEFAULT_BODY_ON): cv.template,
vol.Optional(CONF_IS_ON_TEMPLATE): cv.template,
@ -71,6 +73,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
is_on_template = config.get(CONF_IS_ON_TEMPLATE)
method = config.get(CONF_METHOD)
headers = config.get(CONF_HEADERS)
params = config.get(CONF_PARAMS)
name = config.get(CONF_NAME)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
@ -97,6 +100,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
state_resource,
method,
headers,
params,
auth,
body_on,
body_off,
@ -129,6 +133,7 @@ class RestSwitch(SwitchEntity):
state_resource,
method,
headers,
params,
auth,
body_on,
body_off,
@ -143,6 +148,7 @@ class RestSwitch(SwitchEntity):
self._state_resource = state_resource
self._method = method
self._headers = headers
self._params = params
self._auth = auth
self._body_on = body_on
self._body_off = body_off
@ -201,6 +207,7 @@ class RestSwitch(SwitchEntity):
auth=self._auth,
data=bytes(body, "utf-8"),
headers=self._headers,
params=self._params,
)
return req
@ -219,7 +226,10 @@ class RestSwitch(SwitchEntity):
with async_timeout.timeout(self._timeout):
req = await websession.get(
self._state_resource, auth=self._auth, headers=self._headers
self._state_resource,
auth=self._auth,
headers=self._headers,
params=self._params,
)
text = await req.text()

View file

@ -78,7 +78,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
auth = HTTPBasicAuth(username, password)
else:
auth = None
rest = RestData(method, resource, auth, headers, payload, verify_ssl)
rest = RestData(method, resource, auth, headers, None, payload, verify_ssl)
await rest.async_update()
if rest.data is None:

View file

@ -128,6 +128,7 @@ CONF_NAME = "name"
CONF_OFFSET = "offset"
CONF_OPTIMISTIC = "optimistic"
CONF_PACKAGES = "packages"
CONF_PARAMS = "params"
CONF_PASSWORD = "password"
CONF_PATH = "path"
CONF_PAYLOAD = "payload"

View file

@ -377,5 +377,28 @@ async def test_reload(hass):
assert hass.states.get("binary_sensor.rollout")
@respx.mock
async def test_setup_query_params(hass):
"""Test setup with query params."""
respx.get(
"http://localhost?search=something",
status_code=200,
)
assert await async_setup_component(
hass,
binary_sensor.DOMAIN,
{
"binary_sensor": {
"platform": "rest",
"resource": "http://localhost",
"method": "GET",
"params": {"search": "something"},
}
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 1
def _get_fixtures_base_path():
return path.dirname(path.dirname(path.dirname(__file__)))

View file

@ -249,6 +249,29 @@ async def test_setup_get_xml(hass):
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == DATA_MEGABYTES
@respx.mock
async def test_setup_query_params(hass):
"""Test setup with query params."""
respx.get(
"http://localhost?search=something",
status_code=200,
)
assert await async_setup_component(
hass,
sensor.DOMAIN,
{
"sensor": {
"platform": "rest",
"resource": "http://localhost",
"method": "GET",
"params": {"search": "something"},
}
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 1
@respx.mock
async def test_update_with_json_attrs(hass):
"""Test attributes get extracted from a JSON result."""

View file

@ -8,6 +8,7 @@ from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.const import (
CONF_HEADERS,
CONF_NAME,
CONF_PARAMS,
CONF_PLATFORM,
CONF_RESOURCE,
CONTENT_TYPE_JSON,
@ -28,6 +29,7 @@ RESOURCE = "http://localhost/"
STATE_RESOURCE = RESOURCE
HEADERS = {"Content-type": CONTENT_TYPE_JSON}
AUTH = None
PARAMS = None
async def test_setup_missing_config(hass):
@ -81,6 +83,25 @@ async def test_setup_minimum(hass, aioclient_mock):
assert aioclient_mock.call_count == 1
async def test_setup_query_params(hass, aioclient_mock):
"""Test setup with query params."""
aioclient_mock.get("http://localhost/?search=something", status=HTTP_OK)
with assert_setup_component(1, SWITCH_DOMAIN):
assert await async_setup_component(
hass,
SWITCH_DOMAIN,
{
SWITCH_DOMAIN: {
CONF_PLATFORM: rest.DOMAIN,
CONF_RESOURCE: "http://localhost",
CONF_PARAMS: {"search": "something"},
}
},
)
print(aioclient_mock)
assert aioclient_mock.call_count == 1
async def test_setup(hass, aioclient_mock):
"""Test setup with valid configuration."""
aioclient_mock.get("http://localhost", status=HTTP_OK)
@ -137,6 +158,7 @@ def _setup_test_switch(hass):
STATE_RESOURCE,
METHOD,
HEADERS,
PARAMS,
AUTH,
body_on,
body_off,