diff --git a/homeassistant/components/pvoutput/sensor.py b/homeassistant/components/pvoutput/sensor.py index 0bc2a6f6ca8..fb3446fb652 100644 --- a/homeassistant/components/pvoutput/sensor.py +++ b/homeassistant/components/pvoutput/sensor.py @@ -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: diff --git a/homeassistant/components/rest/binary_sensor.py b/homeassistant/components/rest/binary_sensor.py index c19bfe307d0..7f0f920b843 100644 --- a/homeassistant/components/rest/binary_sensor.py +++ b/homeassistant/components/rest/binary_sensor.py @@ -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 diff --git a/homeassistant/components/rest/data.py b/homeassistant/components/rest/data.py index 9d9e802c2a0..bd35383e981 100644 --- a/homeassistant/components/rest/data.py +++ b/homeassistant/components/rest/data.py @@ -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, diff --git a/homeassistant/components/rest/notify.py b/homeassistant/components/rest/notify.py index b8f81b19e92..3e4f97d5bc7 100644 --- a/homeassistant/components/rest/notify.py +++ b/homeassistant/components/rest/notify.py @@ -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, diff --git a/homeassistant/components/rest/sensor.py b/homeassistant/components/rest/sensor.py index 826160604ba..f048eaa3b47 100644 --- a/homeassistant/components/rest/sensor.py +++ b/homeassistant/components/rest/sensor.py @@ -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: diff --git a/homeassistant/components/rest/switch.py b/homeassistant/components/rest/switch.py index 1b980e12b75..b6bd759d0bf 100644 --- a/homeassistant/components/rest/switch.py +++ b/homeassistant/components/rest/switch.py @@ -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() diff --git a/homeassistant/components/scrape/sensor.py b/homeassistant/components/scrape/sensor.py index 613151511ae..b76995fe39f 100644 --- a/homeassistant/components/scrape/sensor.py +++ b/homeassistant/components/scrape/sensor.py @@ -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: diff --git a/homeassistant/const.py b/homeassistant/const.py index 173a39080b7..84a24ab1bad 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -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" diff --git a/tests/components/rest/test_binary_sensor.py b/tests/components/rest/test_binary_sensor.py index 1f2c88f4278..48d13a716ab 100644 --- a/tests/components/rest/test_binary_sensor.py +++ b/tests/components/rest/test_binary_sensor.py @@ -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__))) diff --git a/tests/components/rest/test_sensor.py b/tests/components/rest/test_sensor.py index d841f69e45f..71bcbedda88 100644 --- a/tests/components/rest/test_sensor.py +++ b/tests/components/rest/test_sensor.py @@ -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.""" diff --git a/tests/components/rest/test_switch.py b/tests/components/rest/test_switch.py index f21eea0e242..5e0c9fbeab3 100644 --- a/tests/components/rest/test_switch.py +++ b/tests/components/rest/test_switch.py @@ -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,