From ea7d989373487de901daa6b3b1db962df6e5cbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Vran=C3=ADk?= Date: Mon, 19 Aug 2019 11:03:31 +0200 Subject: [PATCH 01/72] Update pyrainbird to version 0.2.0 to fix zone number issue: - home-assistant/home-assistant/issues/24519 - jbarrancos/pyrainbird/issues/5 - https://community.home-assistant.io/t/rainbird-zone-switches-5-8-dont-correspond/104705 --- homeassistant/components/rainbird/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/rainbird/manifest.json b/homeassistant/components/rainbird/manifest.json index 584ea22afe23ef..0d16123afd3e17 100644 --- a/homeassistant/components/rainbird/manifest.json +++ b/homeassistant/components/rainbird/manifest.json @@ -3,7 +3,7 @@ "name": "Rainbird", "documentation": "https://www.home-assistant.io/components/rainbird", "requirements": [ - "pyrainbird==0.2.1" + "pyrainbird==0.3.0" ], "dependencies": [], "codeowners": [] From 48c8aa222713ab739b61623eabdcfc96eb7c3003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Vran=C3=ADk?= Date: Mon, 19 Aug 2019 11:18:31 +0200 Subject: [PATCH 02/72] requirements_all.txt regenerated --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index aa9daad808e43d..852a65acc1445f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1365,7 +1365,7 @@ pyqwikswitch==0.93 pyrail==0.0.3 # homeassistant.components.rainbird -pyrainbird==0.2.1 +pyrainbird==0.3.0 # homeassistant.components.recswitch pyrecswitch==1.0.2 From fd64293d91ee633e66f7fe0f0d1f71a886c298de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Vran=C3=ADk?= Date: Mon, 19 Aug 2019 11:39:50 +0200 Subject: [PATCH 03/72] code formatting --- script/check_format | 1 - 1 file changed, 1 deletion(-) diff --git a/script/check_format b/script/check_format index bed35ec63e48c6..c92544696453d8 100755 --- a/script/check_format +++ b/script/check_format @@ -6,5 +6,4 @@ cd "$(dirname "$0")/.." black \ --check \ --fast \ - --quiet \ homeassistant tests script *.py From 4baffc48976c38715cceccf5224354f9b96e9ec9 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Sun, 1 Sep 2019 12:31:47 +0200 Subject: [PATCH 04/72] pyrainbird version 0.3.0 --- homeassistant/components/rainbird/__init__.py | 4 ++-- homeassistant/components/rainbird/sensor.py | 8 ++++---- homeassistant/components/rainbird/switch.py | 13 +++++-------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/rainbird/__init__.py b/homeassistant/components/rainbird/__init__.py index 1d8ed8e37b169c..3ba84cee54ba1d 100644 --- a/homeassistant/components/rainbird/__init__.py +++ b/homeassistant/components/rainbird/__init__.py @@ -33,8 +33,8 @@ def setup(hass, config): _LOGGER.debug("Rain Bird Controller set to: %s", server) - initial_status = controller.currentIrrigation() - if initial_status and initial_status["type"] != "CurrentStationsActiveResponse": + initial_status = controller.command("ModelAndVersion") + if initial_status and initial_status["type"] != "ModelAndVersionResponse": _LOGGER.error("Error getting state. Possible configuration issues") return False diff --git a/homeassistant/components/rainbird/sensor.py b/homeassistant/components/rainbird/sensor.py index 2d4549a21d5dba..070e0bb01e6fed 100644 --- a/homeassistant/components/rainbird/sensor.py +++ b/homeassistant/components/rainbird/sensor.py @@ -3,11 +3,11 @@ import voluptuous as vol +import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import CONF_MONITORED_CONDITIONS -import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity - +from pyrainbird import RainbirdController from . import DATA_RAINBIRD _LOGGER = logging.getLogger(__name__) @@ -38,7 +38,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): class RainBirdSensor(Entity): """A sensor implementation for Rain Bird device.""" - def __init__(self, controller, sensor_type): + def __init__(self, controller: RainbirdController, sensor_type): """Initialize the Rain Bird sensor.""" self._sensor_type = sensor_type self._controller = controller @@ -56,7 +56,7 @@ def update(self): """Get the latest data and updates the states.""" _LOGGER.debug("Updating sensor: %s", self._name) if self._sensor_type == "rainsensor": - result = self._controller.currentRainSensorState() + result = self._controller.get_rain_sensor_state() if result and result["type"] == "CurrentRainSensorStateResponse": self._state = result["sensorState"] else: diff --git a/homeassistant/components/rainbird/switch.py b/homeassistant/components/rainbird/switch.py index a1b82bc1af7453..22de22f9f997ac 100644 --- a/homeassistant/components/rainbird/switch.py +++ b/homeassistant/components/rainbird/switch.py @@ -13,6 +13,7 @@ CONF_ZONE, ) from homeassistant.helpers import config_validation as cv +from pyrainbird import RainbirdController from . import DATA_RAINBIRD @@ -48,7 +49,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): class RainBirdSwitch(SwitchDevice): """Representation of a Rain Bird switch.""" - def __init__(self, rb, dev, dev_id): + def __init__(self, rb: RainbirdController, dev, dev_id): """Initialize a Rain Bird Switch Device.""" self._rainbird = rb self._devid = dev_id @@ -70,23 +71,19 @@ def name(self): def turn_on(self, **kwargs): """Turn the switch on.""" - response = self._rainbird.startIrrigation(int(self._zone), int(self._duration)) + response = self._rainbird.irrigate_zone(int(self._zone), int(self._duration)) if response and response["type"] == "AcknowledgeResponse": self._state = True def turn_off(self, **kwargs): """Turn the switch off.""" - response = self._rainbird.stopIrrigation() + response = self._rainbird.stop_irrigation() if response and response["type"] == "AcknowledgeResponse": self._state = False def get_device_status(self): """Get the status of the switch from Rain Bird Controller.""" - response = self._rainbird.currentIrrigation() - if response is None: - return None - if isinstance(response, dict) and "sprinklers" in response: - return response["sprinklers"][self._zone] + return self._rainbird.zone_state(self._devid) def update(self): """Update switch status.""" From 46452dde6b1a8f2debac74e6cf826a55db112064 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Sun, 1 Sep 2019 12:57:28 +0200 Subject: [PATCH 05/72] zone id --- homeassistant/components/rainbird/switch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/rainbird/switch.py b/homeassistant/components/rainbird/switch.py index 22de22f9f997ac..076c11b873f7ae 100644 --- a/homeassistant/components/rainbird/switch.py +++ b/homeassistant/components/rainbird/switch.py @@ -83,7 +83,7 @@ def turn_off(self, **kwargs): def get_device_status(self): """Get the status of the switch from Rain Bird Controller.""" - return self._rainbird.zone_state(self._devid) + return self._rainbird.zone_state(self._zone) def update(self): """Update switch status.""" From 486583ed90ea8306e3a60db2f0eb6defe79557d9 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Sun, 1 Sep 2019 16:00:28 +0200 Subject: [PATCH 06/72] rainsensor return state --- homeassistant/components/rainbird/sensor.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/homeassistant/components/rainbird/sensor.py b/homeassistant/components/rainbird/sensor.py index 070e0bb01e6fed..04844fb7987085 100644 --- a/homeassistant/components/rainbird/sensor.py +++ b/homeassistant/components/rainbird/sensor.py @@ -56,11 +56,7 @@ def update(self): """Get the latest data and updates the states.""" _LOGGER.debug("Updating sensor: %s", self._name) if self._sensor_type == "rainsensor": - result = self._controller.get_rain_sensor_state() - if result and result["type"] == "CurrentRainSensorStateResponse": - self._state = result["sensorState"] - else: - self._state = None + return self._controller.get_rain_sensor_state() @property def name(self): From 9977060c52bc8f209571c141a5e5bbc999e5ddc3 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Sun, 1 Sep 2019 16:10:02 +0200 Subject: [PATCH 07/72] updating rainsensor --- .../components/rainbird/binary_sensor.py | 74 +++++++++++++++++++ homeassistant/components/rainbird/sensor.py | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/rainbird/binary_sensor.py diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py new file mode 100644 index 00000000000000..8ee032cecf46bb --- /dev/null +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -0,0 +1,74 @@ +"""Support for Rain Bird Irrigation system LNK WiFi Module.""" +import logging + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import CONF_MONITORED_CONDITIONS +from homeassistant.helpers.entity import Entity +from pyrainbird import RainbirdController +from . import DATA_RAINBIRD + +_LOGGER = logging.getLogger(__name__) + +# sensor_type [ description, unit, icon ] +SENSOR_TYPES = {"rainsensor": ["Rainsensor", None, "mdi:water"]} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + vol.Optional(CONF_MONITORED_CONDITIONS, default=list(SENSOR_TYPES)): vol.All( + cv.ensure_list, [vol.In(SENSOR_TYPES)] + ) + } +) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up a Rain Bird sensor.""" + controller = hass.data[DATA_RAINBIRD] + + sensors = [] + for sensor_type in config.get(CONF_MONITORED_CONDITIONS): + sensors.append(RainBirdSensor(controller, sensor_type)) + + add_entities(sensors, True) + + +class RainBirdSensor(Entity): + """A sensor implementation for Rain Bird device.""" + + def __init__(self, controller: RainbirdController, sensor_type): + """Initialize the Rain Bird sensor.""" + self._sensor_type = sensor_type + self._controller = controller + self._name = SENSOR_TYPES[self._sensor_type][0] + self._icon = SENSOR_TYPES[self._sensor_type][2] + self._unit_of_measurement = SENSOR_TYPES[self._sensor_type][1] + self._state = None + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + def update(self): + """Get the latest data and updates the states.""" + _LOGGER.debug("Updating sensor: %s", self._name) + if self._sensor_type == "rainsensor": + self._state = bool(self._controller.get_rain_sensor_state()) + + @property + def name(self): + """Return the name of this camera.""" + return self._name + + @property + def unit_of_measurement(self): + """Return the units of measurement.""" + return self._unit_of_measurement + + @property + def icon(self): + """Return icon.""" + return self._icon diff --git a/homeassistant/components/rainbird/sensor.py b/homeassistant/components/rainbird/sensor.py index 04844fb7987085..c8019279936eab 100644 --- a/homeassistant/components/rainbird/sensor.py +++ b/homeassistant/components/rainbird/sensor.py @@ -56,7 +56,7 @@ def update(self): """Get the latest data and updates the states.""" _LOGGER.debug("Updating sensor: %s", self._name) if self._sensor_type == "rainsensor": - return self._controller.get_rain_sensor_state() + self._state = self._controller.get_rain_sensor_state() @property def name(self): From e642a96cd95bcedcbb4585f5a4956584e5bce037 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 18:57:52 +0200 Subject: [PATCH 08/72] new version of pyrainbird --- homeassistant/components/rainbird/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rainbird/manifest.json b/homeassistant/components/rainbird/manifest.json index 0d16123afd3e17..0e9a4f1a46b0a9 100644 --- a/homeassistant/components/rainbird/manifest.json +++ b/homeassistant/components/rainbird/manifest.json @@ -3,7 +3,7 @@ "name": "Rainbird", "documentation": "https://www.home-assistant.io/components/rainbird", "requirements": [ - "pyrainbird==0.3.0" + "pyrainbird==0.3.1" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index 852a65acc1445f..d097183479445d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1365,7 +1365,7 @@ pyqwikswitch==0.93 pyrail==0.0.3 # homeassistant.components.rainbird -pyrainbird==0.3.0 +pyrainbird==0.3.1 # homeassistant.components.recswitch pyrecswitch==1.0.2 From 8efbce7888a1d32866d325a8ee048a28f71d00b7 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 20:04:20 +0200 Subject: [PATCH 09/72] binary sensor state --- homeassistant/components/rainbird/binary_sensor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index 8ee032cecf46bb..9b6f5d1b6946b4 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -56,7 +56,8 @@ def update(self): """Get the latest data and updates the states.""" _LOGGER.debug("Updating sensor: %s", self._name) if self._sensor_type == "rainsensor": - self._state = bool(self._controller.get_rain_sensor_state()) + state = self._controller.get_rain_sensor_state() + self._state = None if state is None else bool(state) @property def name(self): From ac2d7bfa75d6a36aa2e49f8375566b5d14f9ea5b Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 20:24:42 +0200 Subject: [PATCH 10/72] quiet in check format --- script/check_format | 1 + 1 file changed, 1 insertion(+) diff --git a/script/check_format b/script/check_format index c92544696453d8..bed35ec63e48c6 100755 --- a/script/check_format +++ b/script/check_format @@ -6,4 +6,5 @@ cd "$(dirname "$0")/.." black \ --check \ --fast \ + --quiet \ homeassistant tests script *.py From 781d0560d9c7cc284494b7cf3d5937f368a069ae Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 20:25:46 +0200 Subject: [PATCH 11/72] is_on instead of state for binary_sensor --- homeassistant/components/rainbird/binary_sensor.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index 9b6f5d1b6946b4..8c60b93d3d58b6 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -48,16 +48,15 @@ def __init__(self, controller: RainbirdController, sensor_type): self._state = None @property - def state(self): - """Return the state of the sensor.""" - return self._state + def is_on(self): + self._state = self._controller.get_rain_sensor_state() + return None if self._state is None else bool(self._state) def update(self): """Get the latest data and updates the states.""" _LOGGER.debug("Updating sensor: %s", self._name) if self._sensor_type == "rainsensor": - state = self._controller.get_rain_sensor_state() - self._state = None if state is None else bool(state) + self._state = self._controller.get_rain_sensor_state() @property def name(self): From c8eb58fd10ac2d4b5aab686cdbe7408097991391 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 20:26:15 +0200 Subject: [PATCH 12/72] no unit of measurement for binary sensor --- homeassistant/components/rainbird/binary_sensor.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index 8c60b93d3d58b6..16143c503684f1 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -44,7 +44,6 @@ def __init__(self, controller: RainbirdController, sensor_type): self._controller = controller self._name = SENSOR_TYPES[self._sensor_type][0] self._icon = SENSOR_TYPES[self._sensor_type][2] - self._unit_of_measurement = SENSOR_TYPES[self._sensor_type][1] self._state = None @property @@ -63,11 +62,6 @@ def name(self): """Return the name of this camera.""" return self._name - @property - def unit_of_measurement(self): - """Return the units of measurement.""" - return self._unit_of_measurement - @property def icon(self): """Return icon.""" From 66fabe13a442f753f48c9fb0e03ae2acd1189525 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 20:26:35 +0200 Subject: [PATCH 13/72] no monitored conditions config --- .../components/rainbird/binary_sensor.py | 15 +-------------- homeassistant/components/rainbird/sensor.py | 15 +-------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index 16143c503684f1..b13c1059d11f8e 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -1,11 +1,6 @@ """Support for Rain Bird Irrigation system LNK WiFi Module.""" import logging -import voluptuous as vol - -import homeassistant.helpers.config_validation as cv -from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import CONF_MONITORED_CONDITIONS from homeassistant.helpers.entity import Entity from pyrainbird import RainbirdController from . import DATA_RAINBIRD @@ -15,21 +10,13 @@ # sensor_type [ description, unit, icon ] SENSOR_TYPES = {"rainsensor": ["Rainsensor", None, "mdi:water"]} -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_MONITORED_CONDITIONS, default=list(SENSOR_TYPES)): vol.All( - cv.ensure_list, [vol.In(SENSOR_TYPES)] - ) - } -) - def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Rain Bird sensor.""" controller = hass.data[DATA_RAINBIRD] sensors = [] - for sensor_type in config.get(CONF_MONITORED_CONDITIONS): + for sensor_type in map(lambda k, v: k, SENSOR_TYPES): sensors.append(RainBirdSensor(controller, sensor_type)) add_entities(sensors, True) diff --git a/homeassistant/components/rainbird/sensor.py b/homeassistant/components/rainbird/sensor.py index c8019279936eab..6f2977c8b617e3 100644 --- a/homeassistant/components/rainbird/sensor.py +++ b/homeassistant/components/rainbird/sensor.py @@ -1,11 +1,6 @@ """Support for Rain Bird Irrigation system LNK WiFi Module.""" import logging -import voluptuous as vol - -import homeassistant.helpers.config_validation as cv -from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import CONF_MONITORED_CONDITIONS from homeassistant.helpers.entity import Entity from pyrainbird import RainbirdController from . import DATA_RAINBIRD @@ -15,21 +10,13 @@ # sensor_type [ description, unit, icon ] SENSOR_TYPES = {"rainsensor": ["Rainsensor", None, "mdi:water"]} -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_MONITORED_CONDITIONS, default=list(SENSOR_TYPES)): vol.All( - cv.ensure_list, [vol.In(SENSOR_TYPES)] - ) - } -) - def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Rain Bird sensor.""" controller = hass.data[DATA_RAINBIRD] sensors = [] - for sensor_type in config.get(CONF_MONITORED_CONDITIONS): + for sensor_type in map(lambda k, v: k, SENSOR_TYPES): sensors.append(RainBirdSensor(controller, sensor_type)) add_entities(sensors, True) From a3446c266134fc80e0a5fd08c50ea11f522d23cd Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 20:33:30 +0200 Subject: [PATCH 14/72] get keys of dict directly --- homeassistant/components/rainbird/binary_sensor.py | 2 +- homeassistant/components/rainbird/sensor.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index b13c1059d11f8e..02f92d05362ae5 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -16,7 +16,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): controller = hass.data[DATA_RAINBIRD] sensors = [] - for sensor_type in map(lambda k, v: k, SENSOR_TYPES): + for sensor_type in SENSOR_TYPES.keys(): sensors.append(RainBirdSensor(controller, sensor_type)) add_entities(sensors, True) diff --git a/homeassistant/components/rainbird/sensor.py b/homeassistant/components/rainbird/sensor.py index 6f2977c8b617e3..9fd5b1b9e8df03 100644 --- a/homeassistant/components/rainbird/sensor.py +++ b/homeassistant/components/rainbird/sensor.py @@ -16,7 +16,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): controller = hass.data[DATA_RAINBIRD] sensors = [] - for sensor_type in map(lambda k, v: k, SENSOR_TYPES): + for sensor_type in SENSOR_TYPES.keys(): sensors.append(RainBirdSensor(controller, sensor_type)) add_entities(sensors, True) From 3eed17bddb8693667dcbb8162e7095d5605b768f Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 20:35:33 +0200 Subject: [PATCH 15/72] removed redundant update of state --- homeassistant/components/rainbird/binary_sensor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index 02f92d05362ae5..d67ffa87733745 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -35,7 +35,6 @@ def __init__(self, controller: RainbirdController, sensor_type): @property def is_on(self): - self._state = self._controller.get_rain_sensor_state() return None if self._state is None else bool(self._state) def update(self): From 422d21e4813f92df64e0052a78e993d5cb66f137 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 20:49:09 +0200 Subject: [PATCH 16/72] simplified switch --- homeassistant/components/rainbird/switch.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/homeassistant/components/rainbird/switch.py b/homeassistant/components/rainbird/switch.py index 076c11b873f7ae..a365063cff664d 100644 --- a/homeassistant/components/rainbird/switch.py +++ b/homeassistant/components/rainbird/switch.py @@ -81,13 +81,9 @@ def turn_off(self, **kwargs): if response and response["type"] == "AcknowledgeResponse": self._state = False - def get_device_status(self): - """Get the status of the switch from Rain Bird Controller.""" - return self._rainbird.zone_state(self._zone) - def update(self): """Update switch status.""" - self._state = self.get_device_status() + self._state = self._rainbird.zone_state(self._zone) @property def is_on(self): From 9a2b9c89b33a43b2b668c51eeda379fddc3b3e9d Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 21:01:51 +0200 Subject: [PATCH 17/72] right states for switch --- homeassistant/components/rainbird/switch.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/rainbird/switch.py b/homeassistant/components/rainbird/switch.py index a365063cff664d..39169710be5263 100644 --- a/homeassistant/components/rainbird/switch.py +++ b/homeassistant/components/rainbird/switch.py @@ -71,14 +71,12 @@ def name(self): def turn_on(self, **kwargs): """Turn the switch on.""" - response = self._rainbird.irrigate_zone(int(self._zone), int(self._duration)) - if response and response["type"] == "AcknowledgeResponse": + if self._rainbird.irrigate_zone(int(self._zone), int(self._duration)): self._state = True def turn_off(self, **kwargs): """Turn the switch off.""" - response = self._rainbird.stop_irrigation() - if response and response["type"] == "AcknowledgeResponse": + if self._rainbird.stop_irrigation(): self._state = False def update(self): From 50f2846b958c142496058117aa7ee9350d51d26a Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 21:07:13 +0200 Subject: [PATCH 18/72] raindelay sensor --- homeassistant/components/rainbird/sensor.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/rainbird/sensor.py b/homeassistant/components/rainbird/sensor.py index 9fd5b1b9e8df03..870c93f67a1b2e 100644 --- a/homeassistant/components/rainbird/sensor.py +++ b/homeassistant/components/rainbird/sensor.py @@ -8,7 +8,8 @@ _LOGGER = logging.getLogger(__name__) # sensor_type [ description, unit, icon ] -SENSOR_TYPES = {"rainsensor": ["Rainsensor", None, "mdi:water"]} +SENSOR_TYPES = {"rainsensor": ["Rainsensor", None, "mdi:water"], + "raindelay": ["Raindelay", None, "mdi:water-off"]} def setup_platform(hass, config, add_entities, discovery_info=None): @@ -44,6 +45,8 @@ def update(self): _LOGGER.debug("Updating sensor: %s", self._name) if self._sensor_type == "rainsensor": self._state = self._controller.get_rain_sensor_state() + elif self._sensor_type == "raindelay": + self._state = self._controller.get_rain_delay() @property def name(self): From 374e648c5444fd00eca28af6ce26edce2928648c Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 21:12:47 +0200 Subject: [PATCH 19/72] raindelay sensor --- homeassistant/components/rainbird/__init__.py | 5 +++++ homeassistant/components/rainbird/binary_sensor.py | 10 ++++------ homeassistant/components/rainbird/sensor.py | 8 ++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/rainbird/__init__.py b/homeassistant/components/rainbird/__init__.py index 3ba84cee54ba1d..aba75af6169440 100644 --- a/homeassistant/components/rainbird/__init__.py +++ b/homeassistant/components/rainbird/__init__.py @@ -10,6 +10,9 @@ DATA_RAINBIRD = "rainbird" DOMAIN = "rainbird" +# sensor_type [ description, unit, icon ] +SENSOR_TYPES = {"rainsensor": ["Rainsensor", None, "mdi:water"], + "raindelay": ["Raindelay", None, "mdi:water-off"]} CONFIG_SCHEMA = vol.Schema( { @@ -40,3 +43,5 @@ def setup(hass, config): hass.data[DATA_RAINBIRD] = controller return True + + diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index d67ffa87733745..f41b8b46547c8e 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -3,20 +3,16 @@ from homeassistant.helpers.entity import Entity from pyrainbird import RainbirdController -from . import DATA_RAINBIRD +from . import DATA_RAINBIRD, SENSOR_TYPES _LOGGER = logging.getLogger(__name__) -# sensor_type [ description, unit, icon ] -SENSOR_TYPES = {"rainsensor": ["Rainsensor", None, "mdi:water"]} - - def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Rain Bird sensor.""" controller = hass.data[DATA_RAINBIRD] sensors = [] - for sensor_type in SENSOR_TYPES.keys(): + for sensor_type in SENSOR_TYPES: sensors.append(RainBirdSensor(controller, sensor_type)) add_entities(sensors, True) @@ -42,6 +38,8 @@ def update(self): _LOGGER.debug("Updating sensor: %s", self._name) if self._sensor_type == "rainsensor": self._state = self._controller.get_rain_sensor_state() + elif self._sensor_type == "raindelay": + self._state = self._controller.get_rain_delay() @property def name(self): diff --git a/homeassistant/components/rainbird/sensor.py b/homeassistant/components/rainbird/sensor.py index 870c93f67a1b2e..3bf044c97036ee 100644 --- a/homeassistant/components/rainbird/sensor.py +++ b/homeassistant/components/rainbird/sensor.py @@ -3,21 +3,17 @@ from homeassistant.helpers.entity import Entity from pyrainbird import RainbirdController -from . import DATA_RAINBIRD +from . import DATA_RAINBIRD, SENSOR_TYPES _LOGGER = logging.getLogger(__name__) -# sensor_type [ description, unit, icon ] -SENSOR_TYPES = {"rainsensor": ["Rainsensor", None, "mdi:water"], - "raindelay": ["Raindelay", None, "mdi:water-off"]} - def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Rain Bird sensor.""" controller = hass.data[DATA_RAINBIRD] sensors = [] - for sensor_type in SENSOR_TYPES.keys(): + for sensor_type in SENSOR_TYPES: sensors.append(RainBirdSensor(controller, sensor_type)) add_entities(sensors, True) From 9034b1b74a4fa3060a733df2e4a2adf9df2d5f3c Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 21:24:45 +0200 Subject: [PATCH 20/72] binary sensor state --- homeassistant/components/rainbird/binary_sensor.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index f41b8b46547c8e..3c6a5934aa6162 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -7,6 +7,7 @@ _LOGGER = logging.getLogger(__name__) + def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Rain Bird sensor.""" controller = hass.data[DATA_RAINBIRD] @@ -36,10 +37,12 @@ def is_on(self): def update(self): """Get the latest data and updates the states.""" _LOGGER.debug("Updating sensor: %s", self._name) + state = None if self._sensor_type == "rainsensor": - self._state = self._controller.get_rain_sensor_state() + state = self._controller.get_rain_sensor_state() elif self._sensor_type == "raindelay": - self._state = self._controller.get_rain_delay() + state = self._controller.get_rain_delay() + self._state = None if state is None else bool(state) @property def name(self): From e88ecd9d1e1f07d449d58e510ef53edeb79a58a3 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 21:29:04 +0200 Subject: [PATCH 21/72] binary sensor state --- homeassistant/components/rainbird/binary_sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index 3c6a5934aa6162..39350465d68c11 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -1,7 +1,7 @@ """Support for Rain Bird Irrigation system LNK WiFi Module.""" import logging -from homeassistant.helpers.entity import Entity +from homeassistant.components.binary_sensor import BinarySensorDevice from pyrainbird import RainbirdController from . import DATA_RAINBIRD, SENSOR_TYPES @@ -19,7 +19,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): add_entities(sensors, True) -class RainBirdSensor(Entity): +class RainBirdSensor(BinarySensorDevice): """A sensor implementation for Rain Bird device.""" def __init__(self, controller: RainbirdController, sensor_type): From 17e65f0843ef29982fd09e04a55df2b40bd35031 Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 21:32:07 +0200 Subject: [PATCH 22/72] reorganized imports --- homeassistant/components/rainbird/__init__.py | 4 +--- homeassistant/components/rainbird/binary_sensor.py | 4 +++- homeassistant/components/rainbird/sensor.py | 4 +++- homeassistant/components/rainbird/switch.py | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/rainbird/__init__.py b/homeassistant/components/rainbird/__init__.py index aba75af6169440..95d3afd8980596 100644 --- a/homeassistant/components/rainbird/__init__.py +++ b/homeassistant/components/rainbird/__init__.py @@ -3,8 +3,8 @@ import voluptuous as vol -import homeassistant.helpers.config_validation as cv from homeassistant.const import CONF_HOST, CONF_PASSWORD +import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -43,5 +43,3 @@ def setup(hass, config): hass.data[DATA_RAINBIRD] = controller return True - - diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index 39350465d68c11..89635f12067a57 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -1,8 +1,10 @@ """Support for Rain Bird Irrigation system LNK WiFi Module.""" import logging -from homeassistant.components.binary_sensor import BinarySensorDevice from pyrainbird import RainbirdController + +from homeassistant.components.binary_sensor import BinarySensorDevice + from . import DATA_RAINBIRD, SENSOR_TYPES _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/rainbird/sensor.py b/homeassistant/components/rainbird/sensor.py index 3bf044c97036ee..5bd549a991d2d8 100644 --- a/homeassistant/components/rainbird/sensor.py +++ b/homeassistant/components/rainbird/sensor.py @@ -1,8 +1,10 @@ """Support for Rain Bird Irrigation system LNK WiFi Module.""" import logging -from homeassistant.helpers.entity import Entity from pyrainbird import RainbirdController + +from homeassistant.helpers.entity import Entity + from . import DATA_RAINBIRD, SENSOR_TYPES _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/rainbird/switch.py b/homeassistant/components/rainbird/switch.py index 39169710be5263..55a9f4007cbaaf 100644 --- a/homeassistant/components/rainbird/switch.py +++ b/homeassistant/components/rainbird/switch.py @@ -2,6 +2,7 @@ import logging +from pyrainbird import RainbirdController import voluptuous as vol from homeassistant.components.switch import PLATFORM_SCHEMA, SwitchDevice @@ -13,7 +14,6 @@ CONF_ZONE, ) from homeassistant.helpers import config_validation as cv -from pyrainbird import RainbirdController from . import DATA_RAINBIRD From f7a5ce9ffe937197dbb1190c6b6886b2b13aa37a Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 21:47:12 +0200 Subject: [PATCH 23/72] doc on public method --- homeassistant/components/rainbird/binary_sensor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/rainbird/binary_sensor.py b/homeassistant/components/rainbird/binary_sensor.py index 89635f12067a57..b913cc4883490f 100644 --- a/homeassistant/components/rainbird/binary_sensor.py +++ b/homeassistant/components/rainbird/binary_sensor.py @@ -34,6 +34,7 @@ def __init__(self, controller: RainbirdController, sensor_type): @property def is_on(self): + """Return true if the binary sensor is on.""" return None if self._state is None else bool(self._state) def update(self): From 29893d6f6d1fe4f0629dc35f1bac9cb5f30f466c Mon Sep 17 00:00:00 2001 From: konikvranik Date: Tue, 3 Sep 2019 21:54:59 +0200 Subject: [PATCH 24/72] reformatted --- homeassistant/components/rainbird/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rainbird/__init__.py b/homeassistant/components/rainbird/__init__.py index 95d3afd8980596..724b6f7dd61fdd 100644 --- a/homeassistant/components/rainbird/__init__.py +++ b/homeassistant/components/rainbird/__init__.py @@ -11,8 +11,10 @@ DATA_RAINBIRD = "rainbird" DOMAIN = "rainbird" # sensor_type [ description, unit, icon ] -SENSOR_TYPES = {"rainsensor": ["Rainsensor", None, "mdi:water"], - "raindelay": ["Raindelay", None, "mdi:water-off"]} +SENSOR_TYPES = { + "rainsensor": ["Rainsensor", None, "mdi:water"], + "raindelay": ["Raindelay", None, "mdi:water-off"], +} CONFIG_SCHEMA = vol.Schema( { From 6851474764bdacf0140a23e924a0fe8fa543efa3 Mon Sep 17 00:00:00 2001 From: David Bonnes Date: Sun, 1 Sep 2019 11:45:41 +0100 Subject: [PATCH 25/72] Change evohome to asyncio client (#26042) * fully async now * add convergence (call update() 2 seconds after client API call) (issue#25400) * handle dead TRVs (e.g. flat battery) --- homeassistant/components/evohome/__init__.py | 146 +++++++++--------- homeassistant/components/evohome/climate.py | 94 +++++------ .../components/evohome/manifest.json | 2 +- .../components/evohome/water_heater.py | 31 ++-- requirements_all.txt | 2 +- requirements_test_all.txt | 3 - 6 files changed, 135 insertions(+), 143 deletions(-) diff --git a/homeassistant/components/evohome/__init__.py b/homeassistant/components/evohome/__init__.py index 0530878236236a..adb6e856984079 100644 --- a/homeassistant/components/evohome/__init__.py +++ b/homeassistant/components/evohome/__init__.py @@ -2,14 +2,13 @@ Such systems include evohome (multi-zone), and Round Thermostat (single zone). """ -import asyncio from datetime import datetime, timedelta import logging from typing import Any, Dict, Optional, Tuple -import requests.exceptions +import aiohttp.client_exceptions import voluptuous as vol -import evohomeclient2 +import evohomeasync2 from homeassistant.const import ( CONF_ACCESS_TOKEN, @@ -21,17 +20,10 @@ TEMP_CELSIUS, ) from homeassistant.core import callback +from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.discovery import load_platform -from homeassistant.helpers.dispatcher import ( - async_dispatcher_connect, - async_dispatcher_send, -) +from homeassistant.helpers.discovery import async_load_platform from homeassistant.helpers.entity import Entity -from homeassistant.helpers.event import ( - async_track_point_in_utc_time, - track_time_interval, -) from homeassistant.helpers.typing import ConfigType, HomeAssistantType from homeassistant.util.dt import parse_datetime, utcnow @@ -81,55 +73,60 @@ def _handle_exception(err) -> bool: try: raise err - except evohomeclient2.AuthenticationError: + except evohomeasync2.AuthenticationError: _LOGGER.error( "Failed to (re)authenticate with the vendor's server. " + "Check your network and the vendor's service status page. " "Check that your username and password are correct. " "Message is: %s", err, ) return False - except requests.exceptions.ConnectionError: + except aiohttp.ClientConnectionError: # this appears to be common with Honeywell's servers _LOGGER.warning( "Unable to connect with the vendor's server. " - "Check your network and the vendor's status page." + "Check your network and the vendor's service status page. " "Message is: %s", err, ) return False - except requests.exceptions.HTTPError: - if err.response.status_code == HTTP_SERVICE_UNAVAILABLE: + except aiohttp.ClientResponseError: + if err.status == HTTP_SERVICE_UNAVAILABLE: _LOGGER.warning( - "Vendor says their server is currently unavailable. " - "Check the vendor's status page." + "The vendor says their server is currently unavailable. " + "Check the vendor's service status page." ) return False - if err.response.status_code == HTTP_TOO_MANY_REQUESTS: + if err.status == HTTP_TOO_MANY_REQUESTS: _LOGGER.warning( "The vendor's API rate limit has been exceeded. " - "Consider increasing the %s.", + "If this message persists, consider increasing the %s.", CONF_SCAN_INTERVAL, ) return False - raise # we don't expect/handle any other HTTPErrors + raise # we don't expect/handle any other ClientResponseError -def setup(hass: HomeAssistantType, hass_config: ConfigType) -> bool: +async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: """Create a (EMEA/EU-based) Honeywell evohome system.""" - broker = EvoBroker(hass, hass_config[DOMAIN]) - if not broker.init_client(): + broker = EvoBroker(hass, config[DOMAIN]) + if not await broker.init_client(): return False - load_platform(hass, "climate", DOMAIN, {}, hass_config) + hass.async_create_task(async_load_platform(hass, "climate", DOMAIN, {}, config)) if broker.tcs.hotwater: - load_platform(hass, "water_heater", DOMAIN, {}, hass_config) + hass.async_create_task( + async_load_platform(hass, "water_heater", DOMAIN, {}, config) + ) - track_time_interval(hass, broker.update, hass_config[DOMAIN][CONF_SCAN_INTERVAL]) + hass.helpers.event.async_track_time_interval( + broker.update, config[DOMAIN][CONF_SCAN_INTERVAL] + ) return True @@ -141,8 +138,7 @@ def __init__(self, hass, params) -> None: """Initialize the evohome client and data structure.""" self.hass = hass self.params = params - - self.config = self.status = self.timers = {} + self.config = {} self.client = self.tcs = None self._app_storage = {} @@ -150,32 +146,31 @@ def __init__(self, hass, params) -> None: hass.data[DOMAIN] = {} hass.data[DOMAIN]["broker"] = self - def init_client(self) -> bool: + async def init_client(self) -> bool: """Initialse the evohome data broker. Return True if this is successful, otherwise return False. """ - refresh_token, access_token, access_token_expires = asyncio.run_coroutine_threadsafe( - self._load_auth_tokens(), self.hass.loop - ).result() + refresh_token, access_token, access_token_expires = ( + await self._load_auth_tokens() + ) - # evohomeclient2 uses naive/local datetimes + # evohomeasync2 uses naive/local datetimes if access_token_expires is not None: access_token_expires = _utc_to_local_dt(access_token_expires) - try: - client = self.client = evohomeclient2.EvohomeClient( - self.params[CONF_USERNAME], - self.params[CONF_PASSWORD], - refresh_token=refresh_token, - access_token=access_token, - access_token_expires=access_token_expires, - ) + client = self.client = evohomeasync2.EvohomeClient( + self.params[CONF_USERNAME], + self.params[CONF_PASSWORD], + refresh_token=refresh_token, + access_token=access_token, + access_token_expires=access_token_expires, + session=async_get_clientsession(self.hass), + ) - except ( - requests.exceptions.RequestException, - evohomeclient2.AuthenticationError, - ) as err: + try: + await client.login() + except (aiohttp.ClientError, evohomeasync2.AuthenticationError) as err: if not _handle_exception(err): return False @@ -200,17 +195,14 @@ def init_client(self) -> bool: return False self.tcs = ( - client.locations[loc_idx] # noqa: E501; pylint: disable=protected-access + client.locations[loc_idx] # pylint: disable=protected-access ._gateways[0] ._control_systems[0] ) _LOGGER.debug("Config = %s", self.config) - if _LOGGER.isEnabledFor(logging.DEBUG): - # don't do an I/O unless required - _LOGGER.debug( - "Status = %s", client.locations[loc_idx].status()[GWS][0][TCS][0] - ) + if _LOGGER.isEnabledFor(logging.DEBUG): # don't do an I/O unless required + await self.update() # includes: _LOGGER.debug("Status = %s"... return True @@ -237,7 +229,7 @@ async def _load_auth_tokens( return (None, None, None) # account switched: so tokens wont be valid async def _save_auth_tokens(self, *args) -> None: - # evohomeclient2 uses naive/local datetimes + # evohomeasync2 uses naive/local datetimes access_token_expires = _local_dt_to_utc(self.client.access_token_expires) self._app_storage[CONF_USERNAME] = self.params[CONF_USERNAME] @@ -248,13 +240,12 @@ async def _save_auth_tokens(self, *args) -> None: store = self.hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY) await store.async_save(self._app_storage) - async_track_point_in_utc_time( - self.hass, + self.hass.helpers.event.async_track_point_in_utc_time( self._save_auth_tokens, access_token_expires + self.params[CONF_SCAN_INTERVAL], ) - def update(self, *args, **kwargs) -> None: + async def update(self, *args, **kwargs) -> None: """Get the latest state data of the entire evohome Location. This includes state data for the Controller and all its child devices, @@ -264,19 +255,16 @@ def update(self, *args, **kwargs) -> None: loc_idx = self.params[CONF_LOCATION_IDX] try: - status = self.client.locations[loc_idx].status()[GWS][0][TCS][0] - except ( - requests.exceptions.RequestException, - evohomeclient2.AuthenticationError, - ) as err: + status = await self.client.locations[loc_idx].status() + except (aiohttp.ClientError, evohomeasync2.AuthenticationError) as err: _handle_exception(err) else: - self.timers["statusUpdated"] = utcnow() - - _LOGGER.debug("Status = %s", status) - # inform the evohome devices that state data has been updated - async_dispatcher_send(self.hass, DOMAIN, {"signal": "refresh"}) + self.hass.helpers.dispatcher.async_dispatcher_send( + DOMAIN, {"signal": "refresh"} + ) + + _LOGGER.debug("Status = %s", status[GWS][0][TCS][0]) class EvoDevice(Entity): @@ -289,6 +277,7 @@ class EvoDevice(Entity): def __init__(self, evo_broker, evo_device) -> None: """Initialize the evohome entity.""" self._evo_device = evo_device + self._evo_broker = evo_broker self._evo_tcs = evo_broker.tcs self._name = self._icon = self._precision = None @@ -387,7 +376,7 @@ def supported_features(self) -> int: async def async_added_to_hass(self) -> None: """Run when entity about to be added to hass.""" - async_dispatcher_connect(self.hass, DOMAIN, self._refresh) + self.hass.helpers.dispatcher.async_dispatcher_connect(DOMAIN, self._refresh) @property def precision(self) -> float: @@ -399,14 +388,27 @@ def temperature_unit(self) -> str: """Return the temperature unit to use in the frontend UI.""" return TEMP_CELSIUS - def _update_schedule(self) -> None: + async def _call_client_api(self, api_function) -> None: + try: + await api_function + except (aiohttp.ClientError, evohomeasync2.AuthenticationError) as err: + _handle_exception(err) + + self.hass.helpers.event.async_call_later( + 2, self._evo_broker.update() + ) # call update() in 2 seconds + + async def _update_schedule(self) -> None: """Get the latest state data.""" if ( not self._schedule.get("DailySchedules") or parse_datetime(self.setpoints["next"]["from"]) < utcnow() ): - self._schedule = self._evo_device.schedule() + try: + self._schedule = await self._evo_device.schedule() + except (aiohttp.ClientError, evohomeasync2.AuthenticationError) as err: + _handle_exception(err) - def update(self) -> None: + async def async_update(self) -> None: """Get the latest state data.""" - self._update_schedule() + await self._update_schedule() diff --git a/homeassistant/components/evohome/climate.py b/homeassistant/components/evohome/climate.py index d1b9d5f54c799a..0264f76f38f5db 100644 --- a/homeassistant/components/evohome/climate.py +++ b/homeassistant/components/evohome/climate.py @@ -3,9 +3,6 @@ import logging from typing import Any, Dict, Optional, List -import requests.exceptions -import evohomeclient2 - from homeassistant.components.climate import ClimateDevice from homeassistant.components.climate.const import ( CURRENT_HVAC_HEAT, @@ -25,7 +22,7 @@ from homeassistant.helpers.typing import ConfigType, HomeAssistantType from homeassistant.util.dt import parse_datetime -from . import CONF_LOCATION_IDX, _handle_exception, EvoDevice +from . import CONF_LOCATION_IDX, EvoDevice from .const import ( DOMAIN, EVO_RESET, @@ -65,10 +62,13 @@ HA_PRESET_TO_EVO = {v: k for k, v in EVO_PRESET_TO_HA.items()} -def setup_platform( - hass: HomeAssistantType, hass_config: ConfigType, add_entities, discovery_info=None +async def async_setup_platform( + hass: HomeAssistantType, config: ConfigType, async_add_entities, discovery_info=None ) -> None: """Create the evohome Controller, and its Zones, if any.""" + if discovery_info is None: + return + broker = hass.data[DOMAIN]["broker"] loc_idx = broker.params[CONF_LOCATION_IDX] @@ -91,7 +91,7 @@ def setup_platform( zone.name, ) - add_entities([EvoThermostat(broker, zone)], update_before_add=True) + async_add_entities([EvoThermostat(broker, zone)], update_before_add=True) return controller = EvoController(broker, broker.tcs) @@ -107,7 +107,7 @@ def setup_platform( ) zones.append(EvoZone(broker, zone)) - add_entities([controller] + zones, update_before_add=True) + async_add_entities([controller] + zones, update_before_add=True) class EvoClimateDevice(EvoDevice, ClimateDevice): @@ -119,22 +119,18 @@ def __init__(self, evo_broker, evo_device) -> None: self._preset_modes = None - def _set_temperature( + async def _set_temperature( self, temperature: float, until: Optional[datetime] = None ) -> None: """Set a new target temperature for the Zone. until == None means indefinitely (i.e. PermanentOverride) """ - try: + await self._call_client_api( self._evo_device.set_temperature(temperature, until) - except ( - requests.exceptions.RequestException, - evohomeclient2.AuthenticationError, - ) as err: - _handle_exception(err) + ) - def _set_zone_mode(self, op_mode: str) -> None: + async def _set_zone_mode(self, op_mode: str) -> None: """Set a Zone to one of its native EVO_* operating modes. Zones inherit their _effective_ operating mode from the Controller. @@ -153,35 +149,24 @@ def _set_zone_mode(self, op_mode: str) -> None: (by default) 5C, and 'Away', Zones to (by default) 12C. """ if op_mode == EVO_FOLLOW: - try: - self._evo_device.cancel_temp_override() - except ( - requests.exceptions.RequestException, - evohomeclient2.AuthenticationError, - ) as err: - _handle_exception(err) + await self._call_client_api(self._evo_device.cancel_temp_override()) return temperature = self._evo_device.setpointStatus["targetHeatTemperature"] until = None # EVO_PERMOVER if op_mode == EVO_TEMPOVER and self._schedule["DailySchedules"]: - self._update_schedule() + await self._update_schedule() if self._schedule["DailySchedules"]: until = parse_datetime(self.setpoints["next"]["from"]) - self._set_temperature(temperature, until=until) + await self._set_temperature(temperature, until=until) - def _set_tcs_mode(self, op_mode: str) -> None: + async def _set_tcs_mode(self, op_mode: str) -> None: """Set the Controller to any of its native EVO_* operating modes.""" - try: - # noqa: E501; pylint: disable=protected-access - self._evo_tcs._set_status(op_mode) - except ( - requests.exceptions.RequestException, - evohomeclient2.AuthenticationError, - ) as err: - _handle_exception(err) + await self._call_client_api( + self._evo_tcs._set_status(op_mode) # pylint: disable=protected-access + ) @property def hvac_modes(self) -> List[str]: @@ -216,6 +201,11 @@ def __init__(self, evo_broker, evo_device) -> None: self._supported_features = SUPPORT_PRESET_MODE | SUPPORT_TARGET_TEMPERATURE self._preset_modes = list(HA_PRESET_TO_EVO) + @property + def available(self) -> bool: + """Return True if entity is available.""" + return self._evo_device.temperatureStatus["isAvailable"] + @property def hvac_mode(self) -> str: """Return the current operating mode of the evohome Zone.""" @@ -276,28 +266,28 @@ def max_temp(self) -> float: """ return self._evo_device.setpointCapabilities["maxHeatSetpoint"] - def set_temperature(self, **kwargs) -> None: + async def async_set_temperature(self, **kwargs) -> None: """Set a new target temperature.""" until = kwargs.get("until") if until: until = parse_datetime(until) - self._set_temperature(kwargs["temperature"], until) + await self._set_temperature(kwargs["temperature"], until) - def set_hvac_mode(self, hvac_mode: str) -> None: + async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Set an operating mode for the Zone.""" if hvac_mode == HVAC_MODE_OFF: - self._set_temperature(self.min_temp, until=None) + await self._set_temperature(self.min_temp, until=None) else: # HVAC_MODE_HEAT - self._set_zone_mode(EVO_FOLLOW) + await self._set_zone_mode(EVO_FOLLOW) - def set_preset_mode(self, preset_mode: Optional[str]) -> None: + async def async_set_preset_mode(self, preset_mode: Optional[str]) -> None: """Set a new preset mode. If preset_mode is None, then revert to following the schedule. """ - self._set_zone_mode(HA_PRESET_TO_EVO.get(preset_mode, EVO_FOLLOW)) + await self._set_zone_mode(HA_PRESET_TO_EVO.get(preset_mode, EVO_FOLLOW)) class EvoController(EvoClimateDevice): @@ -344,25 +334,25 @@ def preset_mode(self) -> Optional[str]: """Return the current preset mode, e.g., home, away, temp.""" return TCS_PRESET_TO_HA.get(self._evo_tcs.systemModeStatus["mode"]) - def set_temperature(self, **kwargs) -> None: + async def async_set_temperature(self, **kwargs) -> None: """Do nothing. The evohome Controller doesn't have a target temperature. """ return - def set_hvac_mode(self, hvac_mode: str) -> None: + async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Set an operating mode for the Controller.""" - self._set_tcs_mode(HA_HVAC_TO_TCS.get(hvac_mode)) + await self._set_tcs_mode(HA_HVAC_TO_TCS.get(hvac_mode)) - def set_preset_mode(self, preset_mode: Optional[str]) -> None: + async def async_set_preset_mode(self, preset_mode: Optional[str]) -> None: """Set a new preset mode. If preset_mode is None, then revert to 'Auto' mode. """ - self._set_tcs_mode(HA_PRESET_TO_TCS.get(preset_mode, EVO_AUTO)) + await self._set_tcs_mode(HA_PRESET_TO_TCS.get(preset_mode, EVO_AUTO)) - def update(self) -> None: + async def async_update(self) -> None: """Get the latest state data.""" return @@ -409,16 +399,16 @@ def preset_mode(self) -> Optional[str]: return super().preset_mode - def set_hvac_mode(self, hvac_mode: str) -> None: + async def async_set_hvac_mode(self, hvac_mode: str) -> None: """Set an operating mode.""" - self._set_tcs_mode(HA_HVAC_TO_TCS.get(hvac_mode)) + await self._set_tcs_mode(HA_HVAC_TO_TCS.get(hvac_mode)) - def set_preset_mode(self, preset_mode: Optional[str]) -> None: + async def async_set_preset_mode(self, preset_mode: Optional[str]) -> None: """Set a new preset mode. If preset_mode is None, then revert to following the schedule. """ if preset_mode in list(HA_PRESET_TO_TCS): - self._set_tcs_mode(HA_PRESET_TO_TCS.get(preset_mode)) + await self._set_tcs_mode(HA_PRESET_TO_TCS.get(preset_mode)) else: - self._set_zone_mode(HA_PRESET_TO_EVO.get(preset_mode, EVO_FOLLOW)) + await self._set_zone_mode(HA_PRESET_TO_EVO.get(preset_mode, EVO_FOLLOW)) diff --git a/homeassistant/components/evohome/manifest.json b/homeassistant/components/evohome/manifest.json index 078d4ace776cf1..32a57cf20b1c77 100644 --- a/homeassistant/components/evohome/manifest.json +++ b/homeassistant/components/evohome/manifest.json @@ -3,7 +3,7 @@ "name": "Evohome", "documentation": "https://www.home-assistant.io/components/evohome", "requirements": [ - "evohomeclient==0.3.3" + "evohome-async==0.3.3b4" ], "dependencies": [], "codeowners": ["@zxdavb"] diff --git a/homeassistant/components/evohome/water_heater.py b/homeassistant/components/evohome/water_heater.py index 6309f07a000c74..1b37bc3b2b58c2 100644 --- a/homeassistant/components/evohome/water_heater.py +++ b/homeassistant/components/evohome/water_heater.py @@ -2,9 +2,6 @@ import logging from typing import List -import requests.exceptions -import evohomeclient2 - from homeassistant.components.water_heater import ( SUPPORT_OPERATION_MODE, WaterHeaterDevice, @@ -12,7 +9,7 @@ from homeassistant.const import PRECISION_WHOLE, STATE_OFF, STATE_ON from homeassistant.util.dt import parse_datetime -from . import _handle_exception, EvoDevice +from . import EvoDevice from .const import DOMAIN, EVO_STRFTIME, EVO_FOLLOW, EVO_TEMPOVER, EVO_PERMOVER _LOGGER = logging.getLogger(__name__) @@ -23,8 +20,13 @@ HA_OPMODE_TO_DHW = {STATE_ON: EVO_FOLLOW, STATE_OFF: EVO_PERMOVER} -def setup_platform(hass, hass_config, add_entities, discovery_info=None) -> None: +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None +) -> None: """Create the DHW controller.""" + if discovery_info is None: + return + broker = hass.data[DOMAIN]["broker"] _LOGGER.debug( @@ -33,7 +35,7 @@ def setup_platform(hass, hass_config, add_entities, discovery_info=None) -> None evo_dhw = EvoDHW(broker, broker.tcs.hotwater) - add_entities([evo_dhw], update_before_add=True) + async_add_entities([evo_dhw], update_before_add=True) class EvoDHW(EvoDevice, WaterHeaterDevice): @@ -58,6 +60,11 @@ def __init__(self, evo_broker, evo_device) -> None: self._supported_features = SUPPORT_OPERATION_MODE self._operation_list = list(HA_OPMODE_TO_DHW) + @property + def available(self) -> bool: + """Return True if entity is available.""" + return self._evo_device.temperatureStatus.get("isAvailable", False) + @property def current_operation(self) -> str: """Return the current operating mode (On, or Off).""" @@ -73,7 +80,7 @@ def current_temperature(self) -> float: """Return the current temperature.""" return self._evo_device.temperatureStatus["temperature"] - def set_operation_mode(self, operation_mode: str) -> None: + async def async_set_operation_mode(self, operation_mode: str) -> None: """Set new operation mode for a DHW controller.""" op_mode = HA_OPMODE_TO_DHW[operation_mode] @@ -81,17 +88,13 @@ def set_operation_mode(self, operation_mode: str) -> None: until = None # EVO_FOLLOW, EVO_PERMOVER if op_mode == EVO_TEMPOVER and self._schedule["DailySchedules"]: - self._update_schedule() + await self._update_schedule() if self._schedule["DailySchedules"]: until = parse_datetime(self.setpoints["next"]["from"]) until = until.strftime(EVO_STRFTIME) data = {"Mode": op_mode, "State": state, "UntilTime": until} - try: + await self._call_client_api( self._evo_device._set_dhw(data) # pylint: disable=protected-access - except ( - requests.exceptions.RequestException, - evohomeclient2.AuthenticationError, - ) as err: - _handle_exception(err) + ) diff --git a/requirements_all.txt b/requirements_all.txt index d097183479445d..b8958a70f39670 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -461,7 +461,7 @@ eternalegypt==0.0.10 # evdev==0.6.1 # homeassistant.components.evohome -evohomeclient==0.3.3 +evohome-async==0.3.3b4 # homeassistant.components.dlib_face_detect # homeassistant.components.dlib_face_identify diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 35125387e89e8b..2111149cb55bfc 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -123,9 +123,6 @@ enocean==0.50 # homeassistant.components.season ephem==3.7.6.0 -# homeassistant.components.evohome -evohomeclient==0.3.3 - # homeassistant.components.feedreader feedparser-homeassistant==5.2.2.dev1 From 4dfad3380602c2758a93d21e63f77073374bffc5 Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Sun, 1 Sep 2019 13:10:58 +0200 Subject: [PATCH 26/72] Upgrade sqlalchemy to 1.3.8 (#26331) --- homeassistant/components/recorder/manifest.json | 2 +- homeassistant/components/sql/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/recorder/manifest.json b/homeassistant/components/recorder/manifest.json index c91b910724c5ff..9ecfa88053fa69 100644 --- a/homeassistant/components/recorder/manifest.json +++ b/homeassistant/components/recorder/manifest.json @@ -3,7 +3,7 @@ "name": "Recorder", "documentation": "https://www.home-assistant.io/components/recorder", "requirements": [ - "sqlalchemy==1.3.7" + "sqlalchemy==1.3.8" ], "dependencies": [], "codeowners": [] diff --git a/homeassistant/components/sql/manifest.json b/homeassistant/components/sql/manifest.json index a489e3fd736764..38a320543a9cca 100644 --- a/homeassistant/components/sql/manifest.json +++ b/homeassistant/components/sql/manifest.json @@ -3,7 +3,7 @@ "name": "Sql", "documentation": "https://www.home-assistant.io/components/sql", "requirements": [ - "sqlalchemy==1.3.7" + "sqlalchemy==1.3.8" ], "dependencies": [], "codeowners": [ diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index a1ffd515c5bfa4..5754e3fc391d6d 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -21,7 +21,7 @@ pytz>=2019.02 pyyaml==5.1.2 requests==2.22.0 ruamel.yaml==0.15.100 -sqlalchemy==1.3.7 +sqlalchemy==1.3.8 voluptuous-serialize==2.2.0 voluptuous==0.11.7 zeroconf==0.23.0 diff --git a/requirements_all.txt b/requirements_all.txt index b8958a70f39670..f5e9dfd083fdaa 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1774,7 +1774,7 @@ spotipy-homeassistant==2.4.4.dev1 # homeassistant.components.recorder # homeassistant.components.sql -sqlalchemy==1.3.7 +sqlalchemy==1.3.8 # homeassistant.components.srp_energy srpenergy==1.0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2111149cb55bfc..f7727bd459b532 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -382,7 +382,7 @@ somecomfort==0.5.2 # homeassistant.components.recorder # homeassistant.components.sql -sqlalchemy==1.3.7 +sqlalchemy==1.3.8 # homeassistant.components.srp_energy srpenergy==1.0.6 From 5693fb0e1c6ef8f2b2009ac9c9bebca7e7e369ca Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sun, 1 Sep 2019 13:15:48 +0200 Subject: [PATCH 27/72] Migrate Axis, deCONZ and UniFi to use config entry subclass (#26173) * Use init_subclass for Config Entries * Pylint cant handle subclass being the only user of imports --- homeassistant/components/axis/config_flow.py | 3 +-- homeassistant/components/deconz/config_flow.py | 3 +-- homeassistant/components/unifi/config_flow.py | 5 ++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/axis/config_flow.py b/homeassistant/components/axis/config_flow.py index 4b54982244be65..f93e49d9818c25 100644 --- a/homeassistant/components/axis/config_flow.py +++ b/homeassistant/components/axis/config_flow.py @@ -56,8 +56,7 @@ def configured_devices(hass): } -@config_entries.HANDLERS.register(DOMAIN) -class AxisFlowHandler(config_entries.ConfigFlow): +class AxisFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a Axis config flow.""" VERSION = 1 diff --git a/homeassistant/components/deconz/config_flow.py b/homeassistant/components/deconz/config_flow.py index 306a4fbf839243..60d47a0a4e22b6 100644 --- a/homeassistant/components/deconz/config_flow.py +++ b/homeassistant/components/deconz/config_flow.py @@ -43,8 +43,7 @@ def get_master_gateway(hass): return gateway -@config_entries.HANDLERS.register(DOMAIN) -class DeconzFlowHandler(config_entries.ConfigFlow): +class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a deCONZ config flow.""" VERSION = 1 diff --git a/homeassistant/components/unifi/config_flow.py b/homeassistant/components/unifi/config_flow.py index e1f0a91c774eb1..c885f30af231e4 100644 --- a/homeassistant/components/unifi/config_flow.py +++ b/homeassistant/components/unifi/config_flow.py @@ -11,7 +11,7 @@ CONF_VERIFY_SSL, ) -from .const import ( +from .const import ( # pylint: disable=unused-import CONF_CONTROLLER, CONF_TRACK_CLIENTS, CONF_TRACK_DEVICES, @@ -33,8 +33,7 @@ DEFAULT_VERIFY_SSL = False -@config_entries.HANDLERS.register(DOMAIN) -class UnifiFlowHandler(config_entries.ConfigFlow): +class UnifiFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a UniFi config flow.""" VERSION = 1 From a7226bc7a88313385019cfdf2062e33ddc0f216c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Sun, 1 Sep 2019 15:22:50 +0300 Subject: [PATCH 28/72] Upgrade tibber library (#26332) --- homeassistant/components/tibber/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/tibber/manifest.json b/homeassistant/components/tibber/manifest.json index 1985a85999b14a..d0f358c5902bec 100644 --- a/homeassistant/components/tibber/manifest.json +++ b/homeassistant/components/tibber/manifest.json @@ -3,7 +3,7 @@ "name": "Tibber", "documentation": "https://www.home-assistant.io/components/tibber", "requirements": [ - "pyTibber==0.11.6" + "pyTibber==0.11.7" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index f5e9dfd083fdaa..3ca134fbd62471 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1029,7 +1029,7 @@ pyRFXtrx==0.23 # pySwitchmate==0.4.6 # homeassistant.components.tibber -pyTibber==0.11.6 +pyTibber==0.11.7 # homeassistant.components.dlink pyW215==0.6.0 From 8df39246dd89361a87e40b862fae8b4c6e098425 Mon Sep 17 00:00:00 2001 From: fmartens <17504441+fmartens@users.noreply.github.com> Date: Sun, 1 Sep 2019 17:52:43 +0200 Subject: [PATCH 29/72] Inverted rflink cover (#26038) * Added InvertedRflinkCover class to support COCO/KAKU ASUN-650 devices * Rename TYPE_NORMAL to TYPE_STANDARD * Cleaning up code and removed unused imports * Added unit tests for InvertedRflinkCover * less if/else statements * Autoresolve type for newkaku * Updated tests for InvertedRflinkCover * Added unit test for standard cover without specifying type * Updated comments in unit tests * Updated unit test configuration and comments to be more explanatory * Restore variable names in first part of the unit test that have been changed during a search and replace * Reformated the code according to 4de97ab * remove blank lines at end of rflink test_cover.py * Replace single with double quote in test_cover.py * Replaced single quotes with double qoutes and fixed formatting * Black improvements * Reformated the code of the unit test. * entity_type_for_device_id should return 'TYPE_STANDARD' instead of 'None' --- homeassistant/components/rflink/cover.py | 56 ++- tests/components/rflink/test_cover.py | 412 +++++++++++++++++++++++ 2 files changed, 466 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rflink/cover.py b/homeassistant/components/rflink/cover.py index 7e6de0ec03b5dc..f41c4cde2f7d3f 100644 --- a/homeassistant/components/rflink/cover.py +++ b/homeassistant/components/rflink/cover.py @@ -4,7 +4,7 @@ import voluptuous as vol from homeassistant.components.cover import PLATFORM_SCHEMA, CoverDevice -from homeassistant.const import CONF_NAME, STATE_OPEN +from homeassistant.const import CONF_NAME, CONF_TYPE, STATE_OPEN import homeassistant.helpers.config_validation as cv from homeassistant.helpers.restore_state import RestoreEntity @@ -23,6 +23,8 @@ _LOGGER = logging.getLogger(__name__) +TYPE_STANDARD = "standard" +TYPE_INVERTED = "inverted" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { @@ -33,6 +35,7 @@ { cv.string: { vol.Optional(CONF_NAME): cv.string, + vol.Optional(CONF_TYPE): vol.Any(TYPE_STANDARD, TYPE_INVERTED), vol.Optional(CONF_ALIASES, default=[]): vol.All( cv.ensure_list, [cv.string] ), @@ -52,12 +55,51 @@ ) +def entity_type_for_device_id(device_id): + """Return entity class for protocol of a given device_id. + + Async friendly. + """ + entity_type_mapping = { + # KlikAanKlikUit cover have the controls inverted + "newkaku": TYPE_INVERTED + } + protocol = device_id.split("_")[0] + return entity_type_mapping.get(protocol, TYPE_STANDARD) + + +def entity_class_for_type(entity_type): + """Translate entity type to entity class. + + Async friendly. + """ + entity_device_mapping = { + # default cover implementation + TYPE_STANDARD: RflinkCover, + # cover with open/close commands inverted + # like KAKU/COCO ASUN-650 + TYPE_INVERTED: InvertedRflinkCover, + } + + return entity_device_mapping.get(entity_type, RflinkCover) + + def devices_from_config(domain_config): """Parse configuration and add Rflink cover devices.""" devices = [] for device_id, config in domain_config[CONF_DEVICES].items(): + # Determine what kind of entity to create, RflinkCover + # or InvertedRflinkCover + if CONF_TYPE in config: + # Remove type from config to not pass it as and argument + # to entity instantiation + entity_type = config.pop(CONF_TYPE) + else: + entity_type = entity_type_for_device_id(device_id) + + entity_class = entity_class_for_type(entity_type) device_config = dict(domain_config[CONF_DEVICE_DEFAULTS], **config) - device = RflinkCover(device_id, **device_config) + device = entity_class(device_id, **device_config) devices.append(device) return devices @@ -115,3 +157,13 @@ def async_open_cover(self, **kwargs): def async_stop_cover(self, **kwargs): """Turn the device stop.""" return self._async_handle_command("stop_cover") + + +class InvertedRflinkCover(RflinkCover): + """Rflink cover that has inverted open/close commands.""" + + async def _async_send_command(self, cmd, repetitions): + """Will invert only the UP/DOWN commands.""" + _LOGGER.debug("Getting command: %s for Rflink device: %s", cmd, self._device_id) + cmd_inv = {"UP": "DOWN", "DOWN": "UP"} + await super()._async_send_command(cmd_inv.get(cmd, cmd), repetitions) diff --git a/tests/components/rflink/test_cover.py b/tests/components/rflink/test_cover.py index e4b3154a4c43c3..858258e7efd0c4 100644 --- a/tests/components/rflink/test_cover.py +++ b/tests/components/rflink/test_cover.py @@ -390,3 +390,415 @@ async def test_restore_state(hass, monkeypatch): assert state assert state.state == STATE_CLOSED assert state.attributes["assumed_state"] + + +# The code checks the ID, it will use the +# 'inverted' class when the name starts with +# 'newkaku' +async def test_inverted_cover(hass, monkeypatch): + """Ensure states are restored on startup.""" + config = { + "rflink": {"port": "/dev/ttyABC0"}, + DOMAIN: { + "platform": "rflink", + "devices": { + "nonkaku_device_1": { + "name": "nonkaku_type_standard", + "type": "standard", + }, + "nonkaku_device_2": {"name": "nonkaku_type_none"}, + "nonkaku_device_3": { + "name": "nonkaku_type_inverted", + "type": "inverted", + }, + "newkaku_device_4": { + "name": "newkaku_type_standard", + "type": "standard", + }, + "newkaku_device_5": {"name": "newkaku_type_none"}, + "newkaku_device_6": { + "name": "newkaku_type_inverted", + "type": "inverted", + }, + }, + }, + } + + # setup mocking rflink module + event_callback, _, protocol, _ = await mock_rflink( + hass, config, DOMAIN, monkeypatch + ) + + # test default state of cover loaded from config + standard_cover = hass.states.get(DOMAIN + ".nonkaku_type_standard") + assert standard_cover.state == STATE_CLOSED + assert standard_cover.attributes["assumed_state"] + + # mock incoming up command event for nonkaku_device_1 + event_callback({"id": "nonkaku_device_1", "command": "up"}) + await hass.async_block_till_done() + + standard_cover = hass.states.get(DOMAIN + ".nonkaku_type_standard") + assert standard_cover.state == STATE_OPEN + assert standard_cover.attributes.get("assumed_state") + + # mock incoming up command event for nonkaku_device_2 + event_callback({"id": "nonkaku_device_2", "command": "up"}) + await hass.async_block_till_done() + + standard_cover = hass.states.get(DOMAIN + ".nonkaku_type_none") + assert standard_cover.state == STATE_OPEN + assert standard_cover.attributes.get("assumed_state") + + # mock incoming up command event for nonkaku_device_3 + event_callback({"id": "nonkaku_device_3", "command": "up"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".nonkaku_type_inverted") + assert inverted_cover.state == STATE_OPEN + assert inverted_cover.attributes.get("assumed_state") + + # mock incoming up command event for newkaku_device_4 + event_callback({"id": "newkaku_device_4", "command": "up"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_standard") + assert inverted_cover.state == STATE_OPEN + assert inverted_cover.attributes.get("assumed_state") + + # mock incoming up command event for newkaku_device_5 + event_callback({"id": "newkaku_device_5", "command": "up"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_none") + assert inverted_cover.state == STATE_OPEN + assert inverted_cover.attributes.get("assumed_state") + + # mock incoming up command event for newkaku_device_6 + event_callback({"id": "newkaku_device_6", "command": "up"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_inverted") + assert inverted_cover.state == STATE_OPEN + assert inverted_cover.attributes.get("assumed_state") + + # mock incoming down command event for nonkaku_device_1 + event_callback({"id": "nonkaku_device_1", "command": "down"}) + + await hass.async_block_till_done() + + standard_cover = hass.states.get(DOMAIN + ".nonkaku_type_standard") + assert standard_cover.state == STATE_CLOSED + assert standard_cover.attributes.get("assumed_state") + + # mock incoming down command event for nonkaku_device_2 + event_callback({"id": "nonkaku_device_2", "command": "down"}) + + await hass.async_block_till_done() + + standard_cover = hass.states.get(DOMAIN + ".nonkaku_type_none") + assert standard_cover.state == STATE_CLOSED + assert standard_cover.attributes.get("assumed_state") + + # mock incoming down command event for nonkaku_device_3 + event_callback({"id": "nonkaku_device_3", "command": "down"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".nonkaku_type_inverted") + assert inverted_cover.state == STATE_CLOSED + assert inverted_cover.attributes.get("assumed_state") + + # mock incoming down command event for newkaku_device_4 + event_callback({"id": "newkaku_device_4", "command": "down"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_standard") + assert inverted_cover.state == STATE_CLOSED + assert inverted_cover.attributes.get("assumed_state") + + # mock incoming down command event for newkaku_device_5 + event_callback({"id": "newkaku_device_5", "command": "down"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_none") + assert inverted_cover.state == STATE_CLOSED + assert inverted_cover.attributes.get("assumed_state") + + # mock incoming down command event for newkaku_device_6 + event_callback({"id": "newkaku_device_6", "command": "down"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_inverted") + assert inverted_cover.state == STATE_CLOSED + assert inverted_cover.attributes.get("assumed_state") + + # We are only testing the 'inverted' devices, the 'standard' devices + # are already covered by other test cases. + + # should respond to group command + event_callback({"id": "nonkaku_device_3", "command": "alloff"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".nonkaku_type_inverted") + assert inverted_cover.state == STATE_CLOSED + + # should respond to group command + event_callback({"id": "nonkaku_device_3", "command": "allon"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".nonkaku_type_inverted") + assert inverted_cover.state == STATE_OPEN + + # should respond to group command + event_callback({"id": "newkaku_device_4", "command": "alloff"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_standard") + assert inverted_cover.state == STATE_CLOSED + + # should respond to group command + event_callback({"id": "newkaku_device_4", "command": "allon"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_standard") + assert inverted_cover.state == STATE_OPEN + + # should respond to group command + event_callback({"id": "newkaku_device_5", "command": "alloff"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_none") + assert inverted_cover.state == STATE_CLOSED + + # should respond to group command + event_callback({"id": "newkaku_device_5", "command": "allon"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_none") + assert inverted_cover.state == STATE_OPEN + + # should respond to group command + event_callback({"id": "newkaku_device_6", "command": "alloff"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_inverted") + assert inverted_cover.state == STATE_CLOSED + + # should respond to group command + event_callback({"id": "newkaku_device_6", "command": "allon"}) + + await hass.async_block_till_done() + + inverted_cover = hass.states.get(DOMAIN + ".newkaku_type_inverted") + assert inverted_cover.state == STATE_OPEN + + # Sending the close command from HA should result + # in an 'DOWN' command sent to a non-newkaku device + # that has its type set to 'standard'. + hass.async_create_task( + hass.services.async_call( + DOMAIN, + SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: DOMAIN + ".nonkaku_type_standard"}, + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".nonkaku_type_standard").state == STATE_CLOSED + assert protocol.send_command_ack.call_args_list[0][0][0] == "nonkaku_device_1" + assert protocol.send_command_ack.call_args_list[0][0][1] == "DOWN" + + # Sending the open command from HA should result + # in an 'UP' command sent to a non-newkaku device + # that has its type set to 'standard'. + hass.async_create_task( + hass.services.async_call( + DOMAIN, + SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: DOMAIN + ".nonkaku_type_standard"}, + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".nonkaku_type_standard").state == STATE_OPEN + assert protocol.send_command_ack.call_args_list[1][0][0] == "nonkaku_device_1" + assert protocol.send_command_ack.call_args_list[1][0][1] == "UP" + + # Sending the close command from HA should result + # in an 'DOWN' command sent to a non-newkaku device + # that has its type not specified. + hass.async_create_task( + hass.services.async_call( + DOMAIN, SERVICE_CLOSE_COVER, {ATTR_ENTITY_ID: DOMAIN + ".nonkaku_type_none"} + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".nonkaku_type_none").state == STATE_CLOSED + assert protocol.send_command_ack.call_args_list[2][0][0] == "nonkaku_device_2" + assert protocol.send_command_ack.call_args_list[2][0][1] == "DOWN" + + # Sending the open command from HA should result + # in an 'UP' command sent to a non-newkaku device + # that has its type not specified. + hass.async_create_task( + hass.services.async_call( + DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: DOMAIN + ".nonkaku_type_none"} + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".nonkaku_type_none").state == STATE_OPEN + assert protocol.send_command_ack.call_args_list[3][0][0] == "nonkaku_device_2" + assert protocol.send_command_ack.call_args_list[3][0][1] == "UP" + + # Sending the close command from HA should result + # in an 'UP' command sent to a non-newkaku device + # that has its type set to 'inverted'. + hass.async_create_task( + hass.services.async_call( + DOMAIN, + SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: DOMAIN + ".nonkaku_type_inverted"}, + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".nonkaku_type_inverted").state == STATE_CLOSED + assert protocol.send_command_ack.call_args_list[4][0][0] == "nonkaku_device_3" + assert protocol.send_command_ack.call_args_list[4][0][1] == "UP" + + # Sending the open command from HA should result + # in an 'DOWN' command sent to a non-newkaku device + # that has its type set to 'inverted'. + hass.async_create_task( + hass.services.async_call( + DOMAIN, + SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: DOMAIN + ".nonkaku_type_inverted"}, + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".nonkaku_type_inverted").state == STATE_OPEN + assert protocol.send_command_ack.call_args_list[5][0][0] == "nonkaku_device_3" + assert protocol.send_command_ack.call_args_list[5][0][1] == "DOWN" + + # Sending the close command from HA should result + # in an 'DOWN' command sent to a newkaku device + # that has its type set to 'standard'. + hass.async_create_task( + hass.services.async_call( + DOMAIN, + SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: DOMAIN + ".newkaku_type_standard"}, + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".newkaku_type_standard").state == STATE_CLOSED + assert protocol.send_command_ack.call_args_list[6][0][0] == "newkaku_device_4" + assert protocol.send_command_ack.call_args_list[6][0][1] == "DOWN" + + # Sending the open command from HA should result + # in an 'UP' command sent to a newkaku device + # that has its type set to 'standard'. + hass.async_create_task( + hass.services.async_call( + DOMAIN, + SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: DOMAIN + ".newkaku_type_standard"}, + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".newkaku_type_standard").state == STATE_OPEN + assert protocol.send_command_ack.call_args_list[7][0][0] == "newkaku_device_4" + assert protocol.send_command_ack.call_args_list[7][0][1] == "UP" + + # Sending the close command from HA should result + # in an 'UP' command sent to a newkaku device + # that has its type not specified. + hass.async_create_task( + hass.services.async_call( + DOMAIN, SERVICE_CLOSE_COVER, {ATTR_ENTITY_ID: DOMAIN + ".newkaku_type_none"} + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".newkaku_type_none").state == STATE_CLOSED + assert protocol.send_command_ack.call_args_list[8][0][0] == "newkaku_device_5" + assert protocol.send_command_ack.call_args_list[8][0][1] == "UP" + + # Sending the open command from HA should result + # in an 'DOWN' command sent to a newkaku device + # that has its type not specified. + hass.async_create_task( + hass.services.async_call( + DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: DOMAIN + ".newkaku_type_none"} + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".newkaku_type_none").state == STATE_OPEN + assert protocol.send_command_ack.call_args_list[9][0][0] == "newkaku_device_5" + assert protocol.send_command_ack.call_args_list[9][0][1] == "DOWN" + + # Sending the close command from HA should result + # in an 'UP' command sent to a newkaku device + # that has its type set to 'inverted'. + hass.async_create_task( + hass.services.async_call( + DOMAIN, + SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: DOMAIN + ".newkaku_type_inverted"}, + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".newkaku_type_inverted").state == STATE_CLOSED + assert protocol.send_command_ack.call_args_list[10][0][0] == "newkaku_device_6" + assert protocol.send_command_ack.call_args_list[10][0][1] == "UP" + + # Sending the open command from HA should result + # in an 'DOWN' command sent to a newkaku device + # that has its type set to 'inverted'. + hass.async_create_task( + hass.services.async_call( + DOMAIN, + SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: DOMAIN + ".newkaku_type_inverted"}, + ) + ) + + await hass.async_block_till_done() + + assert hass.states.get(DOMAIN + ".newkaku_type_inverted").state == STATE_OPEN + assert protocol.send_command_ack.call_args_list[11][0][0] == "newkaku_device_6" + assert protocol.send_command_ack.call_args_list[11][0][1] == "DOWN" From 7bcb21498cf50a9cd41c16af3eecd0c460af35f6 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sun, 1 Sep 2019 17:57:25 +0200 Subject: [PATCH 30/72] UniFi - Simplify getting controller from config entry (#26335) * Simplify getting controller from config entry * Lint ignore no longer needed * Fix tests --- homeassistant/components/unifi/__init__.py | 15 +++++-------- homeassistant/components/unifi/config_flow.py | 22 ++++++++++++++++--- .../components/unifi/device_tracker.py | 9 ++------ homeassistant/components/unifi/switch.py | 11 ++-------- tests/components/unifi/test_device_tracker.py | 3 ++- tests/components/unifi/test_init.py | 8 +++++-- tests/components/unifi/test_switch.py | 3 ++- 7 files changed, 38 insertions(+), 33 deletions(-) diff --git a/homeassistant/components/unifi/__init__.py b/homeassistant/components/unifi/__init__.py index 5ad60ddd835af8..db6358285296a3 100644 --- a/homeassistant/components/unifi/__init__.py +++ b/homeassistant/components/unifi/__init__.py @@ -1,6 +1,9 @@ """Support for devices connected to UniFi POE.""" import voluptuous as vol +from homeassistant.components.unifi.config_flow import ( + get_controller_id_from_config_entry, +) from homeassistant.const import CONF_HOST from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC @@ -9,14 +12,12 @@ from .const import ( ATTR_MANUFACTURER, CONF_BLOCK_CLIENT, - CONF_CONTROLLER, CONF_DETECTION_TIME, CONF_DONT_TRACK_CLIENTS, CONF_DONT_TRACK_DEVICES, CONF_DONT_TRACK_WIRED_CLIENTS, CONF_SITE_ID, CONF_SSID_FILTER, - CONTROLLER_ID, DOMAIN, UNIFI_CONFIG, ) @@ -70,10 +71,7 @@ async def async_setup_entry(hass, config_entry): controller = UniFiController(hass, config_entry) - controller_id = CONTROLLER_ID.format( - host=config_entry.data[CONF_CONTROLLER][CONF_HOST], - site=config_entry.data[CONF_CONTROLLER][CONF_SITE_ID], - ) + controller_id = get_controller_id_from_config_entry(config_entry) hass.data[DOMAIN][controller_id] = controller @@ -98,9 +96,6 @@ async def async_setup_entry(hass, config_entry): async def async_unload_entry(hass, config_entry): """Unload a config entry.""" - controller_id = CONTROLLER_ID.format( - host=config_entry.data[CONF_CONTROLLER][CONF_HOST], - site=config_entry.data[CONF_CONTROLLER][CONF_SITE_ID], - ) + controller_id = get_controller_id_from_config_entry(config_entry) controller = hass.data[DOMAIN].pop(controller_id) return await controller.async_reset() diff --git a/homeassistant/components/unifi/config_flow.py b/homeassistant/components/unifi/config_flow.py index c885f30af231e4..00b003746a2568 100644 --- a/homeassistant/components/unifi/config_flow.py +++ b/homeassistant/components/unifi/config_flow.py @@ -11,13 +11,14 @@ CONF_VERIFY_SSL, ) -from .const import ( # pylint: disable=unused-import +from .const import ( CONF_CONTROLLER, + CONF_DETECTION_TIME, + CONF_SITE_ID, CONF_TRACK_CLIENTS, CONF_TRACK_DEVICES, CONF_TRACK_WIRED_CLIENTS, - CONF_DETECTION_TIME, - CONF_SITE_ID, + CONTROLLER_ID, DEFAULT_TRACK_CLIENTS, DEFAULT_TRACK_DEVICES, DEFAULT_TRACK_WIRED_CLIENTS, @@ -33,6 +34,21 @@ DEFAULT_VERIFY_SSL = False +@callback +def get_controller_id_from_config_entry(config_entry): + """Return controller with a matching bridge id.""" + return CONTROLLER_ID.format( + host=config_entry.data[CONF_CONTROLLER][CONF_HOST], + site=config_entry.data[CONF_CONTROLLER][CONF_SITE_ID], + ) + + +@callback +def get_controller_from_config_entry(hass, config_entry): + """Return controller with a matching bridge id.""" + return hass.data[DOMAIN][get_controller_id_from_config_entry(config_entry)] + + class UnifiFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a UniFi config flow.""" diff --git a/homeassistant/components/unifi/device_tracker.py b/homeassistant/components/unifi/device_tracker.py index c4451546776b2c..1f4aef754adc0b 100644 --- a/homeassistant/components/unifi/device_tracker.py +++ b/homeassistant/components/unifi/device_tracker.py @@ -5,7 +5,7 @@ import voluptuous as vol from homeassistant import config_entries -from homeassistant.components import unifi +from homeassistant.components.unifi.config_flow import get_controller_from_config_entry from homeassistant.components.device_tracker import DOMAIN, PLATFORM_SCHEMA from homeassistant.components.device_tracker.config_entry import ScannerEntity from homeassistant.components.device_tracker.const import SOURCE_TYPE_ROUTER @@ -29,7 +29,6 @@ ATTR_MANUFACTURER, CONF_CONTROLLER, CONF_SITE_ID, - CONTROLLER_ID, DOMAIN as UNIFI_DOMAIN, ) @@ -106,11 +105,7 @@ async def async_setup_scanner(hass, config, sync_see, discovery_info): async def async_setup_entry(hass, config_entry, async_add_entities): """Set up device tracker for UniFi component.""" - controller_id = CONTROLLER_ID.format( - host=config_entry.data[CONF_CONTROLLER][CONF_HOST], - site=config_entry.data[CONF_CONTROLLER][CONF_SITE_ID], - ) - controller = hass.data[unifi.DOMAIN][controller_id] + controller = get_controller_from_config_entry(hass, config_entry) tracked = {} registry = await entity_registry.async_get_registry(hass) diff --git a/homeassistant/components/unifi/switch.py b/homeassistant/components/unifi/switch.py index ca4ae46f085c68..f46a55f671ea4f 100644 --- a/homeassistant/components/unifi/switch.py +++ b/homeassistant/components/unifi/switch.py @@ -1,17 +1,14 @@ """Support for devices connected to UniFi POE.""" import logging -from homeassistant.components import unifi +from homeassistant.components.unifi.config_flow import get_controller_from_config_entry from homeassistant.components.switch import SwitchDevice -from homeassistant.const import CONF_HOST from homeassistant.core import callback from homeassistant.helpers import entity_registry from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.restore_state import RestoreEntity -from .const import CONF_CONTROLLER, CONF_SITE_ID, CONTROLLER_ID - LOGGER = logging.getLogger(__name__) @@ -25,11 +22,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): Switches are controlling network switch ports with Poe. """ - controller_id = CONTROLLER_ID.format( - host=config_entry.data[CONF_CONTROLLER][CONF_HOST], - site=config_entry.data[CONF_CONTROLLER][CONF_SITE_ID], - ) - controller = hass.data[unifi.DOMAIN][controller_id] + controller = get_controller_from_config_entry(hass, config_entry) if controller.site_role != "admin": return diff --git a/tests/components/unifi/test_device_tracker.py b/tests/components/unifi/test_device_tracker.py index e099286de7d1aa..437fabf9689469 100644 --- a/tests/components/unifi/test_device_tracker.py +++ b/tests/components/unifi/test_device_tracker.py @@ -17,6 +17,7 @@ CONF_SSID_FILTER, CONF_TRACK_DEVICES, CONF_TRACK_WIRED_CLIENTS, + CONTROLLER_ID as CONF_CONTROLLER_ID, UNIFI_CONFIG, ) from homeassistant.const import ( @@ -101,7 +102,7 @@ ENTRY_CONFIG = {CONF_CONTROLLER: CONTROLLER_DATA} -CONTROLLER_ID = unifi.CONTROLLER_ID.format(host="mock-host", site="mock-site") +CONTROLLER_ID = CONF_CONTROLLER_ID.format(host="mock-host", site="mock-site") @pytest.fixture diff --git a/tests/components/unifi/test_init.py b/tests/components/unifi/test_init.py index b725e34f61dc65..ffd6d97e5b3bcd 100644 --- a/tests/components/unifi/test_init.py +++ b/tests/components/unifi/test_init.py @@ -4,7 +4,11 @@ from homeassistant.components import unifi from homeassistant.components.unifi import config_flow from homeassistant.setup import async_setup_component -from homeassistant.components.unifi.const import CONF_CONTROLLER, CONF_SITE_ID +from homeassistant.components.unifi.const import ( + CONF_CONTROLLER, + CONF_SITE_ID, + CONTROLLER_ID as CONF_CONTROLLER_ID, +) from homeassistant.const import ( CONF_HOST, CONF_PASSWORD, @@ -113,7 +117,7 @@ async def test_controller_fail_setup(hass): mock_cntrlr.return_value.async_setup.return_value = mock_coro(False) assert await unifi.async_setup_entry(hass, entry) is False - controller_id = unifi.CONTROLLER_ID.format(host="0.0.0.0", site="default") + controller_id = CONF_CONTROLLER_ID.format(host="0.0.0.0", site="default") assert controller_id in hass.data[unifi.DOMAIN] diff --git a/tests/components/unifi/test_switch.py b/tests/components/unifi/test_switch.py index 3ac9ddb17dc61b..e660e57fc671d5 100644 --- a/tests/components/unifi/test_switch.py +++ b/tests/components/unifi/test_switch.py @@ -15,6 +15,7 @@ from homeassistant.components.unifi.const import ( CONF_CONTROLLER, CONF_SITE_ID, + CONTROLLER_ID as CONF_CONTROLLER_ID, UNIFI_CONFIG, ) from homeassistant.helpers import entity_registry @@ -213,7 +214,7 @@ ENTRY_CONFIG = {CONF_CONTROLLER: CONTROLLER_DATA} -CONTROLLER_ID = unifi.CONTROLLER_ID.format(host="mock-host", site="mock-site") +CONTROLLER_ID = CONF_CONTROLLER_ID.format(host="mock-host", site="mock-site") @pytest.fixture From 3edfba19d77039e8865539518562683966e38ff9 Mon Sep 17 00:00:00 2001 From: Aleix Murtra Date: Sun, 1 Sep 2019 18:05:46 +0200 Subject: [PATCH 31/72] Add BeeWi SmartClim BLE sensors (#26174) * Add BeeWi SmartClim BLE temperature and humidity sensor * Update missing CODEOWNERS and .coveragerc files * Updated requirements file * Update documentation * Fixed requested changes and decoupled IO library * Add unique_id property * Improve unique_id --- .coveragerc | 1 + CODEOWNERS | 1 + .../components/beewi_smartclim/__init__.py | 1 + .../components/beewi_smartclim/manifest.json | 12 ++ .../components/beewi_smartclim/sensor.py | 108 ++++++++++++++++++ requirements_all.txt | 3 + 6 files changed, 126 insertions(+) create mode 100644 homeassistant/components/beewi_smartclim/__init__.py create mode 100644 homeassistant/components/beewi_smartclim/manifest.json create mode 100644 homeassistant/components/beewi_smartclim/sensor.py diff --git a/.coveragerc b/.coveragerc index 6b239402cb187f..df87a5a1f71d70 100644 --- a/.coveragerc +++ b/.coveragerc @@ -57,6 +57,7 @@ omit = homeassistant/components/avion/light.py homeassistant/components/azure_event_hub/* homeassistant/components/baidu/tts.py + homeassistant/components/beewi_smartclim/sensor.py homeassistant/components/bbb_gpio/* homeassistant/components/bbox/device_tracker.py homeassistant/components/bbox/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 623d6ca9eec328..7c2e69c9af19d8 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -37,6 +37,7 @@ homeassistant/components/awair/* @danielsjf homeassistant/components/aws/* @awarecan @robbiet480 homeassistant/components/axis/* @kane610 homeassistant/components/azure_event_hub/* @eavanvalkenburg +homeassistant/components/beewi_smartclim/* @alemuro homeassistant/components/bitcoin/* @fabaff homeassistant/components/bizkaibus/* @UgaitzEtxebarria homeassistant/components/blink/* @fronzbot diff --git a/homeassistant/components/beewi_smartclim/__init__.py b/homeassistant/components/beewi_smartclim/__init__.py new file mode 100644 index 00000000000000..f907ce95ae6390 --- /dev/null +++ b/homeassistant/components/beewi_smartclim/__init__.py @@ -0,0 +1 @@ +"""The beewi_smartclim component.""" diff --git a/homeassistant/components/beewi_smartclim/manifest.json b/homeassistant/components/beewi_smartclim/manifest.json new file mode 100644 index 00000000000000..3e9ad732b74342 --- /dev/null +++ b/homeassistant/components/beewi_smartclim/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "beewi_smartclim", + "name": "BeeWi SmartClim BLE sensor", + "documentation": "https://www.home-assistant.io/components/beewi_smartclim", + "requirements": [ + "beewi_smartclim==0.0.7" + ], + "dependencies": [], + "codeowners": [ + "@alemuro" + ] +} \ No newline at end of file diff --git a/homeassistant/components/beewi_smartclim/sensor.py b/homeassistant/components/beewi_smartclim/sensor.py new file mode 100644 index 00000000000000..7bfa8883013724 --- /dev/null +++ b/homeassistant/components/beewi_smartclim/sensor.py @@ -0,0 +1,108 @@ +"""Platform for beewi_smartclim integration.""" +import logging + +from beewi_smartclim import BeewiSmartClimPoller +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +import homeassistant.helpers.config_validation as cv +from homeassistant.const import ( + CONF_NAME, + CONF_MAC, + TEMP_CELSIUS, + DEVICE_CLASS_HUMIDITY, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_BATTERY, +) +from homeassistant.helpers.entity import Entity + +_LOGGER = logging.getLogger(__name__) + +# Default values +DEFAULT_NAME = "BeeWi SmartClim" + +# Sensor config +SENSOR_TYPES = [ + [DEVICE_CLASS_TEMPERATURE, "Temperature", TEMP_CELSIUS], + [DEVICE_CLASS_HUMIDITY, "Humidity", "%"], + [DEVICE_CLASS_BATTERY, "Battery", "%"], +] + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + vol.Required(CONF_MAC): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + } +) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up the beewi_smartclim platform.""" + + mac = config[CONF_MAC] + prefix = config[CONF_NAME] + poller = BeewiSmartClimPoller(mac) + + sensors = [] + + for sensor_type in SENSOR_TYPES: + device = sensor_type[0] + name = sensor_type[1] + unit = sensor_type[2] + # `prefix` is the name configured by the user for the sensor, we're appending + # the device type at the end of the name (garden -> garden temperature) + if prefix: + name = f"{prefix} {name}" + + sensors.append(BeewiSmartclimSensor(poller, name, mac, device, unit)) + + add_entities(sensors) + + +class BeewiSmartclimSensor(Entity): + """Representation of a Sensor.""" + + def __init__(self, poller, name, mac, device, unit): + """Initialize the sensor.""" + self._poller = poller + self._name = name + self._mac = mac + self._device = device + self._unit = unit + self._state = None + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def state(self): + """Return the state of the sensor. State is returned in Celsius.""" + return self._state + + @property + def device_class(self): + """Device class of this entity.""" + return self._device + + @property + def unique_id(self): + """Return a unique, HASS-friendly identifier for this entity.""" + return f"{self._mac}_{self._device}" + + @property + def unit_of_measurement(self): + """Return the unit of measurement.""" + return self._unit + + def update(self): + """Fetch new state data from the poller.""" + self._poller.update_sensor() + self._state = None + if self._device == DEVICE_CLASS_TEMPERATURE: + self._state = self._poller.get_temperature() + if self._device == DEVICE_CLASS_HUMIDITY: + self._state = self._poller.get_humidity() + if self._device == DEVICE_CLASS_BATTERY: + self._state = self._poller.get_battery() diff --git a/requirements_all.txt b/requirements_all.txt index 3ca134fbd62471..106a7099e7d28e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -262,6 +262,9 @@ batinfo==0.4.2 # homeassistant.components.sytadin beautifulsoup4==4.8.0 +# homeassistant.components.beewi_smartclim +beewi_smartclim==0.0.7 + # homeassistant.components.zha bellows-homeassistant==0.9.1 From fa164abffa6c6818393ddd429f716cfeec378b28 Mon Sep 17 00:00:00 2001 From: Steven Rollason <2099542+gadgetchnnel@users.noreply.github.com> Date: Sun, 1 Sep 2019 17:12:55 +0100 Subject: [PATCH 32/72] New template sensor attributes (#26127) * updated sensor and test files * Formatting fixes * Updated attribute template code * Black formatting * Code improvements based on feedback on binary_sensor pull request * Updated tests * Remove duplicated code and fix tests * Black formatting on tests * Remove link from docstring * Moved default to schema * Formatting fix and change to use dict[key] to retrieve attribute_templates --- homeassistant/components/template/sensor.py | 54 +++++++++++--- tests/components/template/test_sensor.py | 82 ++++++++++++++++++++- 2 files changed, 123 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index a5397e0ea7d353..b77528e0c324a7 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -1,6 +1,7 @@ """Allows the creation of a sensor that breaks out state_attributes.""" import logging from typing import Optional +from itertools import chain import voluptuous as vol @@ -28,6 +29,8 @@ from homeassistant.helpers.entity import Entity, async_generate_entity_id from homeassistant.helpers.event import async_track_state_change +CONF_ATTRIBUTE_TEMPLATES = "attribute_templates" + _LOGGER = logging.getLogger(__name__) SENSOR_SCHEMA = vol.Schema( @@ -36,6 +39,9 @@ vol.Optional(CONF_ICON_TEMPLATE): cv.template, vol.Optional(CONF_ENTITY_PICTURE_TEMPLATE): cv.template, vol.Optional(CONF_FRIENDLY_NAME_TEMPLATE): cv.template, + vol.Optional(CONF_ATTRIBUTE_TEMPLATES, default={}): vol.Schema( + {cv.string: cv.template} + ), vol.Optional(ATTR_FRIENDLY_NAME): cv.string, vol.Optional(ATTR_UNIT_OF_MEASUREMENT): cv.string, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, @@ -60,17 +66,20 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= friendly_name_template = device_config.get(CONF_FRIENDLY_NAME_TEMPLATE) unit_of_measurement = device_config.get(ATTR_UNIT_OF_MEASUREMENT) device_class = device_config.get(CONF_DEVICE_CLASS) + attribute_templates = device_config[CONF_ATTRIBUTE_TEMPLATES] entity_ids = set() manual_entity_ids = device_config.get(ATTR_ENTITY_ID) invalid_templates = [] - for tpl_name, template in ( - (CONF_VALUE_TEMPLATE, state_template), - (CONF_ICON_TEMPLATE, icon_template), - (CONF_ENTITY_PICTURE_TEMPLATE, entity_picture_template), - (CONF_FRIENDLY_NAME_TEMPLATE, friendly_name_template), - ): + templates = { + CONF_VALUE_TEMPLATE: state_template, + CONF_ICON_TEMPLATE: icon_template, + CONF_ENTITY_PICTURE_TEMPLATE: entity_picture_template, + CONF_FRIENDLY_NAME_TEMPLATE: friendly_name_template, + } + + for tpl_name, template in chain(templates.items(), attribute_templates.items()): if template is None: continue template.hass = hass @@ -82,7 +91,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= if template_entity_ids == MATCH_ALL: entity_ids = MATCH_ALL # Cut off _template from name - invalid_templates.append(tpl_name[:-9]) + invalid_templates.append(tpl_name.replace("_template", "")) elif entity_ids != MATCH_ALL: entity_ids |= set(template_entity_ids) @@ -113,6 +122,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= entity_picture_template, entity_ids, device_class, + attribute_templates, ) ) if not sensors: @@ -138,6 +148,7 @@ def __init__( entity_picture_template, entity_ids, device_class, + attribute_templates, ): """Initialize the sensor.""" self.hass = hass @@ -155,6 +166,8 @@ def __init__( self._entity_picture = None self._entities = entity_ids self._device_class = device_class + self._attribute_templates = attribute_templates + self._attributes = {} async def async_added_to_hass(self): """Register callbacks.""" @@ -209,6 +222,11 @@ def unit_of_measurement(self): """Return the unit_of_measurement of the device.""" return self._unit_of_measurement + @property + def device_state_attributes(self): + """Return the state attributes.""" + return self._attributes + @property def should_poll(self): """No polling needed.""" @@ -229,11 +247,23 @@ async def async_update(self): else: self._state = None _LOGGER.error("Could not render template %s: %s", self._name, ex) - for property_name, template in ( - ("_icon", self._icon_template), - ("_entity_picture", self._entity_picture_template), - ("_name", self._friendly_name_template), - ): + + templates = { + "_icon": self._icon_template, + "_entity_picture": self._entity_picture_template, + "_name": self._friendly_name_template, + } + + attrs = {} + for key, value in self._attribute_templates.items(): + try: + attrs[key] = value.async_render() + except TemplateError as err: + _LOGGER.error("Error rendering attribute %s: %s", key, err) + + self._attributes = attrs + + for property_name, template in templates.items(): if template is None: continue diff --git a/tests/components/template/test_sensor.py b/tests/components/template/test_sensor.py index 298efc6bebbd43..9223399bee7af1 100644 --- a/tests/components/template/test_sensor.py +++ b/tests/components/template/test_sensor.py @@ -174,6 +174,38 @@ def test_friendly_name_template_with_unknown_state(self): state = self.hass.states.get("sensor.test_template_sensor") assert state.attributes["friendly_name"] == "It Works." + def test_attribute_templates(self): + """Test attribute_templates template.""" + with assert_setup_component(1): + assert setup_component( + self.hass, + "sensor", + { + "sensor": { + "platform": "template", + "sensors": { + "test_template_sensor": { + "value_template": "{{ states.sensor.test_state.state }}", + "attribute_templates": { + "test_attribute": "It {{ states.sensor.test_state.state }}." + }, + } + }, + } + }, + ) + + self.hass.start() + self.hass.block_till_done() + + state = self.hass.states.get("sensor.test_template_sensor") + assert state.attributes.get("test_attribute") == "It ." + + self.hass.states.set("sensor.test_state", "Works") + self.hass.block_till_done() + state = self.hass.states.get("sensor.test_template_sensor") + assert state.attributes["test_attribute"] == "It Works." + def test_template_syntax_error(self): """Test templating syntax error.""" with assert_setup_component(0): @@ -345,6 +377,34 @@ def test_setup_valid_device_class(self): assert "device_class" not in state.attributes +async def test_invalid_attribute_template(hass, caplog): + """Test that errors are logged if rendering template fails.""" + hass.states.async_set("sensor.test_sensor", "startup") + + await async_setup_component( + hass, + "sensor", + { + "sensor": { + "platform": "template", + "sensors": { + "invalid_template": { + "value_template": "{{ states.sensor.test_sensor.state }}", + "attribute_templates": { + "test_attribute": "{{ states.sensor.unknown.attributes.picture }}" + }, + } + }, + } + }, + ) + await hass.async_block_till_done() + assert len(hass.states.async_all()) == 2 + await hass.helpers.entity_component.async_update_entity("sensor.invalid_template") + + assert ("Error rendering attribute test_attribute") in caplog.text + + async def test_no_template_match_all(hass, caplog): """Test that we do not allow sensors that match on all.""" hass.states.async_set("sensor.test_sensor", "startup") @@ -369,12 +429,22 @@ async def test_no_template_match_all(hass, caplog): "value_template": "{{ states.sensor.test_sensor.state }}", "friendly_name_template": "{{ 1 + 1 }}", }, + "invalid_attribute": { + "value_template": "{{ states.sensor.test_sensor.state }}", + "attribute_templates": {"test_attribute": "{{ 1 + 1 }}"}, + }, }, } }, ) + + assert hass.states.get("sensor.invalid_state").state == "unknown" + assert hass.states.get("sensor.invalid_icon").state == "unknown" + assert hass.states.get("sensor.invalid_entity_picture").state == "unknown" + assert hass.states.get("sensor.invalid_friendly_name").state == "unknown" + await hass.async_block_till_done() - assert len(hass.states.async_all()) == 5 + assert len(hass.states.async_all()) == 6 assert ( "Template sensor invalid_state has no entity ids " "configured to track nor were we able to extract the entities to " @@ -395,11 +465,17 @@ async def test_no_template_match_all(hass, caplog): "configured to track nor were we able to extract the entities to " "track from the friendly_name template" ) in caplog.text + assert ( + "Template sensor invalid_attribute has no entity ids " + "configured to track nor were we able to extract the entities to " + "track from the test_attribute template" + ) in caplog.text assert hass.states.get("sensor.invalid_state").state == "unknown" assert hass.states.get("sensor.invalid_icon").state == "unknown" assert hass.states.get("sensor.invalid_entity_picture").state == "unknown" assert hass.states.get("sensor.invalid_friendly_name").state == "unknown" + assert hass.states.get("sensor.invalid_attribute").state == "unknown" hass.bus.async_fire(EVENT_HOMEASSISTANT_START) await hass.async_block_till_done() @@ -408,6 +484,7 @@ async def test_no_template_match_all(hass, caplog): assert hass.states.get("sensor.invalid_icon").state == "startup" assert hass.states.get("sensor.invalid_entity_picture").state == "startup" assert hass.states.get("sensor.invalid_friendly_name").state == "startup" + assert hass.states.get("sensor.invalid_attribute").state == "startup" hass.states.async_set("sensor.test_sensor", "hello") await hass.async_block_till_done() @@ -416,6 +493,7 @@ async def test_no_template_match_all(hass, caplog): assert hass.states.get("sensor.invalid_icon").state == "startup" assert hass.states.get("sensor.invalid_entity_picture").state == "startup" assert hass.states.get("sensor.invalid_friendly_name").state == "startup" + assert hass.states.get("sensor.invalid_attribute").state == "startup" await hass.helpers.entity_component.async_update_entity("sensor.invalid_state") await hass.helpers.entity_component.async_update_entity("sensor.invalid_icon") @@ -425,8 +503,10 @@ async def test_no_template_match_all(hass, caplog): await hass.helpers.entity_component.async_update_entity( "sensor.invalid_friendly_name" ) + await hass.helpers.entity_component.async_update_entity("sensor.invalid_attribute") assert hass.states.get("sensor.invalid_state").state == "2" assert hass.states.get("sensor.invalid_icon").state == "hello" assert hass.states.get("sensor.invalid_entity_picture").state == "hello" assert hass.states.get("sensor.invalid_friendly_name").state == "hello" + assert hass.states.get("sensor.invalid_attribute").state == "hello" From d8e097c33f112ff1a33542df887c4797a23aac7f Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 2 Sep 2019 06:40:18 +0200 Subject: [PATCH 33/72] Add improvements of device_automation from frontend PR 3514 (#26295) * Add improvements from frontend PR 3514 * Fix test * Tweak --- homeassistant/components/automation/manifest.json | 1 + homeassistant/components/device_automation/__init__.py | 2 +- homeassistant/components/light/strings.json | 8 ++++++++ tests/components/device_automation/test_init.py | 2 +- 4 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 homeassistant/components/light/strings.json diff --git a/homeassistant/components/automation/manifest.json b/homeassistant/components/automation/manifest.json index ea63d4ff98a31c..935cc7a9175058 100644 --- a/homeassistant/components/automation/manifest.json +++ b/homeassistant/components/automation/manifest.json @@ -4,6 +4,7 @@ "documentation": "https://www.home-assistant.io/components/automation", "requirements": [], "dependencies": [ + "device_automation", "group", "webhook" ], diff --git a/homeassistant/components/device_automation/__init__.py b/homeassistant/components/device_automation/__init__.py index b1f319b0a6ae7c..018e1286d8bc53 100644 --- a/homeassistant/components/device_automation/__init__.py +++ b/homeassistant/components/device_automation/__init__.py @@ -75,7 +75,7 @@ async def async_get_device_automation_triggers(hass, device_id): @websocket_api.async_response @websocket_api.websocket_command( { - vol.Required("type"): "device_automation/list_triggers", + vol.Required("type"): "device_automation/trigger/list", vol.Required("device_id"): str, } ) diff --git a/homeassistant/components/light/strings.json b/homeassistant/components/light/strings.json new file mode 100644 index 00000000000000..94954bb790b198 --- /dev/null +++ b/homeassistant/components/light/strings.json @@ -0,0 +1,8 @@ +{ + "device_automation": { + "trigger_type": { + "turn_on": "{name} turned on", + "turn_off": "{name} turned off" + } + } +} diff --git a/tests/components/device_automation/test_init.py b/tests/components/device_automation/test_init.py index 55367e7696c480..16320257b40bc2 100644 --- a/tests/components/device_automation/test_init.py +++ b/tests/components/device_automation/test_init.py @@ -62,7 +62,7 @@ async def test_websocket_get_triggers(hass, hass_ws_client, device_reg, entity_r await client.send_json( { "id": 1, - "type": "device_automation/list_triggers", + "type": "device_automation/trigger/list", "device_id": device_entry.id, } ) From 82676ba8adfa2c16d5b729db3f8f5964f15dd362 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 1 Sep 2019 21:42:57 -0700 Subject: [PATCH 34/72] Expose current direction properly on state machine (#26298) * Expose current direction properly on state machine * Fix template fan --- homeassistant/components/demo/fan.py | 8 ++++---- homeassistant/components/fan/__init__.py | 2 +- homeassistant/components/template/fan.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/demo/fan.py b/homeassistant/components/demo/fan.py index cdeed5dbfec692..ab8a6f3fae9dc6 100644 --- a/homeassistant/components/demo/fan.py +++ b/homeassistant/components/demo/fan.py @@ -34,13 +34,13 @@ def __init__(self, hass, name: str, supported_features: int) -> None: self._supported_features = supported_features self._speed = STATE_OFF self.oscillating = None - self.direction = None + self._direction = None self._name = name if supported_features & SUPPORT_OSCILLATE: self.oscillating = False if supported_features & SUPPORT_DIRECTION: - self.direction = "forward" + self._direction = "forward" @property def name(self) -> str: @@ -80,7 +80,7 @@ def set_speed(self, speed: str) -> None: def set_direction(self, direction: str) -> None: """Set the direction of the fan.""" - self.direction = direction + self._direction = direction self.schedule_update_ha_state() def oscillate(self, oscillating: bool) -> None: @@ -91,7 +91,7 @@ def oscillate(self, oscillating: bool) -> None: @property def current_direction(self) -> str: """Fan direction.""" - return self.direction + return self._direction @property def supported_features(self) -> int: diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index f5edfe5bb5996e..50d698f733656f 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -54,7 +54,7 @@ "speed": ATTR_SPEED, "speed_list": ATTR_SPEED_LIST, "oscillating": ATTR_OSCILLATING, - "direction": ATTR_DIRECTION, + "current_direction": ATTR_DIRECTION, } # type: dict FAN_SET_SPEED_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( diff --git a/homeassistant/components/template/fan.py b/homeassistant/components/template/fan.py index c3d5a4d878fd9e..7fd8c4d9b3cea6 100644 --- a/homeassistant/components/template/fan.py +++ b/homeassistant/components/template/fan.py @@ -243,7 +243,7 @@ def oscillating(self): return self._oscillating @property - def direction(self): + def current_direction(self): """Return the oscillation state.""" return self._direction From 16604a5330909e8c1ea5ed8f3804192aa69193af Mon Sep 17 00:00:00 2001 From: ChristianKuehnel Date: Mon, 2 Sep 2019 06:44:50 +0200 Subject: [PATCH 35/72] added missing bluepy dependency for miflora (#26297) fixes dependency issue #19362 (only part of the solution) --- homeassistant/components/miflora/manifest.json | 1 + requirements_all.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/homeassistant/components/miflora/manifest.json b/homeassistant/components/miflora/manifest.json index d4e7a333acf287..c7ef2b89611c43 100644 --- a/homeassistant/components/miflora/manifest.json +++ b/homeassistant/components/miflora/manifest.json @@ -3,6 +3,7 @@ "name": "Miflora", "documentation": "https://www.home-assistant.io/components/miflora", "requirements": [ + "bluepy==1.1.4", "miflora==0.4.0" ], "dependencies": [], diff --git a/requirements_all.txt b/requirements_all.txt index 106a7099e7d28e..7be6e8a4265f25 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -287,6 +287,7 @@ blinkstick==1.1.8 blockchain==1.4.4 # homeassistant.components.decora +# homeassistant.components.miflora # bluepy==1.1.4 # homeassistant.components.bme680 From 9d84bb34ccc5150ccd23fba3edea8b8d5aa526de Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 1 Sep 2019 22:30:09 -0700 Subject: [PATCH 36/72] Update translations --- .../components/adguard/.translations/pl.json | 6 ++--- .../ambiclimate/.translations/pl.json | 4 ++-- .../arcam_fmj/.translations/ca.json | 5 ++++ .../arcam_fmj/.translations/da.json | 5 ++++ .../arcam_fmj/.translations/nl.json | 5 ++++ .../arcam_fmj/.translations/no.json | 5 ++++ .../arcam_fmj/.translations/pl.json | 5 ++++ .../arcam_fmj/.translations/ru.json | 5 ++++ .../arcam_fmj/.translations/zh-Hant.json | 5 ++++ .../cert_expiry/.translations/ca.json | 24 +++++++++++++++++++ .../cert_expiry/.translations/da.json | 24 +++++++++++++++++++ .../cert_expiry/.translations/hu.json | 12 ++++++++++ .../cert_expiry/.translations/nl.json | 24 +++++++++++++++++++ .../cert_expiry/.translations/no.json | 24 +++++++++++++++++++ .../cert_expiry/.translations/pl.json | 24 +++++++++++++++++++ .../cert_expiry/.translations/ru.json | 24 +++++++++++++++++++ .../cert_expiry/.translations/zh-Hant.json | 24 +++++++++++++++++++ .../components/deconz/.translations/ca.json | 11 +++++++++ .../components/deconz/.translations/da.json | 11 +++++++++ .../components/deconz/.translations/nl.json | 11 +++++++++ .../components/deconz/.translations/no.json | 11 +++++++++ .../components/deconz/.translations/pl.json | 15 ++++++++++-- .../components/deconz/.translations/ru.json | 11 +++++++++ .../deconz/.translations/zh-Hant.json | 11 +++++++++ .../emulated_roku/.translations/no.json | 2 +- .../esphome/.translations/zh-Hant.json | 2 +- .../geonetnz_quakes/.translations/ca.json | 17 +++++++++++++ .../geonetnz_quakes/.translations/da.json | 17 +++++++++++++ .../geonetnz_quakes/.translations/hu.json | 12 ++++++++++ .../geonetnz_quakes/.translations/nl.json | 17 +++++++++++++ .../geonetnz_quakes/.translations/pl.json | 17 +++++++++++++ .../geonetnz_quakes/.translations/ru.json | 17 +++++++++++++ .../.translations/zh-Hant.json | 17 +++++++++++++ .../components/heos/.translations/pl.json | 2 +- .../homekit_controller/.translations/pl.json | 4 ++-- .../components/life360/.translations/ca.json | 1 + .../components/life360/.translations/da.json | 1 + .../components/life360/.translations/hu.json | 7 ++++++ .../components/life360/.translations/nl.json | 1 + .../components/life360/.translations/pl.json | 1 + .../components/life360/.translations/ru.json | 1 + .../life360/.translations/zh-Hant.json | 1 + .../components/light/.translations/en.json | 8 +++++++ .../logi_circle/.translations/pl.json | 8 +++---- .../components/met/.translations/hu.json | 9 +++++++ .../components/nest/.translations/ca.json | 2 +- .../nest/.translations/zh-Hant.json | 2 +- .../components/notion/.translations/hu.json | 18 ++++++++++++++ .../point/.translations/zh-Hant.json | 2 +- .../components/ps4/.translations/pl.json | 2 +- .../toon/.translations/zh-Hant.json | 2 +- .../components/traccar/.translations/ca.json | 18 ++++++++++++++ .../components/traccar/.translations/da.json | 18 ++++++++++++++ .../components/traccar/.translations/nl.json | 18 ++++++++++++++ .../components/traccar/.translations/pl.json | 18 ++++++++++++++ .../components/traccar/.translations/ru.json | 18 ++++++++++++++ .../traccar/.translations/zh-Hant.json | 18 ++++++++++++++ .../twentemilieu/.translations/ca.json | 23 ++++++++++++++++++ .../twentemilieu/.translations/da.json | 23 ++++++++++++++++++ .../twentemilieu/.translations/hu.json | 18 ++++++++++++++ .../twentemilieu/.translations/nl.json | 23 ++++++++++++++++++ .../twentemilieu/.translations/pl.json | 23 ++++++++++++++++++ .../twentemilieu/.translations/ru.json | 23 ++++++++++++++++++ .../twentemilieu/.translations/zh-Hant.json | 23 ++++++++++++++++++ .../components/unifi/.translations/ca.json | 12 ++++++++++ .../components/unifi/.translations/da.json | 12 ++++++++++ .../components/unifi/.translations/nl.json | 12 ++++++++++ .../components/unifi/.translations/pl.json | 20 ++++++++++++++++ .../components/unifi/.translations/ru.json | 12 ++++++++++ .../unifi/.translations/zh-Hant.json | 12 ++++++++++ .../components/velbus/.translations/ca.json | 21 ++++++++++++++++ .../components/velbus/.translations/da.json | 21 ++++++++++++++++ .../components/velbus/.translations/hu.json | 10 ++++++++ .../components/velbus/.translations/nl.json | 21 ++++++++++++++++ .../components/velbus/.translations/pl.json | 21 ++++++++++++++++ .../components/velbus/.translations/ru.json | 21 ++++++++++++++++ .../velbus/.translations/zh-Hant.json | 21 ++++++++++++++++ .../components/vesync/.translations/ca.json | 20 ++++++++++++++++ .../components/vesync/.translations/da.json | 20 ++++++++++++++++ .../components/vesync/.translations/hu.json | 16 +++++++++++++ .../components/vesync/.translations/nl.json | 20 ++++++++++++++++ .../components/vesync/.translations/pl.json | 20 ++++++++++++++++ .../components/vesync/.translations/ru.json | 20 ++++++++++++++++ .../vesync/.translations/zh-Hant.json | 20 ++++++++++++++++ .../components/withings/.translations/en.json | 17 +++++++++++++ .../components/wwlln/.translations/hu.json | 12 ++++++++++ 86 files changed, 1120 insertions(+), 21 deletions(-) create mode 100644 homeassistant/components/arcam_fmj/.translations/ca.json create mode 100644 homeassistant/components/arcam_fmj/.translations/da.json create mode 100644 homeassistant/components/arcam_fmj/.translations/nl.json create mode 100644 homeassistant/components/arcam_fmj/.translations/no.json create mode 100644 homeassistant/components/arcam_fmj/.translations/pl.json create mode 100644 homeassistant/components/arcam_fmj/.translations/ru.json create mode 100644 homeassistant/components/arcam_fmj/.translations/zh-Hant.json create mode 100644 homeassistant/components/cert_expiry/.translations/ca.json create mode 100644 homeassistant/components/cert_expiry/.translations/da.json create mode 100644 homeassistant/components/cert_expiry/.translations/hu.json create mode 100644 homeassistant/components/cert_expiry/.translations/nl.json create mode 100644 homeassistant/components/cert_expiry/.translations/no.json create mode 100644 homeassistant/components/cert_expiry/.translations/pl.json create mode 100644 homeassistant/components/cert_expiry/.translations/ru.json create mode 100644 homeassistant/components/cert_expiry/.translations/zh-Hant.json create mode 100644 homeassistant/components/geonetnz_quakes/.translations/ca.json create mode 100644 homeassistant/components/geonetnz_quakes/.translations/da.json create mode 100644 homeassistant/components/geonetnz_quakes/.translations/hu.json create mode 100644 homeassistant/components/geonetnz_quakes/.translations/nl.json create mode 100644 homeassistant/components/geonetnz_quakes/.translations/pl.json create mode 100644 homeassistant/components/geonetnz_quakes/.translations/ru.json create mode 100644 homeassistant/components/geonetnz_quakes/.translations/zh-Hant.json create mode 100644 homeassistant/components/life360/.translations/hu.json create mode 100644 homeassistant/components/light/.translations/en.json create mode 100644 homeassistant/components/met/.translations/hu.json create mode 100644 homeassistant/components/notion/.translations/hu.json create mode 100644 homeassistant/components/traccar/.translations/ca.json create mode 100644 homeassistant/components/traccar/.translations/da.json create mode 100644 homeassistant/components/traccar/.translations/nl.json create mode 100644 homeassistant/components/traccar/.translations/pl.json create mode 100644 homeassistant/components/traccar/.translations/ru.json create mode 100644 homeassistant/components/traccar/.translations/zh-Hant.json create mode 100644 homeassistant/components/twentemilieu/.translations/ca.json create mode 100644 homeassistant/components/twentemilieu/.translations/da.json create mode 100644 homeassistant/components/twentemilieu/.translations/hu.json create mode 100644 homeassistant/components/twentemilieu/.translations/nl.json create mode 100644 homeassistant/components/twentemilieu/.translations/pl.json create mode 100644 homeassistant/components/twentemilieu/.translations/ru.json create mode 100644 homeassistant/components/twentemilieu/.translations/zh-Hant.json create mode 100644 homeassistant/components/velbus/.translations/ca.json create mode 100644 homeassistant/components/velbus/.translations/da.json create mode 100644 homeassistant/components/velbus/.translations/hu.json create mode 100644 homeassistant/components/velbus/.translations/nl.json create mode 100644 homeassistant/components/velbus/.translations/pl.json create mode 100644 homeassistant/components/velbus/.translations/ru.json create mode 100644 homeassistant/components/velbus/.translations/zh-Hant.json create mode 100644 homeassistant/components/vesync/.translations/ca.json create mode 100644 homeassistant/components/vesync/.translations/da.json create mode 100644 homeassistant/components/vesync/.translations/hu.json create mode 100644 homeassistant/components/vesync/.translations/nl.json create mode 100644 homeassistant/components/vesync/.translations/pl.json create mode 100644 homeassistant/components/vesync/.translations/ru.json create mode 100644 homeassistant/components/vesync/.translations/zh-Hant.json create mode 100644 homeassistant/components/withings/.translations/en.json create mode 100644 homeassistant/components/wwlln/.translations/hu.json diff --git a/homeassistant/components/adguard/.translations/pl.json b/homeassistant/components/adguard/.translations/pl.json index 199b621c81b7a0..e58c901f3643f4 100644 --- a/homeassistant/components/adguard/.translations/pl.json +++ b/homeassistant/components/adguard/.translations/pl.json @@ -5,11 +5,11 @@ "single_instance_allowed": "Dozwolona jest tylko jedna konfiguracja AdGuard Home." }, "error": { - "connection_error": "Po\u0142\u0105czenie nieudane." + "connection_error": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia." }, "step": { "hassio_confirm": { - "description": "Czy chcesz skonfigurowa\u0107 Home Assistant'a, aby po\u0142\u0105czy\u0142 si\u0119 z AdGuard Home przez dodatek Hass.io {addon}?", + "description": "Czy chcesz skonfigurowa\u0107 Home Assistant, aby po\u0142\u0105czy\u0142 si\u0119 z AdGuard Home przez dodatek Hass.io {addon}?", "title": "AdGuard Home przez dodatek Hass.io" }, "user": { @@ -21,7 +21,7 @@ "username": "Nazwa u\u017cytkownika", "verify_ssl": "AdGuard Home u\u017cywa odpowiedniego certyfikatu." }, - "description": "Skonfiguruj swoj\u0105 instancj\u0119 AdGuard Home, aby umo\u017cliwi\u0107 monitorowanie i nadz\u00f3r sieci.", + "description": "Skonfiguruj instancj\u0119 AdGuard Home, aby umo\u017cliwi\u0107 monitorowanie i kontrol\u0119.", "title": "Po\u0142\u0105cz sw\u00f3j AdGuard Home" } }, diff --git a/homeassistant/components/ambiclimate/.translations/pl.json b/homeassistant/components/ambiclimate/.translations/pl.json index dac6e52dda2af5..47e9c9f35b2897 100644 --- a/homeassistant/components/ambiclimate/.translations/pl.json +++ b/homeassistant/components/ambiclimate/.translations/pl.json @@ -3,14 +3,14 @@ "abort": { "access_token": "Nieznany b\u0142\u0105d podczas generowania tokena dost\u0119pu.", "already_setup": "Konto Ambiclimate jest skonfigurowane.", - "no_config": "Musisz skonfigurowa\u0107 Ambiclimate, zanim b\u0119dziesz m\u00f3g\u0142 si\u0119 z nim uwierzytelni\u0107. [Przeczytaj instrukcj\u0119](https://www.home-assistant.io/components/ambiclimate/)." + "no_config": "Musisz skonfigurowa\u0107 Ambiclimate, zanim b\u0119dziesz m\u00f3g\u0142 si\u0119 w nim uwierzytelni\u0107. [Przeczytaj instrukcj\u0119](https://www.home-assistant.io/components/ambiclimate/)." }, "create_entry": { "default": "Pomy\u015blnie uwierzytelniono z Ambiclimate" }, "error": { "follow_link": "Prosz\u0119 klikn\u0105\u0107 link i uwierzytelni\u0107 przed naci\u015bni\u0119ciem przycisku Prze\u015blij", - "no_token": "Nie uwierzytelniony z Ambiclimate" + "no_token": "Nieuwierzytelniony z Ambiclimate" }, "step": { "auth": { diff --git a/homeassistant/components/arcam_fmj/.translations/ca.json b/homeassistant/components/arcam_fmj/.translations/ca.json new file mode 100644 index 00000000000000..b0ad4660d0fef1 --- /dev/null +++ b/homeassistant/components/arcam_fmj/.translations/ca.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Arcam FMJ" + } +} \ No newline at end of file diff --git a/homeassistant/components/arcam_fmj/.translations/da.json b/homeassistant/components/arcam_fmj/.translations/da.json new file mode 100644 index 00000000000000..b0ad4660d0fef1 --- /dev/null +++ b/homeassistant/components/arcam_fmj/.translations/da.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Arcam FMJ" + } +} \ No newline at end of file diff --git a/homeassistant/components/arcam_fmj/.translations/nl.json b/homeassistant/components/arcam_fmj/.translations/nl.json new file mode 100644 index 00000000000000..b0ad4660d0fef1 --- /dev/null +++ b/homeassistant/components/arcam_fmj/.translations/nl.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Arcam FMJ" + } +} \ No newline at end of file diff --git a/homeassistant/components/arcam_fmj/.translations/no.json b/homeassistant/components/arcam_fmj/.translations/no.json new file mode 100644 index 00000000000000..b0ad4660d0fef1 --- /dev/null +++ b/homeassistant/components/arcam_fmj/.translations/no.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Arcam FMJ" + } +} \ No newline at end of file diff --git a/homeassistant/components/arcam_fmj/.translations/pl.json b/homeassistant/components/arcam_fmj/.translations/pl.json new file mode 100644 index 00000000000000..b0ad4660d0fef1 --- /dev/null +++ b/homeassistant/components/arcam_fmj/.translations/pl.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Arcam FMJ" + } +} \ No newline at end of file diff --git a/homeassistant/components/arcam_fmj/.translations/ru.json b/homeassistant/components/arcam_fmj/.translations/ru.json new file mode 100644 index 00000000000000..b0ad4660d0fef1 --- /dev/null +++ b/homeassistant/components/arcam_fmj/.translations/ru.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Arcam FMJ" + } +} \ No newline at end of file diff --git a/homeassistant/components/arcam_fmj/.translations/zh-Hant.json b/homeassistant/components/arcam_fmj/.translations/zh-Hant.json new file mode 100644 index 00000000000000..b0ad4660d0fef1 --- /dev/null +++ b/homeassistant/components/arcam_fmj/.translations/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Arcam FMJ" + } +} \ No newline at end of file diff --git a/homeassistant/components/cert_expiry/.translations/ca.json b/homeassistant/components/cert_expiry/.translations/ca.json new file mode 100644 index 00000000000000..25c0b26fafc285 --- /dev/null +++ b/homeassistant/components/cert_expiry/.translations/ca.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "host_port_exists": "Aquesta combinaci\u00f3 d'amfitri\u00f3 i port ja est\u00e0 configurada" + }, + "error": { + "certificate_fetch_failed": "No s'ha pogut obtenir el certificat des d'aquesta combinaci\u00f3 d'amfitri\u00f3 i port", + "connection_timeout": "S'ha acabat el temps d'espera durant la connexi\u00f3 amb l'amfitri\u00f3.", + "host_port_exists": "Aquesta combinaci\u00f3 d'amfitri\u00f3 i port ja est\u00e0 configurada", + "resolve_failed": "No s'ha pogut resoldre l'amfitri\u00f3" + }, + "step": { + "user": { + "data": { + "host": "Nom d'amfitri\u00f3 del certificat", + "name": "Nom del certificat", + "port": "Port del certificat" + }, + "title": "Configuraci\u00f3 del certificat a provar" + } + }, + "title": "Caducitat del certificat" + } +} \ No newline at end of file diff --git a/homeassistant/components/cert_expiry/.translations/da.json b/homeassistant/components/cert_expiry/.translations/da.json new file mode 100644 index 00000000000000..667ab5fa4e3d01 --- /dev/null +++ b/homeassistant/components/cert_expiry/.translations/da.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "host_port_exists": "Denne v\u00e6rt- og portkombination er allerede konfigureret" + }, + "error": { + "certificate_fetch_failed": "Kan ikke hente certifikat fra denne v\u00e6rt- og portkombination", + "connection_timeout": "Timeout ved tilslutning til denne v\u00e6rt", + "host_port_exists": "Denne v\u00e6rt- og portkombination er allerede konfigureret", + "resolve_failed": "V\u00e6rten kunne ikke findes" + }, + "step": { + "user": { + "data": { + "host": "Certifikatets v\u00e6rtsnavn", + "name": "Certifikatets navn", + "port": "Certifikatets port" + }, + "title": "Definer certifikatet, der skal testes" + } + }, + "title": "Certifikat udl\u00f8b" + } +} \ No newline at end of file diff --git a/homeassistant/components/cert_expiry/.translations/hu.json b/homeassistant/components/cert_expiry/.translations/hu.json new file mode 100644 index 00000000000000..584f4c2b75961b --- /dev/null +++ b/homeassistant/components/cert_expiry/.translations/hu.json @@ -0,0 +1,12 @@ +{ + "config": { + "step": { + "user": { + "data": { + "name": "A tan\u00fas\u00edtv\u00e1ny neve", + "port": "A tan\u00fas\u00edtv\u00e1ny portja" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/cert_expiry/.translations/nl.json b/homeassistant/components/cert_expiry/.translations/nl.json new file mode 100644 index 00000000000000..d2fe3c76e85001 --- /dev/null +++ b/homeassistant/components/cert_expiry/.translations/nl.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "host_port_exists": "Deze combinatie van host en poort is al geconfigureerd" + }, + "error": { + "certificate_fetch_failed": "Kan certificaat niet ophalen van deze combinatie van host en poort", + "connection_timeout": "Timeout bij verbinding maken met deze host", + "host_port_exists": "Deze combinatie van host en poort is al geconfigureerd", + "resolve_failed": "Deze host kon niet gevonden worden" + }, + "step": { + "user": { + "data": { + "host": "De hostnaam van het certificaat", + "name": "De naam van het certificaat", + "port": "De poort van het certificaat" + }, + "title": "Het certificaat defini\u00ebren dat moet worden getest" + } + }, + "title": "Vervaldatum certificaat" + } +} \ No newline at end of file diff --git a/homeassistant/components/cert_expiry/.translations/no.json b/homeassistant/components/cert_expiry/.translations/no.json new file mode 100644 index 00000000000000..e095cc360a0f4e --- /dev/null +++ b/homeassistant/components/cert_expiry/.translations/no.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "host_port_exists": "Denne verts- og portkombinasjonen er allerede konfigurert" + }, + "error": { + "certificate_fetch_failed": "Kan ikke hente sertifikat fra denne verts- og portkombinasjonen", + "connection_timeout": "Timeout n\u00e5r det kobles til denne verten", + "host_port_exists": "Denne verts- og portkombinasjonen er allerede konfigurert", + "resolve_failed": "Denne verten kan ikke l\u00f8ses" + }, + "step": { + "user": { + "data": { + "host": "Sertifikatets vertsnavn", + "name": "Sertifikatets navn", + "port": "Sertifikatets port" + }, + "title": "Definer sertifikatet som skal testes" + } + }, + "title": "Sertifikat utl\u00f8p" + } +} \ No newline at end of file diff --git a/homeassistant/components/cert_expiry/.translations/pl.json b/homeassistant/components/cert_expiry/.translations/pl.json new file mode 100644 index 00000000000000..162c8bf8a0aae8 --- /dev/null +++ b/homeassistant/components/cert_expiry/.translations/pl.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "host_port_exists": "Ta kombinacja hosta i portu jest ju\u017c skonfigurowana" + }, + "error": { + "certificate_fetch_failed": "Nie mo\u017cna pobra\u0107 certyfikatu z tej kombinacji hosta i portu", + "connection_timeout": "Przekroczono limit czasu po\u0142\u0105czenia z tym hostem", + "host_port_exists": "Ta kombinacja hosta i portu jest ju\u017c skonfigurowana", + "resolve_failed": "Tego hosta nie mo\u017cna rozwi\u0105za\u0107" + }, + "step": { + "user": { + "data": { + "host": "Nazwa hosta certyfikatu", + "name": "Nazwa certyfikatu", + "port": "Port certyfikatu" + }, + "title": "Zdefiniuj certyfikat do przetestowania" + } + }, + "title": "Wa\u017cno\u015b\u0107 certyfikatu" + } +} \ No newline at end of file diff --git a/homeassistant/components/cert_expiry/.translations/ru.json b/homeassistant/components/cert_expiry/.translations/ru.json new file mode 100644 index 00000000000000..6a795dee13e26b --- /dev/null +++ b/homeassistant/components/cert_expiry/.translations/ru.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "host_port_exists": "\u042d\u0442\u0430 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f \u0445\u043e\u0441\u0442\u0430 \u0438 \u043f\u043e\u0440\u0442\u0430 \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430" + }, + "error": { + "certificate_fetch_failed": "\u041d\u0435 \u0443\u0434\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u0441 \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u0445\u043e\u0441\u0442\u0430 \u0438 \u043f\u043e\u0440\u0442\u0430", + "connection_timeout": "\u0418\u0441\u0442\u0435\u043a\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0445\u043e\u0441\u0442\u0443", + "host_port_exists": "\u042d\u0442\u0430 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f \u0445\u043e\u0441\u0442\u0430 \u0438 \u043f\u043e\u0440\u0442\u0430 \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430", + "resolve_failed": "\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0445\u043e\u0441\u0442" + }, + "step": { + "user": { + "data": { + "host": "\u0418\u043c\u044f \u0445\u043e\u0441\u0442\u0430 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430", + "name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430", + "port": "\u041f\u043e\u0440\u0442 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430" + }, + "title": "C\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f" + } + }, + "title": "\u0421\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430" + } +} \ No newline at end of file diff --git a/homeassistant/components/cert_expiry/.translations/zh-Hant.json b/homeassistant/components/cert_expiry/.translations/zh-Hant.json new file mode 100644 index 00000000000000..9af730db969f12 --- /dev/null +++ b/homeassistant/components/cert_expiry/.translations/zh-Hant.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "host_port_exists": "\u6b64\u4e3b\u6a5f\u7aef\u8207\u901a\u8a0a\u57e0\u7d44\u5408\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + }, + "error": { + "certificate_fetch_failed": "\u7121\u6cd5\u81ea\u6b64\u4e3b\u6a5f\u7aef\u8207\u901a\u8a0a\u57e0\u7d44\u5408\u7372\u5f97\u8a8d\u8b49", + "connection_timeout": "\u9023\u7dda\u81f3\u4e3b\u6a5f\u7aef\u903e\u6642", + "host_port_exists": "\u6b64\u4e3b\u6a5f\u7aef\u8207\u901a\u8a0a\u57e0\u7d44\u5408\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", + "resolve_failed": "\u4e3b\u6a5f\u7aef\u7121\u6cd5\u89e3\u6790" + }, + "step": { + "user": { + "data": { + "host": "\u8a8d\u8b49\u4e3b\u6a5f\u7aef\u540d\u7a31", + "name": "\u8a8d\u8b49\u540d\u7a31", + "port": "\u8a8d\u8b49\u901a\u8a0a\u57e0" + }, + "title": "\u5b9a\u7fa9\u8a8d\u8b49\u9032\u884c\u6e2c\u8a66" + } + }, + "title": "\u8a8d\u8b49\u5df2\u904e\u671f" + } +} \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/ca.json b/homeassistant/components/deconz/.translations/ca.json index 7b69b7477f59c2..56ae59c78ba031 100644 --- a/homeassistant/components/deconz/.translations/ca.json +++ b/homeassistant/components/deconz/.translations/ca.json @@ -40,5 +40,16 @@ } }, "title": "Passarel\u00b7la d'enlla\u00e7 deCONZ Zigbee" + }, + "options": { + "step": { + "async_step_deconz_devices": { + "data": { + "allow_clip_sensor": "Permet sensors deCONZ CLIP", + "allow_deconz_groups": "Permet grups de llums deCONZ" + }, + "description": "Configura la visibilitat dels tipus de dispositius deCONZ" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/da.json b/homeassistant/components/deconz/.translations/da.json index f79538ffeb6935..3c8c0377880d75 100644 --- a/homeassistant/components/deconz/.translations/da.json +++ b/homeassistant/components/deconz/.translations/da.json @@ -40,5 +40,16 @@ } }, "title": "deCONZ Zigbee gateway" + }, + "options": { + "step": { + "async_step_deconz_devices": { + "data": { + "allow_clip_sensor": "Tillad deCONZ CLIP sensorer", + "allow_deconz_groups": "Tillad deCONZ lys grupper" + }, + "description": "Konfigurer synligheden af deCONZ-enhedstyper" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/nl.json b/homeassistant/components/deconz/.translations/nl.json index 19477bbed3f33c..785fba4ffc0e02 100644 --- a/homeassistant/components/deconz/.translations/nl.json +++ b/homeassistant/components/deconz/.translations/nl.json @@ -40,5 +40,16 @@ } }, "title": "deCONZ Zigbee gateway" + }, + "options": { + "step": { + "async_step_deconz_devices": { + "data": { + "allow_clip_sensor": "DeCONZ CLIP sensoren toestaan", + "allow_deconz_groups": "DeCONZ-lichtgroepen toestaan" + }, + "description": "De zichtbaarheid van deCONZ-apparaattypen configureren" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/no.json b/homeassistant/components/deconz/.translations/no.json index 7c674c71022fc0..8798248224a582 100644 --- a/homeassistant/components/deconz/.translations/no.json +++ b/homeassistant/components/deconz/.translations/no.json @@ -40,5 +40,16 @@ } }, "title": "deCONZ Zigbee gateway" + }, + "options": { + "step": { + "async_step_deconz_devices": { + "data": { + "allow_clip_sensor": "Tillat deCONZ CLIP-sensorer", + "allow_deconz_groups": "Tillat deCONZ lys grupper" + }, + "description": "Konfigurere synlighet av deCONZ enhetstyper" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/pl.json b/homeassistant/components/deconz/.translations/pl.json index a17835f79a3020..0f2009a46b687b 100644 --- a/homeassistant/components/deconz/.translations/pl.json +++ b/homeassistant/components/deconz/.translations/pl.json @@ -15,9 +15,9 @@ "hassio_confirm": { "data": { "allow_clip_sensor": "Zezwalaj na importowanie wirtualnych sensor\u00f3w", - "allow_deconz_groups": "Zezw\u00f3l na importowanie grup deCONZ" + "allow_deconz_groups": "Zezwalaj na importowanie grup deCONZ" }, - "description": "Czy chcesz skonfigurowa\u0107 Home Assistant'a, aby po\u0142\u0105czy\u0142 si\u0119 z bramk\u0105 deCONZ dostarczon\u0105 przez dodatek Hass.io {addon}?", + "description": "Czy chcesz skonfigurowa\u0107 Home Assistant, aby po\u0142\u0105czy\u0142 si\u0119 z bramk\u0105 deCONZ dostarczon\u0105 przez dodatek Hass.io {addon}?", "title": "Bramka deCONZ Zigbee przez dodatek Hass.io" }, "init": { @@ -40,5 +40,16 @@ } }, "title": "Brama deCONZ Zigbee" + }, + "options": { + "step": { + "async_step_deconz_devices": { + "data": { + "allow_clip_sensor": "Zezwalaj na czujniki deCONZ CLIP", + "allow_deconz_groups": "Zezwalaj na grupy \u015bwiate\u0142 deCONZ" + }, + "description": "Skonfiguruj widoczno\u015b\u0107 urz\u0105dze\u0144 deCONZ" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/ru.json b/homeassistant/components/deconz/.translations/ru.json index ea701b3f759434..ee7208cdf1731a 100644 --- a/homeassistant/components/deconz/.translations/ru.json +++ b/homeassistant/components/deconz/.translations/ru.json @@ -40,5 +40,16 @@ } }, "title": "deCONZ" + }, + "options": { + "step": { + "async_step_deconz_devices": { + "data": { + "allow_clip_sensor": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0434\u0430\u0442\u0447\u0438\u043a\u0438 deCONZ CLIP", + "allow_deconz_groups": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0433\u0440\u0443\u043f\u043f\u044b \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u044f deCONZ" + }, + "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u0438\u043f\u043e\u0432 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 deCONZ" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/zh-Hant.json b/homeassistant/components/deconz/.translations/zh-Hant.json index 0173c90c3b7e5b..53d6f76a60161a 100644 --- a/homeassistant/components/deconz/.translations/zh-Hant.json +++ b/homeassistant/components/deconz/.translations/zh-Hant.json @@ -40,5 +40,16 @@ } }, "title": "deCONZ Zigbee \u9598\u9053\u5668" + }, + "options": { + "step": { + "async_step_deconz_devices": { + "data": { + "allow_clip_sensor": "\u5141\u8a31 deCONZ CLIP \u611f\u61c9\u5668", + "allow_deconz_groups": "\u5141\u8a31 deCONZ \u71c8\u5149\u7fa4\u7d44" + }, + "description": "\u8a2d\u5b9a deCONZ \u53ef\u8996\u88dd\u7f6e\u985e\u578b" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/emulated_roku/.translations/no.json b/homeassistant/components/emulated_roku/.translations/no.json index e83497599ca4cd..b41da3ccde394a 100644 --- a/homeassistant/components/emulated_roku/.translations/no.json +++ b/homeassistant/components/emulated_roku/.translations/no.json @@ -11,7 +11,7 @@ "host_ip": "Vert IP", "listen_port": "Lytte port", "name": "Navn", - "upnp_bind_multicast": "Bind multicast (True/False)" + "upnp_bind_multicast": "Bind multicast (Sant/Usant)" }, "title": "Definer serverkonfigurasjon" } diff --git a/homeassistant/components/esphome/.translations/zh-Hant.json b/homeassistant/components/esphome/.translations/zh-Hant.json index 74d0b925fb2380..0386fd8c468572 100644 --- a/homeassistant/components/esphome/.translations/zh-Hant.json +++ b/homeassistant/components/esphome/.translations/zh-Hant.json @@ -18,7 +18,7 @@ "title": "\u8f38\u5165\u5bc6\u78bc" }, "discovery_confirm": { - "description": "\u662f\u5426\u8981\u5c07 ESPHome \u7bc0\u9ede\u300c{name}\u300d\u65b0\u589e\u81f3 Home Assistant\uff1f", + "description": "\u662f\u5426\u8981\u5c07 ESPHome \u7bc0\u9ede `{name}` \u65b0\u589e\u81f3 Home Assistant\uff1f", "title": "\u767c\u73fe\u5230 ESPHome \u7bc0\u9ede" }, "user": { diff --git a/homeassistant/components/geonetnz_quakes/.translations/ca.json b/homeassistant/components/geonetnz_quakes/.translations/ca.json new file mode 100644 index 00000000000000..57ce2b4ee81bf3 --- /dev/null +++ b/homeassistant/components/geonetnz_quakes/.translations/ca.json @@ -0,0 +1,17 @@ +{ + "config": { + "error": { + "identifier_exists": "Ubicaci\u00f3 ja registrada" + }, + "step": { + "user": { + "data": { + "mmi": "MMI", + "radius": "Radi" + }, + "title": "Introdueix els detalls del filtre." + } + }, + "title": "GeoNet NZ Quakes" + } +} \ No newline at end of file diff --git a/homeassistant/components/geonetnz_quakes/.translations/da.json b/homeassistant/components/geonetnz_quakes/.translations/da.json new file mode 100644 index 00000000000000..0d0e927bc4be4e --- /dev/null +++ b/homeassistant/components/geonetnz_quakes/.translations/da.json @@ -0,0 +1,17 @@ +{ + "config": { + "error": { + "identifier_exists": "Placering allerede registreret" + }, + "step": { + "user": { + "data": { + "mmi": "MMI", + "radius": "Radius" + }, + "title": "Udfyld dine filteroplysninger." + } + }, + "title": "GeoNet NZ Quakes" + } +} \ No newline at end of file diff --git a/homeassistant/components/geonetnz_quakes/.translations/hu.json b/homeassistant/components/geonetnz_quakes/.translations/hu.json new file mode 100644 index 00000000000000..42de5a1314239b --- /dev/null +++ b/homeassistant/components/geonetnz_quakes/.translations/hu.json @@ -0,0 +1,12 @@ +{ + "config": { + "step": { + "user": { + "data": { + "radius": "Sug\u00e1r" + }, + "title": "T\u00f6ltse ki a sz\u0171r\u0151 adatait." + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/geonetnz_quakes/.translations/nl.json b/homeassistant/components/geonetnz_quakes/.translations/nl.json new file mode 100644 index 00000000000000..d6af28240eb3fa --- /dev/null +++ b/homeassistant/components/geonetnz_quakes/.translations/nl.json @@ -0,0 +1,17 @@ +{ + "config": { + "error": { + "identifier_exists": "Locatie al geregistreerd" + }, + "step": { + "user": { + "data": { + "mmi": "MMI", + "radius": "Straal" + }, + "title": "Vul uw filtergegevens in." + } + }, + "title": "GeoNet NZ Quakes" + } +} \ No newline at end of file diff --git a/homeassistant/components/geonetnz_quakes/.translations/pl.json b/homeassistant/components/geonetnz_quakes/.translations/pl.json new file mode 100644 index 00000000000000..427c753f6c1a01 --- /dev/null +++ b/homeassistant/components/geonetnz_quakes/.translations/pl.json @@ -0,0 +1,17 @@ +{ + "config": { + "error": { + "identifier_exists": "Lokalizacja ju\u017c zarejestrowana" + }, + "step": { + "user": { + "data": { + "mmi": "MMI", + "radius": "Promie\u0144" + }, + "title": "Wype\u0142nij szczeg\u00f3\u0142y dotycz\u0105ce filtra." + } + }, + "title": "GeoNet NZ Quakes" + } +} \ No newline at end of file diff --git a/homeassistant/components/geonetnz_quakes/.translations/ru.json b/homeassistant/components/geonetnz_quakes/.translations/ru.json new file mode 100644 index 00000000000000..7d6583bc1d5b59 --- /dev/null +++ b/homeassistant/components/geonetnz_quakes/.translations/ru.json @@ -0,0 +1,17 @@ +{ + "config": { + "error": { + "identifier_exists": "\u041c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e" + }, + "step": { + "user": { + "data": { + "mmi": "MMI", + "radius": "\u0420\u0430\u0434\u0438\u0443\u0441" + }, + "title": "GeoNet" + } + }, + "title": "\u0417\u0435\u043c\u043b\u0435\u0442\u0440\u044f\u0441\u0435\u043d\u0438\u044f \u0432 \u041d\u043e\u0432\u043e\u0439 \u0417\u0435\u043b\u0430\u043d\u0434\u0438\u0438 (GeoNet)" + } +} \ No newline at end of file diff --git a/homeassistant/components/geonetnz_quakes/.translations/zh-Hant.json b/homeassistant/components/geonetnz_quakes/.translations/zh-Hant.json new file mode 100644 index 00000000000000..59b4abf259a12d --- /dev/null +++ b/homeassistant/components/geonetnz_quakes/.translations/zh-Hant.json @@ -0,0 +1,17 @@ +{ + "config": { + "error": { + "identifier_exists": "\u5ea7\u6a19\u5df2\u8a3b\u518a" + }, + "step": { + "user": { + "data": { + "mmi": "MMI", + "radius": "\u534a\u5f91" + }, + "title": "\u586b\u5beb\u904e\u6ffe\u5668\u8cc7\u8a0a\u3002" + } + }, + "title": "GeoNet NZ Quakes" + } +} \ No newline at end of file diff --git a/homeassistant/components/heos/.translations/pl.json b/homeassistant/components/heos/.translations/pl.json index 9b5f9844ddc9e5..d427acc3a986f5 100644 --- a/homeassistant/components/heos/.translations/pl.json +++ b/homeassistant/components/heos/.translations/pl.json @@ -12,7 +12,7 @@ "access_token": "Host", "host": "Host" }, - "description": "Wprowad\u017a nazw\u0119 hosta lub adres IP urz\u0105dzenia Heos (preferowane po\u0142\u0105czenie kablowe, nie WiFi).", + "description": "Wprowad\u017a nazw\u0119 hosta lub adres IP urz\u0105dzenia Heos (najlepiej pod\u0142\u0105czonego przewodowo do sieci).", "title": "Po\u0142\u0105cz si\u0119 z Heos" } }, diff --git a/homeassistant/components/homekit_controller/.translations/pl.json b/homeassistant/components/homekit_controller/.translations/pl.json index 031a7440ed0129..e66353c5000d75 100644 --- a/homeassistant/components/homekit_controller/.translations/pl.json +++ b/homeassistant/components/homekit_controller/.translations/pl.json @@ -13,8 +13,8 @@ "authentication_error": "Niepoprawny kod parowania HomeKit. Sprawd\u017a go i spr\u00f3buj ponownie.", "busy_error": "Urz\u0105dzenie odm\u00f3wi\u0142o parowania, poniewa\u017c jest ju\u017c powi\u0105zane z innym kontrolerem.", "max_peers_error": "Urz\u0105dzenie odm\u00f3wi\u0142o parowania, poniewa\u017c nie ma wolnej pami\u0119ci parowania.", - "max_tries_error": "Urz\u0105dzenie odm\u00f3wi\u0142o parowania, poniewa\u017c otrzyma\u0142o ponad 100 nieudanych pr\u00f3b uwierzytelnienia.", - "pairing_failed": "Wyst\u0105pi\u0142 nieobs\u0142ugiwany b\u0142\u0105d podczas pr\u00f3by sparowania z tym urz\u0105dzeniem. Mo\u017ce to by\u0107 tymczasowa awaria lub Twoje urz\u0105dzenie mo\u017ce nie by\u0107 obecnie obs\u0142ugiwane.", + "max_tries_error": "Urz\u0105dzenie odm\u00f3wi\u0142o dodania parowania, poniewa\u017c otrzyma\u0142o ponad 100 nieudanych pr\u00f3b uwierzytelnienia.", + "pairing_failed": "Wyst\u0105pi\u0142 nieobs\u0142ugiwany b\u0142\u0105d podczas pr\u00f3by sparowania z tym urz\u0105dzeniem. Mo\u017ce to by\u0107 tymczasowa awaria lub urz\u0105dzenie mo\u017ce nie by\u0107 obecnie obs\u0142ugiwane.", "unable_to_pair": "Nie mo\u017cna sparowa\u0107, spr\u00f3buj ponownie.", "unknown_error": "Urz\u0105dzenie zg\u0142osi\u0142o nieznany b\u0142\u0105d. Parowanie nie powiod\u0142o si\u0119." }, diff --git a/homeassistant/components/life360/.translations/ca.json b/homeassistant/components/life360/.translations/ca.json index a7189d69185220..58401a33d1460f 100644 --- a/homeassistant/components/life360/.translations/ca.json +++ b/homeassistant/components/life360/.translations/ca.json @@ -10,6 +10,7 @@ "error": { "invalid_credentials": "Credencials inv\u00e0lides", "invalid_username": "Nom d'usuari incorrecte", + "unexpected": "S'ha produ\u00eft un error inesperat en comunicar-se amb el servidor de Life360.", "user_already_configured": "El compte ja ha estat configurat" }, "step": { diff --git a/homeassistant/components/life360/.translations/da.json b/homeassistant/components/life360/.translations/da.json index 1870c3fdb51eaf..933fce4a4e8798 100644 --- a/homeassistant/components/life360/.translations/da.json +++ b/homeassistant/components/life360/.translations/da.json @@ -10,6 +10,7 @@ "error": { "invalid_credentials": "Ugyldige legitimationsoplysninger", "invalid_username": "Ugyldigt brugernavn", + "unexpected": "Uventet fejl under kommunikation med Life360-serveren", "user_already_configured": "Kontoen er allerede konfigureret" }, "step": { diff --git a/homeassistant/components/life360/.translations/hu.json b/homeassistant/components/life360/.translations/hu.json new file mode 100644 index 00000000000000..227e784b0653eb --- /dev/null +++ b/homeassistant/components/life360/.translations/hu.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "unexpected": "V\u00e1ratlan hiba t\u00f6rt\u00e9nt a kommunik\u00e1ci\u00f3ban a Life360 szerverrel" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/life360/.translations/nl.json b/homeassistant/components/life360/.translations/nl.json index ec7a53329503a0..08be66a89639f1 100644 --- a/homeassistant/components/life360/.translations/nl.json +++ b/homeassistant/components/life360/.translations/nl.json @@ -10,6 +10,7 @@ "error": { "invalid_credentials": "Ongeldige gebruikersgegevens", "invalid_username": "Ongeldige gebruikersnaam", + "unexpected": "Onverwachte fout bij communicatie met Life360-server", "user_already_configured": "Account is al geconfigureerd" }, "step": { diff --git a/homeassistant/components/life360/.translations/pl.json b/homeassistant/components/life360/.translations/pl.json index 15aabaa6308424..cd5e61fc123608 100644 --- a/homeassistant/components/life360/.translations/pl.json +++ b/homeassistant/components/life360/.translations/pl.json @@ -10,6 +10,7 @@ "error": { "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce", "invalid_username": "Nieprawid\u0142owa nazwa u\u017cytkownika", + "unexpected": "Nieoczekiwany b\u0142\u0105d komunikacji z serwerem Life360", "user_already_configured": "Konto zosta\u0142o ju\u017c skonfigurowane." }, "step": { diff --git a/homeassistant/components/life360/.translations/ru.json b/homeassistant/components/life360/.translations/ru.json index 0f698457bf799a..c03ad0f7e1f6a6 100644 --- a/homeassistant/components/life360/.translations/ru.json +++ b/homeassistant/components/life360/.translations/ru.json @@ -10,6 +10,7 @@ "error": { "invalid_credentials": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0443\u0447\u0435\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435", "invalid_username": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d", + "unexpected": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c Life360", "user_already_configured": "\u0423\u0447\u0435\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430" }, "step": { diff --git a/homeassistant/components/life360/.translations/zh-Hant.json b/homeassistant/components/life360/.translations/zh-Hant.json index 8ab5dcf536979e..75081c62d41099 100644 --- a/homeassistant/components/life360/.translations/zh-Hant.json +++ b/homeassistant/components/life360/.translations/zh-Hant.json @@ -10,6 +10,7 @@ "error": { "invalid_credentials": "\u6191\u8b49\u7121\u6548", "invalid_username": "\u4f7f\u7528\u8005\u540d\u7a31\u7121\u6548", + "unexpected": "\u8207 Life360 \u4f3a\u670d\u5668\u901a\u8a0a\u767c\u751f\u672a\u77e5\u932f\u8aa4", "user_already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" }, "step": { diff --git a/homeassistant/components/light/.translations/en.json b/homeassistant/components/light/.translations/en.json new file mode 100644 index 00000000000000..9e5d1abddaf486 --- /dev/null +++ b/homeassistant/components/light/.translations/en.json @@ -0,0 +1,8 @@ +{ + "device_automation": { + "trigger_type": { + "turn_off": "{name} turned off", + "turn_on": "{name} turned on" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/logi_circle/.translations/pl.json b/homeassistant/components/logi_circle/.translations/pl.json index 2c155ffde61b35..f39df48ae5a483 100644 --- a/homeassistant/components/logi_circle/.translations/pl.json +++ b/homeassistant/components/logi_circle/.translations/pl.json @@ -2,8 +2,8 @@ "config": { "abort": { "already_setup": "Mo\u017cesz skonfigurowa\u0107 tylko jedno konto Logi Circle.", - "external_error": "Wyst\u0105pi\u0142 wyj\u0105tek zewn\u0119trzny.", - "external_setup": "Logi Circle pomy\u015blnie skonfigurowano.", + "external_error": "Wyst\u0105pi\u0142 wyj\u0105tek z innego przep\u0142ywu.", + "external_setup": "Logi Circle zosta\u0142o pomy\u015blnie skonfigurowane z innego przep\u0142ywu.", "no_flows": "Musisz skonfigurowa\u0107 Logi Circle, zanim b\u0119dziesz m\u00f3g\u0142 si\u0119 z nim uwierzytelni\u0107. [Przeczytaj instrukcj\u0119](https://www.home-assistant.io/components/logi_circle/)." }, "create_entry": { @@ -12,12 +12,12 @@ "error": { "auth_error": "Autoryzacja API nie powiod\u0142a si\u0119.", "auth_timeout": "Up\u0142yn\u0105\u0142 limit czasu \u017c\u0105dania tokena dost\u0119pu.", - "follow_link": "Prosz\u0119 klikn\u0105\u0107 link i uwierzytelni\u0107 przed naci\u015bni\u0119ciem przycisku Prze\u015blij." + "follow_link": "Post\u0119puj zgodnie z linkiem i uwierzytelnij si\u0119 przed naci\u015bni\u0119ciem przycisku Prze\u015blij." }, "step": { "auth": { "description": "Kliknij poni\u017cszy link i Zaakceptuj dost\u0119p do swojego konta Logi Circle, a nast\u0119pnie wr\u00f3\u0107 i naci\u015bnij Prze\u015blij poni\u017cej. \n\n [Link]({authorization_url})", - "title": "Uwierzytelnienie Logi Circle" + "title": "Uwierzytelnij za pomoc\u0105 Logi Circle" }, "user": { "data": { diff --git a/homeassistant/components/met/.translations/hu.json b/homeassistant/components/met/.translations/hu.json new file mode 100644 index 00000000000000..3b34d8f6354d6a --- /dev/null +++ b/homeassistant/components/met/.translations/hu.json @@ -0,0 +1,9 @@ +{ + "config": { + "step": { + "user": { + "title": "Elhelyezked\u00e9s" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/nest/.translations/ca.json b/homeassistant/components/nest/.translations/ca.json index b242208791b6ae..636568b96d350b 100644 --- a/homeassistant/components/nest/.translations/ca.json +++ b/homeassistant/components/nest/.translations/ca.json @@ -3,7 +3,7 @@ "abort": { "already_setup": "Nom\u00e9s pots configurar un \u00fanic compte Nest.", "authorize_url_fail": "S'ha produ\u00eft un error desconegut al generar l'URL d'autoritzaci\u00f3.", - "authorize_url_timeout": "El temps d'espera m\u00e0xim per generar l'URL d'autoritzaci\u00f3 s'ha esgotat.", + "authorize_url_timeout": "S'ha acabat el temps d'espera durant la generaci\u00f3 de l'URL d'autoritzaci\u00f3.", "no_flows": "Necessites configurar Nest abans de poder autenticar-t'hi. Llegeix les [instruccions](https://www.home-assistant.io/components/nest/)." }, "error": { diff --git a/homeassistant/components/nest/.translations/zh-Hant.json b/homeassistant/components/nest/.translations/zh-Hant.json index 6b9dbdb19b1148..c477557e7ba0c7 100644 --- a/homeassistant/components/nest/.translations/zh-Hant.json +++ b/homeassistant/components/nest/.translations/zh-Hant.json @@ -4,7 +4,7 @@ "already_setup": "\u50c5\u80fd\u8a2d\u5b9a\u4e00\u7d44 Nest \u5e33\u865f\u3002", "authorize_url_fail": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u767c\u751f\u672a\u77e5\u932f\u8aa4", "authorize_url_timeout": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u903e\u6642", - "no_flows": "\u5fc5\u9808\u5148\u8a2d\u5b9a Nest \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15]\uff08https://www.home-assistant.io/components/nest/\uff09\u3002" + "no_flows": "\u5fc5\u9808\u5148\u8a2d\u5b9a Nest \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15](https://www.home-assistant.io/components/nest/)\u3002" }, "error": { "internal_error": "\u8a8d\u8b49\u78bc\u5167\u90e8\u932f\u8aa4", diff --git a/homeassistant/components/notion/.translations/hu.json b/homeassistant/components/notion/.translations/hu.json new file mode 100644 index 00000000000000..2f7664cf74eec1 --- /dev/null +++ b/homeassistant/components/notion/.translations/hu.json @@ -0,0 +1,18 @@ +{ + "config": { + "error": { + "identifier_exists": "Felhaszn\u00e1l\u00f3n\u00e9v m\u00e1r regisztr\u00e1lva van", + "invalid_credentials": "\u00c9rv\u00e9nytelen felhaszn\u00e1l\u00f3n\u00e9v vagy jelsz\u00f3", + "no_devices": "Nem tal\u00e1lhat\u00f3 eszk\u00f6z a fi\u00f3kban" + }, + "step": { + "user": { + "data": { + "password": "Jelsz\u00f3", + "username": "Felhaszn\u00e1l\u00f3n\u00e9v/Email C\u00edm" + }, + "title": "T\u00f6ltse ki adatait" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/point/.translations/zh-Hant.json b/homeassistant/components/point/.translations/zh-Hant.json index 91a86f5e3dba1c..9f688b2e5f9d52 100644 --- a/homeassistant/components/point/.translations/zh-Hant.json +++ b/homeassistant/components/point/.translations/zh-Hant.json @@ -5,7 +5,7 @@ "authorize_url_fail": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u767c\u751f\u672a\u77e5\u932f\u8aa4", "authorize_url_timeout": "\u7522\u751f\u8a8d\u8b49 URL \u6642\u903e\u6642", "external_setup": "\u5df2\u7531\u5176\u4ed6\u6d41\u7a0b\u6210\u529f\u8a2d\u5b9a Point\u3002", - "no_flows": "\u5fc5\u9808\u5148\u8a2d\u5b9a Point \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15]\uff08https://www.home-assistant.io/components/point/\uff09\u3002" + "no_flows": "\u5fc5\u9808\u5148\u8a2d\u5b9a Point \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15](https://www.home-assistant.io/components/point/)\u3002" }, "create_entry": { "default": "\u5df2\u6210\u529f\u8a8d\u8b49 Minut Point \u88dd\u7f6e\u3002" diff --git a/homeassistant/components/ps4/.translations/pl.json b/homeassistant/components/ps4/.translations/pl.json index 3e36960b12c019..9fb4c73f1d056a 100644 --- a/homeassistant/components/ps4/.translations/pl.json +++ b/homeassistant/components/ps4/.translations/pl.json @@ -8,7 +8,7 @@ "port_997_bind_error": "Nie mo\u017cna powi\u0105za\u0107 z portem 997." }, "error": { - "credential_timeout": "Up\u0142yn\u0105\u0142 limit czasu us\u0142ugi po\u015bwiadcze\u0144. Naci\u015bnij przycisk Prze\u015blij, aby ponownie uruchomi\u0107.", + "credential_timeout": "Up\u0142yn\u0105\u0142 limit czasu us\u0142ugi po\u015bwiadcze\u0144. Naci\u015bnij przycisk Prze\u015blij, aby ponowi\u0107.", "login_failed": "Nie uda\u0142o si\u0119 sparowa\u0107 z PlayStation 4. Sprawd\u017a, czy PIN jest poprawny.", "no_ipaddress": "Wprowad\u017a adres IP PlayStation 4, kt\u00f3ry chcesz skonfigurowa\u0107.", "not_ready": "PlayStation 4 nie jest w\u0142\u0105czona lub po\u0142\u0105czona z sieci\u0105." diff --git a/homeassistant/components/toon/.translations/zh-Hant.json b/homeassistant/components/toon/.translations/zh-Hant.json index b09d921268cf11..0156b58c9ac049 100644 --- a/homeassistant/components/toon/.translations/zh-Hant.json +++ b/homeassistant/components/toon/.translations/zh-Hant.json @@ -4,7 +4,7 @@ "client_id": "\u8a2d\u5b9a\u5167\u7528\u6236\u7aef ID \u7121\u6548\u3002", "client_secret": "\u8a2d\u5b9a\u5167\u5ba2\u6236\u7aef\u5bc6\u78bc\u7121\u6548\u3002", "no_agreements": "\u6b64\u5e33\u865f\u4e26\u672a\u64c1\u6709 Toon \u88dd\u7f6e\u3002", - "no_app": "\u5fc5\u9808\u5148\u8a2d\u5b9a Toon \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15]\uff08https://www.home-assistant.io/components/toon/\uff09\u3002", + "no_app": "\u5fc5\u9808\u5148\u8a2d\u5b9a Toon \u65b9\u80fd\u9032\u884c\u8a8d\u8b49\u3002[\u8acb\u53c3\u95b1\u6559\u5b78\u6307\u5f15](https://www.home-assistant.io/components/toon/(\u3002", "unknown_auth_fail": "\u9a57\u8b49\u6642\u767c\u751f\u672a\u77e5\u932f\u8aa4\u3002" }, "error": { diff --git a/homeassistant/components/traccar/.translations/ca.json b/homeassistant/components/traccar/.translations/ca.json new file mode 100644 index 00000000000000..0cfb9738d5dd89 --- /dev/null +++ b/homeassistant/components/traccar/.translations/ca.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "not_internet_accessible": "La inst\u00e0ncia de Home Assistant ha de ser accessible des d'Internet per rebre missatges de Traccar.", + "one_instance_allowed": "Nom\u00e9s cal una sola inst\u00e0ncia." + }, + "create_entry": { + "default": "Per enviar esdeveniments a Home Assistant, haur\u00e0s de configurar l'opci\u00f3 webhook de Traccar.\n\nUtilitza el seg\u00fcent enlla\u00e7: `{webhook_url}`\n\nConsulta la [documentaci\u00f3]({docs_url}) per a m\u00e9s detalls." + }, + "step": { + "user": { + "description": "Est\u00e0s segur que vols configurar Traccar?", + "title": "Configura Traccar" + } + }, + "title": "Traccar" + } +} \ No newline at end of file diff --git a/homeassistant/components/traccar/.translations/da.json b/homeassistant/components/traccar/.translations/da.json new file mode 100644 index 00000000000000..af3963f8c0f7b5 --- /dev/null +++ b/homeassistant/components/traccar/.translations/da.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "not_internet_accessible": "Dit Home Assistant system skal v\u00e6re tilg\u00e6ngeligt fra internettet for at modtage Traccar meddelelser.", + "one_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning." + }, + "create_entry": { + "default": "For at sende begivenheder til Home Assistant skal du konfigurere webhook funktionen i Traccar.\n\n Brug f\u00f8lgende URL: `{webhook_url}`\n \n Se [dokumentationen]({docs_url}) for yderligere oplysninger." + }, + "step": { + "user": { + "description": "Er du sikker p\u00e5 at du vil konfigurere Traccar?", + "title": "Konfigurer Traccar" + } + }, + "title": "Traccar" + } +} \ No newline at end of file diff --git a/homeassistant/components/traccar/.translations/nl.json b/homeassistant/components/traccar/.translations/nl.json new file mode 100644 index 00000000000000..c4ee0544a2e716 --- /dev/null +++ b/homeassistant/components/traccar/.translations/nl.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "not_internet_accessible": "Uw Home Assistant-exemplaar moet toegankelijk zijn vanaf internet om berichten van Traccar te ontvangen.", + "one_instance_allowed": "Slechts \u00e9\u00e9n instantie is nodig." + }, + "create_entry": { + "default": "Voor het verzenden van gebeurtenissen naar Home Assistant, moet u de webhook-functie in Traccar instellen.\n\nGebruik de volgende URL: ' {webhook_url} '\n\nZie [de documentatie] ({docs_url}) voor meer informatie." + }, + "step": { + "user": { + "description": "Weet u zeker dat u Traccar wilt instellen?", + "title": "Traccar instellen" + } + }, + "title": "Traccar" + } +} \ No newline at end of file diff --git a/homeassistant/components/traccar/.translations/pl.json b/homeassistant/components/traccar/.translations/pl.json new file mode 100644 index 00000000000000..66ddbaaa3fdb21 --- /dev/null +++ b/homeassistant/components/traccar/.translations/pl.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "not_internet_accessible": "Twoja instancja Home Assistant musi by\u0107 dost\u0119pna z Internetu, aby otrzymywa\u0107 wiadomo\u015bci z Traccar.", + "one_instance_allowed": "Niezb\u0119dna jest tylko jedna instancja." + }, + "create_entry": { + "default": "Aby wys\u0142a\u0107 wydarzenia do Home Assistant, musisz skonfigurowa\u0107 funkcj\u0119 webhook w Traccar. \n\n U\u017cyj nast\u0119puj\u0105cego URL: ` {webhook_url} ` \n\n Zobacz [dokumentacj\u0119] ( {docs_url} ) w celu uzyskania dalszych szczeg\u00f3\u0142\u00f3w." + }, + "step": { + "user": { + "description": "Czy na pewno chcesz skonfigurowa\u0107 Traccar?", + "title": "Skonfiguruj Traccar" + } + }, + "title": "Traccar" + } +} \ No newline at end of file diff --git a/homeassistant/components/traccar/.translations/ru.json b/homeassistant/components/traccar/.translations/ru.json new file mode 100644 index 00000000000000..afaab87efe4e8e --- /dev/null +++ b/homeassistant/components/traccar/.translations/ru.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "not_internet_accessible": "\u0412\u0430\u0448 Home Assistant \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 Traccar.", + "one_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." + }, + "create_entry": { + "default": "\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 Home Assistant \u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c webhooks \u0434\u043b\u044f Traccar.\n\n\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e:\n\n- URL: `{webhook_url}`\n\n\u041e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439]({docs_url}) \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438." + }, + "step": { + "user": { + "description": "\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Traccar?", + "title": "Traccar" + } + }, + "title": "Traccar" + } +} \ No newline at end of file diff --git a/homeassistant/components/traccar/.translations/zh-Hant.json b/homeassistant/components/traccar/.translations/zh-Hant.json new file mode 100644 index 00000000000000..f5402454294856 --- /dev/null +++ b/homeassistant/components/traccar/.translations/zh-Hant.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "not_internet_accessible": "Home Assistant \u5be6\u4f8b\u5fc5\u9808\u80fd\u5920\u7531\u7db2\u969b\u7db2\u8def\u5b58\u53d6\uff0c\u65b9\u80fd\u63a5\u53d7 Traccar \u8a0a\u606f\u3002", + "one_instance_allowed": "\u50c5\u9700\u8a2d\u5b9a\u4e00\u7d44\u7269\u4ef6\u5373\u53ef\u3002" + }, + "create_entry": { + "default": "\u6b32\u50b3\u9001\u4e8b\u4ef6\u81f3 Home Assistant\uff0c\u5c07\u9700\u65bc Traccar \u5167\u8a2d\u5b9a webhook \u529f\u80fd\u3002\n\n\u8acb\u4f7f\u7528 url: `{webhook_url}`\n\n\u8acb\u53c3\u95b1 [\u6587\u4ef6]({docs_url})\u4ee5\u4e86\u89e3\u66f4\u8a73\u7d30\u8cc7\u6599\u3002" + }, + "step": { + "user": { + "description": "\u662f\u5426\u8981\u8a2d\u5b9a Traccar\uff1f", + "title": "\u8a2d\u5b9a Traccar" + } + }, + "title": "Traccar" + } +} \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/.translations/ca.json b/homeassistant/components/twentemilieu/.translations/ca.json new file mode 100644 index 00000000000000..27ab8e8a8b2b0b --- /dev/null +++ b/homeassistant/components/twentemilieu/.translations/ca.json @@ -0,0 +1,23 @@ +{ + "config": { + "abort": { + "address_exists": "Adre\u00e7a ja configurada." + }, + "error": { + "connection_error": "No s'ha pogut connectar.", + "invalid_address": "No s'ha trobat l'adre\u00e7a a l'\u00e0rea de servei de Twente Milieu." + }, + "step": { + "user": { + "data": { + "house_letter": "Lletra/addicional de casa", + "house_number": "N\u00famero de casa", + "post_code": "Codi postal" + }, + "description": "Configura Twente Milieu amb informaci\u00f3 de la recollida de residus a la teva adre\u00e7a.", + "title": "Twente Milieu" + } + }, + "title": "Twente Milieu" + } +} \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/.translations/da.json b/homeassistant/components/twentemilieu/.translations/da.json new file mode 100644 index 00000000000000..1e3ca933e3895a --- /dev/null +++ b/homeassistant/components/twentemilieu/.translations/da.json @@ -0,0 +1,23 @@ +{ + "config": { + "abort": { + "address_exists": "Adresse er allerede konfigureret." + }, + "error": { + "connection_error": "Forbindelse mislykkedes.", + "invalid_address": "Adresse ikke fundet i Twente Milieu serviceomr\u00e5de." + }, + "step": { + "user": { + "data": { + "house_letter": "Hus nummer/yderligere", + "house_number": "Husnummer", + "post_code": "Postnummer" + }, + "description": "Konfigurer Twente Milieu, der leverer oplysninger om indsamling af affald p\u00e5 din adresse.", + "title": "Twente Milieu" + } + }, + "title": "Twente Milieu" + } +} \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/.translations/hu.json b/homeassistant/components/twentemilieu/.translations/hu.json new file mode 100644 index 00000000000000..439e02d1027813 --- /dev/null +++ b/homeassistant/components/twentemilieu/.translations/hu.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "address_exists": "A c\u00edm m\u00e1r be lett \u00e1ll\u00edtva." + }, + "error": { + "connection_error": "Nem siker\u00fclt csatlakozni." + }, + "step": { + "user": { + "data": { + "house_number": "h\u00e1zsz\u00e1m", + "post_code": "ir\u00e1ny\u00edt\u00f3sz\u00e1m" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/.translations/nl.json b/homeassistant/components/twentemilieu/.translations/nl.json new file mode 100644 index 00000000000000..a420133f464c93 --- /dev/null +++ b/homeassistant/components/twentemilieu/.translations/nl.json @@ -0,0 +1,23 @@ +{ + "config": { + "abort": { + "address_exists": "Adres al ingesteld." + }, + "error": { + "connection_error": "Kon niet verbinden.", + "invalid_address": "Adres niet gevonden in servicegebied Twente Milieu." + }, + "step": { + "user": { + "data": { + "house_letter": "Huisnummer / toevoeging", + "house_number": "Huisnummer", + "post_code": "Postcode" + }, + "description": "Stel Twente Milieu in voor het inzamelen van afval op uw adres.", + "title": "Twente Milieu" + } + }, + "title": "Twente Milieu" + } +} \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/.translations/pl.json b/homeassistant/components/twentemilieu/.translations/pl.json new file mode 100644 index 00000000000000..042fcf0dda66d4 --- /dev/null +++ b/homeassistant/components/twentemilieu/.translations/pl.json @@ -0,0 +1,23 @@ +{ + "config": { + "abort": { + "address_exists": "Adres ju\u017c skonfigurowany." + }, + "error": { + "connection_error": "Po\u0142\u0105czenie nieudane.", + "invalid_address": "Nie znaleziono adresu w obszarze us\u0142ugi Twente Milieu." + }, + "step": { + "user": { + "data": { + "house_letter": "List domowy / dodatkowy", + "house_number": "Numer domu", + "post_code": "Kod pocztowy" + }, + "description": "Skonfiguruj Twente Milieu, dostarczaj\u0105c informacji o zbieraniu odpad\u00f3w pod swoim adresem.", + "title": "Twente Milieu" + } + }, + "title": "Twente Milieu" + } +} \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/.translations/ru.json b/homeassistant/components/twentemilieu/.translations/ru.json new file mode 100644 index 00000000000000..5d964604a77312 --- /dev/null +++ b/homeassistant/components/twentemilieu/.translations/ru.json @@ -0,0 +1,23 @@ +{ + "config": { + "abort": { + "address_exists": "\u0410\u0434\u0440\u0435\u0441 \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d." + }, + "error": { + "connection_error": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.", + "invalid_address": "\u0410\u0434\u0440\u0435\u0441 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0432 \u0437\u043e\u043d\u0435 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f Twente Milieu." + }, + "step": { + "user": { + "data": { + "house_letter": "\u041b\u0438\u0442\u0435\u0440 \u0434\u043e\u043c\u0430 / \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435", + "house_number": "\u041d\u043e\u043c\u0435\u0440 \u0434\u043e\u043c\u0430", + "post_code": "\u041f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441" + }, + "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 Twente Milieu \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0432\u044b\u0432\u043e\u0437\u0435 \u043c\u0443\u0441\u043e\u0440\u0430 \u043f\u043e \u0412\u0430\u0448\u0435\u043c\u0443 \u0430\u0434\u0440\u0435\u0441\u0443.", + "title": "Twente Milieu" + } + }, + "title": "Twente Milieu" + } +} \ No newline at end of file diff --git a/homeassistant/components/twentemilieu/.translations/zh-Hant.json b/homeassistant/components/twentemilieu/.translations/zh-Hant.json new file mode 100644 index 00000000000000..0e0083ec5c1750 --- /dev/null +++ b/homeassistant/components/twentemilieu/.translations/zh-Hant.json @@ -0,0 +1,23 @@ +{ + "config": { + "abort": { + "address_exists": "\u5730\u5740\u5df2\u8a2d\u5b9a\u3002" + }, + "error": { + "connection_error": "\u9023\u7dda\u5931\u6557\u3002", + "invalid_address": "Twente Milieu \u670d\u52d9\u5340\u57df\u5167\u627e\u4e0d\u5230\u6b64\u5730\u5740\u3002" + }, + "step": { + "user": { + "data": { + "house_letter": "\u9580\u724c\u5b57\u6bcd/\u9644\u52a0\u8cc7\u8a0a", + "house_number": "\u9580\u724c\u865f\u78bc", + "post_code": "\u90f5\u905e\u5340\u865f" + }, + "description": "\u8a2d\u5b9a Twente Milieu \u4ee5\u53d6\u5f97\u8a72\u5730\u5740\u5ee2\u68c4\u7269\u56de\u6536\u8cc7\u8a0a\u3002", + "title": "Twente Milieu" + } + }, + "title": "Twente Milieu" + } +} \ No newline at end of file diff --git a/homeassistant/components/unifi/.translations/ca.json b/homeassistant/components/unifi/.translations/ca.json index 442d82d9a3f35e..8a8d8b11f57661 100644 --- a/homeassistant/components/unifi/.translations/ca.json +++ b/homeassistant/components/unifi/.translations/ca.json @@ -22,5 +22,17 @@ } }, "title": "Controlador UniFi" + }, + "options": { + "step": { + "device_tracker": { + "data": { + "detection_time": "Temps (en segons) des de s'ha vist per \u00faltima vegada fins que es considera a fora", + "track_clients": "Segueix clients de la xarxa", + "track_devices": "Segueix dispositius de la xarxa (dispositius Ubiquiti)", + "track_wired_clients": "Inclou clients de xarxa per cable" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/unifi/.translations/da.json b/homeassistant/components/unifi/.translations/da.json index 4155658d7deae5..53b794ed4353ff 100644 --- a/homeassistant/components/unifi/.translations/da.json +++ b/homeassistant/components/unifi/.translations/da.json @@ -22,5 +22,17 @@ } }, "title": "UniFi Controller" + }, + "options": { + "step": { + "device_tracker": { + "data": { + "detection_time": "Tid i sekunder fra sidst set indtil betragtet som v\u00e6k", + "track_clients": "Spor netv\u00e6rksklienter", + "track_devices": "Spor netv\u00e6rksenheder (Ubiquiti-enheder)", + "track_wired_clients": "Inkluder kablede netv\u00e6rksklienter" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/unifi/.translations/nl.json b/homeassistant/components/unifi/.translations/nl.json index 7a1eea546a2941..f907364327c958 100644 --- a/homeassistant/components/unifi/.translations/nl.json +++ b/homeassistant/components/unifi/.translations/nl.json @@ -22,5 +22,17 @@ } }, "title": "UniFi-controller" + }, + "options": { + "step": { + "device_tracker": { + "data": { + "detection_time": "Tijd in seconden vanaf laatst gezien tot beschouwd als weg", + "track_clients": "Volg netwerkclients", + "track_devices": "Netwerkapparaten volgen (Ubiquiti-apparaten)", + "track_wired_clients": "Inclusief bedrade netwerkcli\u00ebnten" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/unifi/.translations/pl.json b/homeassistant/components/unifi/.translations/pl.json index 5382adcbf7d97b..6366f82b3da0a8 100644 --- a/homeassistant/components/unifi/.translations/pl.json +++ b/homeassistant/components/unifi/.translations/pl.json @@ -22,5 +22,25 @@ } }, "title": "Kontroler UniFi" + }, + "options": { + "step": { + "device_tracker": { + "data": { + "detection_time": "Czas w sekundach od momentu, kiedy ostatnio widziano, a\u017c do momentu, kiedy uznano go za nieobecny.", + "track_clients": "\u015aled\u017a klient\u00f3w sieciowych", + "track_devices": "\u015aled\u017a urz\u0105dzenia sieciowe (urz\u0105dzenia Ubiquiti)", + "track_wired_clients": "Uwzgl\u0119dnij klient\u00f3w sieci przewodowej" + } + }, + "init": { + "data": { + "few": "Kilka", + "many": "Wiele", + "one": "Jeden", + "other": "Inne" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/unifi/.translations/ru.json b/homeassistant/components/unifi/.translations/ru.json index f4d86300acaed2..76802a96367677 100644 --- a/homeassistant/components/unifi/.translations/ru.json +++ b/homeassistant/components/unifi/.translations/ru.json @@ -22,5 +22,17 @@ } }, "title": "UniFi Controller" + }, + "options": { + "step": { + "device_tracker": { + "data": { + "detection_time": "\u0412\u0440\u0435\u043c\u044f \u043e\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0441\u0435\u0430\u043d\u0441\u0430 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c (\u0441\u0435\u043a.), \u043f\u043e \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 \"\u041d\u0435 \u0434\u043e\u043c\u0430\".", + "track_clients": "\u041e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0441\u0435\u0442\u0438", + "track_devices": "\u041e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 (\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Ubiquiti)", + "track_wired_clients": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u043e\u0434\u043d\u043e\u0439 \u0441\u0435\u0442\u0438" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/unifi/.translations/zh-Hant.json b/homeassistant/components/unifi/.translations/zh-Hant.json index e506c582cb7177..2d5bd9027ac44d 100644 --- a/homeassistant/components/unifi/.translations/zh-Hant.json +++ b/homeassistant/components/unifi/.translations/zh-Hant.json @@ -22,5 +22,17 @@ } }, "title": "UniFi \u63a7\u5236\u5668" + }, + "options": { + "step": { + "device_tracker": { + "data": { + "detection_time": "\u6700\u7d42\u51fa\u73fe\u5f8c\u8996\u70ba\u96e2\u958b\u7684\u6642\u9593\uff08\u4ee5\u79d2\u70ba\u55ae\u4f4d\uff09", + "track_clients": "\u8ffd\u8e64\u7db2\u8def\u5ba2\u6236\u7aef", + "track_devices": "\u8ffd\u8e64\u7db2\u8def\u88dd\u7f6e\uff08Ubiquiti \u88dd\u7f6e\uff09", + "track_wired_clients": "\u5305\u542b\u6709\u7dda\u7db2\u8def\u5ba2\u6236\u7aef" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/velbus/.translations/ca.json b/homeassistant/components/velbus/.translations/ca.json new file mode 100644 index 00000000000000..e38977a483fa5f --- /dev/null +++ b/homeassistant/components/velbus/.translations/ca.json @@ -0,0 +1,21 @@ +{ + "config": { + "abort": { + "port_exists": "El port ja est\u00e0 configurat" + }, + "error": { + "connection_failed": "Ha fallat la connexi\u00f3 Velbus", + "port_exists": "El port ja est\u00e0 configurat" + }, + "step": { + "user": { + "data": { + "name": "Nom de la connexi\u00f3 Velbus", + "port": "Cadena de connexi\u00f3" + }, + "title": "Tipus de connexi\u00f3 Velbus" + } + }, + "title": "Interf\u00edcie Velbus" + } +} \ No newline at end of file diff --git a/homeassistant/components/velbus/.translations/da.json b/homeassistant/components/velbus/.translations/da.json new file mode 100644 index 00000000000000..5e636c8bcd77a3 --- /dev/null +++ b/homeassistant/components/velbus/.translations/da.json @@ -0,0 +1,21 @@ +{ + "config": { + "abort": { + "port_exists": "Denne port er allerede konfigureret" + }, + "error": { + "connection_failed": "Velbus forbindelsen mislykkedes", + "port_exists": "Denne port er allerede konfigureret" + }, + "step": { + "user": { + "data": { + "name": "Navnet p\u00e5 denne velbus forbindelse", + "port": "Forbindelsesstreng" + }, + "title": "Definer velbus forbindelsestypen" + } + }, + "title": "Velbus-interface" + } +} \ No newline at end of file diff --git a/homeassistant/components/velbus/.translations/hu.json b/homeassistant/components/velbus/.translations/hu.json new file mode 100644 index 00000000000000..c836b414746de4 --- /dev/null +++ b/homeassistant/components/velbus/.translations/hu.json @@ -0,0 +1,10 @@ +{ + "config": { + "abort": { + "port_exists": "Ez a port m\u00e1r konfigur\u00e1lva van" + }, + "error": { + "port_exists": "Ez a port m\u00e1r konfigur\u00e1lva van" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/velbus/.translations/nl.json b/homeassistant/components/velbus/.translations/nl.json new file mode 100644 index 00000000000000..b2908e8d2210cf --- /dev/null +++ b/homeassistant/components/velbus/.translations/nl.json @@ -0,0 +1,21 @@ +{ + "config": { + "abort": { + "port_exists": "Deze poort is al geconfigureerd" + }, + "error": { + "connection_failed": "De velbus verbinding is mislukt.", + "port_exists": "Deze poort is al geconfigureerd" + }, + "step": { + "user": { + "data": { + "name": "De naam voor deze velbus-verbinding", + "port": "Verbindingsreeks" + }, + "title": "Definieer de velbus-verbindingstype" + } + }, + "title": "Velbus interface" + } +} \ No newline at end of file diff --git a/homeassistant/components/velbus/.translations/pl.json b/homeassistant/components/velbus/.translations/pl.json new file mode 100644 index 00000000000000..72e18b0e2c89fa --- /dev/null +++ b/homeassistant/components/velbus/.translations/pl.json @@ -0,0 +1,21 @@ +{ + "config": { + "abort": { + "port_exists": "Ten port jest ju\u017c skonfigurowany" + }, + "error": { + "connection_failed": "Po\u0142\u0105czenie Velbus nie powiod\u0142o si\u0119", + "port_exists": "Ten port jest ju\u017c skonfigurowany" + }, + "step": { + "user": { + "data": { + "name": "Nazwa tego po\u0142\u0105czenia Velbus", + "port": "Parametry po\u0142\u0105czenia" + }, + "title": "Zdefiniuj typ po\u0142\u0105czenia Velbus" + } + }, + "title": "Interfejs Velbus" + } +} \ No newline at end of file diff --git a/homeassistant/components/velbus/.translations/ru.json b/homeassistant/components/velbus/.translations/ru.json new file mode 100644 index 00000000000000..3434c584221455 --- /dev/null +++ b/homeassistant/components/velbus/.translations/ru.json @@ -0,0 +1,21 @@ +{ + "config": { + "abort": { + "port_exists": "\u042d\u0442\u043e\u0442 \u043f\u043e\u0440\u0442 \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d." + }, + "error": { + "connection_failed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 Velbus.", + "port_exists": "\u042d\u0442\u043e\u0442 \u043f\u043e\u0440\u0442 \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d." + }, + "step": { + "user": { + "data": { + "name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f Velbus", + "port": "\u0421\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f" + }, + "title": "Velbus" + } + }, + "title": "Velbus" + } +} \ No newline at end of file diff --git a/homeassistant/components/velbus/.translations/zh-Hant.json b/homeassistant/components/velbus/.translations/zh-Hant.json new file mode 100644 index 00000000000000..33f9191e8a2163 --- /dev/null +++ b/homeassistant/components/velbus/.translations/zh-Hant.json @@ -0,0 +1,21 @@ +{ + "config": { + "abort": { + "port_exists": "\u6b64\u901a\u8a0a\u57e0\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + }, + "error": { + "connection_failed": "Velbus \u9023\u7dda\u5931\u6557", + "port_exists": "\u6b64\u901a\u8a0a\u57e0\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210" + }, + "step": { + "user": { + "data": { + "name": "Velbus \u9023\u7dda\u540d\u7a31", + "port": "\u9023\u7dda\u5b57\u4e32" + }, + "title": "\u5b9a\u7fa9 Velbus \u9023\u7dda\u985e\u578b" + } + }, + "title": "Velbus \u4ecb\u9762" + } +} \ No newline at end of file diff --git a/homeassistant/components/vesync/.translations/ca.json b/homeassistant/components/vesync/.translations/ca.json new file mode 100644 index 00000000000000..0c253fd4812c11 --- /dev/null +++ b/homeassistant/components/vesync/.translations/ca.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_setup": "Nom\u00e9s es permet una \u00fanica inst\u00e0ncia de VeSync" + }, + "error": { + "invalid_login": "Nom d'usuari o contrasenya incorrectes" + }, + "step": { + "user": { + "data": { + "password": "Contrasenya", + "username": "Correu electr\u00f2nic" + }, + "title": "Introdueix el nom d\u2019usuari i contrasenya" + } + }, + "title": "VeSync" + } +} \ No newline at end of file diff --git a/homeassistant/components/vesync/.translations/da.json b/homeassistant/components/vesync/.translations/da.json new file mode 100644 index 00000000000000..43e56328f99785 --- /dev/null +++ b/homeassistant/components/vesync/.translations/da.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_setup": "Kun en Vesync-forekomst er tilladt" + }, + "error": { + "invalid_login": "Ugyldigt brugernavn eller adgangskode" + }, + "step": { + "user": { + "data": { + "password": "Adgangskode", + "username": "Email adresse" + }, + "title": "Indtast brugernavn og adgangskode" + } + }, + "title": "VeSync" + } +} \ No newline at end of file diff --git a/homeassistant/components/vesync/.translations/hu.json b/homeassistant/components/vesync/.translations/hu.json new file mode 100644 index 00000000000000..4735140216fd04 --- /dev/null +++ b/homeassistant/components/vesync/.translations/hu.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "invalid_login": "\u00c9rv\u00e9nytelen felhaszn\u00e1l\u00f3n\u00e9v vagy jelsz\u00f3" + }, + "step": { + "user": { + "data": { + "password": "Jelsz\u00f3", + "username": "Email c\u00edm" + }, + "title": "\u00cdrja be a felhaszn\u00e1l\u00f3nevet \u00e9s a jelsz\u00f3t" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/vesync/.translations/nl.json b/homeassistant/components/vesync/.translations/nl.json new file mode 100644 index 00000000000000..d19d528c61a32f --- /dev/null +++ b/homeassistant/components/vesync/.translations/nl.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_setup": "Er is slechts \u00e9\u00e9n Vesync instantie toegestaan." + }, + "error": { + "invalid_login": "Ongeldige gebruikersnaam of wachtwoord" + }, + "step": { + "user": { + "data": { + "password": "Wachtwoord", + "username": "E-mailadres" + }, + "title": "Voer gebruikersnaam en wachtwoord in" + } + }, + "title": "VeSync" + } +} \ No newline at end of file diff --git a/homeassistant/components/vesync/.translations/pl.json b/homeassistant/components/vesync/.translations/pl.json new file mode 100644 index 00000000000000..d6584f11d29041 --- /dev/null +++ b/homeassistant/components/vesync/.translations/pl.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_setup": "Dozwolona jest tylko jedna instancja Vesync" + }, + "error": { + "invalid_login": "Nieprawid\u0142owa nazwa u\u017cytkownika lub has\u0142o" + }, + "step": { + "user": { + "data": { + "password": "Has\u0142o", + "username": "Adres e-mail" + }, + "title": "Wprowad\u017a nazw\u0119 u\u017cytkownika i has\u0142o." + } + }, + "title": "VeSync" + } +} \ No newline at end of file diff --git a/homeassistant/components/vesync/.translations/ru.json b/homeassistant/components/vesync/.translations/ru.json new file mode 100644 index 00000000000000..38b86e9e29f479 --- /dev/null +++ b/homeassistant/components/vesync/.translations/ru.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_setup": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." + }, + "error": { + "invalid_login": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c" + }, + "step": { + "user": { + "data": { + "password": "\u041f\u0430\u0440\u043e\u043b\u044c", + "username": "\u0410\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b" + }, + "title": "VeSync" + } + }, + "title": "VeSync" + } +} \ No newline at end of file diff --git a/homeassistant/components/vesync/.translations/zh-Hant.json b/homeassistant/components/vesync/.translations/zh-Hant.json new file mode 100644 index 00000000000000..05e4a1bbc7974a --- /dev/null +++ b/homeassistant/components/vesync/.translations/zh-Hant.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_setup": "\u50c5\u5141\u8a31\u8a2d\u5b9a\u4e00\u7d44 Vesync \u7269\u4ef6" + }, + "error": { + "invalid_login": "\u4f7f\u7528\u8005\u540d\u7a31\u6216\u5bc6\u78bc\u7121\u6548" + }, + "step": { + "user": { + "data": { + "password": "\u5bc6\u78bc", + "username": "\u96fb\u5b50\u90f5\u4ef6\u5730\u5740" + }, + "title": "\u8acb\u8f38\u5165\u4f7f\u7528\u8005\u540d\u7a31\u8207\u5bc6\u78bc" + } + }, + "title": "VeSync" + } +} \ No newline at end of file diff --git a/homeassistant/components/withings/.translations/en.json b/homeassistant/components/withings/.translations/en.json new file mode 100644 index 00000000000000..2b906dd80030fb --- /dev/null +++ b/homeassistant/components/withings/.translations/en.json @@ -0,0 +1,17 @@ +{ + "config": { + "create_entry": { + "default": "Successfully authenticated with Withings for the selected profile." + }, + "step": { + "user": { + "data": { + "profile": "Profile" + }, + "description": "Select a user profile to which you want Home Assistant to map with a Withings profile. On the withings page, be sure to select the same user or data will not be labeled correctly.", + "title": "User Profile." + } + }, + "title": "Withings" + } +} \ No newline at end of file diff --git a/homeassistant/components/wwlln/.translations/hu.json b/homeassistant/components/wwlln/.translations/hu.json new file mode 100644 index 00000000000000..740fc1a8179c96 --- /dev/null +++ b/homeassistant/components/wwlln/.translations/hu.json @@ -0,0 +1,12 @@ +{ + "config": { + "step": { + "user": { + "data": { + "latitude": "Sz\u00e9less\u00e9g", + "longitude": "Hossz\u00fas\u00e1g" + } + } + } + } +} \ No newline at end of file From a9594b1566e739cd93300d92d29a762a92fd3db9 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 1 Sep 2019 22:30:21 -0700 Subject: [PATCH 37/72] Updated frontend to 20190901.0 --- homeassistant/components/frontend/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index fa6145a7af21de..2b17091ba5cb94 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -3,7 +3,7 @@ "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/components/frontend", "requirements": [ - "home-assistant-frontend==20190828.0" + "home-assistant-frontend==20190901.0" ], "dependencies": [ "api", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 5754e3fc391d6d..2fa5a1cd41ae4b 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -11,7 +11,7 @@ contextvars==2.4;python_version<"3.7" cryptography==2.7 distro==1.4.0 hass-nabucasa==0.17 -home-assistant-frontend==20190828.0 +home-assistant-frontend==20190901.0 importlib-metadata==0.19 jinja2>=2.10.1 netdisco==2.6.0 diff --git a/requirements_all.txt b/requirements_all.txt index 7be6e8a4265f25..5be7de93bc27a9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -628,7 +628,7 @@ hole==0.5.0 holidays==0.9.11 # homeassistant.components.frontend -home-assistant-frontend==20190828.0 +home-assistant-frontend==20190901.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f7727bd459b532..c76473cd3287a0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -176,7 +176,7 @@ hdate==0.9.0 holidays==0.9.11 # homeassistant.components.frontend -home-assistant-frontend==20190828.0 +home-assistant-frontend==20190901.0 # homeassistant.components.homekit_controller homekit[IP]==0.15.0 From 2b3b12491bbb9337d7fea735b5a4a789c178ecea Mon Sep 17 00:00:00 2001 From: Malte Franken Date: Mon, 2 Sep 2019 21:37:12 +1000 Subject: [PATCH 38/72] USGS Earthquakes icon for geolocation entities (#26353) * define icon * updated tests * added codeowner * updated codeowners --- CODEOWNERS | 1 + .../components/usgs_earthquakes_feed/geo_location.py | 5 +++++ homeassistant/components/usgs_earthquakes_feed/manifest.json | 4 +++- tests/components/usgs_earthquakes_feed/test_geo_location.py | 4 ++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 7c2e69c9af19d8..27c4f03ae93720 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -289,6 +289,7 @@ homeassistant/components/upcloud/* @scop homeassistant/components/updater/* @home-assistant/core homeassistant/components/upnp/* @robbiet480 homeassistant/components/uptimerobot/* @ludeeus +homeassistant/components/usgs_earthquakes_feed/* @exxamalte homeassistant/components/utility_meter/* @dgomes homeassistant/components/velbus/* @cereal2nd homeassistant/components/velux/* @Julius2342 diff --git a/homeassistant/components/usgs_earthquakes_feed/geo_location.py b/homeassistant/components/usgs_earthquakes_feed/geo_location.py index 7e5d6f5ebfef47..7890243c1e0acc 100644 --- a/homeassistant/components/usgs_earthquakes_feed/geo_location.py +++ b/homeassistant/components/usgs_earthquakes_feed/geo_location.py @@ -243,6 +243,11 @@ def _update_from_feed(self, feed_entry): self._type = feed_entry.type self._alert = feed_entry.alert + @property + def icon(self): + """Return the icon to use in the frontend.""" + return "mdi:pulse" + @property def source(self) -> str: """Return source value of this external event.""" diff --git a/homeassistant/components/usgs_earthquakes_feed/manifest.json b/homeassistant/components/usgs_earthquakes_feed/manifest.json index 00aa23c3d4d0d3..0d1c116786ab6b 100644 --- a/homeassistant/components/usgs_earthquakes_feed/manifest.json +++ b/homeassistant/components/usgs_earthquakes_feed/manifest.json @@ -6,5 +6,7 @@ "geojson_client==0.4" ], "dependencies": [], - "codeowners": [] + "codeowners": [ + "@exxamalte" + ] } diff --git a/tests/components/usgs_earthquakes_feed/test_geo_location.py b/tests/components/usgs_earthquakes_feed/test_geo_location.py index 69037e3b5f57f1..65ceec4d425efc 100644 --- a/tests/components/usgs_earthquakes_feed/test_geo_location.py +++ b/tests/components/usgs_earthquakes_feed/test_geo_location.py @@ -26,6 +26,7 @@ ATTR_ATTRIBUTION, CONF_LATITUDE, CONF_LONGITUDE, + ATTR_ICON, ) from homeassistant.setup import async_setup_component from tests.common import assert_setup_component, async_fire_time_changed @@ -148,6 +149,7 @@ async def test_setup(hass): ATTR_MAGNITUDE: 5.7, ATTR_UNIT_OF_MEASUREMENT: "km", ATTR_SOURCE: "usgs_earthquakes_feed", + ATTR_ICON: "mdi:pulse", } assert round(abs(float(state.state) - 15.5), 7) == 0 @@ -161,6 +163,7 @@ async def test_setup(hass): ATTR_FRIENDLY_NAME: "Title 2", ATTR_UNIT_OF_MEASUREMENT: "km", ATTR_SOURCE: "usgs_earthquakes_feed", + ATTR_ICON: "mdi:pulse", } assert round(abs(float(state.state) - 20.5), 7) == 0 @@ -174,6 +177,7 @@ async def test_setup(hass): ATTR_FRIENDLY_NAME: "Title 3", ATTR_UNIT_OF_MEASUREMENT: "km", ATTR_SOURCE: "usgs_earthquakes_feed", + ATTR_ICON: "mdi:pulse", } assert round(abs(float(state.state) - 25.5), 7) == 0 From 7c3eaf692114e2cb583cac8cde22a794004d02fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Mon, 2 Sep 2019 16:51:59 +0300 Subject: [PATCH 39/72] Test with 3.6.1 in Travis (#26347) https://github.com/home-assistant/architecture/issues/278 --- .travis.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3447571a3e8571..525a4c8e72c1f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,18 +16,14 @@ addons: matrix: fast_finish: true include: - - python: "3.6.0" + - python: "3.6.1" env: TOXENV=lint - dist: trusty - - python: "3.6.0" + - python: "3.6.1" env: TOXENV=pylint - dist: trusty - - python: "3.6.0" + - python: "3.6.1" env: TOXENV=typing - dist: trusty - - python: "3.6.0" + - python: "3.6.1" env: TOXENV=py36 - dist: trusty - python: "3.7" env: TOXENV=py37 From 1a7000d13d1c806f458311dfbe405926d31ba6ca Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 2 Sep 2019 21:15:00 +0200 Subject: [PATCH 40/72] Push to version 0.7.10 of denonavr (#26362) --- homeassistant/components/denonavr/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/denonavr/manifest.json b/homeassistant/components/denonavr/manifest.json index 5e40dbb89da102..34699d666ad02d 100644 --- a/homeassistant/components/denonavr/manifest.json +++ b/homeassistant/components/denonavr/manifest.json @@ -3,7 +3,7 @@ "name": "Denonavr", "documentation": "https://www.home-assistant.io/components/denonavr", "requirements": [ - "denonavr==0.7.9" + "denonavr==0.7.10" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index 5be7de93bc27a9..9195f7fa0f93b9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -384,7 +384,7 @@ defusedxml==0.6.0 deluge-client==1.7.1 # homeassistant.components.denonavr -denonavr==0.7.9 +denonavr==0.7.10 # homeassistant.components.directv directpy==0.5 From 2560d4ed0ffbe5463f0311b2747e249dce23436d Mon Sep 17 00:00:00 2001 From: Jeff Irion Date: Mon, 2 Sep 2019 13:08:01 -0700 Subject: [PATCH 41/72] Bump androidtv to 0.0.26 and update tests (#26340) * Move the patchers to a separate file * Got a pytest test working (mostly) * Checkpoint * Switch to pytest for all tests * Bump androidtv to 0.0.26 and update tests * More robust patching * Remove unused constants * Combine two lines * Add 2 additional checks * Check that state objects are not None; add more description to tests * Use f strings --- .../components/androidtv/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/androidtv/patchers.py | 129 ++++++ .../components/androidtv/test_media_player.py | 393 +++++++++--------- 5 files changed, 337 insertions(+), 191 deletions(-) create mode 100644 tests/components/androidtv/patchers.py diff --git a/homeassistant/components/androidtv/manifest.json b/homeassistant/components/androidtv/manifest.json index 91ea4019c05f74..2c8fc98e24865a 100644 --- a/homeassistant/components/androidtv/manifest.json +++ b/homeassistant/components/androidtv/manifest.json @@ -3,7 +3,7 @@ "name": "Androidtv", "documentation": "https://www.home-assistant.io/components/androidtv", "requirements": [ - "androidtv==0.0.25" + "androidtv==0.0.26" ], "dependencies": [], "codeowners": ["@JeffLIrion"] diff --git a/requirements_all.txt b/requirements_all.txt index 9195f7fa0f93b9..5116a7a2dfdaf9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -194,7 +194,7 @@ ambiclimate==0.2.1 amcrest==1.5.3 # homeassistant.components.androidtv -androidtv==0.0.25 +androidtv==0.0.26 # homeassistant.components.anel_pwrctrl anel_pwrctrl-homeassistant==0.0.1.dev2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index c76473cd3287a0..37e45278e33124 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -79,7 +79,7 @@ aiowwlln==1.0.0 ambiclimate==0.2.1 # homeassistant.components.androidtv -androidtv==0.0.25 +androidtv==0.0.26 # homeassistant.components.apns apns2==0.3.0 diff --git a/tests/components/androidtv/patchers.py b/tests/components/androidtv/patchers.py new file mode 100644 index 00000000000000..86d1c1c15bdc02 --- /dev/null +++ b/tests/components/androidtv/patchers.py @@ -0,0 +1,129 @@ +"""Define patches used for androidtv tests.""" + +from socket import error as socket_error +from unittest.mock import patch + + +class AdbCommandsFake: + """A fake of the `adb.adb_commands.AdbCommands` class.""" + + def ConnectDevice(self, *args, **kwargs): # pylint: disable=invalid-name + """Try to connect to a device.""" + raise NotImplementedError + + def Shell(self, cmd): # pylint: disable=invalid-name + """Send an ADB shell command.""" + raise NotImplementedError + + +class AdbCommandsFakeSuccess(AdbCommandsFake): + """A fake of the `adb.adb_commands.AdbCommands` class when the connection attempt succeeds.""" + + def ConnectDevice(self, *args, **kwargs): # pylint: disable=invalid-name + """Successfully connect to a device.""" + return self + + +class AdbCommandsFakeFail(AdbCommandsFake): + """A fake of the `adb.adb_commands.AdbCommands` class when the connection attempt fails.""" + + def ConnectDevice( + self, *args, **kwargs + ): # pylint: disable=invalid-name, no-self-use + """Fail to connect to a device.""" + raise socket_error + + +class ClientFakeSuccess: + """A fake of the `adb_messenger.client.Client` class when the connection and shell commands succeed.""" + + def __init__(self, host="127.0.0.1", port=5037): + """Initialize a `ClientFakeSuccess` instance.""" + self._devices = [] + + def devices(self): + """Get a list of the connected devices.""" + return self._devices + + def device(self, serial): + """Mock the `Client.device` method when the device is connected via ADB.""" + device = DeviceFake(serial) + self._devices.append(device) + return device + + +class ClientFakeFail: + """A fake of the `adb_messenger.client.Client` class when the connection and shell commands fail.""" + + def __init__(self, host="127.0.0.1", port=5037): + """Initialize a `ClientFakeFail` instance.""" + self._devices = [] + + def devices(self): + """Get a list of the connected devices.""" + return self._devices + + def device(self, serial): + """Mock the `Client.device` method when the device is not connected via ADB.""" + self._devices = [] + + +class DeviceFake: + """A fake of the `adb_messenger.device.Device` class.""" + + def __init__(self, host): + """Initialize a `DeviceFake` instance.""" + self.host = host + + def get_serial_no(self): + """Get the serial number for the device (IP:PORT).""" + return self.host + + def shell(self, cmd): + """Send an ADB shell command.""" + raise NotImplementedError + + +def patch_connect(success): + """Mock the `adb.adb_commands.AdbCommands` and `adb_messenger.client.Client` classes.""" + + if success: + return { + "python": patch( + "androidtv.adb_manager.AdbCommands", AdbCommandsFakeSuccess + ), + "server": patch("androidtv.adb_manager.Client", ClientFakeSuccess), + } + return { + "python": patch("androidtv.adb_manager.AdbCommands", AdbCommandsFakeFail), + "server": patch("androidtv.adb_manager.Client", ClientFakeFail), + } + + +def patch_shell(response=None, error=False): + """Mock the `AdbCommandsFake.Shell` and `DeviceFake.shell` methods.""" + + def shell_success(self, cmd): + """Mock the `AdbCommandsFake.Shell` and `DeviceFake.shell` methods when they are successful.""" + self.shell_cmd = cmd + return response + + def shell_fail_python(self, cmd): + """Mock the `AdbCommandsFake.Shell` method when it fails.""" + self.shell_cmd = cmd + raise AttributeError + + def shell_fail_server(self, cmd): + """Mock the `DeviceFake.shell` method when it fails.""" + self.shell_cmd = cmd + raise ConnectionResetError + + if not error: + return { + "python": patch(f"{__name__}.AdbCommandsFake.Shell", shell_success), + "server": patch(f"{__name__}.DeviceFake.shell", shell_success), + } + return { + "python": patch(f"{__name__}.AdbCommandsFake.Shell", shell_fail_python), + "server": patch(f"{__name__}.DeviceFake.shell", shell_fail_server), + } diff --git a/tests/components/androidtv/test_media_player.py b/tests/components/androidtv/test_media_player.py index e787fddd3bcb04..39b392c97ee306 100644 --- a/tests/components/androidtv/test_media_player.py +++ b/tests/components/androidtv/test_media_player.py @@ -1,232 +1,249 @@ """The tests for the androidtv platform.""" import logging -from socket import error as socket_error -import unittest -from unittest.mock import patch +from homeassistant.setup import async_setup_component from homeassistant.components.androidtv.media_player import ( - AndroidTVDevice, - FireTVDevice, - setup, + ANDROIDTV_DOMAIN, + CONF_ADB_SERVER_IP, +) +from homeassistant.components.media_player.const import DOMAIN +from homeassistant.const import ( + CONF_DEVICE_CLASS, + CONF_HOST, + CONF_NAME, + CONF_PLATFORM, + STATE_IDLE, + STATE_OFF, + STATE_UNAVAILABLE, ) +from . import patchers + + +# Android TV device with Python ADB implementation +CONFIG_ANDROIDTV_PYTHON_ADB = { + DOMAIN: { + CONF_PLATFORM: ANDROIDTV_DOMAIN, + CONF_HOST: "127.0.0.1", + CONF_NAME: "Android TV", + } +} + +# Android TV device with ADB server +CONFIG_ANDROIDTV_ADB_SERVER = { + DOMAIN: { + CONF_PLATFORM: ANDROIDTV_DOMAIN, + CONF_HOST: "127.0.0.1", + CONF_NAME: "Android TV", + CONF_ADB_SERVER_IP: "127.0.0.1", + } +} + +# Fire TV device with Python ADB implementation +CONFIG_FIRETV_PYTHON_ADB = { + DOMAIN: { + CONF_PLATFORM: ANDROIDTV_DOMAIN, + CONF_HOST: "127.0.0.1", + CONF_NAME: "Fire TV", + CONF_DEVICE_CLASS: "firetv", + } +} + +# Fire TV device with ADB server +CONFIG_FIRETV_ADB_SERVER = { + DOMAIN: { + CONF_PLATFORM: ANDROIDTV_DOMAIN, + CONF_HOST: "127.0.0.1", + CONF_NAME: "Fire TV", + CONF_DEVICE_CLASS: "firetv", + CONF_ADB_SERVER_IP: "127.0.0.1", + } +} + + +async def _test_reconnect(hass, caplog, config): + """Test that the error and reconnection attempts are logged correctly. + + "Handles device/service unavailable. Log a warning once when + unavailable, log once when reconnected." + + https://developers.home-assistant.io/docs/en/integration_quality_scale_index.html + """ + if CONF_ADB_SERVER_IP not in config[DOMAIN]: + patch_key = "python" + else: + patch_key = "server" + + if config[DOMAIN].get(CONF_DEVICE_CLASS) != "firetv": + entity_id = "media_player.android_tv" + else: + entity_id = "media_player.fire_tv" + + with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]: + assert await async_setup_component(hass, DOMAIN, config) + await hass.helpers.entity_component.async_update_entity(entity_id) + state = hass.states.get(entity_id) + assert state is not None + assert state.state == STATE_OFF + + caplog.clear() + caplog.set_level(logging.WARNING) + + with patchers.patch_connect(False)[patch_key], patchers.patch_shell(error=True)[ + patch_key + ]: + for _ in range(5): + await hass.helpers.entity_component.async_update_entity(entity_id) + state = hass.states.get(entity_id) + assert state is not None + assert state.state == STATE_UNAVAILABLE + + assert len(caplog.record_tuples) == 2 + assert caplog.record_tuples[0][1] == logging.ERROR + assert caplog.record_tuples[1][1] == logging.WARNING + + caplog.set_level(logging.DEBUG) + with patchers.patch_connect(True)[patch_key], patchers.patch_shell("1")[patch_key]: + # Update 1 will reconnect + await hass.helpers.entity_component.async_update_entity(entity_id) + + # If using an ADB server, the state will get updated; otherwise, the + # state will be the last known state + state = hass.states.get(entity_id) + if patch_key == "server": + assert state.state == STATE_IDLE + else: + assert state.state == STATE_OFF + + # Update 2 will update the state, regardless of which ADB connection + # method is used + await hass.helpers.entity_component.async_update_entity(entity_id) + state = hass.states.get(entity_id) + assert state is not None + assert state.state == STATE_IDLE + + if patch_key == "python": + assert ( + "ADB connection to 127.0.0.1:5555 successfully established" + in caplog.record_tuples[2] + ) + else: + assert ( + "ADB connection to 127.0.0.1:5555 via ADB server 127.0.0.1:5037 successfully established" + in caplog.record_tuples[2] + ) -def connect_device_success(self, *args, **kwargs): - """Return `self`, which will result in the ADB connection being interpreted as available.""" - return self + return True -def connect_device_fail(self, *args, **kwargs): - """Raise a socket error.""" - raise socket_error +async def _test_adb_shell_returns_none(hass, config): + """Test the case that the ADB shell command returns `None`. + The state should be `None` and the device should be unavailable. + """ + if CONF_ADB_SERVER_IP not in config[DOMAIN]: + patch_key = "python" + else: + patch_key = "server" -def adb_shell_python_adb_error(self, cmd): - """Raise an error that is among those caught for the Python ADB implementation.""" - raise AttributeError + if config[DOMAIN].get(CONF_DEVICE_CLASS) != "firetv": + entity_id = "media_player.android_tv" + else: + entity_id = "media_player.fire_tv" + with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]: + assert await async_setup_component(hass, DOMAIN, config) + await hass.helpers.entity_component.async_update_entity(entity_id) + state = hass.states.get(entity_id) + assert state is not None + assert state.state != STATE_UNAVAILABLE -def adb_shell_adb_server_error(self, cmd): - """Raise an error that is among those caught for the ADB server implementation.""" - raise ConnectionResetError + with patchers.patch_shell(None)[patch_key], patchers.patch_shell(error=True)[ + patch_key + ]: + await hass.helpers.entity_component.async_update_entity(entity_id) + state = hass.states.get(entity_id) + assert state is not None + assert state.state == STATE_UNAVAILABLE + return True -class AdbAvailable: - """A class that indicates the ADB connection is available.""" - def shell(self, cmd): - """Send an ADB shell command (ADB server implementation).""" - return "" +async def test_reconnect_androidtv_python_adb(hass, caplog): + """Test that the error and reconnection attempts are logged correctly. + * Device type: Android TV + * ADB connection method: Python ADB implementation -class AdbUnavailable: - """A class with ADB shell methods that raise errors.""" + """ + assert await _test_reconnect(hass, caplog, CONFIG_ANDROIDTV_PYTHON_ADB) - def __bool__(self): - """Return `False` to indicate that the ADB connection is unavailable.""" - return False - def shell(self, cmd): - """Raise an error that pertains to the Python ADB implementation.""" - raise ConnectionResetError +async def test_adb_shell_returns_none_androidtv_python_adb(hass): + """Test the case that the ADB shell command returns `None`. + * Device type: Android TV + * ADB connection method: Python ADB implementation -PATCH_PYTHON_ADB_CONNECT_SUCCESS = patch( - "adb.adb_commands.AdbCommands.ConnectDevice", connect_device_success -) -PATCH_PYTHON_ADB_COMMAND_SUCCESS = patch( - "adb.adb_commands.AdbCommands.Shell", return_value="" -) -PATCH_PYTHON_ADB_CONNECT_FAIL = patch( - "adb.adb_commands.AdbCommands.ConnectDevice", connect_device_fail -) -PATCH_PYTHON_ADB_COMMAND_FAIL = patch( - "adb.adb_commands.AdbCommands.Shell", adb_shell_python_adb_error -) -PATCH_PYTHON_ADB_COMMAND_NONE = patch( - "adb.adb_commands.AdbCommands.Shell", return_value=None -) + """ + assert await _test_adb_shell_returns_none(hass, CONFIG_ANDROIDTV_PYTHON_ADB) -PATCH_ADB_SERVER_CONNECT_SUCCESS = patch( - "adb_messenger.client.Client.device", return_value=AdbAvailable() -) -PATCH_ADB_SERVER_AVAILABLE = patch( - "androidtv.basetv.BaseTV.available", return_value=True -) -PATCH_ADB_SERVER_CONNECT_FAIL = patch( - "adb_messenger.client.Client.device", return_value=AdbUnavailable() -) -PATCH_ADB_SERVER_COMMAND_FAIL = patch( - "{}.AdbAvailable.shell".format(__name__), adb_shell_adb_server_error -) -PATCH_ADB_SERVER_COMMAND_NONE = patch( - "{}.AdbAvailable.shell".format(__name__), return_value=None -) +async def test_reconnect_firetv_python_adb(hass, caplog): + """Test that the error and reconnection attempts are logged correctly. -class TestAndroidTVPythonImplementation(unittest.TestCase): - """Test the androidtv media player for an Android TV device.""" + * Device type: Fire TV + * ADB connection method: Python ADB implementation - def setUp(self): - """Set up an `AndroidTVDevice` media player.""" - with PATCH_PYTHON_ADB_CONNECT_SUCCESS, PATCH_PYTHON_ADB_COMMAND_SUCCESS: - aftv = setup("IP:PORT", device_class="androidtv") - self.aftv = AndroidTVDevice(aftv, "Fake Android TV", {}, None, None) + """ + assert await _test_reconnect(hass, caplog, CONFIG_FIRETV_PYTHON_ADB) - def test_reconnect(self): - """Test that the error and reconnection attempts are logged correctly. - "Handles device/service unavailable. Log a warning once when - unavailable, log once when reconnected." +async def test_adb_shell_returns_none_firetv_python_adb(hass): + """Test the case that the ADB shell command returns `None`. - https://developers.home-assistant.io/docs/en/integration_quality_scale_index.html - """ - with self.assertLogs(level=logging.WARNING) as logs: - with PATCH_PYTHON_ADB_CONNECT_FAIL, PATCH_PYTHON_ADB_COMMAND_FAIL: - for _ in range(5): - self.aftv.update() - self.assertFalse(self.aftv.available) - self.assertIsNone(self.aftv.state) + * Device type: Fire TV + * ADB connection method: Python ADB implementation - assert len(logs.output) == 2 - assert logs.output[0].startswith("ERROR") - assert logs.output[1].startswith("WARNING") + """ + assert await _test_adb_shell_returns_none(hass, CONFIG_FIRETV_PYTHON_ADB) - with self.assertLogs(level=logging.DEBUG) as logs: - with PATCH_PYTHON_ADB_CONNECT_SUCCESS, PATCH_PYTHON_ADB_COMMAND_SUCCESS: - # Update 1 will reconnect - self.aftv.update() - self.assertTrue(self.aftv.available) - # Update 2 will update the state - self.aftv.update() - self.assertTrue(self.aftv.available) - self.assertIsNotNone(self.aftv.state) +async def test_reconnect_androidtv_adb_server(hass, caplog): + """Test that the error and reconnection attempts are logged correctly. - assert ( - "ADB connection to {} successfully established".format(self.aftv.aftv.host) - in logs.output[0] - ) + * Device type: Android TV + * ADB connection method: ADB server - def test_adb_shell_returns_none(self): - """Test the case that the ADB shell command returns `None`. - - The state should be `None` and the device should be unavailable. - """ - with PATCH_PYTHON_ADB_COMMAND_NONE: - self.aftv.update() - self.assertFalse(self.aftv.available) - self.assertIsNone(self.aftv.state) - - with PATCH_PYTHON_ADB_CONNECT_SUCCESS, PATCH_PYTHON_ADB_COMMAND_SUCCESS: - # Update 1 will reconnect - self.aftv.update() - self.assertTrue(self.aftv.available) - - # Update 2 will update the state - self.aftv.update() - self.assertTrue(self.aftv.available) - self.assertIsNotNone(self.aftv.state) - - -class TestAndroidTVServerImplementation(unittest.TestCase): - """Test the androidtv media player for an Android TV device.""" - - def setUp(self): - """Set up an `AndroidTVDevice` media player.""" - with PATCH_ADB_SERVER_CONNECT_SUCCESS, PATCH_ADB_SERVER_AVAILABLE: - aftv = setup( - "IP:PORT", adb_server_ip="ADB_SERVER_IP", device_class="androidtv" - ) - self.aftv = AndroidTVDevice(aftv, "Fake Android TV", {}, None, None) - - def test_reconnect(self): - """Test that the error and reconnection attempts are logged correctly. - - "Handles device/service unavailable. Log a warning once when - unavailable, log once when reconnected." - - https://developers.home-assistant.io/docs/en/integration_quality_scale_index.html - """ - with self.assertLogs(level=logging.WARNING) as logs: - with PATCH_ADB_SERVER_CONNECT_FAIL, PATCH_ADB_SERVER_COMMAND_FAIL: - for _ in range(5): - self.aftv.update() - self.assertFalse(self.aftv.available) - self.assertIsNone(self.aftv.state) - - assert len(logs.output) == 2 - assert logs.output[0].startswith("ERROR") - assert logs.output[1].startswith("WARNING") - - with self.assertLogs(level=logging.DEBUG) as logs: - with PATCH_ADB_SERVER_CONNECT_SUCCESS: - self.aftv.update() - self.assertTrue(self.aftv.available) - self.assertIsNotNone(self.aftv.state) + """ + assert await _test_reconnect(hass, caplog, CONFIG_ANDROIDTV_ADB_SERVER) - assert ( - "ADB connection to {} via ADB server {}:{} successfully established".format( - self.aftv.aftv.host, - self.aftv.aftv.adb_server_ip, - self.aftv.aftv.adb_server_port, - ) - in logs.output[0] - ) - def test_adb_shell_returns_none(self): - """Test the case that the ADB shell command returns `None`. +async def test_adb_shell_returns_none_androidtv_adb_server(hass): + """Test the case that the ADB shell command returns `None`. + + * Device type: Android TV + * ADB connection method: ADB server + + """ + assert await _test_adb_shell_returns_none(hass, CONFIG_ANDROIDTV_ADB_SERVER) - The state should be `None` and the device should be unavailable. - """ - with PATCH_ADB_SERVER_COMMAND_NONE: - self.aftv.update() - self.assertFalse(self.aftv.available) - self.assertIsNone(self.aftv.state) - with PATCH_ADB_SERVER_CONNECT_SUCCESS: - self.aftv.update() - self.assertTrue(self.aftv.available) - self.assertIsNotNone(self.aftv.state) +async def test_reconnect_firetv_adb_server(hass, caplog): + """Test that the error and reconnection attempts are logged correctly. + * Device type: Fire TV + * ADB connection method: ADB server -class TestFireTVPythonImplementation(TestAndroidTVPythonImplementation): - """Test the androidtv media player for a Fire TV device.""" + """ + assert await _test_reconnect(hass, caplog, CONFIG_FIRETV_ADB_SERVER) - def setUp(self): - """Set up a `FireTVDevice` media player.""" - with PATCH_PYTHON_ADB_CONNECT_SUCCESS, PATCH_PYTHON_ADB_COMMAND_SUCCESS: - aftv = setup("IP:PORT", device_class="firetv") - self.aftv = FireTVDevice(aftv, "Fake Fire TV", {}, True, None, None) +async def test_adb_shell_returns_none_firetv_adb_server(hass): + """Test the case that the ADB shell command returns `None`. -class TestFireTVServerImplementation(TestAndroidTVServerImplementation): - """Test the androidtv media player for a Fire TV device.""" + * Device type: Fire TV + * ADB connection method: ADB server - def setUp(self): - """Set up a `FireTVDevice` media player.""" - with PATCH_ADB_SERVER_CONNECT_SUCCESS, PATCH_ADB_SERVER_AVAILABLE: - aftv = setup( - "IP:PORT", adb_server_ip="ADB_SERVER_IP", device_class="firetv" - ) - self.aftv = FireTVDevice(aftv, "Fake Fire TV", {}, True, None, None) + """ + assert await _test_adb_shell_returns_none(hass, CONFIG_FIRETV_ADB_SERVER) From 75d6ffcb79997f7cbc8978a2eeb1d5f06eb1e7d1 Mon Sep 17 00:00:00 2001 From: Costas Date: Mon, 2 Sep 2019 22:17:34 +0200 Subject: [PATCH 42/72] Update google_maps dependency and improve error message (#26361) * updated dependency and made error message a bit more accurate. * updated dependency and made error message a bit more accurate. --- homeassistant/components/google_maps/device_tracker.py | 5 +---- homeassistant/components/google_maps/manifest.json | 2 +- requirements_all.txt | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/google_maps/device_tracker.py b/homeassistant/components/google_maps/device_tracker.py index 2b5550860ee5b5..75f370e502eafb 100644 --- a/homeassistant/components/google_maps/device_tracker.py +++ b/homeassistant/components/google_maps/device_tracker.py @@ -67,10 +67,7 @@ def __init__(self, hass, config: ConfigType, see) -> None: except InvalidCookies: _LOGGER.error( - "You have specified invalid login credentials. " - "Please make sure you have saved your credentials" - " in the following file: %s", - credfile, + "The cookie file provided does not provide a valid session. Please create another one and try again." ) self.success_init = False diff --git a/homeassistant/components/google_maps/manifest.json b/homeassistant/components/google_maps/manifest.json index 5f31f533a38788..ec48e5252a8ab2 100644 --- a/homeassistant/components/google_maps/manifest.json +++ b/homeassistant/components/google_maps/manifest.json @@ -3,7 +3,7 @@ "name": "Google maps", "documentation": "https://www.home-assistant.io/components/google_maps", "requirements": [ - "locationsharinglib==4.0.2" + "locationsharinglib==4.1.0" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index 5116a7a2dfdaf9..a3b046aa52b350 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -748,7 +748,7 @@ liveboxplaytv==2.0.2 lmnotify==0.0.4 # homeassistant.components.google_maps -locationsharinglib==4.0.2 +locationsharinglib==4.1.0 # homeassistant.components.logi_circle logi_circle==0.2.2 From 141bfe70dc3e06a49916b35c9752494138d69dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20RAMAGE?= Date: Mon, 2 Sep 2019 22:21:09 +0200 Subject: [PATCH 43/72] Update zigpy_zigate to 0.2.0 (#26327) * Update zigpy_zigate to 0.2.0 * Update requirements_all.txt --- homeassistant/components/zha/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index 8e7de41e626b35..bf97dca1c708eb 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -9,7 +9,7 @@ "zigpy-deconz==0.2.2", "zigpy-homeassistant==0.7.1", "zigpy-xbee-homeassistant==0.4.0", - "zigpy-zigate==0.1.0" + "zigpy-zigate==0.2.0" ], "dependencies": [], "codeowners": ["@dmulcahey", "@adminiuga"] diff --git a/requirements_all.txt b/requirements_all.txt index a3b046aa52b350..b18330cc10a2d2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2002,7 +2002,7 @@ zigpy-homeassistant==0.7.1 zigpy-xbee-homeassistant==0.4.0 # homeassistant.components.zha -zigpy-zigate==0.1.0 +zigpy-zigate==0.2.0 # homeassistant.components.zoneminder zm-py==0.3.3 From 9cae15ce3174ca32e6b5c3501cb297ad910c52a2 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Tue, 3 Sep 2019 07:12:10 +0200 Subject: [PATCH 44/72] String has nothing to do with class method naming (#26368) --- homeassistant/components/deconz/.translations/en.json | 2 +- homeassistant/components/deconz/strings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/deconz/.translations/en.json b/homeassistant/components/deconz/.translations/en.json index 57da3c706a035c..3c6656d6ae696b 100644 --- a/homeassistant/components/deconz/.translations/en.json +++ b/homeassistant/components/deconz/.translations/en.json @@ -43,7 +43,7 @@ }, "options": { "step": { - "async_step_deconz_devices": { + "deconz_devices": { "data": { "allow_clip_sensor": "Allow deCONZ CLIP sensors", "allow_deconz_groups": "Allow deCONZ light groups" diff --git a/homeassistant/components/deconz/strings.json b/homeassistant/components/deconz/strings.json index ea9ea2805155c6..7081f816e6ae08 100644 --- a/homeassistant/components/deconz/strings.json +++ b/homeassistant/components/deconz/strings.json @@ -43,7 +43,7 @@ }, "options": { "step": { - "async_step_deconz_devices": { + "deconz_devices": { "description": "Configure visibility of deCONZ device types", "data": { "allow_clip_sensor": "Allow deCONZ CLIP sensors", From 5213a43b480db20d1792780545b5abfec3bb4b06 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 3 Sep 2019 09:35:03 +0200 Subject: [PATCH 45/72] Add token support --- azure-pipelines-release.yml | 6 +++--- azure-pipelines-translation.yml | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 azure-pipelines-translation.yml diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 7c88e615fa5baa..510e16a351c14f 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -68,11 +68,11 @@ stages: - script: python setup.py sdist bdist_wheel displayName: 'Build package' - script: | - export TWINE_USERNAME="$(twineUser)" - export TWINE_PASSWORD="$(twinePassword)" - twine upload dist/* --skip-existing displayName: 'Upload pypi' + env: + TWINE_USERNAME: '$(twineUser)' + TWINE_PASSWORD: '$(twinePassword)' - job: 'ReleaseDocker' timeoutInMinutes: 240 pool: diff --git a/azure-pipelines-translation.yml b/azure-pipelines-translation.yml new file mode 100644 index 00000000000000..ad536aa9068d1c --- /dev/null +++ b/azure-pipelines-translation.yml @@ -0,0 +1,27 @@ +# https://dev.azure.com/home-assistant + +trigger: + batch: true + branches: + include: + - dev +pr: none +variables: + - group: translation + + +jobs: + +- job: 'Upload' + pool: + vmImage: 'ubuntu-latest' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: '3.7' + - script: | + ./script/translations_upload + displayName: 'Upload Translation' + env: + LOKALISE_TOKEN: $(lokaliseToken) From 67edf3ca2b9ecd51be9635e5e73ebfffa70e1858 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 3 Sep 2019 00:50:24 -0700 Subject: [PATCH 46/72] Allow passing dictionaries to async_register_entity_service (#26370) --- homeassistant/components/light/__init__.py | 9 ++++++--- homeassistant/components/switch/__init__.py | 15 +++------------ homeassistant/helpers/entity_component.py | 3 +++ 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index c70a209a35ac9b..94ba43b85458d9 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -128,9 +128,12 @@ } ) -LIGHT_TURN_OFF_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( - {ATTR_TRANSITION: VALID_TRANSITION, ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG])} -) + +LIGHT_TURN_OFF_SCHEMA = { + ATTR_TRANSITION: VALID_TRANSITION, + ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]), +} + LIGHT_TOGGLE_SCHEMA = LIGHT_TURN_ON_SCHEMA diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index 348c2a8616bc6c..aa7459d1d3cec7 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -10,7 +10,6 @@ from homeassistant.helpers.config_validation import ( # noqa PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, - ENTITY_SERVICE_SCHEMA, ) from homeassistant.const import ( STATE_ON, @@ -68,17 +67,9 @@ async def async_setup(hass, config): ) await component.async_setup(config) - component.async_register_entity_service( - SERVICE_TURN_OFF, ENTITY_SERVICE_SCHEMA, "async_turn_off" - ) - - component.async_register_entity_service( - SERVICE_TURN_ON, ENTITY_SERVICE_SCHEMA, "async_turn_on" - ) - - component.async_register_entity_service( - SERVICE_TOGGLE, ENTITY_SERVICE_SCHEMA, "async_toggle" - ) + component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off") + component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on") + component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle") return True diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index a923763570285e..42b19da889ece1 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -15,6 +15,7 @@ from homeassistant.core import callback from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import config_per_platform, discovery +from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.helpers.service import async_extract_entity_ids from homeassistant.loader import bind_hass, async_get_integration from homeassistant.util import slugify @@ -202,6 +203,8 @@ async def async_extract_from_service(self, service, expand_group=True): @callback def async_register_entity_service(self, name, schema, func, required_features=None): """Register an entity service.""" + if isinstance(schema, dict): + schema = ENTITY_SERVICE_SCHEMA.extend(schema) async def handle_service(call): """Handle the service.""" From bb782f7f96e895a50f7d01a88f69e3d86684f542 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 3 Sep 2019 10:17:03 +0200 Subject: [PATCH 47/72] Upgrade pyhaversion to 3.1.0 (#26232) --- homeassistant/components/version/manifest.json | 2 +- homeassistant/components/version/sensor.py | 12 ++++++++++-- requirements_all.txt | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/version/manifest.json b/homeassistant/components/version/manifest.json index 2a48f91a6f8887..815e7ff9a25794 100644 --- a/homeassistant/components/version/manifest.json +++ b/homeassistant/components/version/manifest.json @@ -3,7 +3,7 @@ "name": "Version", "documentation": "https://www.home-assistant.io/components/version", "requirements": [ - "pyhaversion==3.0.2" + "pyhaversion==3.1.0" ], "dependencies": [], "codeowners": [ diff --git a/homeassistant/components/version/sensor.py b/homeassistant/components/version/sensor.py index 438ea8f690cda4..3e00b87e9840d2 100644 --- a/homeassistant/components/version/sensor.py +++ b/homeassistant/components/version/sensor.py @@ -28,7 +28,7 @@ "odroid-c2", "odroid-xu", ] -ALL_SOURCES = ["local", "pypi", "hassio", "docker"] +ALL_SOURCES = ["local", "pypi", "hassio", "docker", "haio"] CONF_BETA = "beta" CONF_IMAGE = "image" @@ -54,7 +54,13 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Version sensor platform.""" - from pyhaversion import LocalVersion, DockerVersion, HassioVersion, PyPiVersion + from pyhaversion import ( + LocalVersion, + DockerVersion, + HassioVersion, + PyPiVersion, + HaIoVersion, + ) beta = config.get(CONF_BETA) image = config.get(CONF_IMAGE) @@ -74,6 +80,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= haversion = VersionData(HassioVersion(hass.loop, session, branch, image)) elif source == "docker": haversion = VersionData(DockerVersion(hass.loop, session, branch, image)) + elif source == "haio": + haversion = VersionData(HaIoVersion(hass.loop, session)) else: haversion = VersionData(LocalVersion(hass.loop, session)) diff --git a/requirements_all.txt b/requirements_all.txt index b18330cc10a2d2..33367248372b06 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1193,7 +1193,7 @@ pygtfs==0.1.5 pygtt==1.1.2 # homeassistant.components.version -pyhaversion==3.0.2 +pyhaversion==3.1.0 # homeassistant.components.heos pyheos==0.6.0 From 59c732804fd80eb09a30280095e66e8b239e1da5 Mon Sep 17 00:00:00 2001 From: "ruohan.chen" Date: Tue, 3 Sep 2019 16:18:08 +0800 Subject: [PATCH 48/72] Support new climate arch for zhong_hong (#26309) * support new climate arch for zhong_hong * use black to format * mapping the states between lib and HA * Add zhong_hong mapping constant --- .../components/zhong_hong/climate.py | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/zhong_hong/climate.py b/homeassistant/components/zhong_hong/climate.py index 8514ec711cbc3a..f1a363cfedecd5 100644 --- a/homeassistant/components/zhong_hong/climate.py +++ b/homeassistant/components/zhong_hong/climate.py @@ -10,6 +10,7 @@ HVAC_MODE_DRY, HVAC_MODE_FAN_ONLY, HVAC_MODE_HEAT, + HVAC_MODE_OFF, SUPPORT_FAN_MODE, SUPPORT_TARGET_TEMPERATURE, ) @@ -46,7 +47,26 @@ } ) -SUPPORT_HVAC = [HVAC_MODE_COOL, HVAC_MODE_HEAT, HVAC_MODE_DRY, HVAC_MODE_FAN_ONLY] +SUPPORT_HVAC = [ + HVAC_MODE_COOL, + HVAC_MODE_HEAT, + HVAC_MODE_DRY, + HVAC_MODE_FAN_ONLY, + HVAC_MODE_OFF, +] + +ZHONG_HONG_MODE_COOL = "cool" +ZHONG_HONG_MODE_HEAT = "heat" +ZHONG_HONG_MODE_DRY = "dry" +ZHONG_HONG_MODE_FAN_ONLY = "fan_only" + + +MODE_TO_STATE = { + ZHONG_HONG_MODE_COOL: HVAC_MODE_COOL, + ZHONG_HONG_MODE_HEAT: HVAC_MODE_HEAT, + ZHONG_HONG_MODE_DRY: HVAC_MODE_DRY, + ZHONG_HONG_MODE_FAN_ONLY: HVAC_MODE_FAN_ONLY, +} def setup_platform(hass, config, add_entities, discovery_info=None): @@ -117,7 +137,9 @@ def _after_update(self, climate): """Handle state update.""" _LOGGER.debug("async update ha state") if self._device.current_operation: - self._current_operation = self._device.current_operation.lower() + self._current_operation = MODE_TO_STATE[ + self._device.current_operation.lower() + ] if self._device.current_temperature: self._current_temperature = self._device.current_temperature if self._device.current_fan_mode: @@ -156,7 +178,9 @@ def temperature_unit(self): @property def hvac_mode(self): """Return current operation ie. heat, cool, idle.""" - return self._current_operation + if self.is_on: + return self._current_operation + return HVAC_MODE_OFF @property def hvac_modes(self): @@ -223,6 +247,14 @@ def set_temperature(self, **kwargs): def set_hvac_mode(self, hvac_mode): """Set new target operation mode.""" + if hvac_mode == HVAC_MODE_OFF: + if self.is_on: + self.turn_off() + return + + if not self.is_on: + self.turn_on() + self._device.set_operation_mode(hvac_mode.upper()) def set_fan_mode(self, fan_mode): From dc47efedca3512679103305bd4e10964499aecd9 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 3 Sep 2019 10:39:23 +0200 Subject: [PATCH 49/72] Update azure-pipelines-wheels.yml --- azure-pipelines-wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines-wheels.yml b/azure-pipelines-wheels.yml index 2a557d87ee7985..eec3f678981b53 100644 --- a/azure-pipelines-wheels.yml +++ b/azure-pipelines-wheels.yml @@ -30,7 +30,7 @@ jobs: - template: templates/azp-job-wheels.yaml@azure parameters: builderVersion: '$(versionWheels)' - builderApk: 'build-base;cmake;git;linux-headers;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;autoconf;automake;cups-dev;linux-headers;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev' + builderApk: 'build-base;cmake;git;linux-headers;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;autoconf;automake;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev' builderPip: 'Cython;numpy' wheelsRequirement: 'requirements_wheels.txt' wheelsRequirementDiff: 'requirements_diff.txt' From 7a68d76c562b2f99e352dfe460aa3572b4d0fdaa Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 14:13:44 +0200 Subject: [PATCH 50/72] Correct file permissions, removing executable bits (#26376) --- homeassistant/components/bizkaibus/sensor.py | 0 homeassistant/components/cppm_tracker/device_tracker.py | 0 homeassistant/components/environment_canada/camera.py | 0 homeassistant/components/environment_canada/sensor.py | 0 homeassistant/components/fortios/device_tracker.py | 0 homeassistant/components/lcn/binary_sensor.py | 0 homeassistant/components/lcn/cover.py | 0 homeassistant/components/lcn/scene.py | 0 homeassistant/components/lcn/sensor.py | 0 homeassistant/components/lcn/services.py | 0 homeassistant/components/lcn/services.yaml | 0 homeassistant/components/lcn/switch.py | 0 homeassistant/components/rejseplanen/sensor.py | 0 homeassistant/components/repetier/__init__.py | 0 homeassistant/components/repetier/manifest.json | 0 homeassistant/components/repetier/sensor.py | 0 homeassistant/components/somfy_mylink/__init__.py | 0 homeassistant/components/somfy_mylink/cover.py | 0 homeassistant/components/yale_smart_alarm/alarm_control_panel.py | 0 homeassistant/components/zwave/lock.py | 0 20 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 homeassistant/components/bizkaibus/sensor.py mode change 100755 => 100644 homeassistant/components/cppm_tracker/device_tracker.py mode change 100755 => 100644 homeassistant/components/environment_canada/camera.py mode change 100755 => 100644 homeassistant/components/environment_canada/sensor.py mode change 100755 => 100644 homeassistant/components/fortios/device_tracker.py mode change 100755 => 100644 homeassistant/components/lcn/binary_sensor.py mode change 100755 => 100644 homeassistant/components/lcn/cover.py mode change 100755 => 100644 homeassistant/components/lcn/scene.py mode change 100755 => 100644 homeassistant/components/lcn/sensor.py mode change 100755 => 100644 homeassistant/components/lcn/services.py mode change 100755 => 100644 homeassistant/components/lcn/services.yaml mode change 100755 => 100644 homeassistant/components/lcn/switch.py mode change 100755 => 100644 homeassistant/components/rejseplanen/sensor.py mode change 100755 => 100644 homeassistant/components/repetier/__init__.py mode change 100755 => 100644 homeassistant/components/repetier/manifest.json mode change 100755 => 100644 homeassistant/components/repetier/sensor.py mode change 100755 => 100644 homeassistant/components/somfy_mylink/__init__.py mode change 100755 => 100644 homeassistant/components/somfy_mylink/cover.py mode change 100755 => 100644 homeassistant/components/yale_smart_alarm/alarm_control_panel.py mode change 100755 => 100644 homeassistant/components/zwave/lock.py diff --git a/homeassistant/components/bizkaibus/sensor.py b/homeassistant/components/bizkaibus/sensor.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/cppm_tracker/device_tracker.py b/homeassistant/components/cppm_tracker/device_tracker.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/environment_canada/camera.py b/homeassistant/components/environment_canada/camera.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/environment_canada/sensor.py b/homeassistant/components/environment_canada/sensor.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/fortios/device_tracker.py b/homeassistant/components/fortios/device_tracker.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/lcn/binary_sensor.py b/homeassistant/components/lcn/binary_sensor.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/lcn/cover.py b/homeassistant/components/lcn/cover.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/lcn/scene.py b/homeassistant/components/lcn/scene.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/lcn/sensor.py b/homeassistant/components/lcn/sensor.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/lcn/services.py b/homeassistant/components/lcn/services.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/lcn/services.yaml b/homeassistant/components/lcn/services.yaml old mode 100755 new mode 100644 diff --git a/homeassistant/components/lcn/switch.py b/homeassistant/components/lcn/switch.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/rejseplanen/sensor.py b/homeassistant/components/rejseplanen/sensor.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/repetier/__init__.py b/homeassistant/components/repetier/__init__.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/repetier/manifest.json b/homeassistant/components/repetier/manifest.json old mode 100755 new mode 100644 diff --git a/homeassistant/components/repetier/sensor.py b/homeassistant/components/repetier/sensor.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/somfy_mylink/__init__.py b/homeassistant/components/somfy_mylink/__init__.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/somfy_mylink/cover.py b/homeassistant/components/somfy_mylink/cover.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/yale_smart_alarm/alarm_control_panel.py b/homeassistant/components/yale_smart_alarm/alarm_control_panel.py old mode 100755 new mode 100644 diff --git a/homeassistant/components/zwave/lock.py b/homeassistant/components/zwave/lock.py old mode 100755 new mode 100644 From 29c868ed0738d5802f02dc9fc9f15023ae5d1705 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Tue, 3 Sep 2019 14:14:33 +0200 Subject: [PATCH 51/72] Fix race during initial Sonos group construction (#26371) * Fix race during initial Sonos group construction * Update homeassistant/components/sonos/media_player.py --- homeassistant/components/sonos/media_player.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/sonos/media_player.py b/homeassistant/components/sonos/media_player.py index 86e30621334579..70461ad15d2fa6 100644 --- a/homeassistant/components/sonos/media_player.py +++ b/homeassistant/components/sonos/media_player.py @@ -337,8 +337,16 @@ def __init__(self, player): async def async_added_to_hass(self): """Subscribe sonos events.""" await self.async_seen() + self.hass.data[DATA_SONOS].entities.append(self) + def _rebuild_groups(): + """Build the current group topology.""" + for entity in self.hass.data[DATA_SONOS].entities: + entity.update_groups() + + self.hass.async_add_executor_job(_rebuild_groups) + @property def unique_id(self): """Return a unique ID.""" @@ -469,10 +477,6 @@ def _attach_player(self): self.update_volume() self._set_favorites() - # New player available, build the current group topology - for entity in self.hass.data[DATA_SONOS].entities: - entity.update_groups() - player = self.soco def subscribe(service, action): From e28fc36f3f88727518a52378c1d59d55039404e7 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 16:11:36 +0200 Subject: [PATCH 52/72] Use literal string interpolation in integrations A (f-strings) (#26377) * Use literal string interpolation in integrations A (f-strings) * Black --- homeassistant/components/adguard/sensor.py | 4 +-- homeassistant/components/airvisual/sensor.py | 8 +++--- .../components/aladdin_connect/cover.py | 2 +- .../alarmdecoder/alarm_control_panel.py | 10 +++---- homeassistant/components/alexa/errors.py | 4 +-- homeassistant/components/alexa/handlers.py | 4 +-- homeassistant/components/alexa/intent.py | 2 +- .../components/alexa/state_report.py | 6 ++-- .../components/alpha_vantage/sensor.py | 2 +- .../components/ambiclimate/config_flow.py | 2 +- .../components/ambient_station/__init__.py | 4 +-- homeassistant/components/amcrest/camera.py | 4 +-- homeassistant/components/amcrest/helpers.py | 2 +- homeassistant/components/ampio/air_quality.py | 2 +- .../android_ip_webcam/binary_sensor.py | 2 +- .../components/android_ip_webcam/sensor.py | 2 +- .../components/android_ip_webcam/switch.py | 2 +- .../components/androidtv/media_player.py | 2 +- .../components/apache_kafka/__init__.py | 2 +- homeassistant/components/apns/notify.py | 8 +++--- .../components/apple_tv/media_player.py | 2 +- .../components/aprs/device_tracker.py | 5 ++-- homeassistant/components/arcam_fmj/const.py | 4 +-- .../components/arcam_fmj/media_player.py | 2 +- .../components/arest/binary_sensor.py | 8 ++---- homeassistant/components/arest/sensor.py | 6 ++-- homeassistant/components/arest/switch.py | 28 ++++++------------- homeassistant/components/august/camera.py | 2 +- homeassistant/components/august/lock.py | 2 +- .../components/aurora/binary_sensor.py | 2 +- .../components/aurora_abb_powerone/sensor.py | 2 +- .../components/auth/mfa_setup_flow.py | 8 ++---- homeassistant/components/awair/sensor.py | 4 +-- homeassistant/components/axis/axis_base.py | 4 +-- homeassistant/components/axis/camera.py | 2 +- homeassistant/components/axis/config_flow.py | 6 ++-- homeassistant/components/axis/device.py | 8 +++--- 37 files changed, 74 insertions(+), 95 deletions(-) diff --git a/homeassistant/components/adguard/sensor.py b/homeassistant/components/adguard/sensor.py index 17e53270f257be..e0c86e42d26677 100644 --- a/homeassistant/components/adguard/sensor.py +++ b/homeassistant/components/adguard/sensor.py @@ -132,7 +132,7 @@ def __init__(self, adguard): async def _adguard_update(self) -> None: """Update AdGuard Home entity.""" percentage = await self.adguard.stats.blocked_percentage() - self._state = "{:.2f}".format(percentage) + self._state = f"{percentage:.2f}" class AdGuardHomeReplacedParentalSensor(AdGuardHomeSensor): @@ -205,7 +205,7 @@ def __init__(self, adguard): async def _adguard_update(self) -> None: """Update AdGuard Home entity.""" average = await self.adguard.stats.avg_processing_time() - self._state = "{:.2f}".format(average) + self._state = f"{average:.2f}" class AdGuardHomeRulesCountSensor(AdGuardHomeSensor): diff --git a/homeassistant/components/airvisual/sensor.py b/homeassistant/components/airvisual/sensor.py index ec2dea6903189b..20e5196c0f1fdd 100644 --- a/homeassistant/components/airvisual/sensor.py +++ b/homeassistant/components/airvisual/sensor.py @@ -194,7 +194,7 @@ def state(self): @property def unique_id(self): """Return a unique, HASS-friendly identifier for this entity.""" - return "{0}_{1}_{2}".format(self._location_id, self._locale, self._type) + return f"{self._location_id}_{self._locale}_{self._type}" @property def unit_of_measurement(self): @@ -210,7 +210,7 @@ async def async_update(self): return if self._type == SENSOR_TYPE_LEVEL: - aqi = data["aqi{0}".format(self._locale)] + aqi = data[f"aqi{self._locale}"] [level] = [ i for i in POLLUTANT_LEVEL_MAPPING @@ -219,9 +219,9 @@ async def async_update(self): self._state = level["label"] self._icon = level["icon"] elif self._type == SENSOR_TYPE_AQI: - self._state = data["aqi{0}".format(self._locale)] + self._state = data[f"aqi{self._locale}"] elif self._type == SENSOR_TYPE_POLLUTANT: - symbol = data["main{0}".format(self._locale)] + symbol = data[f"main{self._locale}"] self._state = POLLUTANT_MAPPING[symbol]["label"] self._attrs.update( { diff --git a/homeassistant/components/aladdin_connect/cover.py b/homeassistant/components/aladdin_connect/cover.py index 770b663e8a3f21..b3da4fb4cbc3f0 100644 --- a/homeassistant/components/aladdin_connect/cover.py +++ b/homeassistant/components/aladdin_connect/cover.py @@ -85,7 +85,7 @@ def supported_features(self): @property def unique_id(self): """Return a unique ID.""" - return "{}-{}".format(self._device_id, self._number) + return f"{self._device_id}-{self._number}" @property def name(self): diff --git a/homeassistant/components/alarmdecoder/alarm_control_panel.py b/homeassistant/components/alarmdecoder/alarm_control_panel.py index c05dfd30d21634..288c1dfd1c75a8 100644 --- a/homeassistant/components/alarmdecoder/alarm_control_panel.py +++ b/homeassistant/components/alarmdecoder/alarm_control_panel.py @@ -140,27 +140,27 @@ def device_state_attributes(self): def alarm_disarm(self, code=None): """Send disarm command.""" if code: - self.hass.data[DATA_AD].send("{!s}1".format(code)) + self.hass.data[DATA_AD].send(f"{code!s}1") def alarm_arm_away(self, code=None): """Send arm away command.""" if code: - self.hass.data[DATA_AD].send("{!s}2".format(code)) + self.hass.data[DATA_AD].send(f"{code!s}2") def alarm_arm_home(self, code=None): """Send arm home command.""" if code: - self.hass.data[DATA_AD].send("{!s}3".format(code)) + self.hass.data[DATA_AD].send(f"{code!s}3") def alarm_arm_night(self, code=None): """Send arm night command.""" if code: - self.hass.data[DATA_AD].send("{!s}33".format(code)) + self.hass.data[DATA_AD].send(f"{code!s}33") def alarm_toggle_chime(self, code=None): """Send toggle chime command.""" if code: - self.hass.data[DATA_AD].send("{!s}9".format(code)) + self.hass.data[DATA_AD].send(f"{code!s}9") def alarm_keypress(self, keypress): """Send custom keypresses.""" diff --git a/homeassistant/components/alexa/errors.py b/homeassistant/components/alexa/errors.py index 56202b23e20e0b..8c2fa692267fb0 100644 --- a/homeassistant/components/alexa/errors.py +++ b/homeassistant/components/alexa/errors.py @@ -40,7 +40,7 @@ class AlexaInvalidEndpointError(AlexaError): def __init__(self, endpoint_id): """Initialize invalid endpoint error.""" - msg = "The endpoint {} does not exist".format(endpoint_id) + msg = f"The endpoint {endpoint_id} does not exist" AlexaError.__init__(self, msg) self.endpoint_id = endpoint_id @@ -73,7 +73,7 @@ def __init__(self, hass, temp, min_temp, max_temp): "maximumValue": {"value": max_temp, "scale": API_TEMP_UNITS[unit]}, } payload = {"validRange": temp_range} - msg = "The requested temperature {} is out of range".format(temp) + msg = f"The requested temperature {temp} is out of range" AlexaError.__init__(self, msg, payload) diff --git a/homeassistant/components/alexa/handlers.py b/homeassistant/components/alexa/handlers.py index cd5b56d60e2790..1e636b96ee5205 100644 --- a/homeassistant/components/alexa/handlers.py +++ b/homeassistant/components/alexa/handlers.py @@ -744,7 +744,7 @@ async def async_api_set_thermostat_mode(hass, config, directive, context): presets = entity.attributes.get(climate.ATTR_PRESET_MODES, []) if ha_preset not in presets: - msg = "The requested thermostat mode {} is not supported".format(ha_preset) + msg = f"The requested thermostat mode {ha_preset} is not supported" raise AlexaUnsupportedThermostatModeError(msg) service = climate.SERVICE_SET_PRESET_MODE @@ -754,7 +754,7 @@ async def async_api_set_thermostat_mode(hass, config, directive, context): operation_list = entity.attributes.get(climate.ATTR_HVAC_MODES) ha_mode = next((k for k, v in API_THERMOSTAT_MODES.items() if v == mode), None) if ha_mode not in operation_list: - msg = "The requested thermostat mode {} is not supported".format(mode) + msg = f"The requested thermostat mode {mode} is not supported" raise AlexaUnsupportedThermostatModeError(msg) service = climate.SERVICE_SET_HVAC_MODE diff --git a/homeassistant/components/alexa/intent.py b/homeassistant/components/alexa/intent.py index edeb6865aad8f5..4cb75c65bc9758 100644 --- a/homeassistant/components/alexa/intent.py +++ b/homeassistant/components/alexa/intent.py @@ -113,7 +113,7 @@ async def async_handle_message(hass, message): handler = HANDLERS.get(req_type) if not handler: - raise UnknownRequest("Received unknown request {}".format(req_type)) + raise UnknownRequest(f"Received unknown request {req_type}") return await handler(hass, message) diff --git a/homeassistant/components/alexa/state_report.py b/homeassistant/components/alexa/state_report.py index 1e22d5fc09f23b..e956abec7ad997 100644 --- a/homeassistant/components/alexa/state_report.py +++ b/homeassistant/components/alexa/state_report.py @@ -60,7 +60,7 @@ async def async_send_changereport_message( """ token = await config.async_get_access_token() - headers = {"Authorization": "Bearer {}".format(token)} + headers = {"Authorization": f"Bearer {token}"} endpoint = alexa_entity.alexa_id() @@ -122,7 +122,7 @@ async def async_send_add_or_update_message(hass, config, entity_ids): """ token = await config.async_get_access_token() - headers = {"Authorization": "Bearer {}".format(token)} + headers = {"Authorization": f"Bearer {token}"} endpoints = [] @@ -152,7 +152,7 @@ async def async_send_delete_message(hass, config, entity_ids): """ token = await config.async_get_access_token() - headers = {"Authorization": "Bearer {}".format(token)} + headers = {"Authorization": f"Bearer {token}"} endpoints = [] diff --git a/homeassistant/components/alpha_vantage/sensor.py b/homeassistant/components/alpha_vantage/sensor.py index 6d790e0719b61a..188567e4cf4276 100644 --- a/homeassistant/components/alpha_vantage/sensor.py +++ b/homeassistant/components/alpha_vantage/sensor.py @@ -168,7 +168,7 @@ def __init__(self, foreign_exchange, config): if CONF_NAME in config: self._name = config.get(CONF_NAME) else: - self._name = "{}/{}".format(self._to_currency, self._from_currency) + self._name = f"{self._to_currency}/{self._from_currency}" self._unit_of_measurement = self._to_currency self._icon = ICONS.get(self._from_currency, "USD") self.values = None diff --git a/homeassistant/components/ambiclimate/config_flow.py b/homeassistant/components/ambiclimate/config_flow.py index db6d42d1d5c611..99563dcb97de1a 100644 --- a/homeassistant/components/ambiclimate/config_flow.py +++ b/homeassistant/components/ambiclimate/config_flow.py @@ -130,7 +130,7 @@ def _generate_oauth(self): return oauth def _cb_url(self): - return "{}{}".format(self.hass.config.api.base_url, AUTH_CALLBACK_PATH) + return f"{self.hass.config.api.base_url}{AUTH_CALLBACK_PATH}" async def _get_authorize_url(self): oauth = self._generate_oauth() diff --git a/homeassistant/components/ambient_station/__init__.py b/homeassistant/components/ambient_station/__init__.py index 82c29f79983055..bff03eb422b231 100644 --- a/homeassistant/components/ambient_station/__init__.py +++ b/homeassistant/components/ambient_station/__init__.py @@ -492,7 +492,7 @@ def device_info(self): @property def name(self): """Return the name of the sensor.""" - return "{0}_{1}".format(self._station_name, self._sensor_name) + return f"{self._station_name}_{self._sensor_name}" @property def should_poll(self): @@ -502,7 +502,7 @@ def should_poll(self): @property def unique_id(self): """Return a unique, unchanging string that represents this sensor.""" - return "{0}_{1}".format(self._mac_address, self._sensor_type) + return f"{self._mac_address}_{self._sensor_type}" async def async_added_to_hass(self): """Register callbacks.""" diff --git a/homeassistant/components/amcrest/camera.py b/homeassistant/components/amcrest/camera.py index 483bdb2c7cf604..f75a5adbe9cd0a 100644 --- a/homeassistant/components/amcrest/camera.py +++ b/homeassistant/components/amcrest/camera.py @@ -490,7 +490,7 @@ def _goto_preset(self, preset): self._api.go_to_preset(action="start", preset_point_number=preset) except AmcrestError as error: log_update_error( - _LOGGER, "move", self.name, "camera to preset {}".format(preset), error + _LOGGER, "move", self.name, f"camera to preset {preset}", error ) def _set_color_bw(self, cbw): @@ -499,7 +499,7 @@ def _set_color_bw(self, cbw): self._api.day_night_color = _CBW.index(cbw) except AmcrestError as error: log_update_error( - _LOGGER, "set", self.name, "camera color mode to {}".format(cbw), error + _LOGGER, "set", self.name, f"camera color mode to {cbw}", error ) else: self._color_bw = cbw diff --git a/homeassistant/components/amcrest/helpers.py b/homeassistant/components/amcrest/helpers.py index d24d6e0e7071df..a40d6ace50a31d 100644 --- a/homeassistant/components/amcrest/helpers.py +++ b/homeassistant/components/amcrest/helpers.py @@ -4,7 +4,7 @@ def service_signal(service, ident=None): """Encode service and identifier into signal.""" - signal = "{}_{}".format(DOMAIN, service) + signal = f"{DOMAIN}_{service}" if ident: signal += "_{}".format(ident.replace(".", "_")) return signal diff --git a/homeassistant/components/ampio/air_quality.py b/homeassistant/components/ampio/air_quality.py index f55f20fc150259..e63f59839a80fd 100644 --- a/homeassistant/components/ampio/air_quality.py +++ b/homeassistant/components/ampio/air_quality.py @@ -57,7 +57,7 @@ def name(self): @property def unique_id(self): """Return unique_name.""" - return "ampio_smog_{}".format(self._station_id) + return f"ampio_smog_{self._station_id}" @property def particulate_matter_2_5(self): diff --git a/homeassistant/components/android_ip_webcam/binary_sensor.py b/homeassistant/components/android_ip_webcam/binary_sensor.py index d7bf009701d0ca..0e9cca46afbfd2 100644 --- a/homeassistant/components/android_ip_webcam/binary_sensor.py +++ b/homeassistant/components/android_ip_webcam/binary_sensor.py @@ -25,7 +25,7 @@ def __init__(self, name, host, ipcam, sensor): self._sensor = sensor self._mapped_name = KEY_MAP.get(self._sensor, self._sensor) - self._name = "{} {}".format(name, self._mapped_name) + self._name = f"{name} {self._mapped_name}" self._state = None self._unit = None diff --git a/homeassistant/components/android_ip_webcam/sensor.py b/homeassistant/components/android_ip_webcam/sensor.py index 20f4acebca61db..05c1fe16c61c2d 100644 --- a/homeassistant/components/android_ip_webcam/sensor.py +++ b/homeassistant/components/android_ip_webcam/sensor.py @@ -39,7 +39,7 @@ def __init__(self, name, host, ipcam, sensor): self._sensor = sensor self._mapped_name = KEY_MAP.get(self._sensor, self._sensor) - self._name = "{} {}".format(name, self._mapped_name) + self._name = f"{name} {self._mapped_name}" self._state = None self._unit = None diff --git a/homeassistant/components/android_ip_webcam/switch.py b/homeassistant/components/android_ip_webcam/switch.py index 5b2f5dad5e1052..2d5f2412d85285 100644 --- a/homeassistant/components/android_ip_webcam/switch.py +++ b/homeassistant/components/android_ip_webcam/switch.py @@ -39,7 +39,7 @@ def __init__(self, name, host, ipcam, setting): self._setting = setting self._mapped_name = KEY_MAP.get(self._setting, self._setting) - self._name = "{} {}".format(name, self._mapped_name) + self._name = f"{name} {self._mapped_name}" self._state = False @property diff --git a/homeassistant/components/androidtv/media_player.py b/homeassistant/components/androidtv/media_player.py index 2db210b56f3e52..d68f47b1b0a3b7 100644 --- a/homeassistant/components/androidtv/media_player.py +++ b/homeassistant/components/androidtv/media_player.py @@ -392,7 +392,7 @@ def adb_command(self, cmd): """Send an ADB command to an Android TV / Fire TV device.""" key = self._keys.get(cmd) if key: - self.aftv.adb_shell("input keyevent {}".format(key)) + self.aftv.adb_shell(f"input keyevent {key}") self._adb_response = None self.schedule_update_ha_state() return diff --git a/homeassistant/components/apache_kafka/__init__.py b/homeassistant/components/apache_kafka/__init__.py index caf96c61fb87b5..e0c8b824913e48 100644 --- a/homeassistant/components/apache_kafka/__init__.py +++ b/homeassistant/components/apache_kafka/__init__.py @@ -81,7 +81,7 @@ def __init__(self, hass, ip_address, port, topic, entities_filter): self._hass = hass self._producer = AIOKafkaProducer( loop=hass.loop, - bootstrap_servers="{0}:{1}".format(ip_address, port), + bootstrap_servers=f"{ip_address}:{port}", compression_type="gzip", ) self._topic = topic diff --git a/homeassistant/components/apns/notify.py b/homeassistant/components/apns/notify.py index 0b95cb9f0cb32a..dbd45013a3ce95 100644 --- a/homeassistant/components/apns/notify.py +++ b/homeassistant/components/apns/notify.py @@ -50,7 +50,7 @@ def get_service(hass, config, discovery_info=None): service = ApnsNotificationService(hass, name, topic, sandbox, cert_file) hass.services.register( - DOMAIN, "apns_{}".format(name), service.register, schema=REGISTER_SERVICE_SCHEMA + DOMAIN, f"apns_{name}", service.register, schema=REGISTER_SERVICE_SCHEMA ) return service @@ -98,7 +98,7 @@ def full_tracking_device_id(self): The full id of a device that is tracked by the device tracking component. """ - return "{}.{}".format(DEVICE_TRACKER_DOMAIN, self.tracking_id) + return f"{DEVICE_TRACKER_DOMAIN}.{self.tracking_id}" @property def disabled(self): @@ -124,9 +124,9 @@ def _write_device(out, device): """Write a single device to file.""" attributes = [] if device.name is not None: - attributes.append("name: {}".format(device.name)) + attributes.append(f"name: {device.name}") if device.tracking_device_id is not None: - attributes.append("tracking_device_id: {}".format(device.tracking_device_id)) + attributes.append(f"tracking_device_id: {device.tracking_device_id}") if device.disabled: attributes.append("disabled: True") diff --git a/homeassistant/components/apple_tv/media_player.py b/homeassistant/components/apple_tv/media_player.py index 3e77c7a1cfd8e3..9ac5ba77f98d48 100644 --- a/homeassistant/components/apple_tv/media_player.py +++ b/homeassistant/components/apple_tv/media_player.py @@ -213,7 +213,7 @@ def media_title(self): title = self._playing.title return title if title else "No title" - return "Establishing a connection to {0}...".format(self._name) + return f"Establishing a connection to {self._name}..." @property def supported_features(self): diff --git a/homeassistant/components/aprs/device_tracker.py b/homeassistant/components/aprs/device_tracker.py index c5ae8ed8414554..86b0b6f48afd65 100644 --- a/homeassistant/components/aprs/device_tracker.py +++ b/homeassistant/components/aprs/device_tracker.py @@ -70,7 +70,7 @@ def gps_accuracy(gps, posambiguity: int) -> int: accuracy = round(dist_m) else: - message = "APRS position ambiguity must be 0-4, not '{0}'.".format(posambiguity) + message = f"APRS position ambiguity must be 0-4, not '{posambiguity}'." raise ValueError(message) return accuracy @@ -147,8 +147,7 @@ def run(self): ) self.ais.connect() self.start_complete( - True, - "Connected to {0} with callsign {1}.".format(self.host, self.callsign), + True, f"Connected to {self.host} with callsign {self.callsign}." ) self.ais.consumer(callback=self.rx_msg, immortal=True) except (AprsConnectionError, LoginError) as err: diff --git a/homeassistant/components/arcam_fmj/const.py b/homeassistant/components/arcam_fmj/const.py index b065e1a0833290..dc5a576acec067 100644 --- a/homeassistant/components/arcam_fmj/const.py +++ b/homeassistant/components/arcam_fmj/const.py @@ -9,5 +9,5 @@ DEFAULT_NAME = "Arcam FMJ" DEFAULT_SCAN_INTERVAL = 5 -DOMAIN_DATA_ENTRIES = "{}.entries".format(DOMAIN) -DOMAIN_DATA_CONFIG = "{}.config".format(DOMAIN) +DOMAIN_DATA_ENTRIES = f"{DOMAIN}.entries" +DOMAIN_DATA_CONFIG = f"{DOMAIN}.config" diff --git a/homeassistant/components/arcam_fmj/media_player.py b/homeassistant/components/arcam_fmj/media_player.py index 971abc3e26d5ab..231e9821dc6ddc 100644 --- a/homeassistant/components/arcam_fmj/media_player.py +++ b/homeassistant/components/arcam_fmj/media_player.py @@ -319,7 +319,7 @@ def media_title(self): channel = self.media_channel if channel: - value = "{} - {}".format(source.name, channel) + value = f"{source.name} - {channel}" else: value = source.name return value diff --git a/homeassistant/components/arest/binary_sensor.py b/homeassistant/components/arest/binary_sensor.py index 96ffa371864682..669a28b707800b 100644 --- a/homeassistant/components/arest/binary_sensor.py +++ b/homeassistant/components/arest/binary_sensor.py @@ -73,9 +73,7 @@ def __init__(self, arest, resource, name, device_class, pin): self._pin = pin if self._pin is not None: - request = requests.get( - "{}/mode/{}/i".format(self._resource, self._pin), timeout=10 - ) + request = requests.get(f"{self._resource}/mode/{self._pin}/i", timeout=10) if request.status_code != 200: _LOGGER.error("Can't set mode of %s", self._resource) @@ -112,9 +110,7 @@ def __init__(self, resource, pin): def update(self): """Get the latest data from aREST device.""" try: - response = requests.get( - "{}/digital/{}".format(self._resource, self._pin), timeout=10 - ) + response = requests.get(f"{self._resource}/digital/{self._pin}", timeout=10) self.data = {"state": response.json()["return_value"]} except requests.exceptions.ConnectionError: _LOGGER.error("No route to device '%s'", self._resource) diff --git a/homeassistant/components/arest/sensor.py b/homeassistant/components/arest/sensor.py index 533adeccb5eb1b..2416eeb0ebb08f 100644 --- a/homeassistant/components/arest/sensor.py +++ b/homeassistant/components/arest/sensor.py @@ -148,9 +148,7 @@ def __init__( self._renderer = renderer if self._pin is not None: - request = requests.get( - "{}/mode/{}/i".format(self._resource, self._pin), timeout=10 - ) + request = requests.get(f"{self._resource}/mode/{self._pin}/i", timeout=10) if request.status_code != 200: _LOGGER.error("Can't set mode of %s", self._resource) @@ -212,7 +210,7 @@ def update(self): self.data = {"value": response.json()["return_value"]} except TypeError: response = requests.get( - "{}/digital/{}".format(self._resource, self._pin), timeout=10 + f"{self._resource}/digital/{self._pin}", timeout=10 ) self.data = {"value": response.json()["return_value"]} self.available = True diff --git a/homeassistant/components/arest/switch.py b/homeassistant/components/arest/switch.py index 558df89100eed7..e1a7edacb7e59b 100644 --- a/homeassistant/components/arest/switch.py +++ b/homeassistant/components/arest/switch.py @@ -114,7 +114,7 @@ def __init__(self, resource, location, name, func): super().__init__(resource, location, name) self._func = func - request = requests.get("{}/{}".format(self._resource, self._func), timeout=10) + request = requests.get(f"{self._resource}/{self._func}", timeout=10) if request.status_code != 200: _LOGGER.error("Can't find function") @@ -130,9 +130,7 @@ def __init__(self, resource, location, name, func): def turn_on(self, **kwargs): """Turn the device on.""" request = requests.get( - "{}/{}".format(self._resource, self._func), - timeout=10, - params={"params": "1"}, + f"{self._resource}/{self._func}", timeout=10, params={"params": "1"} ) if request.status_code == 200: @@ -143,9 +141,7 @@ def turn_on(self, **kwargs): def turn_off(self, **kwargs): """Turn the device off.""" request = requests.get( - "{}/{}".format(self._resource, self._func), - timeout=10, - params={"params": "0"}, + f"{self._resource}/{self._func}", timeout=10, params={"params": "0"} ) if request.status_code == 200: @@ -158,9 +154,7 @@ def turn_off(self, **kwargs): def update(self): """Get the latest data from aREST API and update the state.""" try: - request = requests.get( - "{}/{}".format(self._resource, self._func), timeout=10 - ) + request = requests.get(f"{self._resource}/{self._func}", timeout=10) self._state = request.json()["return_value"] != 0 self._available = True except requests.exceptions.ConnectionError: @@ -177,9 +171,7 @@ def __init__(self, resource, location, name, pin, invert): self._pin = pin self.invert = invert - request = requests.get( - "{}/mode/{}/o".format(self._resource, self._pin), timeout=10 - ) + request = requests.get(f"{self._resource}/mode/{self._pin}/o", timeout=10) if request.status_code != 200: _LOGGER.error("Can't set mode") self._available = False @@ -188,8 +180,7 @@ def turn_on(self, **kwargs): """Turn the device on.""" turn_on_payload = int(not self.invert) request = requests.get( - "{}/digital/{}/{}".format(self._resource, self._pin, turn_on_payload), - timeout=10, + f"{self._resource}/digital/{self._pin}/{turn_on_payload}", timeout=10 ) if request.status_code == 200: self._state = True @@ -200,8 +191,7 @@ def turn_off(self, **kwargs): """Turn the device off.""" turn_off_payload = int(self.invert) request = requests.get( - "{}/digital/{}/{}".format(self._resource, self._pin, turn_off_payload), - timeout=10, + f"{self._resource}/digital/{self._pin}/{turn_off_payload}", timeout=10 ) if request.status_code == 200: self._state = False @@ -211,9 +201,7 @@ def turn_off(self, **kwargs): def update(self): """Get the latest data from aREST API and update the state.""" try: - request = requests.get( - "{}/digital/{}".format(self._resource, self._pin), timeout=10 - ) + request = requests.get(f"{self._resource}/digital/{self._pin}", timeout=10) status_value = int(self.invert) self._state = request.json()["return_value"] != status_value self._available = True diff --git a/homeassistant/components/august/camera.py b/homeassistant/components/august/camera.py index a8335d1aa52ffe..2492eb754181ab 100644 --- a/homeassistant/components/august/camera.py +++ b/homeassistant/components/august/camera.py @@ -73,4 +73,4 @@ def camera_image(self): @property def unique_id(self) -> str: """Get the unique id of the camera.""" - return "{:s}_camera".format(self._doorbell.device_id) + return f"{self._doorbell.device_id:s}_camera" diff --git a/homeassistant/components/august/lock.py b/homeassistant/components/august/lock.py index e919c47dd4c2e2..8b8c019eb2db90 100644 --- a/homeassistant/components/august/lock.py +++ b/homeassistant/components/august/lock.py @@ -93,4 +93,4 @@ def device_state_attributes(self): @property def unique_id(self) -> str: """Get the unique id of the lock.""" - return "{:s}_lock".format(self._lock.device_id) + return f"{self._lock.device_id:s}_lock" diff --git a/homeassistant/components/aurora/binary_sensor.py b/homeassistant/components/aurora/binary_sensor.py index 0d983f35e37ffa..a69433c418617f 100644 --- a/homeassistant/components/aurora/binary_sensor.py +++ b/homeassistant/components/aurora/binary_sensor.py @@ -64,7 +64,7 @@ def __init__(self, aurora_data, name): @property def name(self): """Return the name of the sensor.""" - return "{}".format(self._name) + return f"{self._name}" @property def is_on(self): diff --git a/homeassistant/components/aurora_abb_powerone/sensor.py b/homeassistant/components/aurora_abb_powerone/sensor.py index 456b508048443f..05ed5fa99bf2b1 100644 --- a/homeassistant/components/aurora_abb_powerone/sensor.py +++ b/homeassistant/components/aurora_abb_powerone/sensor.py @@ -49,7 +49,7 @@ class AuroraABBSolarPVMonitorSensor(Entity): def __init__(self, client, name, typename): """Initialize the sensor.""" - self._name = "{} {}".format(name, typename) + self._name = f"{name} {typename}" self.client = client self._state = None diff --git a/homeassistant/components/auth/mfa_setup_flow.py b/homeassistant/components/auth/mfa_setup_flow.py index c18bc276a449cb..42dab7ebb5a0d6 100644 --- a/homeassistant/components/auth/mfa_setup_flow.py +++ b/homeassistant/components/auth/mfa_setup_flow.py @@ -34,7 +34,7 @@ async def _async_create_setup_flow(handler, context, data): """Create a setup flow. handler is a mfa module.""" mfa_module = hass.auth.get_auth_mfa_module(handler) if mfa_module is None: - raise ValueError("Mfa module {} is not found".format(handler)) + raise ValueError(f"Mfa module {handler} is not found") user_id = data.pop("user_id") return await mfa_module.async_setup_flow(user_id) @@ -80,9 +80,7 @@ async def async_setup_flow(msg): if mfa_module is None: connection.send_message( websocket_api.error_message( - msg["id"], - "no_module", - "MFA module {} is not found".format(mfa_module_id), + msg["id"], "no_module", f"MFA module {mfa_module_id} is not found" ) ) return @@ -117,7 +115,7 @@ async def async_depose(msg): websocket_api.error_message( msg["id"], "disable_failed", - "Cannot disable MFA Module {}: {}".format(mfa_module_id, err), + f"Cannot disable MFA Module {mfa_module_id}: {err}", ) ) return diff --git a/homeassistant/components/awair/sensor.py b/homeassistant/components/awair/sensor.py index 85b5a0be191533..c899e0097964d9 100644 --- a/homeassistant/components/awair/sensor.py +++ b/homeassistant/components/awair/sensor.py @@ -150,7 +150,7 @@ def __init__(self, data, device, sensor_type, throttle): """Initialize the sensor.""" self._uuid = device[CONF_UUID] self._device_class = SENSOR_TYPES[sensor_type]["device_class"] - self._name = "Awair {}".format(self._device_class) + self._name = f"Awair {self._device_class}" unit = SENSOR_TYPES[sensor_type]["unit_of_measurement"] self._unit_of_measurement = unit self._data = data @@ -202,7 +202,7 @@ def available(self): @property def unique_id(self): """Return the unique id of this entity.""" - return "{}_{}".format(self._uuid, self._type) + return f"{self._uuid}_{self._type}" @property def unit_of_measurement(self): diff --git a/homeassistant/components/axis/axis_base.py b/homeassistant/components/axis/axis_base.py index 3864ac344e1487..f22a169a1023de 100644 --- a/homeassistant/components/axis/axis_base.py +++ b/homeassistant/components/axis/axis_base.py @@ -72,7 +72,7 @@ def device_class(self): @property def name(self): """Return the name of the event.""" - return "{} {} {}".format(self.device.name, self.event.TYPE, self.event.id) + return f"{self.device.name} {self.event.TYPE} {self.event.id}" @property def should_poll(self): @@ -82,4 +82,4 @@ def should_poll(self): @property def unique_id(self): """Return a unique identifier for this device.""" - return "{}-{}-{}".format(self.device.serial, self.event.topic, self.event.id) + return f"{self.device.serial}-{self.event.topic}-{self.event.id}" diff --git a/homeassistant/components/axis/camera.py b/homeassistant/components/axis/camera.py index e7e0f7459f30e6..a55e45dd37468d 100644 --- a/homeassistant/components/axis/camera.py +++ b/homeassistant/components/axis/camera.py @@ -92,4 +92,4 @@ def _new_address(self): @property def unique_id(self): """Return a unique identifier for this device.""" - return "{}-camera".format(self.device.serial) + return f"{self.device.serial}-camera" diff --git a/homeassistant/components/axis/config_flow.py b/homeassistant/components/axis/config_flow.py index f93e49d9818c25..3b5efe96760efd 100644 --- a/homeassistant/components/axis/config_flow.py +++ b/homeassistant/components/axis/config_flow.py @@ -137,9 +137,9 @@ async def _create_entry(self): if entry.data[CONF_MODEL] == self.model ] - self.name = "{}".format(self.model) + self.name = f"{self.model}" for idx in range(len(same_model) + 1): - self.name = "{} {}".format(self.model, idx) + self.name = f"{self.model} {idx}" if self.name not in same_model: break @@ -150,7 +150,7 @@ async def _create_entry(self): CONF_MODEL: self.model, } - title = "{} - {}".format(self.model, self.serial_number) + title = f"{self.model} - {self.serial_number}" return self.async_create_entry(title=title, data=data) async def _update_entry(self, entry, host): diff --git a/homeassistant/components/axis/device.py b/homeassistant/components/axis/device.py index 465d8c73b74205..3b91f7e147456b 100644 --- a/homeassistant/components/axis/device.py +++ b/homeassistant/components/axis/device.py @@ -65,7 +65,7 @@ async def async_update_device_registry(self): connections={(CONNECTION_NETWORK_MAC, self.serial)}, identifiers={(DOMAIN, self.serial)}, manufacturer="Axis Communications AB", - model="{} {}".format(self.model, self.product_type), + model=f"{self.model} {self.product_type}", name=self.name, sw_version=self.fw_version, ) @@ -115,7 +115,7 @@ async def async_setup(self): @property def event_new_address(self): """Device specific event to signal new device address.""" - return "axis_new_address_{}".format(self.serial) + return f"axis_new_address_{self.serial}" @staticmethod async def async_new_address_callback(hass, entry): @@ -131,7 +131,7 @@ async def async_new_address_callback(hass, entry): @property def event_reachable(self): """Device specific event to signal a change in connection status.""" - return "axis_reachable_{}".format(self.serial) + return f"axis_reachable_{self.serial}" @callback def async_connection_status_callback(self, status): @@ -149,7 +149,7 @@ def async_connection_status_callback(self, status): @property def event_new_sensor(self): """Device specific event to signal new sensor available.""" - return "axis_add_sensor_{}".format(self.serial) + return f"axis_add_sensor_{self.serial}" @callback def async_event_callback(self, action, event_id): From 9ac869ddc65d8fbf45aaec88cb201d4863daacde Mon Sep 17 00:00:00 2001 From: ThaStealth Date: Tue, 3 Sep 2019 17:05:23 +0200 Subject: [PATCH 53/72] Remove solaredge_local duplicate code (#25941) * Removed duplicate code * Update sensor.py Splitted exceptions into two seperate ones * Update sensor.py * Update sensor.py * Update sensor.py Fixed linting errors * Update sensor.py --- .../components/solaredge_local/sensor.py | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/solaredge_local/sensor.py b/homeassistant/components/solaredge_local/sensor.py index 4bf015a74893bd..80bd8e1f61ed8c 100644 --- a/homeassistant/components/solaredge_local/sensor.py +++ b/homeassistant/components/solaredge_local/sensor.py @@ -149,25 +149,19 @@ def update(self): try: response = self.api.get_status() _LOGGER.debug("response from SolarEdge: %s", response) + except (ConnectTimeout): + _LOGGER.error("Connection timeout, skipping update") + return + except (HTTPError): + _LOGGER.error("Could not retrieve data, skipping update") + return + try: self.data["energyTotal"] = response.energy.total self.data["energyThisYear"] = response.energy.thisYear self.data["energyThisMonth"] = response.energy.thisMonth self.data["energyToday"] = response.energy.today self.data["currentPower"] = response.powerWatt - _LOGGER.debug("Updated SolarEdge overview data: %s", self.data) except AttributeError: - _LOGGER.error("Missing details data in solaredge response") - _LOGGER.debug("Response is: %s", response) - return - except (ConnectTimeout, HTTPError): - _LOGGER.error("Could not retrieve data, skipping update") - return - - self.data["energyTotal"] = response.energy.total - self.data["energyThisYear"] = response.energy.thisYear - self.data["energyThisMonth"] = response.energy.thisMonth - self.data["energyToday"] = response.energy.today - self.data["currentPower"] = response.powerWatt - _LOGGER.debug("Updated SolarEdge overview data: %s", self.data) + _LOGGER.error("Missing details data in SolarEdge response") From a81eb145008fa3111637993240d9ba106c51a6b2 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 17:09:59 +0200 Subject: [PATCH 54/72] Use literal string interpolation in integrations B-D (f-strings) (#26378) --- homeassistant/components/bbox/sensor.py | 2 +- .../components/blackbird/media_player.py | 2 +- .../components/blink/alarm_control_panel.py | 2 +- .../components/blink/binary_sensor.py | 4 +-- homeassistant/components/blink/camera.py | 4 +-- homeassistant/components/blink/sensor.py | 4 +-- homeassistant/components/blinkt/light.py | 2 +- homeassistant/components/bloomsky/__init__.py | 2 +- .../components/bloomsky/binary_sensor.py | 2 +- homeassistant/components/bloomsky/sensor.py | 4 +-- .../components/bluesound/media_player.py | 16 +++++------ .../bluetooth_tracker/device_tracker.py | 2 +- homeassistant/components/bme280/sensor.py | 2 +- homeassistant/components/bme680/sensor.py | 2 +- .../bmw_connected_drive/binary_sensor.py | 12 ++++---- .../components/bmw_connected_drive/lock.py | 4 +-- .../components/bmw_connected_drive/sensor.py | 4 +-- homeassistant/components/bom/camera.py | 4 +-- homeassistant/components/bom/sensor.py | 2 +- .../components/broadlink/__init__.py | 2 +- homeassistant/components/broadlink/switch.py | 8 +++--- homeassistant/components/buienradar/sensor.py | 2 +- homeassistant/components/camera/__init__.py | 16 ++++------- homeassistant/components/canary/sensor.py | 2 +- .../components/cisco_webex_teams/notify.py | 4 +-- homeassistant/components/clicksend/notify.py | 4 +-- .../components/clicksend_tts/notify.py | 4 +-- homeassistant/components/cloud/http_api.py | 2 +- homeassistant/components/cmus/media_player.py | 2 +- homeassistant/components/co2signal/sensor.py | 2 +- homeassistant/components/coinbase/sensor.py | 4 +-- .../concord232/alarm_control_panel.py | 2 +- .../components/concord232/binary_sensor.py | 2 +- .../components/crimereports/sensor.py | 2 +- homeassistant/components/cups/sensor.py | 2 +- .../components/currencylayer/sensor.py | 2 +- homeassistant/components/daikin/sensor.py | 2 +- homeassistant/components/daikin/switch.py | 2 +- homeassistant/components/darksky/sensor.py | 8 +++--- homeassistant/components/datadog/__init__.py | 6 ++-- .../components/ddwrt/device_tracker.py | 6 ++-- homeassistant/components/deconz/gateway.py | 4 +-- homeassistant/components/deluge/sensor.py | 2 +- .../components/deutsche_bahn/sensor.py | 2 +- homeassistant/components/dht/sensor.py | 2 +- .../components/digitalloggers/switch.py | 2 +- homeassistant/components/doorbird/__init__.py | 14 ++++------ homeassistant/components/doorbird/switch.py | 4 +-- .../components/downloader/__init__.py | 8 +++--- .../components/duke_energy/sensor.py | 2 +- .../components/dwd_weather_warnings/sensor.py | 28 +++++++++---------- homeassistant/components/dyson/sensor.py | 12 ++++---- 52 files changed, 116 insertions(+), 126 deletions(-) diff --git a/homeassistant/components/bbox/sensor.py b/homeassistant/components/bbox/sensor.py index 76621b7792b5df..b59b166e41f145 100644 --- a/homeassistant/components/bbox/sensor.py +++ b/homeassistant/components/bbox/sensor.py @@ -91,7 +91,7 @@ def __init__(self, bbox_data, sensor_type, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/blackbird/media_player.py b/homeassistant/components/blackbird/media_player.py index a77fad69663f46..eca7fa84f504fe 100644 --- a/homeassistant/components/blackbird/media_player.py +++ b/homeassistant/components/blackbird/media_player.py @@ -99,7 +99,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): devices = [] for zone_id, extra in config[CONF_ZONES].items(): _LOGGER.info("Adding zone %d - %s", zone_id, extra[CONF_NAME]) - unique_id = "{}-{}".format(connection, zone_id) + unique_id = f"{connection}-{zone_id}" device = BlackbirdZone(blackbird, sources, zone_id, extra[CONF_NAME]) hass.data[DATA_BLACKBIRD][unique_id] = device devices.append(device) diff --git a/homeassistant/components/blink/alarm_control_panel.py b/homeassistant/components/blink/alarm_control_panel.py index adcefeddf239e8..b1c9f6a7ec07fd 100644 --- a/homeassistant/components/blink/alarm_control_panel.py +++ b/homeassistant/components/blink/alarm_control_panel.py @@ -55,7 +55,7 @@ def state(self): @property def name(self): """Return the name of the panel.""" - return "{} {}".format(BLINK_DATA, self._name) + return f"{BLINK_DATA} {self._name}" @property def device_state_attributes(self): diff --git a/homeassistant/components/blink/binary_sensor.py b/homeassistant/components/blink/binary_sensor.py index 4c268989d32bac..e8c01953bffd62 100644 --- a/homeassistant/components/blink/binary_sensor.py +++ b/homeassistant/components/blink/binary_sensor.py @@ -26,11 +26,11 @@ def __init__(self, data, camera, sensor_type): self.data = data self._type = sensor_type name, icon = BINARY_SENSORS[sensor_type] - self._name = "{} {} {}".format(BLINK_DATA, camera, name) + self._name = f"{BLINK_DATA} {camera} {name}" self._icon = icon self._camera = data.cameras[camera] self._state = None - self._unique_id = "{}-{}".format(self._camera.serial, self._type) + self._unique_id = f"{self._camera.serial}-{self._type}" @property def name(self): diff --git a/homeassistant/components/blink/camera.py b/homeassistant/components/blink/camera.py index 5e8b5323f896f0..52043324a40f99 100644 --- a/homeassistant/components/blink/camera.py +++ b/homeassistant/components/blink/camera.py @@ -30,9 +30,9 @@ def __init__(self, data, name, camera): """Initialize a camera.""" super().__init__() self.data = data - self._name = "{} {}".format(BLINK_DATA, name) + self._name = f"{BLINK_DATA} {name}" self._camera = camera - self._unique_id = "{}-camera".format(camera.serial) + self._unique_id = f"{camera.serial}-camera" self.response = None self.current_image = None self.last_image = None diff --git a/homeassistant/components/blink/sensor.py b/homeassistant/components/blink/sensor.py index fba2d0bd493b33..81616b463ecfbe 100644 --- a/homeassistant/components/blink/sensor.py +++ b/homeassistant/components/blink/sensor.py @@ -28,7 +28,7 @@ class BlinkSensor(Entity): def __init__(self, data, camera, sensor_type): """Initialize sensors from Blink camera.""" name, units, icon = SENSORS[sensor_type] - self._name = "{} {} {}".format(BLINK_DATA, camera, name) + self._name = f"{BLINK_DATA} {camera} {name}" self._camera_name = name self._type = sensor_type self.data = data @@ -36,7 +36,7 @@ def __init__(self, data, camera, sensor_type): self._state = None self._unit_of_measurement = units self._icon = icon - self._unique_id = "{}-{}".format(self._camera.serial, self._type) + self._unique_id = f"{self._camera.serial}-{self._type}" self._sensor_key = self._type if self._type == "temperature": self._sensor_key = "temperature_calibrated" diff --git a/homeassistant/components/blinkt/light.py b/homeassistant/components/blinkt/light.py index 9fee72662c6449..e626a73d287c64 100644 --- a/homeassistant/components/blinkt/light.py +++ b/homeassistant/components/blinkt/light.py @@ -51,7 +51,7 @@ def __init__(self, blinkt, name, index): Default brightness and white color. """ self._blinkt = blinkt - self._name = "{}_{}".format(name, index) + self._name = f"{name}_{index}" self._index = index self._is_on = False self._brightness = 255 diff --git a/homeassistant/components/bloomsky/__init__.py b/homeassistant/components/bloomsky/__init__.py index dc0723730c4899..6373471fe7a6c6 100644 --- a/homeassistant/components/bloomsky/__init__.py +++ b/homeassistant/components/bloomsky/__init__.py @@ -63,7 +63,7 @@ def refresh_devices(self): """Use the API to retrieve a list of devices.""" _LOGGER.debug("Fetching BloomSky update") response = requests.get( - "{}?{}".format(self.API_URL, self._endpoint_argument), + f"{self.API_URL}?{self._endpoint_argument}", headers={AUTHORIZATION: self._api_key}, timeout=10, ) diff --git a/homeassistant/components/bloomsky/binary_sensor.py b/homeassistant/components/bloomsky/binary_sensor.py index 3a8242929c5e56..99951fcf5c54e8 100644 --- a/homeassistant/components/bloomsky/binary_sensor.py +++ b/homeassistant/components/bloomsky/binary_sensor.py @@ -42,7 +42,7 @@ def __init__(self, bs, device, sensor_name): self._sensor_name = sensor_name self._name = "{} {}".format(device["DeviceName"], sensor_name) self._state = None - self._unique_id = "{}-{}".format(self._device_id, self._sensor_name) + self._unique_id = f"{self._device_id}-{self._sensor_name}" @property def unique_id(self): diff --git a/homeassistant/components/bloomsky/sensor.py b/homeassistant/components/bloomsky/sensor.py index cca57bcae82d70..18f60036397b9f 100644 --- a/homeassistant/components/bloomsky/sensor.py +++ b/homeassistant/components/bloomsky/sensor.py @@ -72,7 +72,7 @@ def __init__(self, bs, device, sensor_name): self._sensor_name = sensor_name self._name = "{} {}".format(device["DeviceName"], sensor_name) self._state = None - self._unique_id = "{}-{}".format(self._device_id, self._sensor_name) + self._unique_id = f"{self._device_id}-{self._sensor_name}" @property def unique_id(self): @@ -103,6 +103,6 @@ def update(self): state = self._bloomsky.devices[self._device_id]["Data"][self._sensor_name] if self._sensor_name in FORMAT_NUMBERS: - self._state = "{0:.2f}".format(state) + self._state = f"{state:.2f}" else: self._state = state diff --git a/homeassistant/components/bluesound/media_player.py b/homeassistant/components/bluesound/media_player.py index e5f264b5f73c65..bf0568aed16c29 100644 --- a/homeassistant/components/bluesound/media_player.py +++ b/homeassistant/components/bluesound/media_player.py @@ -336,7 +336,7 @@ async def send_bluesound_command( if method[0] == "/": method = method[1:] - url = "http://{}:{}/{}".format(self.host, self.port, method) + url = f"http://{self.host}:{self.port}/{method}" _LOGGER.debug("Calling URL: %s", url) response = None @@ -380,8 +380,8 @@ async def async_update_status(self): etag = self._status.get("@etag", "") if etag != "": - url = "Status?etag={}&timeout=120.0".format(etag) - url = "http://{}:{}/{}".format(self.host, self.port, url) + url = f"Status?etag={etag}&timeout=120.0" + url = f"http://{self.host}:{self.port}/{url}" _LOGGER.debug("Calling URL: %s", url) @@ -595,7 +595,7 @@ def media_image_url(self): if not url: return if url[0] == "/": - url = "http://{}:{}{}".format(self.host, self.port, url) + url = f"http://{self.host}:{self.port}{url}" return url @@ -843,13 +843,13 @@ async def async_unjoin(self): async def async_add_slave(self, slave_device): """Add slave to master.""" return await self.send_bluesound_command( - "/AddSlave?slave={}&port={}".format(slave_device.host, slave_device.port) + f"/AddSlave?slave={slave_device.host}&port={slave_device.port}" ) async def async_remove_slave(self, slave_device): """Remove slave to master.""" return await self.send_bluesound_command( - "/RemoveSlave?slave={}&port={}".format(slave_device.host, slave_device.port) + f"/RemoveSlave?slave={slave_device.host}&port={slave_device.port}" ) async def async_increase_timer(self): @@ -870,7 +870,7 @@ async def async_clear_timer(self): async def async_set_shuffle(self, shuffle): """Enable or disable shuffle mode.""" value = "1" if shuffle else "0" - return await self.send_bluesound_command("/Shuffle?state={}".format(value)) + return await self.send_bluesound_command(f"/Shuffle?state={value}") async def async_select_source(self, source): """Select input source.""" @@ -967,7 +967,7 @@ async def async_play_media(self, media_type, media_id, **kwargs): if self.is_grouped and not self.is_master: return - url = "Play?url={}".format(media_id) + url = f"Play?url={media_id}" if kwargs.get(ATTR_MEDIA_ENQUEUE): return await self.send_bluesound_command(url) diff --git a/homeassistant/components/bluetooth_tracker/device_tracker.py b/homeassistant/components/bluetooth_tracker/device_tracker.py index 65db87fa072aba..e760f91070a163 100644 --- a/homeassistant/components/bluetooth_tracker/device_tracker.py +++ b/homeassistant/components/bluetooth_tracker/device_tracker.py @@ -54,7 +54,7 @@ def see_device(mac, name, rssi=None): if rssi is not None: attributes["rssi"] = rssi see( - mac="{}{}".format(BT_PREFIX, mac), + mac=f"{BT_PREFIX}{mac}", host_name=name, attributes=attributes, source_type=SOURCE_TYPE_BLUETOOTH, diff --git a/homeassistant/components/bme280/sensor.py b/homeassistant/components/bme280/sensor.py index bdd91e6dfe1bdf..ee4e1731156c17 100644 --- a/homeassistant/components/bme280/sensor.py +++ b/homeassistant/components/bme280/sensor.py @@ -147,7 +147,7 @@ def __init__(self, bme280_client, sensor_type, temp_unit, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/bme680/sensor.py b/homeassistant/components/bme680/sensor.py index 58b343b3de0ad6..20fdfc9ee79f6f 100644 --- a/homeassistant/components/bme680/sensor.py +++ b/homeassistant/components/bme680/sensor.py @@ -331,7 +331,7 @@ def __init__(self, bme680_client, sensor_type, temp_unit, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/bmw_connected_drive/binary_sensor.py b/homeassistant/components/bmw_connected_drive/binary_sensor.py index 418ccbabffe17b..c9cc9b2d33373f 100644 --- a/homeassistant/components/bmw_connected_drive/binary_sensor.py +++ b/homeassistant/components/bmw_connected_drive/binary_sensor.py @@ -61,8 +61,8 @@ def __init__( self._account = account self._vehicle = vehicle self._attribute = attribute - self._name = "{} {}".format(self._vehicle.name, self._attribute) - self._unique_id = "{}-{}".format(self._vehicle.vin, self._attribute) + self._name = f"{self._vehicle.name} {self._attribute}" + self._unique_id = f"{self._vehicle.vin}-{self._attribute}" self._sensor_name = sensor_name self._device_class = device_class self._icon = icon @@ -177,16 +177,14 @@ def update(self): def _format_cbs_report(self, report): result = {} service_type = report.service_type.lower().replace("_", " ") - result["{} status".format(service_type)] = report.state.value + result[f"{service_type} status"] = report.state.value if report.due_date is not None: - result["{} date".format(service_type)] = report.due_date.strftime( - "%Y-%m-%d" - ) + result[f"{service_type} date"] = report.due_date.strftime("%Y-%m-%d") if report.due_distance is not None: distance = round( self.hass.config.units.length(report.due_distance, LENGTH_KILOMETERS) ) - result["{} distance".format(service_type)] = "{} {}".format( + result[f"{service_type} distance"] = "{} {}".format( distance, self.hass.config.units.length_unit ) return result diff --git a/homeassistant/components/bmw_connected_drive/lock.py b/homeassistant/components/bmw_connected_drive/lock.py index a16dbc6b341b65..2055b442dcd17a 100644 --- a/homeassistant/components/bmw_connected_drive/lock.py +++ b/homeassistant/components/bmw_connected_drive/lock.py @@ -30,8 +30,8 @@ def __init__(self, account, vehicle, attribute: str, sensor_name): self._account = account self._vehicle = vehicle self._attribute = attribute - self._name = "{} {}".format(self._vehicle.name, self._attribute) - self._unique_id = "{}-{}".format(self._vehicle.vin, self._attribute) + self._name = f"{self._vehicle.name} {self._attribute}" + self._unique_id = f"{self._vehicle.vin}-{self._attribute}" self._sensor_name = sensor_name self._state = None diff --git a/homeassistant/components/bmw_connected_drive/sensor.py b/homeassistant/components/bmw_connected_drive/sensor.py index 8248ded4f8bcef..011908d54585e4 100644 --- a/homeassistant/components/bmw_connected_drive/sensor.py +++ b/homeassistant/components/bmw_connected_drive/sensor.py @@ -68,8 +68,8 @@ def __init__(self, account, vehicle, attribute: str, attribute_info): self._account = account self._attribute = attribute self._state = None - self._name = "{} {}".format(self._vehicle.name, self._attribute) - self._unique_id = "{}-{}".format(self._vehicle.vin, self._attribute) + self._name = f"{self._vehicle.name} {self._attribute}" + self._unique_id = f"{self._vehicle.vin}-{self._attribute}" self._attribute_info = attribute_info @property diff --git a/homeassistant/components/bom/camera.py b/homeassistant/components/bom/camera.py index 3a5d6cdc503f32..f417cf769a40ac 100644 --- a/homeassistant/components/bom/camera.py +++ b/homeassistant/components/bom/camera.py @@ -84,7 +84,7 @@ def _validate_schema(config): LOCATIONS_MSG = "Set '{}' to one of: {}".format( CONF_LOCATION, ", ".join(sorted(LOCATIONS)) ) -XOR_MSG = "Specify exactly one of '{}' or '{}'".format(CONF_ID, CONF_LOCATION) +XOR_MSG = f"Specify exactly one of '{CONF_ID}' or '{CONF_LOCATION}'" PLATFORM_SCHEMA = vol.All( PLATFORM_SCHEMA.extend( @@ -106,7 +106,7 @@ def _validate_schema(config): def setup_platform(hass, config, add_entities, discovery_info=None): """Set up BOM radar-loop camera component.""" location = config.get(CONF_LOCATION) or "ID {}".format(config.get(CONF_ID)) - name = config.get(CONF_NAME) or "BOM Radar Loop - {}".format(location) + name = config.get(CONF_NAME) or f"BOM Radar Loop - {location}" args = [ config.get(x) for x in (CONF_LOCATION, CONF_ID, CONF_DELTA, CONF_FRAMES, CONF_OUTFILE) diff --git a/homeassistant/components/bom/sensor.py b/homeassistant/components/bom/sensor.py index 790b2ddc74fef2..33444f1099652a 100644 --- a/homeassistant/components/bom/sensor.py +++ b/homeassistant/components/bom/sensor.py @@ -117,7 +117,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): CONF_WMO_ID, ) elif zone_id and wmo_id: - station = "{}.{}".format(zone_id, wmo_id) + station = f"{zone_id}.{wmo_id}" else: station = closest_station( config.get(CONF_LATITUDE), diff --git a/homeassistant/components/broadlink/__init__.py b/homeassistant/components/broadlink/__init__.py index 5fb5af2732b01b..589da62feaa13b 100644 --- a/homeassistant/components/broadlink/__init__.py +++ b/homeassistant/components/broadlink/__init__.py @@ -64,7 +64,7 @@ async def _learn_command(call): packet = await hass.async_add_executor_job(device.check_data) if packet: data = b64encode(packet).decode("utf8") - log_msg = "Received packet is: {}".format(data) + log_msg = f"Received packet is: {data}" _LOGGER.info(log_msg) hass.components.persistent_notification.async_create( log_msg, title="Broadlink switch" diff --git a/homeassistant/components/broadlink/switch.py b/homeassistant/components/broadlink/switch.py index 277260c0336e03..d60331aaa4407e 100644 --- a/homeassistant/components/broadlink/switch.py +++ b/homeassistant/components/broadlink/switch.py @@ -103,9 +103,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): def _get_mp1_slot_name(switch_friendly_name, slot): """Get slot name.""" - if not slots["slot_{}".format(slot)]: - return "{} slot {}".format(switch_friendly_name, slot) - return slots["slot_{}".format(slot)] + if not slots[f"slot_{slot}"]: + return f"{switch_friendly_name} slot {slot}" + return slots[f"slot_{slot}"] if switch_type in RM_TYPES: broadlink_device = broadlink.rm((ip_addr, 80), mac_addr, None) @@ -371,7 +371,7 @@ def get_outlet_status(self, slot): """Get status of outlet from cached status list.""" if self._states is None: return None - return self._states["s{}".format(slot)] + return self._states[f"s{slot}"] @Throttle(TIME_BETWEEN_UPDATES) def update(self): diff --git a/homeassistant/components/buienradar/sensor.py b/homeassistant/components/buienradar/sensor.py index 841cc428bac37a..ef65db74f165e7 100644 --- a/homeassistant/components/buienradar/sensor.py +++ b/homeassistant/components/buienradar/sensor.py @@ -401,7 +401,7 @@ def unique_id(self): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 597d67fcdeec63..68cd1f51dda198 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -134,7 +134,7 @@ async def async_request_stream(hass, entity_id, fmt): if not source: raise HomeAssistantError( - "{} does not support play stream service".format(camera.entity_id) + f"{camera.entity_id} does not support play stream service" ) return request_stream(hass, source, fmt=fmt, keepalive=camera_prefs.preload_stream) @@ -534,9 +534,7 @@ async def handle(self, request, camera): # Compose camera stream from stills interval = float(request.query.get("interval")) if interval < MIN_STREAM_INTERVAL: - raise ValueError( - "Stream interval must be be > {}".format(MIN_STREAM_INTERVAL) - ) + raise ValueError(f"Stream interval must be be > {MIN_STREAM_INTERVAL}") return await camera.handle_async_still_stream(request, interval) except ValueError: raise web.HTTPBadRequest() @@ -588,7 +586,7 @@ async def ws_camera_stream(hass, connection, msg): if not source: raise HomeAssistantError( - "{} does not support play stream service".format(camera.entity_id) + f"{camera.entity_id} does not support play stream service" ) fmt = msg["format"] @@ -670,7 +668,7 @@ async def async_handle_play_stream_service(camera, service_call): if not source: raise HomeAssistantError( - "{} does not support play stream service".format(camera.entity_id) + f"{camera.entity_id} does not support play stream service" ) hass = camera.hass @@ -681,7 +679,7 @@ async def async_handle_play_stream_service(camera, service_call): url = request_stream(hass, source, fmt=fmt, keepalive=camera_prefs.preload_stream) data = { ATTR_ENTITY_ID: entity_ids, - ATTR_MEDIA_CONTENT_ID: "{}{}".format(hass.config.api.base_url, url), + ATTR_MEDIA_CONTENT_ID: f"{hass.config.api.base_url}{url}", ATTR_MEDIA_CONTENT_TYPE: FORMAT_CONTENT_TYPE[fmt], } @@ -696,9 +694,7 @@ async def async_handle_record_service(camera, call): source = await camera.stream_source() if not source: - raise HomeAssistantError( - "{} does not support record service".format(camera.entity_id) - ) + raise HomeAssistantError(f"{camera.entity_id} does not support record service") hass = camera.hass filename = call.data[CONF_FILENAME] diff --git a/homeassistant/components/canary/sensor.py b/homeassistant/components/canary/sensor.py index dcb54a772a3c59..6bb01c9d114804 100644 --- a/homeassistant/components/canary/sensor.py +++ b/homeassistant/components/canary/sensor.py @@ -53,7 +53,7 @@ def __init__(self, data, sensor_type, location, device): self._sensor_value = None sensor_type_name = sensor_type[0].replace("_", " ").title() - self._name = "{} {} {}".format(location.name, device.name, sensor_type_name) + self._name = f"{location.name} {device.name} {sensor_type_name}" @property def name(self): diff --git a/homeassistant/components/cisco_webex_teams/notify.py b/homeassistant/components/cisco_webex_teams/notify.py index 9feac3207adf6d..a77f5673df723e 100644 --- a/homeassistant/components/cisco_webex_teams/notify.py +++ b/homeassistant/components/cisco_webex_teams/notify.py @@ -52,9 +52,7 @@ def send_message(self, message="", **kwargs): title = "{}{}".format(kwargs.get(ATTR_TITLE), "
") try: - self.client.messages.create( - roomId=self.room, html="{}{}".format(title, message) - ) + self.client.messages.create(roomId=self.room, html=f"{title}{message}") except ApiError as api_error: _LOGGER.error( "Could not send CiscoWebexTeams notification. " "Error: %s", api_error diff --git a/homeassistant/components/clicksend/notify.py b/homeassistant/components/clicksend/notify.py index 1ec828b4a28bf8..87fc217ac42396 100644 --- a/homeassistant/components/clicksend/notify.py +++ b/homeassistant/components/clicksend/notify.py @@ -73,7 +73,7 @@ def send_message(self, message="", **kwargs): } ) - api_url = "{}/sms/send".format(BASE_API_URL) + api_url = f"{BASE_API_URL}/sms/send" resp = requests.post( api_url, data=json.dumps(data), @@ -94,7 +94,7 @@ def send_message(self, message="", **kwargs): def _authenticate(config): """Authenticate with ClickSend.""" - api_url = "{}/account".format(BASE_API_URL) + api_url = f"{BASE_API_URL}/account" resp = requests.get( api_url, headers=HEADERS, diff --git a/homeassistant/components/clicksend_tts/notify.py b/homeassistant/components/clicksend_tts/notify.py index 7c73c346a3317c..ba30c61e937f9a 100644 --- a/homeassistant/components/clicksend_tts/notify.py +++ b/homeassistant/components/clicksend_tts/notify.py @@ -79,7 +79,7 @@ def send_message(self, message="", **kwargs): } ] } - api_url = "{}/voice/send".format(BASE_API_URL) + api_url = f"{BASE_API_URL}/voice/send" resp = requests.post( api_url, data=json.dumps(data), @@ -100,7 +100,7 @@ def send_message(self, message="", **kwargs): def _authenticate(config): """Authenticate with ClickSend.""" - api_url = "{}/account".format(BASE_API_URL) + api_url = f"{BASE_API_URL}/account" resp = requests.get( api_url, headers=HEADERS, diff --git a/homeassistant/components/cloud/http_api.py b/homeassistant/components/cloud/http_api.py index d261c9e494c107..fce530ddce5dc7 100644 --- a/homeassistant/components/cloud/http_api.py +++ b/homeassistant/components/cloud/http_api.py @@ -157,7 +157,7 @@ def _process_cloud_exception(exc, where): err_info = _CLOUD_ERRORS.get(exc.__class__) if err_info is None: _LOGGER.exception("Unexpected error processing request for %s", where) - err_info = (502, "Unexpected error: {}".format(exc)) + err_info = (502, f"Unexpected error: {exc}") return err_info diff --git a/homeassistant/components/cmus/media_player.py b/homeassistant/components/cmus/media_player.py index a491bcc09ee149..dbaa763c46174b 100644 --- a/homeassistant/components/cmus/media_player.py +++ b/homeassistant/components/cmus/media_player.py @@ -82,7 +82,7 @@ def __init__(self, server, password, port, name): if server: self.cmus = remote.PyCmus(server=server, password=password, port=port) - auto_name = "cmus-{}".format(server) + auto_name = f"cmus-{server}" else: self.cmus = remote.PyCmus() auto_name = "cmus-local" diff --git a/homeassistant/components/co2signal/sensor.py b/homeassistant/components/co2signal/sensor.py index d881482ed1a2fd..9098a053fff2ae 100644 --- a/homeassistant/components/co2signal/sensor.py +++ b/homeassistant/components/co2signal/sensor.py @@ -68,7 +68,7 @@ def __init__(self, token, country_code, lat, lon): lat=round(self._latitude, 2), lon=round(self._longitude, 2) ) - self._friendly_name = "CO2 intensity - {}".format(device_name) + self._friendly_name = f"CO2 intensity - {device_name}" @property def name(self): diff --git a/homeassistant/components/coinbase/sensor.py b/homeassistant/components/coinbase/sensor.py index c5f53ef609d874..4a3e85d5e4313d 100644 --- a/homeassistant/components/coinbase/sensor.py +++ b/homeassistant/components/coinbase/sensor.py @@ -44,7 +44,7 @@ class AccountSensor(Entity): def __init__(self, coinbase_data, name, currency): """Initialize the sensor.""" self._coinbase_data = coinbase_data - self._name = "Coinbase {}".format(name) + self._name = f"Coinbase {name}" self._state = None self._unit_of_measurement = currency self._native_balance = None @@ -97,7 +97,7 @@ def __init__(self, coinbase_data, exchange_currency, native_currency): """Initialize the sensor.""" self._coinbase_data = coinbase_data self.currency = exchange_currency - self._name = "{} Exchange Rate".format(exchange_currency) + self._name = f"{exchange_currency} Exchange Rate" self._state = None self._unit_of_measurement = native_currency diff --git a/homeassistant/components/concord232/alarm_control_panel.py b/homeassistant/components/concord232/alarm_control_panel.py index 2383700f42af14..68f0d77e307a82 100644 --- a/homeassistant/components/concord232/alarm_control_panel.py +++ b/homeassistant/components/concord232/alarm_control_panel.py @@ -47,7 +47,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): host = config.get(CONF_HOST) port = config.get(CONF_PORT) - url = "http://{}:{}".format(host, port) + url = f"http://{host}:{port}" try: add_entities([Concord232Alarm(url, name, code, mode)], True) diff --git a/homeassistant/components/concord232/binary_sensor.py b/homeassistant/components/concord232/binary_sensor.py index 89b6ab6af97e5a..10643f134d70e8 100644 --- a/homeassistant/components/concord232/binary_sensor.py +++ b/homeassistant/components/concord232/binary_sensor.py @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): try: _LOGGER.debug("Initializing client") - client = concord232_client.Client("http://{}:{}".format(host, port)) + client = concord232_client.Client(f"http://{host}:{port}") client.zones = client.list_zones() client.last_zone_update = datetime.datetime.now() diff --git a/homeassistant/components/crimereports/sensor.py b/homeassistant/components/crimereports/sensor.py index 2ad31e7513b6cd..6295125b7cabd0 100644 --- a/homeassistant/components/crimereports/sensor.py +++ b/homeassistant/components/crimereports/sensor.py @@ -29,7 +29,7 @@ DOMAIN = "crimereports" -EVENT_INCIDENT = "{}_incident".format(DOMAIN) +EVENT_INCIDENT = f"{DOMAIN}_incident" SCAN_INTERVAL = timedelta(minutes=30) diff --git a/homeassistant/components/cups/sensor.py b/homeassistant/components/cups/sensor.py index 79bb050a617ad4..f6a5133d8a9851 100644 --- a/homeassistant/components/cups/sensor.py +++ b/homeassistant/components/cups/sensor.py @@ -333,7 +333,7 @@ def update(self): else: for ipp_printer in self._ipp_printers: self.attributes[ipp_printer] = conn.getPrinterAttributes( - uri="ipp://{}:{}/{}".format(self._host, self._port, ipp_printer) + uri=f"ipp://{self._host}:{self._port}/{ipp_printer}" ) self.available = True diff --git a/homeassistant/components/currencylayer/sensor.py b/homeassistant/components/currencylayer/sensor.py index dbafae551876a0..d4660d70286d8c 100644 --- a/homeassistant/components/currencylayer/sensor.py +++ b/homeassistant/components/currencylayer/sensor.py @@ -95,7 +95,7 @@ def update(self): self.rest.update() value = self.rest.data if value is not None: - self._state = round(value["{}{}".format(self._base, self._quote)], 4) + self._state = round(value[f"{self._base}{self._quote}"], 4) class CurrencylayerData: diff --git a/homeassistant/components/daikin/sensor.py b/homeassistant/components/daikin/sensor.py index c55988b8dc144e..f83566e66e8a7f 100644 --- a/homeassistant/components/daikin/sensor.py +++ b/homeassistant/components/daikin/sensor.py @@ -58,7 +58,7 @@ def __init__(self, api, monitored_state, units: UnitSystem, name=None) -> None: @property def unique_id(self): """Return a unique ID.""" - return "{}-{}".format(self._api.mac, self._device_attribute) + return f"{self._api.mac}-{self._device_attribute}" @property def icon(self): diff --git a/homeassistant/components/daikin/switch.py b/homeassistant/components/daikin/switch.py index 6290e6fecef2f3..4d3b0d3eadea7f 100644 --- a/homeassistant/components/daikin/switch.py +++ b/homeassistant/components/daikin/switch.py @@ -44,7 +44,7 @@ def __init__(self, daikin_api, zone_id): @property def unique_id(self): """Return a unique ID.""" - return "{}-zone{}".format(self._api.mac, self._zone_id) + return f"{self._api.mac}-zone{self._zone_id}" @property def icon(self): diff --git a/homeassistant/components/darksky/sensor.py b/homeassistant/components/darksky/sensor.py index 0f33935c66c919..4f000253245f1f 100644 --- a/homeassistant/components/darksky/sensor.py +++ b/homeassistant/components/darksky/sensor.py @@ -553,10 +553,10 @@ def __init__( def name(self): """Return the name of the sensor.""" if self.forecast_day is not None: - return "{} {} {}d".format(self.client_name, self._name, self.forecast_day) + return f"{self.client_name} {self._name} {self.forecast_day}d" if self.forecast_hour is not None: - return "{} {} {}h".format(self.client_name, self._name, self.forecast_hour) - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name} {self.forecast_hour}h" + return f"{self.client_name} {self._name}" @property def state(self): @@ -704,7 +704,7 @@ def __init__(self, forecast_data, sensor_type, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/datadog/__init__.py b/homeassistant/components/datadog/__init__.py index 1ad4ed9aab8e77..5517e41d5c66df 100644 --- a/homeassistant/components/datadog/__init__.py +++ b/homeassistant/components/datadog/__init__.py @@ -59,7 +59,7 @@ def logbook_entry_listener(event): statsd.event( title="Home Assistant", - text="%%% \n **{}** {} \n %%%".format(name, message), + text=f"%%% \n **{name}** {message} \n %%%", tags=[ "entity:{}".format(event.data.get("entity_id")), "domain:{}".format(event.data.get("domain")), @@ -79,8 +79,8 @@ def state_changed_listener(event): return states = dict(state.attributes) - metric = "{}.{}".format(prefix, state.domain) - tags = ["entity:{}".format(state.entity_id)] + metric = f"{prefix}.{state.domain}" + tags = [f"entity:{state.entity_id}"] for key, value in states.items(): if isinstance(value, (float, int)): diff --git a/homeassistant/components/ddwrt/device_tracker.py b/homeassistant/components/ddwrt/device_tracker.py index 4a40561b9e3485..4e661376719ec9 100644 --- a/homeassistant/components/ddwrt/device_tracker.py +++ b/homeassistant/components/ddwrt/device_tracker.py @@ -65,7 +65,7 @@ def __init__(self, config): self.mac2name = {} # Test the router is accessible - url = "{}://{}/Status_Wireless.live.asp".format(self.protocol, self.host) + url = f"{self.protocol}://{self.host}/Status_Wireless.live.asp" data = self.get_ddwrt_data(url) if not data: raise ConnectionError("Cannot connect to DD-Wrt router") @@ -80,7 +80,7 @@ def get_device_name(self, device): """Return the name of the given device or None if we don't know.""" # If not initialised and not already scanned and not found. if device not in self.mac2name: - url = "{}://{}/Status_Lan.live.asp".format(self.protocol, self.host) + url = f"{self.protocol}://{self.host}/Status_Lan.live.asp" data = self.get_ddwrt_data(url) if not data: @@ -115,7 +115,7 @@ def _update_info(self): _LOGGER.info("Checking ARP") endpoint = "Wireless" if self.wireless_only else "Lan" - url = "{}://{}/Status_{}.live.asp".format(self.protocol, self.host, endpoint) + url = f"{self.protocol}://{self.host}/Status_{endpoint}.live.asp" data = self.get_ddwrt_data(url) if not data: diff --git a/homeassistant/components/deconz/gateway.py b/homeassistant/components/deconz/gateway.py index 0ed3ffd2a564ca..2117f8dc6bb3cf 100644 --- a/homeassistant/components/deconz/gateway.py +++ b/homeassistant/components/deconz/gateway.py @@ -138,7 +138,7 @@ async def async_new_address_callback(hass, entry): @property def event_reachable(self): """Gateway specific event to signal a change in connection status.""" - return "deconz_reachable_{}".format(self.bridgeid) + return f"deconz_reachable_{self.bridgeid}" @callback def async_connection_status_callback(self, available): @@ -241,7 +241,7 @@ def __init__(self, hass, device): self._hass = hass self._device = device self._device.register_async_callback(self.async_update_callback) - self._event = "deconz_{}".format(CONF_EVENT) + self._event = f"deconz_{CONF_EVENT}" self._id = slugify(self._device.name) _LOGGER.debug("deCONZ event created: %s", self._id) diff --git a/homeassistant/components/deluge/sensor.py b/homeassistant/components/deluge/sensor.py index 8b42b6175ce6d5..098484cf7ae6e2 100644 --- a/homeassistant/components/deluge/sensor.py +++ b/homeassistant/components/deluge/sensor.py @@ -84,7 +84,7 @@ def __init__(self, sensor_type, deluge_client, client_name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/deutsche_bahn/sensor.py b/homeassistant/components/deutsche_bahn/sensor.py index db094bb9b12439..fbe0efa15ac7a2 100644 --- a/homeassistant/components/deutsche_bahn/sensor.py +++ b/homeassistant/components/deutsche_bahn/sensor.py @@ -47,7 +47,7 @@ class DeutscheBahnSensor(Entity): def __init__(self, start, goal, offset, only_direct): """Initialize the sensor.""" - self._name = "{} to {}".format(start, goal) + self._name = f"{start} to {goal}" self.data = SchieneData(start, goal, offset, only_direct) self._state = None diff --git a/homeassistant/components/dht/sensor.py b/homeassistant/components/dht/sensor.py index 6ea5e7a46a28c4..aadb6b2d4cbf92 100644 --- a/homeassistant/components/dht/sensor.py +++ b/homeassistant/components/dht/sensor.py @@ -115,7 +115,7 @@ def __init__( @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/digitalloggers/switch.py b/homeassistant/components/digitalloggers/switch.py index d80385d0f542d3..9983ccc93fa355 100644 --- a/homeassistant/components/digitalloggers/switch.py +++ b/homeassistant/components/digitalloggers/switch.py @@ -88,7 +88,7 @@ def __init__(self, controller_name, parent_device, outlet): @property def name(self): """Return the display name of this relay.""" - return "{}_{}".format(self._controller_name, self._name) + return f"{self._controller_name}_{self._name}" @property def is_on(self): diff --git a/homeassistant/components/doorbird/__init__.py b/homeassistant/components/doorbird/__init__.py index 3afa9c58e66ab7..ff0bbd7119407d 100644 --- a/homeassistant/components/doorbird/__init__.py +++ b/homeassistant/components/doorbird/__init__.py @@ -20,7 +20,7 @@ DOMAIN = "doorbird" -API_URL = "/api/{}".format(DOMAIN) +API_URL = f"/api/{DOMAIN}" CONF_CUSTOM_URL = "hass_url_override" CONF_EVENTS = "events" @@ -195,17 +195,15 @@ def slug(self): return slugify(self._name) def _get_event_name(self, event): - return "{}_{}".format(self.slug, event) + return f"{self.slug}_{event}" def _register_event(self, hass_url, event): """Add a schedule entry in the device for a sensor.""" - url = "{}{}/{}?token={}".format(hass_url, API_URL, event, self._token) + url = f"{hass_url}{API_URL}/{event}?token={self._token}" # Register HA URL as webhook if not already, then get the ID if not self.webhook_is_registered(url): - self.device.change_favorite( - "http", "Home Assistant ({})".format(event), url - ) + self.device.change_favorite("http", f"Home Assistant ({event})", url) fav_id = self.get_webhook_id(url) @@ -288,9 +286,9 @@ async def get(self, request, event): if event == "clear": hass.bus.async_fire(RESET_DEVICE_FAVORITES, {"token": token}) - message = "HTTP Favorites cleared for {}".format(device.slug) + message = f"HTTP Favorites cleared for {device.slug}" return web.Response(status=200, text=message) - hass.bus.async_fire("{}_{}".format(DOMAIN, event), event_data) + hass.bus.async_fire(f"{DOMAIN}_{event}", event_data) return web.Response(status=200, text="OK") diff --git a/homeassistant/components/doorbird/switch.py b/homeassistant/components/doorbird/switch.py index a907099cba4c0f..643e006dfef0ed 100644 --- a/homeassistant/components/doorbird/switch.py +++ b/homeassistant/components/doorbird/switch.py @@ -45,9 +45,9 @@ def __init__(self, doorstation, relay): def name(self): """Return the name of the switch.""" if self._relay == IR_RELAY: - return "{} IR".format(self._doorstation.name) + return f"{self._doorstation.name} IR" - return "{} Relay {}".format(self._doorstation.name, self._relay) + return f"{self._doorstation.name} Relay {self._relay}" @property def icon(self): diff --git a/homeassistant/components/downloader/__init__.py b/homeassistant/components/downloader/__init__.py index 0fe589f2765656..9c725d9b3a273b 100644 --- a/homeassistant/components/downloader/__init__.py +++ b/homeassistant/components/downloader/__init__.py @@ -81,7 +81,7 @@ def do_download(): "downloading '%s' failed, status_code=%d", url, req.status_code ) hass.bus.fire( - "{}_{}".format(DOMAIN, DOWNLOAD_FAILED_EVENT), + f"{DOMAIN}_{DOWNLOAD_FAILED_EVENT}", {"url": url, "filename": filename}, ) @@ -126,7 +126,7 @@ def do_download(): while os.path.isfile(final_path): tries += 1 - final_path = "{}_{}.{}".format(path, tries, ext) + final_path = f"{path}_{tries}.{ext}" _LOGGER.debug("%s -> %s", url, final_path) @@ -136,14 +136,14 @@ def do_download(): _LOGGER.debug("Downloading of %s done", url) hass.bus.fire( - "{}_{}".format(DOMAIN, DOWNLOAD_COMPLETED_EVENT), + f"{DOMAIN}_{DOWNLOAD_COMPLETED_EVENT}", {"url": url, "filename": filename}, ) except requests.exceptions.ConnectionError: _LOGGER.exception("ConnectionError occurred for %s", url) hass.bus.fire( - "{}_{}".format(DOMAIN, DOWNLOAD_FAILED_EVENT), + f"{DOMAIN}_{DOWNLOAD_FAILED_EVENT}", {"url": url, "filename": filename}, ) diff --git a/homeassistant/components/duke_energy/sensor.py b/homeassistant/components/duke_energy/sensor.py index b8a9bec5db82df..998809decc02f4 100644 --- a/homeassistant/components/duke_energy/sensor.py +++ b/homeassistant/components/duke_energy/sensor.py @@ -44,7 +44,7 @@ def __init__(self, meter): @property def name(self): """Return the name.""" - return "duke_energy_{}".format(self.duke_meter.id) + return f"duke_energy_{self.duke_meter.id}" @property def unique_id(self): diff --git a/homeassistant/components/dwd_weather_warnings/sensor.py b/homeassistant/components/dwd_weather_warnings/sensor.py index a019a5c7b3ae5a..4d7ad04e38257d 100644 --- a/homeassistant/components/dwd_weather_warnings/sensor.py +++ b/homeassistant/components/dwd_weather_warnings/sensor.py @@ -92,7 +92,7 @@ def __init__(self, api, name, variable): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._name, self._var_name) + return f"{self._name} {self._var_name}" @property def icon(self): @@ -140,23 +140,23 @@ def device_state_attributes(self): for event in self._api.data[prefix + "_warnings"]: i = i + 1 - data["warning_{}_name".format(i)] = event["event"] - data["warning_{}_level".format(i)] = event["level"] - data["warning_{}_type".format(i)] = event["type"] + data[f"warning_{i}_name"] = event["event"] + data[f"warning_{i}_level"] = event["level"] + data[f"warning_{i}_type"] = event["type"] if event["headline"]: - data["warning_{}_headline".format(i)] = event["headline"] + data[f"warning_{i}_headline"] = event["headline"] if event["description"]: - data["warning_{}_description".format(i)] = event["description"] + data[f"warning_{i}_description"] = event["description"] if event["instruction"]: - data["warning_{}_instruction".format(i)] = event["instruction"] + data[f"warning_{i}_instruction"] = event["instruction"] if event["start"] is not None: - data["warning_{}_start".format(i)] = dt_util.as_local( + data[f"warning_{i}_start"] = dt_util.as_local( dt_util.utc_from_timestamp(event["start"] / 1000) ) if event["end"] is not None: - data["warning_{}_end".format(i)] = dt_util.as_local( + data[f"warning_{i}_end"] = dt_util.as_local( dt_util.utc_from_timestamp(event["end"] / 1000) ) @@ -212,7 +212,7 @@ def update(self): "Found %d %s global DWD warnings", len(json_obj[myvalue]), mykey ) - data["{}_warning_level".format(mykey)] = 0 + data[f"{mykey}_warning_level"] = 0 my_warnings = [] if self.region_id is not None: @@ -234,13 +234,13 @@ def update(self): break # Get max warning level - maxlevel = data["{}_warning_level".format(mykey)] + maxlevel = data[f"{mykey}_warning_level"] for event in my_warnings: if event["level"] >= maxlevel: - data["{}_warning_level".format(mykey)] = event["level"] + data[f"{mykey}_warning_level"] = event["level"] - data["{}_warning_count".format(mykey)] = len(my_warnings) - data["{}_warnings".format(mykey)] = my_warnings + data[f"{mykey}_warning_count"] = len(my_warnings) + data[f"{mykey}_warnings"] = my_warnings _LOGGER.debug("Found %d %s local DWD warnings", len(my_warnings), mykey) diff --git a/homeassistant/components/dyson/sensor.py b/homeassistant/components/dyson/sensor.py index f89823b143fcb8..1eb2b79c0735ac 100644 --- a/homeassistant/components/dyson/sensor.py +++ b/homeassistant/components/dyson/sensor.py @@ -101,7 +101,7 @@ def icon(self): @property def unique_id(self): """Return the sensor's unique id.""" - return "{}-{}".format(self._device.serial, self._sensor_type) + return f"{self._device.serial}-{self._sensor_type}" class DysonFilterLifeSensor(DysonSensor): @@ -110,7 +110,7 @@ class DysonFilterLifeSensor(DysonSensor): def __init__(self, device): """Create a new Dyson Filter Life sensor.""" super().__init__(device, "filter_life") - self._name = "{} Filter Life".format(self._device.name) + self._name = f"{self._device.name} Filter Life" @property def state(self): @@ -126,7 +126,7 @@ class DysonDustSensor(DysonSensor): def __init__(self, device): """Create a new Dyson Dust sensor.""" super().__init__(device, "dust") - self._name = "{} Dust".format(self._device.name) + self._name = f"{self._device.name} Dust" @property def state(self): @@ -142,7 +142,7 @@ class DysonHumiditySensor(DysonSensor): def __init__(self, device): """Create a new Dyson Humidity sensor.""" super().__init__(device, "humidity") - self._name = "{} Humidity".format(self._device.name) + self._name = f"{self._device.name} Humidity" @property def state(self): @@ -160,7 +160,7 @@ class DysonTemperatureSensor(DysonSensor): def __init__(self, device, unit): """Create a new Dyson Temperature sensor.""" super().__init__(device, "temperature") - self._name = "{} Temperature".format(self._device.name) + self._name = f"{self._device.name} Temperature" self._unit = unit @property @@ -187,7 +187,7 @@ class DysonAirQualitySensor(DysonSensor): def __init__(self, device): """Create a new Dyson Air Quality sensor.""" super().__init__(device, "air_quality") - self._name = "{} AQI".format(self._device.name) + self._name = f"{self._device.name} AQI" @property def state(self): From e609530669d0931044b8c4bd283914e4b224d988 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 17:10:56 +0200 Subject: [PATCH 55/72] Use literal string interpolation in integrations E-G (f-strings) (#26379) --- homeassistant/components/ebox/sensor.py | 2 +- homeassistant/components/ebusd/sensor.py | 2 +- homeassistant/components/ecobee/weather.py | 2 +- homeassistant/components/efergy/sensor.py | 8 ++++---- homeassistant/components/eight_sleep/__init__.py | 4 ++-- homeassistant/components/eight_sleep/binary_sensor.py | 2 +- homeassistant/components/eight_sleep/sensor.py | 6 +++--- homeassistant/components/elkm1/__init__.py | 6 +++--- homeassistant/components/elkm1/alarm_control_panel.py | 8 +++----- homeassistant/components/emby/media_player.py | 3 +-- homeassistant/components/emoncms/sensor.py | 4 ++-- homeassistant/components/emoncms_history/__init__.py | 4 ++-- homeassistant/components/emulated_hue/hue_api.py | 2 +- .../components/entur_public_transport/sensor.py | 2 +- homeassistant/components/esphome/__init__.py | 8 ++++---- homeassistant/components/essent/sensor.py | 2 +- homeassistant/components/everlights/light.py | 4 ++-- homeassistant/components/facebox/image_processing.py | 8 ++++---- homeassistant/components/fail2ban/sensor.py | 2 +- homeassistant/components/fastdotcom/__init__.py | 2 +- homeassistant/components/feedreader/__init__.py | 2 +- homeassistant/components/fibaro/__init__.py | 8 ++++---- homeassistant/components/fibaro/climate.py | 2 +- homeassistant/components/fido/sensor.py | 2 +- homeassistant/components/file/notify.py | 2 +- homeassistant/components/filter/sensor.py | 2 +- homeassistant/components/fints/sensor.py | 10 +++++----- homeassistant/components/fitbit/sensor.py | 8 ++++---- homeassistant/components/flock/notify.py | 2 +- homeassistant/components/flunearyou/sensor.py | 2 +- homeassistant/components/foobot/sensor.py | 2 +- homeassistant/components/fritzdect/switch.py | 4 ++-- homeassistant/components/garadget/cover.py | 6 +++--- homeassistant/components/geniushub/binary_sensor.py | 4 ++-- homeassistant/components/geniushub/sensor.py | 4 ++-- homeassistant/components/geo_rss_events/sensor.py | 2 +- homeassistant/components/geofency/__init__.py | 4 ++-- homeassistant/components/google/__init__.py | 4 ++-- homeassistant/components/google_assistant/error.py | 4 +--- homeassistant/components/google_assistant/helpers.py | 2 +- homeassistant/components/google_wifi/sensor.py | 4 ++-- homeassistant/components/gpmdp/media_player.py | 2 +- homeassistant/components/gpslogger/__init__.py | 4 ++-- homeassistant/components/gtfs/sensor.py | 10 +++++----- homeassistant/components/gtt/sensor.py | 2 +- 45 files changed, 87 insertions(+), 92 deletions(-) diff --git a/homeassistant/components/ebox/sensor.py b/homeassistant/components/ebox/sensor.py index 1482ab34c682f4..66c58b828826cb 100644 --- a/homeassistant/components/ebox/sensor.py +++ b/homeassistant/components/ebox/sensor.py @@ -106,7 +106,7 @@ def __init__(self, ebox_data, sensor_type, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/ebusd/sensor.py b/homeassistant/components/ebusd/sensor.py index 37b7d2dd060c4e..ac156e040d7332 100644 --- a/homeassistant/components/ebusd/sensor.py +++ b/homeassistant/components/ebusd/sensor.py @@ -44,7 +44,7 @@ def __init__(self, data, sensor, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._client_name, self._name) + return f"{self._client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/ecobee/weather.py b/homeassistant/components/ecobee/weather.py index 0680ef67f82ded..b09e06bd822dd4 100644 --- a/homeassistant/components/ecobee/weather.py +++ b/homeassistant/components/ecobee/weather.py @@ -123,7 +123,7 @@ def attribution(self): if self.weather: station = self.weather.get("weatherStation", "UNKNOWN") time = self.weather.get("timestamp", "UNKNOWN") - return "Ecobee weather provided by {} at {}".format(station, time) + return f"Ecobee weather provided by {station} at {time}" return None @property diff --git a/homeassistant/components/efergy/sensor.py b/homeassistant/components/efergy/sensor.py index 53c89097a59eea..43c3b67457a755 100644 --- a/homeassistant/components/efergy/sensor.py +++ b/homeassistant/components/efergy/sensor.py @@ -99,7 +99,7 @@ def __init__(self, sensor_type, app_token, utc_offset, period, currency, sid=Non """Initialize the sensor.""" self.sid = sid if sid: - self._name = "efergy_{}".format(sid) + self._name = f"efergy_{sid}" else: self._name = SENSOR_TYPES[sensor_type][0] self.type = sensor_type @@ -109,7 +109,7 @@ def __init__(self, sensor_type, app_token, utc_offset, period, currency, sid=Non self.period = period self.currency = currency if self.type == "cost": - self._unit_of_measurement = "{}/{}".format(self.currency, self.period) + self._unit_of_measurement = f"{self.currency}/{self.period}" else: self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] @@ -132,7 +132,7 @@ def update(self): """Get the Efergy monitor data from the web service.""" try: if self.type == "instant_readings": - url_string = "{}getInstant?token={}".format(_RESOURCE, self.app_token) + url_string = f"{_RESOURCE}getInstant?token={self.app_token}" response = requests.get(url_string, timeout=10) self._state = response.json()["reading"] elif self.type == "amount": @@ -142,7 +142,7 @@ def update(self): response = requests.get(url_string, timeout=10) self._state = response.json()["sum"] elif self.type == "budget": - url_string = "{}getBudget?token={}".format(_RESOURCE, self.app_token) + url_string = f"{_RESOURCE}getBudget?token={self.app_token}" response = requests.get(url_string, timeout=10) self._state = response.json()["status"] elif self.type == "cost": diff --git a/homeassistant/components/eight_sleep/__init__.py b/homeassistant/components/eight_sleep/__init__.py index 2479ea5440feba..923c3f7d309124 100644 --- a/homeassistant/components/eight_sleep/__init__.py +++ b/homeassistant/components/eight_sleep/__init__.py @@ -141,8 +141,8 @@ async def async_update_user_data(now): for user in eight.users: obj = eight.users[user] for sensor in SENSORS: - sensors.append("{}_{}".format(obj.side, sensor)) - binary_sensors.append("{}_presence".format(obj.side)) + sensors.append(f"{obj.side}_{sensor}") + binary_sensors.append(f"{obj.side}_presence") sensors.append("room_temp") else: # No users, cannot continue diff --git a/homeassistant/components/eight_sleep/binary_sensor.py b/homeassistant/components/eight_sleep/binary_sensor.py index 7d7ebecafee944..7b801578ccd4bf 100644 --- a/homeassistant/components/eight_sleep/binary_sensor.py +++ b/homeassistant/components/eight_sleep/binary_sensor.py @@ -34,7 +34,7 @@ def __init__(self, name, eight, sensor): self._sensor = sensor self._mapped_name = NAME_MAP.get(self._sensor, self._sensor) - self._name = "{} {}".format(name, self._mapped_name) + self._name = f"{name} {self._mapped_name}" self._state = None self._side = self._sensor.split("_")[0] diff --git a/homeassistant/components/eight_sleep/sensor.py b/homeassistant/components/eight_sleep/sensor.py index afc06986ea61e7..d3d54fd58caa92 100644 --- a/homeassistant/components/eight_sleep/sensor.py +++ b/homeassistant/components/eight_sleep/sensor.py @@ -68,7 +68,7 @@ def __init__(self, name, eight, sensor): self._sensor = sensor self._mapped_name = NAME_MAP.get(self._sensor, self._sensor) - self._name = "{} {}".format(name, self._mapped_name) + self._name = f"{name} {self._mapped_name}" self._state = None self._side = self._sensor.split("_")[0] @@ -122,7 +122,7 @@ def __init__(self, name, eight, sensor, units): self._sensor = sensor self._sensor_root = self._sensor.split("_", 1)[1] self._mapped_name = NAME_MAP.get(self._sensor, self._sensor) - self._name = "{} {}".format(name, self._mapped_name) + self._name = f"{name} {self._mapped_name}" self._state = None self._attr = None self._units = units @@ -261,7 +261,7 @@ def __init__(self, name, eight, sensor, units): self._sensor = sensor self._mapped_name = NAME_MAP.get(self._sensor, self._sensor) - self._name = "{} {}".format(name, self._mapped_name) + self._name = f"{name} {self._mapped_name}" self._state = None self._attr = None self._units = units diff --git a/homeassistant/components/elkm1/__init__.py b/homeassistant/components/elkm1/__init__.py index e26749e6f6b069..d15399df67b15a 100644 --- a/homeassistant/components/elkm1/__init__.py +++ b/homeassistant/components/elkm1/__init__.py @@ -146,7 +146,7 @@ async def async_setup(hass: HomeAssistant, hass_config: ConfigType) -> bool: def _included(ranges, set_to, values): for rng in ranges: if not rng[0] <= rng[1] <= len(values): - raise vol.Invalid("Invalid range {}".format(rng)) + raise vol.Invalid(f"Invalid range {rng}") values[rng[0] - 1 : rng[1]] = [set_to] * (rng[1] - rng[0] + 1) for index, conf in enumerate(hass_config[DOMAIN]): @@ -250,7 +250,7 @@ def __init__(self, element, elk, elk_data): # we could have used elkm1__foo_bar for the latter, but that # would have been a breaking change if self._prefix != "": - uid_start = "elkm1m_{prefix}".format(prefix=self._prefix) + uid_start = f"elkm1m_{self._prefix}" else: uid_start = "elkm1" self._unique_id = "{uid_start}_{name}".format( @@ -260,7 +260,7 @@ def __init__(self, element, elk, elk_data): @property def name(self): """Name of the element.""" - return "{p}{n}".format(p=self._prefix, n=self._element.name) + return f"{self._prefix}{self._element.name}" @property def unique_id(self): diff --git a/homeassistant/components/elkm1/alarm_control_panel.py b/homeassistant/components/elkm1/alarm_control_panel.py index 275d94efa66fd0..927ed53115e5e6 100644 --- a/homeassistant/components/elkm1/alarm_control_panel.py +++ b/homeassistant/components/elkm1/alarm_control_panel.py @@ -59,7 +59,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= def _dispatch(signal, entity_ids, *args): for entity_id in entity_ids: - async_dispatcher_send(hass, "{}_{}".format(signal, entity_id), *args) + async_dispatcher_send(hass, f"{signal}_{entity_id}", *args) def _arm_service(service): entity_ids = service.data.get(ATTR_ENTITY_ID, []) @@ -117,13 +117,11 @@ async def async_added_to_hass(self): for keypad in self._elk.keypads: keypad.add_callback(self._watch_keypad) async_dispatcher_connect( - self.hass, - "{}_{}".format(SIGNAL_ARM_ENTITY, self.entity_id), - self._arm_service, + self.hass, f"{SIGNAL_ARM_ENTITY}_{self.entity_id}", self._arm_service ) async_dispatcher_connect( self.hass, - "{}_{}".format(SIGNAL_DISPLAY_MESSAGE, self.entity_id), + f"{SIGNAL_DISPLAY_MESSAGE}_{self.entity_id}", self._display_message, ) diff --git a/homeassistant/components/emby/media_player.py b/homeassistant/components/emby/media_player.py index 409dd8ec472d62..d8a98a96585903 100644 --- a/homeassistant/components/emby/media_player.py +++ b/homeassistant/components/emby/media_player.py @@ -209,8 +209,7 @@ def supports_remote_control(self): def name(self): """Return the name of the device.""" return ( - "Emby - {} - {}".format(self.device.client, self.device.name) - or DEVICE_DEFAULT_NAME + f"Emby - {self.device.client} - {self.device.name}" or DEVICE_DEFAULT_NAME ) @property diff --git a/homeassistant/components/emoncms/sensor.py b/homeassistant/components/emoncms/sensor.py index 8d79b771fb93ff..5f9d31697b86f8 100644 --- a/homeassistant/components/emoncms/sensor.py +++ b/homeassistant/components/emoncms/sensor.py @@ -135,7 +135,7 @@ def __init__( id_for_name = "" if str(sensorid) == "1" else sensorid # Use the feed name assigned in EmonCMS or fall back to the feed ID feed_name = elem.get("name") or "Feed {}".format(elem["id"]) - self._name = "EmonCMS{} {}".format(id_for_name, feed_name) + self._name = f"EmonCMS{id_for_name} {feed_name}" else: self._name = name self._identifier = get_id( @@ -225,7 +225,7 @@ class EmonCmsData: def __init__(self, hass, url, apikey, interval): """Initialize the data object.""" self._apikey = apikey - self._url = "{}/feed/list.json".format(url) + self._url = f"{url}/feed/list.json" self._interval = interval self._hass = hass self.data = None diff --git a/homeassistant/components/emoncms_history/__init__.py b/homeassistant/components/emoncms_history/__init__.py index 779a25872f9df2..3b30a29960b3fd 100644 --- a/homeassistant/components/emoncms_history/__init__.py +++ b/homeassistant/components/emoncms_history/__init__.py @@ -47,7 +47,7 @@ def setup(hass, config): def send_data(url, apikey, node, payload): """Send payload data to Emoncms.""" try: - fullurl = "{}/input/post.json".format(url) + fullurl = f"{url}/input/post.json" data = {"apikey": apikey, "data": payload} parameters = {"node": node} req = requests.post( @@ -83,7 +83,7 @@ def update_emoncms(time): if payload_dict: payload = "{%s}" % ",".join( - "{}:{}".format(key, val) for key, val in payload_dict.items() + f"{key}:{val}" for key, val in payload_dict.items() ) send_data( diff --git a/homeassistant/components/emulated_hue/hue_api.py b/homeassistant/components/emulated_hue/hue_api.py index fc00746fc7f493..5e1c72618b6e43 100644 --- a/homeassistant/components/emulated_hue/hue_api.py +++ b/homeassistant/components/emulated_hue/hue_api.py @@ -590,5 +590,5 @@ def entity_to_json(config, entity, state): def create_hue_success_response(entity_id, attr, value): """Create a success response for an attribute set on a light.""" - success_key = "/lights/{}/state/{}".format(entity_id, attr) + success_key = f"/lights/{entity_id}/state/{attr}" return {"success": {success_key: value}} diff --git a/homeassistant/components/entur_public_transport/sensor.py b/homeassistant/components/entur_public_transport/sensor.py index 46ba62ba3fa0c9..0f8324ded9e099 100644 --- a/homeassistant/components/entur_public_transport/sensor.py +++ b/homeassistant/components/entur_public_transport/sensor.py @@ -121,7 +121,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= try: given_name = "{} {}".format(name, data.get_stop_info(place).name) except KeyError: - given_name = "{} {}".format(name, place) + given_name = f"{name} {place}" entities.append( EnturPublicTransportSensor(proxy, given_name, place, show_on_map) diff --git a/homeassistant/components/esphome/__init__.py b/homeassistant/components/esphome/__init__.py index 8780d2b67aed2f..182d4003e30664 100644 --- a/homeassistant/components/esphome/__init__.py +++ b/homeassistant/components/esphome/__init__.py @@ -80,7 +80,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool host, port, password, - client_info="Home Assistant {}".format(const.__version__), + client_info=f"Home Assistant {const.__version__}", ) # Store client in per-config-entry hass.data @@ -254,7 +254,7 @@ async def _async_setup_device_registry( """Set up device registry feature for a particular config entry.""" sw_version = device_info.esphome_version if device_info.compilation_time: - sw_version += " ({})".format(device_info.compilation_time) + sw_version += f" ({device_info.compilation_time})" device_registry = await dr.async_get_registry(hass) device_registry.async_get_or_create( config_entry_id=entry.entry_id, @@ -269,7 +269,7 @@ async def _async_setup_device_registry( async def _register_service( hass: HomeAssistantType, entry_data: RuntimeEntryData, service: UserService ): - service_name = "{}_{}".format(entry_data.device_info.name, service.name) + service_name = f"{entry_data.device_info.name}_{service.name}" schema = {} for arg in service.args: schema[vol.Required(arg.name)] = { @@ -315,7 +315,7 @@ async def _setup_services( entry_data.services = {serv.key: serv for serv in services} for service in to_unregister: - service_name = "{}_{}".format(entry_data.device_info.name, service.name) + service_name = f"{entry_data.device_info.name}_{service.name}" hass.services.async_remove(DOMAIN, service_name) for service in to_register: diff --git a/homeassistant/components/essent/sensor.py b/homeassistant/components/essent/sensor.py index 83d3164e3ff875..b106d9d2ae660c 100644 --- a/homeassistant/components/essent/sensor.py +++ b/homeassistant/components/essent/sensor.py @@ -95,7 +95,7 @@ def __init__(self, essent_base, meter, meter_type, tariff, unit): @property def name(self): """Return the name of the sensor.""" - return "Essent {} ({})".format(self._type, self._tariff) + return f"Essent {self._type} ({self._tariff})" @property def state(self): diff --git a/homeassistant/components/everlights/light.py b/homeassistant/components/everlights/light.py index 21629360ac792f..506617e4c6028d 100644 --- a/homeassistant/components/everlights/light.py +++ b/homeassistant/components/everlights/light.py @@ -87,7 +87,7 @@ def __init__(self, api, channel, status, effects): @property def unique_id(self) -> str: """Return a unique ID.""" - return "{}-{}".format(self._mac, self._channel) + return f"{self._mac}-{self._channel}" @property def available(self) -> bool: @@ -102,7 +102,7 @@ def name(self): @property def is_on(self): """Return true if device is on.""" - return self._status["ch{}Active".format(self._channel)] == 1 + return self._status[f"ch{self._channel}Active"] == 1 @property def brightness(self): diff --git a/homeassistant/components/facebox/image_processing.py b/homeassistant/components/facebox/image_processing.py index a1e686bcbd02ad..228cae2f19d54f 100644 --- a/homeassistant/components/facebox/image_processing.py +++ b/homeassistant/components/facebox/image_processing.py @@ -168,7 +168,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): port = config[CONF_PORT] username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) - url_health = "http://{}:{}/healthz".format(ip_address, port) + url_health = f"http://{ip_address}:{port}/healthz" hostname = check_box_health(url_health, username, password) if hostname is None: return @@ -214,8 +214,8 @@ def __init__( ): """Init with the API key and model id.""" super().__init__() - self._url_check = "http://{}:{}/{}/check".format(ip_address, port, CLASSIFIER) - self._url_teach = "http://{}:{}/{}/teach".format(ip_address, port, CLASSIFIER) + self._url_check = f"http://{ip_address}:{port}/{CLASSIFIER}/check" + self._url_teach = f"http://{ip_address}:{port}/{CLASSIFIER}/teach" self._username = username self._password = password self._hostname = hostname @@ -224,7 +224,7 @@ def __init__( self._name = name else: camera_name = split_entity_id(camera_entity)[1] - self._name = "{} {}".format(CLASSIFIER, camera_name) + self._name = f"{CLASSIFIER} {camera_name}" self._matched = {} def process_image(self, image): diff --git a/homeassistant/components/fail2ban/sensor.py b/homeassistant/components/fail2ban/sensor.py index d5e3d6064ea87f..2dc528b2cff776 100644 --- a/homeassistant/components/fail2ban/sensor.py +++ b/homeassistant/components/fail2ban/sensor.py @@ -57,7 +57,7 @@ class BanSensor(Entity): def __init__(self, name, jail, log_parser): """Initialize the sensor.""" - self._name = "{} {}".format(name, jail) + self._name = f"{name} {jail}" self.jail = jail self.ban_dict = {STATE_CURRENT_BANS: [], STATE_ALL_BANS: []} self.last_ban = None diff --git a/homeassistant/components/fastdotcom/__init__.py b/homeassistant/components/fastdotcom/__init__.py index a40c2597222ad6..b070eef031010c 100644 --- a/homeassistant/components/fastdotcom/__init__.py +++ b/homeassistant/components/fastdotcom/__init__.py @@ -11,7 +11,7 @@ from homeassistant.helpers.event import async_track_time_interval DOMAIN = "fastdotcom" -DATA_UPDATED = "{}_data_updated".format(DOMAIN) +DATA_UPDATED = f"{DOMAIN}_data_updated" _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/feedreader/__init__.py b/homeassistant/components/feedreader/__init__.py index cdd76a56e167f9..44ec95f8213154 100644 --- a/homeassistant/components/feedreader/__init__.py +++ b/homeassistant/components/feedreader/__init__.py @@ -44,7 +44,7 @@ def setup(hass, config): urls = config.get(DOMAIN)[CONF_URLS] scan_interval = config.get(DOMAIN).get(CONF_SCAN_INTERVAL) max_entries = config.get(DOMAIN).get(CONF_MAX_ENTRIES) - data_file = hass.config.path("{}.pickle".format(DOMAIN)) + data_file = hass.config.path(f"{DOMAIN}.pickle") storage = StoredData(data_file) feeds = [ FeedManager(url, scan_interval, max_entries, hass, storage) for url in urls diff --git a/homeassistant/components/fibaro/__init__.py b/homeassistant/components/fibaro/__init__.py index d47c2b0c2d2af9..f500b38664307c 100644 --- a/homeassistant/components/fibaro/__init__.py +++ b/homeassistant/components/fibaro/__init__.py @@ -247,11 +247,11 @@ def _read_scenes(self): else: room_name = self._room_map[device.roomID].name device.room_name = room_name - device.friendly_name = "{} {}".format(room_name, device.name) + device.friendly_name = f"{room_name} {device.name}" device.ha_id = "scene_{}_{}_{}".format( slugify(room_name), slugify(device.name), device.id ) - device.unique_id_str = "{}.scene.{}".format(self.hub_serial, device.id) + device.unique_id_str = f"{self.hub_serial}.scene.{device.id}" self._scene_map[device.id] = device self.fibaro_devices["scene"].append(device) @@ -287,7 +287,7 @@ def _read_devices(self): device.mapped_type = None dtype = device.mapped_type if dtype: - device.unique_id_str = "{}.{}".format(self.hub_serial, device.id) + device.unique_id_str = f"{self.hub_serial}.{device.id}" self._device_map[device.id] = device if dtype != "climate": self.fibaro_devices[dtype].append(device) @@ -414,7 +414,7 @@ def call_set_color(self, red, green, blue, white): green = int(max(0, min(255, green))) blue = int(max(0, min(255, blue))) white = int(max(0, min(255, white))) - color_str = "{},{},{},{}".format(red, green, blue, white) + color_str = f"{red},{green},{blue},{white}" self.fibaro_device.properties.color = color_str self.action("setColor", str(red), str(green), str(blue), str(white)) diff --git a/homeassistant/components/fibaro/climate.py b/homeassistant/components/fibaro/climate.py index ed399fac209458..71be289e27b3c2 100644 --- a/homeassistant/components/fibaro/climate.py +++ b/homeassistant/components/fibaro/climate.py @@ -115,7 +115,7 @@ def __init__(self, fibaro_device): self._op_mode_device = None self._fan_mode_device = None self._support_flags = 0 - self.entity_id = "climate.{}".format(self.ha_id) + self.entity_id = f"climate.{self.ha_id}" self._hvac_support = [] self._preset_support = [] self._fan_support = [] diff --git a/homeassistant/components/fido/sensor.py b/homeassistant/components/fido/sensor.py index e556903638c314..e85b45db4d3aa0 100644 --- a/homeassistant/components/fido/sensor.py +++ b/homeassistant/components/fido/sensor.py @@ -108,7 +108,7 @@ def __init__(self, fido_data, sensor_type, name, number): @property def name(self): """Return the name of the sensor.""" - return "{} {} {}".format(self.client_name, self._number, self._name) + return f"{self.client_name} {self._number} {self._name}" @property def state(self): diff --git a/homeassistant/components/file/notify.py b/homeassistant/components/file/notify.py index f4d31a5fd6fa2e..b190bf5d12187a 100644 --- a/homeassistant/components/file/notify.py +++ b/homeassistant/components/file/notify.py @@ -57,5 +57,5 @@ def send_message(self, message="", **kwargs): if self.add_timestamp: text = "{} {}\n".format(dt_util.utcnow().isoformat(), message) else: - text = "{}\n".format(message) + text = f"{message}\n" file.write(text) diff --git a/homeassistant/components/filter/sensor.py b/homeassistant/components/filter/sensor.py index e8c532547c1466..81c4623c53f52a 100644 --- a/homeassistant/components/filter/sensor.py +++ b/homeassistant/components/filter/sensor.py @@ -332,7 +332,7 @@ def __str__(self): def __repr__(self): """Return timestamp and state as the representation of FilterState.""" - return "{} : {}".format(self.timestamp, self.state) + return f"{self.timestamp} : {self.state}" class Filter: diff --git a/homeassistant/components/fints/sensor.py b/homeassistant/components/fints/sensor.py index 7a1760ea3d5a95..008337f88eb077 100644 --- a/homeassistant/components/fints/sensor.py +++ b/homeassistant/components/fints/sensor.py @@ -77,7 +77,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): account_name = account_config.get(account.iban) if not account_name: - account_name = "{} - {}".format(fints_name, account.iban) + account_name = f"{fints_name} - {account.iban}" accounts.append(FinTsAccount(client, account, account_name)) _LOGGER.debug("Creating account %s for bank %s", account.iban, fints_name) @@ -90,7 +90,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): account_name = holdings_config.get(account.accountnumber) if not account_name: - account_name = "{} - {}".format(fints_name, account.accountnumber) + account_name = f"{fints_name} - {account.accountnumber}" accounts.append(FinTsHoldingsAccount(client, account, account_name)) _LOGGER.debug( "Creating holdings %s for bank %s", account.accountnumber, fints_name @@ -265,11 +265,11 @@ def device_state_attributes(self) -> dict: if self._client.name: attributes[ATTR_BANK] = self._client.name for holding in self._holdings: - total_name = "{} total".format(holding.name) + total_name = f"{holding.name} total" attributes[total_name] = holding.total_value - pieces_name = "{} pieces".format(holding.name) + pieces_name = f"{holding.name} pieces" attributes[pieces_name] = holding.pieces - price_name = "{} price".format(holding.name) + price_name = f"{holding.name} price" attributes[price_name] = holding.market_value return attributes diff --git a/homeassistant/components/fitbit/sensor.py b/homeassistant/components/fitbit/sensor.py index 830914ce113945..534477d88cf792 100644 --- a/homeassistant/components/fitbit/sensor.py +++ b/homeassistant/components/fitbit/sensor.py @@ -167,7 +167,7 @@ def fitbit_configuration_callback(callback_data): else: setup_platform(hass, config, add_entities, discovery_info) - start_url = "{}{}".format(hass.config.api.base_url, FITBIT_AUTH_CALLBACK_PATH) + start_url = f"{hass.config.api.base_url}{FITBIT_AUTH_CALLBACK_PATH}" description = """Please create a Fitbit developer app at https://dev.fitbit.com/apps/new. @@ -204,9 +204,9 @@ def request_oauth_completion(hass): def fitbit_configuration_callback(callback_data): """Handle configuration updates.""" - start_url = "{}{}".format(hass.config.api.base_url, FITBIT_AUTH_START) + start_url = f"{hass.config.api.base_url}{FITBIT_AUTH_START}" - description = "Please authorize Fitbit by visiting {}".format(start_url) + description = f"Please authorize Fitbit by visiting {start_url}" _CONFIGURING["fitbit"] = configurator.request_config( "Fitbit", @@ -498,7 +498,7 @@ def update(self): hours -= 12 elif hours == 0: hours = 12 - self._state = "{}:{:02d} {}".format(hours, minutes, setting) + self._state = f"{hours}:{minutes:02d} {setting}" else: self._state = raw_state else: diff --git a/homeassistant/components/flock/notify.py b/homeassistant/components/flock/notify.py index 07abd097c87015..ba52d3b4beb03e 100644 --- a/homeassistant/components/flock/notify.py +++ b/homeassistant/components/flock/notify.py @@ -20,7 +20,7 @@ async def get_service(hass, config, discovery_info=None): """Get the Flock notification service.""" access_token = config.get(CONF_ACCESS_TOKEN) - url = "{}{}".format(_RESOURCE, access_token) + url = f"{_RESOURCE}{access_token}" session = async_get_clientsession(hass) return FlockNotificationService(url, session) diff --git a/homeassistant/components/flunearyou/sensor.py b/homeassistant/components/flunearyou/sensor.py index 97453c41af074c..0df61fd24e114e 100644 --- a/homeassistant/components/flunearyou/sensor.py +++ b/homeassistant/components/flunearyou/sensor.py @@ -143,7 +143,7 @@ def state(self): @property def unique_id(self): """Return a unique, HASS-friendly identifier for this entity.""" - return "{0},{1}_{2}".format(self.fny.latitude, self.fny.longitude, self._kind) + return f"{self.fny.latitude},{self.fny.longitude}_{self._kind}" @property def unit_of_measurement(self): diff --git a/homeassistant/components/foobot/sensor.py b/homeassistant/components/foobot/sensor.py index 8ec3541d188c78..8d3cf6de27de2a 100644 --- a/homeassistant/components/foobot/sensor.py +++ b/homeassistant/components/foobot/sensor.py @@ -117,7 +117,7 @@ def state(self): @property def unique_id(self): """Return the unique id of this entity.""" - return "{}_{}".format(self._uuid, self.type) + return f"{self._uuid}_{self.type}" @property def unit_of_measurement(self): diff --git a/homeassistant/components/fritzdect/switch.py b/homeassistant/components/fritzdect/switch.py index 22a44a11133cdd..dcb700d6636663 100644 --- a/homeassistant/components/fritzdect/switch.py +++ b/homeassistant/components/fritzdect/switch.py @@ -95,7 +95,7 @@ def device_state_attributes(self): attrs[ATTR_CURRENT_CONSUMPTION_UNIT] = "{}".format( ATTR_CURRENT_CONSUMPTION_UNIT_VALUE ) - attrs[ATTR_TOTAL_CONSUMPTION] = "{:.3f}".format(self.data.total_consumption) + attrs[ATTR_TOTAL_CONSUMPTION] = f"{self.data.total_consumption:.3f}" attrs[ATTR_TOTAL_CONSUMPTION_UNIT] = "{}".format( ATTR_TOTAL_CONSUMPTION_UNIT_VALUE ) @@ -104,7 +104,7 @@ def device_state_attributes(self): attrs[ATTR_TEMPERATURE] = "{}".format( self.units.temperature(self.data.temperature, TEMP_CELSIUS) ) - attrs[ATTR_TEMPERATURE_UNIT] = "{}".format(self.units.temperature_unit) + attrs[ATTR_TEMPERATURE_UNIT] = f"{self.units.temperature_unit}" return attrs @property diff --git a/homeassistant/components/garadget/cover.py b/homeassistant/components/garadget/cover.py index 2e52b49c5f4b87..d487c39db6bfa5 100644 --- a/homeassistant/components/garadget/cover.py +++ b/homeassistant/components/garadget/cover.py @@ -177,7 +177,7 @@ def get_token(self): "username": self._username, "password": self._password, } - url = "{}/oauth/token".format(self.particle_url) + url = f"{self.particle_url}/oauth/token" ret = requests.post(url, auth=("particle", "particle"), data=args, timeout=10) try: @@ -187,7 +187,7 @@ def get_token(self): def remove_token(self): """Remove authorization token from API.""" - url = "{}/v1/access_tokens/{}".format(self.particle_url, self.access_token) + url = f"{self.particle_url}/v1/access_tokens/{self.access_token}" ret = requests.delete(url, auth=(self._username, self._password), timeout=10) return ret.text @@ -266,6 +266,6 @@ def _put_command(self, func, arg=None): params = {"access_token": self.access_token} if arg: params["command"] = arg - url = "{}/v1/devices/{}/{}".format(self.particle_url, self.device_id, func) + url = f"{self.particle_url}/v1/devices/{self.device_id}/{func}" ret = requests.post(url, data=params, timeout=10) return ret.json() diff --git a/homeassistant/components/geniushub/binary_sensor.py b/homeassistant/components/geniushub/binary_sensor.py index 1cc8cd3f4063b0..105a03bf757c68 100644 --- a/homeassistant/components/geniushub/binary_sensor.py +++ b/homeassistant/components/geniushub/binary_sensor.py @@ -29,9 +29,9 @@ def __init__(self, device) -> None: self._device = device if device.type[:21] == "Dual Channel Receiver": - self._name = "Dual Channel Receiver {}".format(device.id) + self._name = f"Dual Channel Receiver {device.id}" else: - self._name = "{} {}".format(device.type, device.id) + self._name = f"{device.type} {device.id}" @property def is_on(self) -> bool: diff --git a/homeassistant/components/geniushub/sensor.py b/homeassistant/components/geniushub/sensor.py index 5e39be1620a983..e87a43fc1ae688 100644 --- a/homeassistant/components/geniushub/sensor.py +++ b/homeassistant/components/geniushub/sensor.py @@ -34,7 +34,7 @@ def __init__(self, device) -> None: super().__init__() self._device = device - self._name = "{} {}".format(device.type, device.id) + self._name = f"{device.type} {device.id}" @property def icon(self) -> str: @@ -112,7 +112,7 @@ def state(self) -> str: @property def device_state_attributes(self) -> Dict[str, Any]: """Return the device state attributes.""" - return {"{}_list".format(self._level): self._issues} + return {f"{self._level}_list": self._issues} async def async_update(self) -> Awaitable[None]: """Process the sensor's state data.""" diff --git a/homeassistant/components/geo_rss_events/sensor.py b/homeassistant/components/geo_rss_events/sensor.py index a4d13bdef9d065..9f336668142155 100644 --- a/homeassistant/components/geo_rss_events/sensor.py +++ b/homeassistant/components/geo_rss_events/sensor.py @@ -157,7 +157,7 @@ def update(self): # And now compute the attributes from the filtered events. matrix = {} for entry in feed_entries: - matrix[entry.title] = "{:.0f}km".format(entry.distance_to_home) + matrix[entry.title] = f"{entry.distance_to_home:.0f}km" self._state_attributes = matrix elif status == georss_client.UPDATE_OK_NO_DATA: _LOGGER.debug("Update successful, but no data received from %s", self._feed) diff --git a/homeassistant/components/geofency/__init__.py b/homeassistant/components/geofency/__init__.py index 6835103968a83f..9d8e0b29f5d191 100644 --- a/homeassistant/components/geofency/__init__.py +++ b/homeassistant/components/geofency/__init__.py @@ -50,7 +50,7 @@ LOCATION_ENTRY = "1" LOCATION_EXIT = "0" -TRACKER_UPDATE = "{}_tracker_update".format(DOMAIN) +TRACKER_UPDATE = f"{DOMAIN}_tracker_update" def _address(value: str) -> str: @@ -131,7 +131,7 @@ def _set_location(hass, data, location_name): data, ) - return web.Response(text="Setting location for {}".format(device), status=HTTP_OK) + return web.Response(text=f"Setting location for {device}", status=HTTP_OK) async def async_setup_entry(hass, entry): diff --git a/homeassistant/components/google/__init__.py b/homeassistant/components/google/__init__.py index 41901a71704aa8..62aa2212bb1b72 100644 --- a/homeassistant/components/google/__init__.py +++ b/homeassistant/components/google/__init__.py @@ -59,10 +59,10 @@ DATA_INDEX = "google_calendars" -YAML_DEVICES = "{}_calendars.yaml".format(DOMAIN) +YAML_DEVICES = f"{DOMAIN}_calendars.yaml" SCOPES = "https://www.googleapis.com/auth/calendar" -TOKEN_FILE = ".{}.token".format(DOMAIN) +TOKEN_FILE = f".{DOMAIN}.token" CONFIG_SCHEMA = vol.Schema( { diff --git a/homeassistant/components/google_assistant/error.py b/homeassistant/components/google_assistant/error.py index a2ff72511c71d4..82c256067eb80d 100644 --- a/homeassistant/components/google_assistant/error.py +++ b/homeassistant/components/google_assistant/error.py @@ -26,9 +26,7 @@ class ChallengeNeeded(SmartHomeError): def __init__(self, challenge_type): """Initialize challenge needed error.""" - super().__init__( - ERR_CHALLENGE_NEEDED, "Challenge needed: {}".format(challenge_type) - ) + super().__init__(ERR_CHALLENGE_NEEDED, f"Challenge needed: {challenge_type}") self.challenge_type = challenge_type def to_response(self): diff --git a/homeassistant/components/google_assistant/helpers.py b/homeassistant/components/google_assistant/helpers.py index 066ed0057acb55..daaf790a0c1521 100644 --- a/homeassistant/components/google_assistant/helpers.py +++ b/homeassistant/components/google_assistant/helpers.py @@ -212,7 +212,7 @@ async def execute(self, data, command_payload): if not executed: raise SmartHomeError( ERR_FUNCTION_NOT_SUPPORTED, - "Unable to execute {} for {}".format(command, self.state.entity_id), + f"Unable to execute {command} for {self.state.entity_id}", ) @callback diff --git a/homeassistant/components/google_wifi/sensor.py b/homeassistant/components/google_wifi/sensor.py index a910e91b1641e3..1d4ed8d84f812c 100644 --- a/homeassistant/components/google_wifi/sensor.py +++ b/homeassistant/components/google_wifi/sensor.py @@ -88,7 +88,7 @@ def __init__(self, api, name, variable): @property def name(self): """Return the name of the sensor.""" - return "{}_{}".format(self._name, self._var_name) + return f"{self._name}_{self._var_name}" @property def icon(self): @@ -125,7 +125,7 @@ class GoogleWifiAPI: def __init__(self, host, conditions): """Initialize the data object.""" uri = "http://" - resource = "{}{}{}".format(uri, host, ENDPOINT) + resource = f"{uri}{host}{ENDPOINT}" self._request = requests.Request("GET", resource).prepare() self.raw_data = None self.conditions = conditions diff --git a/homeassistant/components/gpmdp/media_player.py b/homeassistant/components/gpmdp/media_player.py index 90522a84ce51b5..e6df8b0fe8b1be 100644 --- a/homeassistant/components/gpmdp/media_player.py +++ b/homeassistant/components/gpmdp/media_player.py @@ -142,7 +142,7 @@ def setup_gpmdp(hass, config, code, add_entities): name = config.get(CONF_NAME) host = config.get(CONF_HOST) port = config.get(CONF_PORT) - url = "ws://{}:{}".format(host, port) + url = f"ws://{host}:{port}" if not code: request_configuration(hass, config, url, add_entities) diff --git a/homeassistant/components/gpslogger/__init__.py b/homeassistant/components/gpslogger/__init__.py index 839adec2f5bff7..3ac09457d81541 100644 --- a/homeassistant/components/gpslogger/__init__.py +++ b/homeassistant/components/gpslogger/__init__.py @@ -29,7 +29,7 @@ _LOGGER = logging.getLogger(__name__) -TRACKER_UPDATE = "{}_tracker_update".format(DOMAIN) +TRACKER_UPDATE = f"{DOMAIN}_tracker_update" DEFAULT_ACCURACY = 200 @@ -90,7 +90,7 @@ async def handle_webhook(hass, webhook_id, request): attrs, ) - return web.Response(text="Setting location for {}".format(device), status=HTTP_OK) + return web.Response(text=f"Setting location for {device}", status=HTTP_OK) async def async_setup_entry(hass, entry): diff --git a/homeassistant/components/gtfs/sensor.py b/homeassistant/components/gtfs/sensor.py index b5c1000681dd30..d70e1016f07e84 100644 --- a/homeassistant/components/gtfs/sensor.py +++ b/homeassistant/components/gtfs/sensor.py @@ -139,9 +139,9 @@ def get_next_departure( if include_tomorrow: limit = int(limit / 2 * 3) tomorrow_name = tomorrow.strftime("%A").lower() - tomorrow_select = "calendar.{} AS tomorrow,".format(tomorrow_name) - tomorrow_where = "OR calendar.{} = 1".format(tomorrow_name) - tomorrow_order = "calendar.{} DESC,".format(tomorrow_name) + tomorrow_select = f"calendar.{tomorrow_name} AS tomorrow," + tomorrow_where = f"OR calendar.{tomorrow_name} = 1" + tomorrow_order = f"calendar.{tomorrow_name} DESC," sql_query = """ SELECT trip.trip_id, trip.route_id, @@ -357,7 +357,7 @@ def setup_platform( (gtfs_root, _) = os.path.splitext(data) - sqlite_file = "{}.sqlite?check_same_thread=False".format(gtfs_root) + sqlite_file = f"{gtfs_root}.sqlite?check_same_thread=False" joined_path = os.path.join(gtfs_dir, sqlite_file) gtfs = pygtfs.Schedule(joined_path) @@ -673,7 +673,7 @@ def append_keys(self, resource: dict, prefix: Optional[str] = None) -> None: continue key = attr if prefix and not key.startswith(prefix): - key = "{} {}".format(prefix, key) + key = f"{prefix} {key}" key = slugify(key) self._attributes[key] = val diff --git a/homeassistant/components/gtt/sensor.py b/homeassistant/components/gtt/sensor.py index 43f13c9462020a..cd66a670696eb4 100644 --- a/homeassistant/components/gtt/sensor.py +++ b/homeassistant/components/gtt/sensor.py @@ -38,7 +38,7 @@ def __init__(self, stop, bus_name): """Initialize the Gtt sensor.""" self.data = GttData(stop, bus_name) self._state = None - self._name = "Stop {}".format(stop) + self._name = f"Stop {stop}" @property def name(self): From 5787af136eab878f7308ed17738bf1f44c102d27 Mon Sep 17 00:00:00 2001 From: Malte Franken Date: Wed, 4 Sep 2019 01:16:13 +1000 Subject: [PATCH 56/72] GeoNet NZ Quakes Sensor (#26078) * working version of status sensor * changed unit of measurement * align naming with feed source * simplified sensor name * fix potential issue during initialisation * fixed tests * changed icon to constant * added tests for new sensor * split tests for geolocation vs sensor * fixed lint * fixed pylint * fixed test * removed config entry id from attributes * moved entity manager to component * fix issue with multiple config entries overriding each other's data * creating async tasks instead of awaiting each unloading * moved manager to component * correctly triggering update only when this component is loaded * fixed tests after major code refactorings * fixed pylint * moved actual creation of new events to geolocation platform * changed all timestamps to utc * changed the way platforms are setup and manager is updated * simplify assert statement * changed the way waiting for unloading platforms --- .../components/geonetnz_quakes/__init__.py | 154 ++++++++++++++++-- .../components/geonetnz_quakes/const.py | 9 + .../geonetnz_quakes/geo_location.py | 131 ++------------- .../components/geonetnz_quakes/sensor.py | 139 ++++++++++++++++ tests/components/geonetnz_quakes/__init__.py | 30 ++++ .../geonetnz_quakes/test_geo_location.py | 61 ++----- .../components/geonetnz_quakes/test_sensor.py | 115 +++++++++++++ 7 files changed, 472 insertions(+), 167 deletions(-) create mode 100644 homeassistant/components/geonetnz_quakes/sensor.py create mode 100644 tests/components/geonetnz_quakes/test_sensor.py diff --git a/homeassistant/components/geonetnz_quakes/__init__.py b/homeassistant/components/geonetnz_quakes/__init__.py index e786b4130296c7..069c9ab7daa165 100644 --- a/homeassistant/components/geonetnz_quakes/__init__.py +++ b/homeassistant/components/geonetnz_quakes/__init__.py @@ -1,27 +1,47 @@ """The GeoNet NZ Quakes integration.""" +import asyncio +import logging +from datetime import timedelta + import voluptuous as vol +from aio_geojson_geonetnz_quakes import GeonetnzQuakesFeedManager +from homeassistant.core import callback +from homeassistant.util.unit_system import METRIC_SYSTEM from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import ( CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS, CONF_SCAN_INTERVAL, + CONF_UNIT_SYSTEM_IMPERIAL, + CONF_UNIT_SYSTEM, + LENGTH_MILES, ) -from homeassistant.helpers import config_validation as cv +from homeassistant.helpers import config_validation as cv, aiohttp_client +from homeassistant.helpers.dispatcher import async_dispatcher_send +from homeassistant.helpers.event import async_track_time_interval from .config_flow import configured_instances from .const import ( + PLATFORMS, CONF_MINIMUM_MAGNITUDE, CONF_MMI, + DEFAULT_FILTER_TIME_INTERVAL, DEFAULT_MINIMUM_MAGNITUDE, DEFAULT_MMI, DEFAULT_RADIUS, DEFAULT_SCAN_INTERVAL, DOMAIN, FEED, + SIGNAL_DELETE_ENTITY, + SIGNAL_NEW_GEOLOCATION, + SIGNAL_STATUS, + SIGNAL_UPDATE_ENTITY, ) +_LOGGER = logging.getLogger(__name__) + CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( @@ -81,13 +101,20 @@ async def async_setup(hass, config): async def async_setup_entry(hass, config_entry): """Set up the GeoNet NZ Quakes component as config entry.""" - hass.data[DOMAIN] = {} - hass.data[DOMAIN][FEED] = {} - - hass.async_create_task( - hass.config_entries.async_forward_entry_setup(config_entry, "geo_location") - ) - + if DOMAIN not in hass.data: + hass.data[DOMAIN] = {} + if FEED not in hass.data[DOMAIN]: + hass.data[DOMAIN][FEED] = {} + + radius = config_entry.data[CONF_RADIUS] + unit_system = config_entry.data[CONF_UNIT_SYSTEM] + if unit_system == CONF_UNIT_SYSTEM_IMPERIAL: + radius = METRIC_SYSTEM.length(radius, LENGTH_MILES) + # Create feed entity manager for all platforms. + manager = GeonetnzQuakesFeedEntityManager(hass, config_entry, radius, unit_system) + hass.data[DOMAIN][FEED][config_entry.entry_id] = manager + _LOGGER.debug("Feed entity manager added for %s", config_entry.entry_id) + await manager.async_init() return True @@ -95,7 +122,114 @@ async def async_unload_entry(hass, config_entry): """Unload an GeoNet NZ Quakes component config entry.""" manager = hass.data[DOMAIN][FEED].pop(config_entry.entry_id) await manager.async_stop() + await asyncio.wait( + [ + hass.config_entries.async_forward_entry_unload(config_entry, domain) + for domain in PLATFORMS + ] + ) + return True - await hass.config_entries.async_forward_entry_unload(config_entry, "geo_location") - return True +class GeonetnzQuakesFeedEntityManager: + """Feed Entity Manager for GeoNet NZ Quakes feed.""" + + def __init__(self, hass, config_entry, radius_in_km, unit_system): + """Initialize the Feed Entity Manager.""" + self._hass = hass + self._config_entry = config_entry + coordinates = ( + config_entry.data[CONF_LATITUDE], + config_entry.data[CONF_LONGITUDE], + ) + websession = aiohttp_client.async_get_clientsession(hass) + self._feed_manager = GeonetnzQuakesFeedManager( + websession, + self._generate_entity, + self._update_entity, + self._remove_entity, + coordinates, + mmi=config_entry.data[CONF_MMI], + filter_radius=radius_in_km, + filter_minimum_magnitude=config_entry.data[CONF_MINIMUM_MAGNITUDE], + filter_time=DEFAULT_FILTER_TIME_INTERVAL, + status_callback=self._status_update, + ) + self._config_entry_id = config_entry.entry_id + self._scan_interval = timedelta(seconds=config_entry.data[CONF_SCAN_INTERVAL]) + self._unit_system = unit_system + self._track_time_remove_callback = None + self._status_info = None + self.listeners = [] + + async def async_init(self): + """Schedule initial and regular updates based on configured time interval.""" + + for domain in PLATFORMS: + self._hass.async_create_task( + self._hass.config_entries.async_forward_entry_setup( + self._config_entry, domain + ) + ) + + async def update(event_time): + """Update.""" + await self.async_update() + + # Trigger updates at regular intervals. + self._track_time_remove_callback = async_track_time_interval( + self._hass, update, self._scan_interval + ) + + _LOGGER.debug("Feed entity manager initialized") + + async def async_update(self): + """Refresh data.""" + await self._feed_manager.update() + _LOGGER.debug("Feed entity manager updated") + + async def async_stop(self): + """Stop this feed entity manager from refreshing.""" + for unsub_dispatcher in self.listeners: + unsub_dispatcher() + self.listeners = [] + if self._track_time_remove_callback: + self._track_time_remove_callback() + _LOGGER.debug("Feed entity manager stopped") + + @callback + def async_event_new_entity(self): + """Return manager specific event to signal new entity.""" + return SIGNAL_NEW_GEOLOCATION.format(self._config_entry_id) + + def get_entry(self, external_id): + """Get feed entry by external id.""" + return self._feed_manager.feed_entries.get(external_id) + + def status_info(self): + """Return latest status update info received.""" + return self._status_info + + async def _generate_entity(self, external_id): + """Generate new entity.""" + async_dispatcher_send( + self._hass, + self.async_event_new_entity(), + self, + external_id, + self._unit_system, + ) + + async def _update_entity(self, external_id): + """Update entity.""" + async_dispatcher_send(self._hass, SIGNAL_UPDATE_ENTITY.format(external_id)) + + async def _remove_entity(self, external_id): + """Remove entity.""" + async_dispatcher_send(self._hass, SIGNAL_DELETE_ENTITY.format(external_id)) + + async def _status_update(self, status_info): + """Propagate status update.""" + _LOGGER.debug("Status update received: %s", status_info) + self._status_info = status_info + async_dispatcher_send(self._hass, SIGNAL_STATUS.format(self._config_entry_id)) diff --git a/homeassistant/components/geonetnz_quakes/const.py b/homeassistant/components/geonetnz_quakes/const.py index d06e85ee2cb51b..d564d407f7c7e9 100644 --- a/homeassistant/components/geonetnz_quakes/const.py +++ b/homeassistant/components/geonetnz_quakes/const.py @@ -3,12 +3,21 @@ DOMAIN = "geonetnz_quakes" +PLATFORMS = ("sensor", "geo_location") + CONF_MINIMUM_MAGNITUDE = "minimum_magnitude" CONF_MMI = "mmi" FEED = "feed" +DEFAULT_FILTER_TIME_INTERVAL = timedelta(days=7) DEFAULT_MINIMUM_MAGNITUDE = 0.0 DEFAULT_MMI = 3 DEFAULT_RADIUS = 50.0 DEFAULT_SCAN_INTERVAL = timedelta(minutes=5) + +SIGNAL_DELETE_ENTITY = "geonetnz_quakes_delete_{}" +SIGNAL_UPDATE_ENTITY = "geonetnz_quakes_update_{}" +SIGNAL_STATUS = "geonetnz_quakes_status_{}" + +SIGNAL_NEW_GEOLOCATION = "geonetnz_quakes_new_geolocation_{}" diff --git a/homeassistant/components/geonetnz_quakes/geo_location.py b/homeassistant/components/geonetnz_quakes/geo_location.py index 9d4be94e3aa27d..1ee7c287c6170e 100644 --- a/homeassistant/components/geonetnz_quakes/geo_location.py +++ b/homeassistant/components/geonetnz_quakes/geo_location.py @@ -1,33 +1,20 @@ """Geolocation support for GeoNet NZ Quakes Feeds.""" -from datetime import timedelta import logging from typing import Optional -from aio_geojson_geonetnz_quakes import GeonetnzQuakesFeedManager - from homeassistant.components.geo_location import GeolocationEvent from homeassistant.const import ( ATTR_ATTRIBUTION, - CONF_LATITUDE, - CONF_LONGITUDE, - CONF_RADIUS, - CONF_SCAN_INTERVAL, - CONF_UNIT_SYSTEM, CONF_UNIT_SYSTEM_IMPERIAL, LENGTH_KILOMETERS, LENGTH_MILES, ATTR_TIME, ) from homeassistant.core import callback -from homeassistant.helpers import aiohttp_client -from homeassistant.helpers.dispatcher import ( - async_dispatcher_connect, - async_dispatcher_send, -) -from homeassistant.helpers.event import async_track_time_interval -from homeassistant.util.unit_system import IMPERIAL_SYSTEM, METRIC_SYSTEM +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.util.unit_system import IMPERIAL_SYSTEM -from .const import CONF_MINIMUM_MAGNITUDE, CONF_MMI, DOMAIN, FEED +from .const import DOMAIN, FEED, SIGNAL_DELETE_ENTITY, SIGNAL_UPDATE_ENTITY _LOGGER = logging.getLogger(__name__) @@ -39,111 +26,27 @@ ATTR_PUBLICATION_DATE = "publication_date" ATTR_QUALITY = "quality" -DEFAULT_FILTER_TIME_INTERVAL = timedelta(days=7) - -SIGNAL_DELETE_ENTITY = "geonetnz_quakes_delete_{}" -SIGNAL_UPDATE_ENTITY = "geonetnz_quakes_update_{}" - SOURCE = "geonetnz_quakes" async def async_setup_entry(hass, entry, async_add_entities): """Set up the GeoNet NZ Quakes Feed platform.""" - radius = entry.data[CONF_RADIUS] - unit_system = entry.data[CONF_UNIT_SYSTEM] - if unit_system == CONF_UNIT_SYSTEM_IMPERIAL: - radius = METRIC_SYSTEM.length(radius, LENGTH_MILES) - manager = GeonetnzQuakesFeedEntityManager( - hass, - async_add_entities, - entry.data[CONF_SCAN_INTERVAL], - entry.data[CONF_LATITUDE], - entry.data[CONF_LONGITUDE], - entry.data[CONF_MMI], - radius, - unit_system, - entry.data[CONF_MINIMUM_MAGNITUDE], - ) - hass.data[DOMAIN][FEED][entry.entry_id] = manager - await manager.async_init() - - -class GeonetnzQuakesFeedEntityManager: - """Feed Entity Manager for GeoNet NZ Quakes feed.""" - - def __init__( - self, - hass, - async_add_entities, - scan_interval, - latitude, - longitude, - mmi, - radius_in_km, - unit_system, - minimum_magnitude, - ): - """Initialize the Feed Entity Manager.""" - self._hass = hass - coordinates = (latitude, longitude) - websession = aiohttp_client.async_get_clientsession(hass) - self._feed_manager = GeonetnzQuakesFeedManager( - websession, - self._generate_entity, - self._update_entity, - self._remove_entity, - coordinates, - mmi=mmi, - filter_radius=radius_in_km, - filter_minimum_magnitude=minimum_magnitude, - filter_time=DEFAULT_FILTER_TIME_INTERVAL, - ) - self._async_add_entities = async_add_entities - self._scan_interval = timedelta(seconds=scan_interval) - self._unit_system = unit_system - self._track_time_remove_callback = None - - async def async_init(self): - """Schedule regular updates based on configured time interval.""" + manager = hass.data[DOMAIN][FEED][entry.entry_id] - async def update(event_time): - """Update.""" - await self.async_update() - - await self.async_update() - self._track_time_remove_callback = async_track_time_interval( - self._hass, update, self._scan_interval + @callback + def async_add_geolocation(feed_manager, external_id, unit_system): + """Add gelocation entity from feed.""" + new_entity = GeonetnzQuakesEvent(feed_manager, external_id, unit_system) + _LOGGER.debug("Adding geolocation %s", new_entity) + async_add_entities([new_entity], True) + + manager.listeners.append( + async_dispatcher_connect( + hass, manager.async_event_new_entity(), async_add_geolocation ) - _LOGGER.debug("Feed entity manager initialized") - - async def async_update(self): - """Refresh data.""" - await self._feed_manager.update() - _LOGGER.debug("Feed entity manager updated") - - async def async_stop(self): - """Stop this feed entity manager from refreshing.""" - if self._track_time_remove_callback: - self._track_time_remove_callback() - _LOGGER.debug("Feed entity manager stopped") - - def get_entry(self, external_id): - """Get feed entry by external id.""" - return self._feed_manager.feed_entries.get(external_id) - - async def _generate_entity(self, external_id): - """Generate new entity.""" - new_entity = GeonetnzQuakesEvent(self, external_id, self._unit_system) - # Add new entities to HA. - self._async_add_entities([new_entity], True) - - async def _update_entity(self, external_id): - """Update entity.""" - async_dispatcher_send(self._hass, SIGNAL_UPDATE_ENTITY.format(external_id)) - - async def _remove_entity(self, external_id): - """Remove entity.""" - async_dispatcher_send(self._hass, SIGNAL_DELETE_ENTITY.format(external_id)) + ) + hass.async_create_task(manager.async_update()) + _LOGGER.debug("Geolocation setup done") class GeonetnzQuakesEvent(GeolocationEvent): diff --git a/homeassistant/components/geonetnz_quakes/sensor.py b/homeassistant/components/geonetnz_quakes/sensor.py new file mode 100644 index 00000000000000..e0be94d1b261d4 --- /dev/null +++ b/homeassistant/components/geonetnz_quakes/sensor.py @@ -0,0 +1,139 @@ +"""Feed Entity Manager Sensor support for GeoNet NZ Quakes Feeds.""" +import logging +from typing import Optional + +from homeassistant.core import callback +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.entity import Entity +from homeassistant.util import dt + +from .const import DOMAIN, FEED, SIGNAL_STATUS + +_LOGGER = logging.getLogger(__name__) + +ATTR_STATUS = "status" +ATTR_LAST_UPDATE = "last_update" +ATTR_LAST_UPDATE_SUCCESSFUL = "last_update_successful" +ATTR_LAST_TIMESTAMP = "last_timestamp" +ATTR_CREATED = "created" +ATTR_UPDATED = "updated" +ATTR_REMOVED = "removed" + +DEFAULT_ICON = "mdi:pulse" +DEFAULT_UNIT_OF_MEASUREMENT = "quakes" + + +async def async_setup_entry(hass, entry, async_add_entities): + """Set up the GeoNet NZ Quakes Feed platform.""" + manager = hass.data[DOMAIN][FEED][entry.entry_id] + sensor = GeonetnzQuakesSensor(entry.entry_id, entry.title, manager) + async_add_entities([sensor]) + _LOGGER.debug("Sensor setup done") + + +class GeonetnzQuakesSensor(Entity): + """This is a status sensor for the GeoNet NZ Quakes integration.""" + + def __init__(self, config_entry_id, config_title, manager): + """Initialize entity.""" + self._config_entry_id = config_entry_id + self._config_title = config_title + self._manager = manager + self._status = None + self._last_update = None + self._last_update_successful = None + self._last_timestamp = None + self._total = None + self._created = None + self._updated = None + self._removed = None + self._remove_signal_status = None + + async def async_added_to_hass(self): + """Call when entity is added to hass.""" + self._remove_signal_status = async_dispatcher_connect( + self.hass, + SIGNAL_STATUS.format(self._config_entry_id), + self._update_status_callback, + ) + _LOGGER.debug("Waiting for updates %s", self._config_entry_id) + # First update is manual because of how the feed entity manager is updated. + await self.async_update() + + async def async_will_remove_from_hass(self) -> None: + """Call when entity will be removed from hass.""" + if self._remove_signal_status: + self._remove_signal_status() + + @callback + def _update_status_callback(self): + """Call status update method.""" + _LOGGER.debug("Received status update for %s", self._config_entry_id) + self.async_schedule_update_ha_state(True) + + @property + def should_poll(self): + """No polling needed for GeoNet NZ Quakes status sensor.""" + return False + + async def async_update(self): + """Update this entity from the data held in the feed manager.""" + _LOGGER.debug("Updating %s", self._config_entry_id) + if self._manager: + status_info = self._manager.status_info() + if status_info: + self._update_from_status_info(status_info) + + def _update_from_status_info(self, status_info): + """Update the internal state from the provided information.""" + self._status = status_info.status + self._last_update = ( + dt.as_utc(status_info.last_update) if status_info.last_update else None + ) + self._last_update_successful = ( + dt.as_utc(status_info.last_update_successful) + if status_info.last_update_successful + else None + ) + self._last_timestamp = status_info.last_timestamp + self._total = status_info.total + self._created = status_info.created + self._updated = status_info.updated + self._removed = status_info.removed + + @property + def state(self): + """Return the state of the sensor.""" + return self._total + + @property + def name(self) -> Optional[str]: + """Return the name of the entity.""" + return f"GeoNet NZ Quakes ({self._config_title})" + + @property + def icon(self): + """Return the icon to use in the frontend, if any.""" + return DEFAULT_ICON + + @property + def unit_of_measurement(self): + """Return the unit of measurement.""" + return DEFAULT_UNIT_OF_MEASUREMENT + + @property + def device_state_attributes(self): + """Return the device state attributes.""" + attributes = {} + for key, value in ( + (ATTR_STATUS, self._status), + (ATTR_LAST_UPDATE, self._last_update), + (ATTR_LAST_UPDATE_SUCCESSFUL, self._last_update_successful), + (ATTR_LAST_TIMESTAMP, self._last_timestamp), + (ATTR_CREATED, self._created), + (ATTR_UPDATED, self._updated), + (ATTR_REMOVED, self._removed), + ): + if value or isinstance(value, bool): + attributes[key] = value + return attributes diff --git a/tests/components/geonetnz_quakes/__init__.py b/tests/components/geonetnz_quakes/__init__.py index 95c50679338bb3..424c6372ea8c6f 100644 --- a/tests/components/geonetnz_quakes/__init__.py +++ b/tests/components/geonetnz_quakes/__init__.py @@ -1 +1,31 @@ """Tests for the geonetnz_quakes component.""" +from unittest.mock import MagicMock + + +def _generate_mock_feed_entry( + external_id, + title, + distance_to_home, + coordinates, + attribution=None, + depth=None, + magnitude=None, + mmi=None, + locality=None, + quality=None, + time=None, +): + """Construct a mock feed entry for testing purposes.""" + feed_entry = MagicMock() + feed_entry.external_id = external_id + feed_entry.title = title + feed_entry.distance_to_home = distance_to_home + feed_entry.coordinates = coordinates + feed_entry.attribution = attribution + feed_entry.depth = depth + feed_entry.magnitude = magnitude + feed_entry.mmi = mmi + feed_entry.locality = locality + feed_entry.quality = quality + feed_entry.time = time + return feed_entry diff --git a/tests/components/geonetnz_quakes/test_geo_location.py b/tests/components/geonetnz_quakes/test_geo_location.py index c5b7282f320df2..04bbdc9dcf03c9 100644 --- a/tests/components/geonetnz_quakes/test_geo_location.py +++ b/tests/components/geonetnz_quakes/test_geo_location.py @@ -1,6 +1,5 @@ """The tests for the GeoNet NZ Quakes Feed integration.""" import datetime -from unittest.mock import MagicMock from asynctest import patch, CoroutineMock @@ -30,39 +29,11 @@ from homeassistant.util.unit_system import IMPERIAL_SYSTEM from tests.common import async_fire_time_changed import homeassistant.util.dt as dt_util +from tests.components.geonetnz_quakes import _generate_mock_feed_entry CONFIG = {geonetnz_quakes.DOMAIN: {CONF_RADIUS: 200}} -def _generate_mock_feed_entry( - external_id, - title, - distance_to_home, - coordinates, - attribution=None, - depth=None, - magnitude=None, - mmi=None, - locality=None, - quality=None, - time=None, -): - """Construct a mock feed entry for testing purposes.""" - feed_entry = MagicMock() - feed_entry.external_id = external_id - feed_entry.title = title - feed_entry.distance_to_home = distance_to_home - feed_entry.coordinates = coordinates - feed_entry.attribution = attribution - feed_entry.depth = depth - feed_entry.magnitude = magnitude - feed_entry.mmi = mmi - feed_entry.locality = locality - feed_entry.quality = quality - feed_entry.time = time - return feed_entry - - async def test_setup(hass): """Test the general setup of the integration.""" # Set up some mock feed entries for this test. @@ -94,13 +65,13 @@ async def test_setup(hass): ) as mock_feed_update: mock_feed_update.return_value = "OK", [mock_entry_1, mock_entry_2, mock_entry_3] assert await async_setup_component(hass, geonetnz_quakes.DOMAIN, CONFIG) - # Artificially trigger update. + # Artificially trigger update and collect events. hass.bus.async_fire(EVENT_HOMEASSISTANT_START) - # Collect events. await hass.async_block_till_done() all_states = hass.states.async_all() - assert len(all_states) == 3 + # 3 geolocation and 1 sensor entities + assert len(all_states) == 4 state = hass.states.get("geo_location.title_1") assert state is not None @@ -155,14 +126,13 @@ async def test_setup(hass): } assert float(state.state) == 25.5 - # Simulate an update - one existing, one new entry, - # one outdated entry + # Simulate an update - two existing, one new entry, one outdated entry mock_feed_update.return_value = "OK", [mock_entry_1, mock_entry_4, mock_entry_3] async_fire_time_changed(hass, utcnow + DEFAULT_SCAN_INTERVAL) await hass.async_block_till_done() all_states = hass.states.async_all() - assert len(all_states) == 3 + assert len(all_states) == 4 # Simulate an update - empty data, but successful update, # so no changes to entities. @@ -171,7 +141,7 @@ async def test_setup(hass): await hass.async_block_till_done() all_states = hass.states.async_all() - assert len(all_states) == 3 + assert len(all_states) == 4 # Simulate an update - empty data, removes all entities mock_feed_update.return_value = "ERROR", None @@ -179,7 +149,7 @@ async def test_setup(hass): await hass.async_block_till_done() all_states = hass.states.async_all() - assert len(all_states) == 0 + assert len(all_states) == 1 async def test_setup_imperial(hass): @@ -193,17 +163,22 @@ async def test_setup_imperial(hass): with patch("homeassistant.util.dt.utcnow", return_value=utcnow), patch( "aio_geojson_client.feed.GeoJsonFeed.update", new_callable=CoroutineMock ) as mock_feed_update, patch( - "aio_geojson_client.feed.GeoJsonFeed.__init__", new_callable=CoroutineMock - ) as mock_feed_init: + "aio_geojson_client.feed.GeoJsonFeed.__init__", + new_callable=CoroutineMock, + create=True, + ) as mock_feed_init, patch( + "aio_geojson_client.feed.GeoJsonFeed.last_timestamp", + new_callable=CoroutineMock, + create=True, + ): mock_feed_update.return_value = "OK", [mock_entry_1] assert await async_setup_component(hass, geonetnz_quakes.DOMAIN, CONFIG) - # Artificially trigger update. + # Artificially trigger update and collect events. hass.bus.async_fire(EVENT_HOMEASSISTANT_START) - # Collect events. await hass.async_block_till_done() all_states = hass.states.async_all() - assert len(all_states) == 1 + assert len(all_states) == 2 # Test conversion of 200 miles to kilometers. assert mock_feed_init.call_args[1].get("filter_radius") == 321.8688 diff --git a/tests/components/geonetnz_quakes/test_sensor.py b/tests/components/geonetnz_quakes/test_sensor.py new file mode 100644 index 00000000000000..518e08f02bb7b1 --- /dev/null +++ b/tests/components/geonetnz_quakes/test_sensor.py @@ -0,0 +1,115 @@ +"""The tests for the GeoNet NZ Quakes Feed integration.""" +import datetime + +from asynctest import patch, CoroutineMock + +from homeassistant.components import geonetnz_quakes +from homeassistant.components.geonetnz_quakes import DEFAULT_SCAN_INTERVAL +from homeassistant.components.geonetnz_quakes.sensor import ( + ATTR_STATUS, + ATTR_LAST_UPDATE, + ATTR_CREATED, + ATTR_UPDATED, + ATTR_REMOVED, + ATTR_LAST_UPDATE_SUCCESSFUL, +) +from homeassistant.const import ( + EVENT_HOMEASSISTANT_START, + CONF_RADIUS, + ATTR_UNIT_OF_MEASUREMENT, + ATTR_ICON, +) +from homeassistant.setup import async_setup_component +from tests.common import async_fire_time_changed +import homeassistant.util.dt as dt_util +from tests.components.geonetnz_quakes import _generate_mock_feed_entry + +CONFIG = {geonetnz_quakes.DOMAIN: {CONF_RADIUS: 200}} + + +async def test_setup(hass): + """Test the general setup of the integration.""" + # Set up some mock feed entries for this test. + mock_entry_1 = _generate_mock_feed_entry( + "1234", + "Title 1", + 15.5, + (38.0, -3.0), + locality="Locality 1", + attribution="Attribution 1", + time=datetime.datetime(2018, 9, 22, 8, 0, tzinfo=datetime.timezone.utc), + magnitude=5.7, + mmi=5, + depth=10.5, + quality="best", + ) + mock_entry_2 = _generate_mock_feed_entry( + "2345", "Title 2", 20.5, (38.1, -3.1), magnitude=4.6 + ) + mock_entry_3 = _generate_mock_feed_entry( + "3456", "Title 3", 25.5, (38.2, -3.2), locality="Locality 3" + ) + mock_entry_4 = _generate_mock_feed_entry("4567", "Title 4", 12.5, (38.3, -3.3)) + + # Patching 'utcnow' to gain more control over the timed update. + utcnow = dt_util.utcnow() + with patch("homeassistant.util.dt.utcnow", return_value=utcnow), patch( + "aio_geojson_client.feed.GeoJsonFeed.update", new_callable=CoroutineMock + ) as mock_feed_update: + mock_feed_update.return_value = "OK", [mock_entry_1, mock_entry_2, mock_entry_3] + assert await async_setup_component(hass, geonetnz_quakes.DOMAIN, CONFIG) + # Artificially trigger update and collect events. + hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + await hass.async_block_till_done() + + all_states = hass.states.async_all() + # 3 geolocation and 1 sensor entities + assert len(all_states) == 4 + + state = hass.states.get("sensor.geonet_nz_quakes_32_87336_117_22743") + assert state is not None + assert int(state.state) == 3 + assert state.name == "GeoNet NZ Quakes (32.87336, -117.22743)" + attributes = state.attributes + assert attributes[ATTR_STATUS] == "OK" + assert attributes[ATTR_CREATED] == 3 + assert attributes[ATTR_LAST_UPDATE].tzinfo == dt_util.UTC + assert attributes[ATTR_LAST_UPDATE_SUCCESSFUL].tzinfo == dt_util.UTC + assert attributes[ATTR_LAST_UPDATE] == attributes[ATTR_LAST_UPDATE_SUCCESSFUL] + assert attributes[ATTR_UNIT_OF_MEASUREMENT] == "quakes" + assert attributes[ATTR_ICON] == "mdi:pulse" + + # Simulate an update - two existing, one new entry, one outdated entry + mock_feed_update.return_value = "OK", [mock_entry_1, mock_entry_4, mock_entry_3] + async_fire_time_changed(hass, utcnow + DEFAULT_SCAN_INTERVAL) + await hass.async_block_till_done() + + all_states = hass.states.async_all() + assert len(all_states) == 4 + + state = hass.states.get("sensor.geonet_nz_quakes_32_87336_117_22743") + attributes = state.attributes + assert attributes[ATTR_CREATED] == 1 + assert attributes[ATTR_UPDATED] == 2 + assert attributes[ATTR_REMOVED] == 1 + + # Simulate an update - empty data, but successful update, + # so no changes to entities. + mock_feed_update.return_value = "OK_NO_DATA", None + async_fire_time_changed(hass, utcnow + 2 * DEFAULT_SCAN_INTERVAL) + await hass.async_block_till_done() + + all_states = hass.states.async_all() + assert len(all_states) == 4 + + # Simulate an update - empty data, removes all entities + mock_feed_update.return_value = "ERROR", None + async_fire_time_changed(hass, utcnow + 3 * DEFAULT_SCAN_INTERVAL) + await hass.async_block_till_done() + + all_states = hass.states.async_all() + assert len(all_states) == 1 + + state = hass.states.get("sensor.geonet_nz_quakes_32_87336_117_22743") + attributes = state.attributes + assert attributes[ATTR_REMOVED] == 3 From 2c04a4a92b1ac738849821c044adf6731f9425e2 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 17:27:14 +0200 Subject: [PATCH 57/72] Use literal string interpolation in integrations H-J (f-strings) (#26380) --- homeassistant/components/habitica/sensor.py | 2 +- .../components/hangouts/hangouts_bot.py | 2 +- homeassistant/components/hangouts/intents.py | 2 +- .../components/haveibeenpwned/sensor.py | 4 ++-- homeassistant/components/hddtemp/sensor.py | 2 +- homeassistant/components/hdmi_cec/__init__.py | 6 +++--- homeassistant/components/heos/config_flow.py | 2 +- homeassistant/components/heos/media_player.py | 8 ++++---- .../components/hikvision/binary_sensor.py | 8 ++++---- .../components/hitron_coda/device_tracker.py | 4 ++-- homeassistant/components/hive/binary_sensor.py | 6 +++--- homeassistant/components/hive/climate.py | 8 ++++---- homeassistant/components/hive/light.py | 6 +++--- homeassistant/components/hive/sensor.py | 6 +++--- homeassistant/components/hive/switch.py | 6 +++--- homeassistant/components/hive/water_heater.py | 6 +++--- .../components/homeassistant/__init__.py | 2 +- homeassistant/components/homekit/type_lights.py | 10 +++------- .../components/homekit/type_thermostats.py | 8 ++++---- homeassistant/components/homekit/util.py | 4 +--- .../components/homekit_controller/__init__.py | 6 +++--- .../components/homekit_controller/const.py | 6 +++--- .../components/homekit_controller/storage.py | 2 +- homeassistant/components/homematic/__init__.py | 6 +++--- .../components/homematicip_cloud/__init__.py | 2 +- .../homematicip_cloud/alarm_control_panel.py | 4 ++-- .../homematicip_cloud/binary_sensor.py | 2 +- .../components/homematicip_cloud/device.py | 6 +++--- .../components/homematicip_cloud/light.py | 2 +- .../components/homematicip_cloud/switch.py | 6 +++--- homeassistant/components/homeworks/__init__.py | 2 +- homeassistant/components/honeywell/climate.py | 17 ++++++----------- homeassistant/components/hp_ilo/sensor.py | 2 +- homeassistant/components/html5/notify.py | 4 ++-- homeassistant/components/htu21d/sensor.py | 2 +- homeassistant/components/huawei_lte/sensor.py | 2 +- .../components/huawei_router/device_tracker.py | 8 ++++---- homeassistant/components/hue/config_flow.py | 2 +- homeassistant/components/hydroquebec/sensor.py | 4 ++-- .../components/ialarm/alarm_control_panel.py | 4 ++-- .../components/icloud/device_tracker.py | 8 ++++---- .../components/ign_sismologia/geo_location.py | 4 ++-- homeassistant/components/ihc/__init__.py | 4 ++-- .../components/imap_email_content/sensor.py | 2 +- homeassistant/components/incomfort/climate.py | 2 +- .../components/incomfort/water_heater.py | 2 +- homeassistant/components/influxdb/__init__.py | 2 +- homeassistant/components/insteon/__init__.py | 10 +++++----- homeassistant/components/ios/sensor.py | 6 +++--- homeassistant/components/iota/sensor.py | 2 +- homeassistant/components/iperf3/__init__.py | 2 +- homeassistant/components/ipma/weather.py | 2 +- homeassistant/components/iqvia/__init__.py | 2 +- homeassistant/components/iqvia/sensor.py | 10 +++++----- homeassistant/components/isy994/__init__.py | 6 +++--- homeassistant/components/isy994/sensor.py | 2 +- homeassistant/components/itach/remote.py | 2 +- homeassistant/components/itunes/media_player.py | 6 +++--- .../components/jewish_calendar/sensor.py | 2 +- 59 files changed, 128 insertions(+), 139 deletions(-) diff --git a/homeassistant/components/habitica/sensor.py b/homeassistant/components/habitica/sensor.py index e70d0eb696a1fb..1fa4ad63b36bf4 100644 --- a/homeassistant/components/habitica/sensor.py +++ b/homeassistant/components/habitica/sensor.py @@ -66,7 +66,7 @@ def icon(self): @property def name(self): """Return the name of the sensor.""" - return "{0}_{1}_{2}".format(habitica.DOMAIN, self._name, self._sensor_name) + return f"{habitica.DOMAIN}_{self._name}_{self._sensor_name}" @property def state(self): diff --git a/homeassistant/components/hangouts/hangouts_bot.py b/homeassistant/components/hangouts/hangouts_bot.py index d444e852cca885..35f866b3d813aa 100644 --- a/homeassistant/components/hangouts/hangouts_bot.py +++ b/homeassistant/components/hangouts/hangouts_bot.py @@ -323,7 +323,7 @@ async def _async_list_conversations(self): } self.hass.states.async_set( - "{}.conversations".format(DOMAIN), + f"{DOMAIN}.conversations", len(self._conversation_list.get_all()), attributes=conversations, ) diff --git a/homeassistant/components/hangouts/intents.py b/homeassistant/components/hangouts/intents.py index a26da7a4872e9c..5e4c6ff206bfe5 100644 --- a/homeassistant/components/hangouts/intents.py +++ b/homeassistant/components/hangouts/intents.py @@ -25,7 +25,7 @@ async def async_handle(self, intent_obj): help_text = "I understand the following sentences:" for intent_data in intents.values(): for sentence in intent_data["sentences"]: - help_text += "\n'{}'".format(sentence) + help_text += f"\n'{sentence}'" response.async_set_speech(help_text) return response diff --git a/homeassistant/components/haveibeenpwned/sensor.py b/homeassistant/components/haveibeenpwned/sensor.py index ec43d9444a238c..7fa3f422300fb5 100644 --- a/homeassistant/components/haveibeenpwned/sensor.py +++ b/homeassistant/components/haveibeenpwned/sensor.py @@ -61,7 +61,7 @@ def __init__(self, data, email): @property def name(self): """Return the name of the sensor.""" - return "Breaches {}".format(self._email) + return f"Breaches {self._email}" @property def unit_of_measurement(self): @@ -151,7 +151,7 @@ def update_no_throttle(self): def update(self, **kwargs): """Get the latest data for current email from REST service.""" try: - url = "{}{}?truncateResponse=false".format(URL, self._email) + url = f"{URL}{self._email}?truncateResponse=false" header = {USER_AGENT: HA_USER_AGENT, "hibp-api-key": self._api_key} _LOGGER.debug("Checking for breaches for email: %s", self._email) req = requests.get(url, headers=header, allow_redirects=True, timeout=5) diff --git a/homeassistant/components/hddtemp/sensor.py b/homeassistant/components/hddtemp/sensor.py index fa3b5fd256ce69..d0dd5018dca8b6 100644 --- a/homeassistant/components/hddtemp/sensor.py +++ b/homeassistant/components/hddtemp/sensor.py @@ -67,7 +67,7 @@ def __init__(self, name, disk, hddtemp): """Initialize a HDDTemp sensor.""" self.hddtemp = hddtemp self.disk = disk - self._name = "{} {}".format(name, disk) + self._name = f"{name} {disk}" self._state = None self._details = None self._unit = None diff --git a/homeassistant/components/hdmi_cec/__init__.py b/homeassistant/components/hdmi_cec/__init__.py index 969925182fde23..d1637f96d95db8 100644 --- a/homeassistant/components/hdmi_cec/__init__.py +++ b/homeassistant/components/hdmi_cec/__init__.py @@ -264,7 +264,7 @@ def _tx(call): if isinstance(data[ATTR_ATT], (list,)): att = data[ATTR_ATT] else: - att = reduce(lambda x, y: "%s:%x" % (x, y), data[ATTR_ATT]) + att = reduce(lambda x, y: f"{x}:{y:x}", data[ATTR_ATT]) else: att = "" command = CecCommand(cmd, dst, src, att) @@ -312,7 +312,7 @@ def _update(call): def _new_device(device): """Handle new devices which are detected by HDMI network.""" - key = "{}.{}".format(DOMAIN, device.name) + key = f"{DOMAIN}.{device.name}" hass.data[key] = device ent_platform = base_config[DOMAIN][CONF_TYPES].get(key, platform) discovery.load_platform( @@ -399,7 +399,7 @@ def _update(self, device=None): def name(self): """Return the name of the device.""" return ( - "%s %s" % (self.vendor_name, self._device.osd_name) + f"{self.vendor_name} {self._device.osd_name}" if ( self._device.osd_name is not None and self.vendor_name is not None diff --git a/homeassistant/components/heos/config_flow.py b/homeassistant/components/heos/config_flow.py index 1d56478ba3ac6f..4380cb4d8ba09a 100644 --- a/homeassistant/components/heos/config_flow.py +++ b/homeassistant/components/heos/config_flow.py @@ -10,7 +10,7 @@ def format_title(host: str) -> str: """Format the title for config entries.""" - return "Controller ({})".format(host) + return f"Controller ({host})" @config_entries.HANDLERS.register(DOMAIN) diff --git a/homeassistant/components/heos/media_player.py b/homeassistant/components/heos/media_player.py index 40f6113a80d794..10ea28ca16cb19 100644 --- a/homeassistant/components/heos/media_player.py +++ b/homeassistant/components/heos/media_player.py @@ -183,7 +183,7 @@ async def async_play_media(self, media_type, media_id, **kwargs): None, ) if index is None: - raise ValueError("Invalid quick select '{}'".format(media_id)) + raise ValueError(f"Invalid quick select '{media_id}'") await self._player.play_quick_select(index) return @@ -191,7 +191,7 @@ async def async_play_media(self, media_type, media_id, **kwargs): playlists = await self._player.heos.get_playlists() playlist = next((p for p in playlists if p.name == media_id), None) if not playlist: - raise ValueError("Invalid playlist '{}'".format(media_id)) + raise ValueError(f"Invalid playlist '{media_id}'") add_queue_option = ( heos_const.ADD_QUEUE_ADD_TO_END if kwargs.get(ATTR_MEDIA_ENQUEUE) @@ -215,11 +215,11 @@ async def async_play_media(self, media_type, media_id, **kwargs): None, ) if index is None: - raise ValueError("Invalid favorite '{}'".format(media_id)) + raise ValueError(f"Invalid favorite '{media_id}'") await self._player.play_favorite(index) return - raise ValueError("Unsupported media type '{}'".format(media_type)) + raise ValueError(f"Unsupported media type '{media_type}'") @log_command_error("select source") async def async_select_source(self, source): diff --git a/homeassistant/components/hikvision/binary_sensor.py b/homeassistant/components/hikvision/binary_sensor.py index a9ab242c2fda0e..b898f5d860c2bb 100644 --- a/homeassistant/components/hikvision/binary_sensor.py +++ b/homeassistant/components/hikvision/binary_sensor.py @@ -93,7 +93,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): else: protocol = "http" - url = "{}://{}".format(protocol, host) + url = f"{protocol}://{host}" data = HikvisionData(hass, url, port, name, username, password) @@ -196,11 +196,11 @@ def __init__(self, hass, sensor, channel, cam, delay): self._channel = channel if self._cam.type == "NVR": - self._name = "{} {} {}".format(self._cam.name, sensor, channel) + self._name = f"{self._cam.name} {sensor} {channel}" else: - self._name = "{} {}".format(self._cam.name, sensor) + self._name = f"{self._cam.name} {sensor}" - self._id = "{}.{}.{}".format(self._cam.cam_id, sensor, channel) + self._id = f"{self._cam.cam_id}.{sensor}.{channel}" if delay is None: self._delay = 0 diff --git a/homeassistant/components/hitron_coda/device_tracker.py b/homeassistant/components/hitron_coda/device_tracker.py index e3e8975c1257c8..2f3526d45b6dbc 100644 --- a/homeassistant/components/hitron_coda/device_tracker.py +++ b/homeassistant/components/hitron_coda/device_tracker.py @@ -44,8 +44,8 @@ def __init__(self, config): """Initialize the scanner.""" self.last_results = [] host = config[CONF_HOST] - self._url = "http://{}/data/getConnectInfo.asp".format(host) - self._loginurl = "http://{}/goform/login".format(host) + self._url = f"http://{host}/data/getConnectInfo.asp" + self._loginurl = f"http://{host}/goform/login" self._username = config.get(CONF_USERNAME) self._password = config.get(CONF_PASSWORD) diff --git a/homeassistant/components/hive/binary_sensor.py b/homeassistant/components/hive/binary_sensor.py index 80aaaf8646311a..50c8277302fbc7 100644 --- a/homeassistant/components/hive/binary_sensor.py +++ b/homeassistant/components/hive/binary_sensor.py @@ -26,8 +26,8 @@ def __init__(self, hivesession, hivedevice): self.node_device_type = hivedevice["Hive_DeviceType"] self.session = hivesession self.attributes = {} - self.data_updatesource = "{}.{}".format(self.device_type, self.node_id) - self._unique_id = "{}-{}".format(self.node_id, self.device_type) + self.data_updatesource = f"{self.device_type}.{self.node_id}" + self._unique_id = f"{self.node_id}-{self.device_type}" self.session.entities.append(self) @property @@ -42,7 +42,7 @@ def device_info(self): def handle_update(self, updatesource): """Handle the new update request.""" - if "{}.{}".format(self.device_type, self.node_id) not in updatesource: + if f"{self.device_type}.{self.node_id}" not in updatesource: self.schedule_update_ha_state() @property diff --git a/homeassistant/components/hive/climate.py b/homeassistant/components/hive/climate.py index d4a1c915518eff..861957e6ef0166 100644 --- a/homeassistant/components/hive/climate.py +++ b/homeassistant/components/hive/climate.py @@ -54,8 +54,8 @@ def __init__(self, hivesession, hivedevice): self.thermostat_node_id = hivedevice["Thermostat_NodeID"] self.session = hivesession self.attributes = {} - self.data_updatesource = "{}.{}".format(self.device_type, self.node_id) - self._unique_id = "{}-{}".format(self.node_id, self.device_type) + self.data_updatesource = f"{self.device_type}.{self.node_id}" + self._unique_id = f"{self.node_id}-{self.device_type}" @property def unique_id(self): @@ -74,7 +74,7 @@ def supported_features(self): def handle_update(self, updatesource): """Handle the new update request.""" - if "{}.{}".format(self.device_type, self.node_id) not in updatesource: + if f"{self.device_type}.{self.node_id}" not in updatesource: self.schedule_update_ha_state() @property @@ -82,7 +82,7 @@ def name(self): """Return the name of the Climate device.""" friendly_name = "Heating" if self.node_name is not None: - friendly_name = "{} {}".format(self.node_name, friendly_name) + friendly_name = f"{self.node_name} {friendly_name}" return friendly_name @property diff --git a/homeassistant/components/hive/light.py b/homeassistant/components/hive/light.py index 5892e304379ba4..a85c3a43992eb8 100644 --- a/homeassistant/components/hive/light.py +++ b/homeassistant/components/hive/light.py @@ -33,8 +33,8 @@ def __init__(self, hivesession, hivedevice): self.light_device_type = hivedevice["Hive_Light_DeviceType"] self.session = hivesession self.attributes = {} - self.data_updatesource = "{}.{}".format(self.device_type, self.node_id) - self._unique_id = "{}-{}".format(self.node_id, self.device_type) + self.data_updatesource = f"{self.device_type}.{self.node_id}" + self._unique_id = f"{self.node_id}-{self.device_type}" self.session.entities.append(self) @property @@ -49,7 +49,7 @@ def device_info(self): def handle_update(self, updatesource): """Handle the new update request.""" - if "{}.{}".format(self.device_type, self.node_id) not in updatesource: + if f"{self.device_type}.{self.node_id}" not in updatesource: self.schedule_update_ha_state() @property diff --git a/homeassistant/components/hive/sensor.py b/homeassistant/components/hive/sensor.py index dd3343633d8b47..c43fe461a8e6a1 100644 --- a/homeassistant/components/hive/sensor.py +++ b/homeassistant/components/hive/sensor.py @@ -37,8 +37,8 @@ def __init__(self, hivesession, hivedevice): self.device_type = hivedevice["HA_DeviceType"] self.node_device_type = hivedevice["Hive_DeviceType"] self.session = hivesession - self.data_updatesource = "{}.{}".format(self.device_type, self.node_id) - self._unique_id = "{}-{}".format(self.node_id, self.device_type) + self.data_updatesource = f"{self.device_type}.{self.node_id}" + self._unique_id = f"{self.node_id}-{self.device_type}" self.session.entities.append(self) @property @@ -53,7 +53,7 @@ def device_info(self): def handle_update(self, updatesource): """Handle the new update request.""" - if "{}.{}".format(self.device_type, self.node_id) not in updatesource: + if f"{self.device_type}.{self.node_id}" not in updatesource: self.schedule_update_ha_state() @property diff --git a/homeassistant/components/hive/switch.py b/homeassistant/components/hive/switch.py index 4644ccaec00614..75efdfe3e5d461 100644 --- a/homeassistant/components/hive/switch.py +++ b/homeassistant/components/hive/switch.py @@ -23,8 +23,8 @@ def __init__(self, hivesession, hivedevice): self.device_type = hivedevice["HA_DeviceType"] self.session = hivesession self.attributes = {} - self.data_updatesource = "{}.{}".format(self.device_type, self.node_id) - self._unique_id = "{}-{}".format(self.node_id, self.device_type) + self.data_updatesource = f"{self.device_type}.{self.node_id}" + self._unique_id = f"{self.node_id}-{self.device_type}" self.session.entities.append(self) @property @@ -39,7 +39,7 @@ def device_info(self): def handle_update(self, updatesource): """Handle the new update request.""" - if "{}.{}".format(self.device_type, self.node_id) not in updatesource: + if f"{self.device_type}.{self.node_id}" not in updatesource: self.schedule_update_ha_state() @property diff --git a/homeassistant/components/hive/water_heater.py b/homeassistant/components/hive/water_heater.py index f186d804d34c89..1b009582c1aec7 100644 --- a/homeassistant/components/hive/water_heater.py +++ b/homeassistant/components/hive/water_heater.py @@ -42,8 +42,8 @@ def __init__(self, hivesession, hivedevice): self.node_name = hivedevice["Hive_NodeName"] self.device_type = hivedevice["HA_DeviceType"] self.session = hivesession - self.data_updatesource = "{}.{}".format(self.device_type, self.node_id) - self._unique_id = "{}-{}".format(self.node_id, self.device_type) + self.data_updatesource = f"{self.device_type}.{self.node_id}" + self._unique_id = f"{self.node_id}-{self.device_type}" self._unit_of_measurement = TEMP_CELSIUS @property @@ -63,7 +63,7 @@ def supported_features(self): def handle_update(self, updatesource): """Handle the new update request.""" - if "{}.{}".format(self.device_type, self.node_id) not in updatesource: + if f"{self.device_type}.{self.node_id}" not in updatesource: self.schedule_update_ha_state() @property diff --git a/homeassistant/components/homeassistant/__init__.py b/homeassistant/components/homeassistant/__init__.py index 2bd0a62cebb1a9..02e53d1de108e8 100644 --- a/homeassistant/components/homeassistant/__init__.py +++ b/homeassistant/components/homeassistant/__init__.py @@ -110,7 +110,7 @@ async def async_handle_core_service(call): hass.components.persistent_notification.async_create( "Config error. See dev-info panel for details.", "Config validating", - "{0}.check_config".format(ha.DOMAIN), + f"{ha.DOMAIN}.check_config", ) return diff --git a/homeassistant/components/homekit/type_lights.py b/homeassistant/components/homekit/type_lights.py index fce81d0adf7366..8e1b07fbbfff34 100644 --- a/homeassistant/components/homekit/type_lights.py +++ b/homeassistant/components/homekit/type_lights.py @@ -127,9 +127,7 @@ def set_brightness(self, value): self.set_state(0) # Turn off light return params = {ATTR_ENTITY_ID: self.entity_id, ATTR_BRIGHTNESS_PCT: value} - self.call_service( - DOMAIN, SERVICE_TURN_ON, params, "brightness at {}%".format(value) - ) + self.call_service(DOMAIN, SERVICE_TURN_ON, params, f"brightness at {value}%") def set_color_temperature(self, value): """Set color temperature if call came from HomeKit.""" @@ -137,7 +135,7 @@ def set_color_temperature(self, value): self._flag[CHAR_COLOR_TEMPERATURE] = True params = {ATTR_ENTITY_ID: self.entity_id, ATTR_COLOR_TEMP: value} self.call_service( - DOMAIN, SERVICE_TURN_ON, params, "color temperature at {}".format(value) + DOMAIN, SERVICE_TURN_ON, params, f"color temperature at {value}" ) def set_saturation(self, value): @@ -167,9 +165,7 @@ def set_color(self): {CHAR_HUE: False, CHAR_SATURATION: False, RGB_COLOR: True} ) params = {ATTR_ENTITY_ID: self.entity_id, ATTR_HS_COLOR: color} - self.call_service( - DOMAIN, SERVICE_TURN_ON, params, "set color at {}".format(color) - ) + self.call_service(DOMAIN, SERVICE_TURN_ON, params, f"set color at {color}") def update_state(self, new_state): """Update light after state change.""" diff --git a/homeassistant/components/homekit/type_thermostats.py b/homeassistant/components/homekit/type_thermostats.py index e00912d340eb26..63eb688a0c1866 100644 --- a/homeassistant/components/homekit/type_thermostats.py +++ b/homeassistant/components/homekit/type_thermostats.py @@ -209,7 +209,7 @@ def set_cooling_threshold(self, value): DOMAIN_CLIMATE, SERVICE_SET_TEMPERATURE_THERMOSTAT, params, - "cooling threshold {}{}".format(temperature, self._unit), + f"cooling threshold {temperature}{self._unit}", ) @debounce @@ -230,7 +230,7 @@ def set_heating_threshold(self, value): DOMAIN_CLIMATE, SERVICE_SET_TEMPERATURE_THERMOSTAT, params, - "heating threshold {}{}".format(temperature, self._unit), + f"heating threshold {temperature}{self._unit}", ) @debounce @@ -244,7 +244,7 @@ def set_target_temperature(self, value): DOMAIN_CLIMATE, SERVICE_SET_TEMPERATURE_THERMOSTAT, params, - "{}{}".format(temperature, self._unit), + f"{temperature}{self._unit}", ) def update_state(self, new_state): @@ -378,7 +378,7 @@ def set_target_temperature(self, value): DOMAIN_WATER_HEATER, SERVICE_SET_TEMPERATURE_WATER_HEATER, params, - "{}{}".format(temperature, self._unit), + f"{temperature}{self._unit}", ) def update_state(self, new_state): diff --git a/homeassistant/components/homekit/util.py b/homeassistant/components/homekit/util.py index 3b5f3c814368d5..d60c94d420deb9 100644 --- a/homeassistant/components/homekit/util.py +++ b/homeassistant/components/homekit/util.py @@ -116,9 +116,7 @@ def validate_entity_config(values): params = MEDIA_PLAYER_SCHEMA(feature) key = params.pop(CONF_FEATURE) if key in feature_list: - raise vol.Invalid( - "A feature can be added only once for {}".format(entity) - ) + raise vol.Invalid(f"A feature can be added only once for {entity}") feature_list[key] = params config[CONF_FEATURE_LIST] = feature_list diff --git a/homeassistant/components/homekit_controller/__init__.py b/homeassistant/components/homekit_controller/__init__.py index 5ae82d0f124af8..6a6492847225f1 100644 --- a/homeassistant/components/homekit_controller/__init__.py +++ b/homeassistant/components/homekit_controller/__init__.py @@ -106,7 +106,7 @@ def _setup_characteristic(self, char): # Callback to allow entity to configure itself based on this # characteristics metadata (valid values, value ranges, features, etc) setup_fn_name = escape_characteristic_name(short_name) - setup_fn = getattr(self, "_setup_{}".format(setup_fn_name), None) + setup_fn = getattr(self, f"_setup_{setup_fn_name}", None) if not setup_fn: return # pylint: disable=not-callable @@ -128,7 +128,7 @@ def async_state_changed(self): # Callback to update the entity with this characteristic value char_name = escape_characteristic_name(self._char_names[iid]) - update_fn = getattr(self, "_update_{}".format(char_name), None) + update_fn = getattr(self, f"_update_{char_name}", None) if not update_fn: continue @@ -141,7 +141,7 @@ def async_state_changed(self): def unique_id(self): """Return the ID of this device.""" serial = self._accessory_info["serial-number"] - return "homekit-{}-{}".format(serial, self._iid) + return f"homekit-{serial}-{self._iid}" @property def name(self): diff --git a/homeassistant/components/homekit_controller/const.py b/homeassistant/components/homekit_controller/const.py index ad12f3fdb71213..09a7df2a2bfa67 100644 --- a/homeassistant/components/homekit_controller/const.py +++ b/homeassistant/components/homekit_controller/const.py @@ -1,9 +1,9 @@ """Constants for the homekit_controller component.""" DOMAIN = "homekit_controller" -KNOWN_DEVICES = "{}-devices".format(DOMAIN) -CONTROLLER = "{}-controller".format(DOMAIN) -ENTITY_MAP = "{}-entity-map".format(DOMAIN) +KNOWN_DEVICES = f"{DOMAIN}-devices" +CONTROLLER = f"{DOMAIN}-controller" +ENTITY_MAP = f"{DOMAIN}-entity-map" HOMEKIT_DIR = ".homekit" PAIRING_FILE = "pairing.json" diff --git a/homeassistant/components/homekit_controller/storage.py b/homeassistant/components/homekit_controller/storage.py index ec5a2e7cc4334e..46d095b5631823 100644 --- a/homeassistant/components/homekit_controller/storage.py +++ b/homeassistant/components/homekit_controller/storage.py @@ -5,7 +5,7 @@ from .const import DOMAIN -ENTITY_MAP_STORAGE_KEY = "{}-entity-map".format(DOMAIN) +ENTITY_MAP_STORAGE_KEY = f"{DOMAIN}-entity-map" ENTITY_MAP_STORAGE_VERSION = 1 ENTITY_MAP_SAVE_DELAY = 10 diff --git a/homeassistant/components/homematic/__init__.py b/homeassistant/components/homematic/__init__.py index 0ab47247edc201..598e3765612420 100644 --- a/homeassistant/components/homematic/__init__.py +++ b/homeassistant/components/homematic/__init__.py @@ -711,15 +711,15 @@ def _create_ha_id(name, channel, param, count): # Has multiple elements/channels if count > 1 and param is None: - return "{} {}".format(name, channel) + return f"{name} {channel}" # With multiple parameters on first channel if count == 1 and param is not None: - return "{} {}".format(name, param) + return f"{name} {param}" # Multiple parameters with multiple channels if count > 1 and param is not None: - return "{} {} {}".format(name, channel, param) + return f"{name} {channel} {param}" def _hm_event_handler(hass, interface, device, caller, attribute, value): diff --git a/homeassistant/components/homematicip_cloud/__init__.py b/homeassistant/components/homematicip_cloud/__init__.py index f2d84095b19357..c8fb31998ef4ad 100644 --- a/homeassistant/components/homematicip_cloud/__init__.py +++ b/homeassistant/components/homematicip_cloud/__init__.py @@ -234,7 +234,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: device_registry = await dr.async_get_registry(hass) home = hap.home # Add the HAP name from configuration if set. - hapname = home.label if not home.name else "{} {}".format(home.label, home.name) + hapname = home.label if not home.name else f"{home.label} {home.name}" device_registry.async_get_or_create( config_entry_id=home.id, identifiers={(DOMAIN, home.id)}, diff --git a/homeassistant/components/homematicip_cloud/alarm_control_panel.py b/homeassistant/components/homematicip_cloud/alarm_control_panel.py index 38097afc1b65f3..592d234225cff9 100644 --- a/homeassistant/components/homematicip_cloud/alarm_control_panel.py +++ b/homeassistant/components/homematicip_cloud/alarm_control_panel.py @@ -112,7 +112,7 @@ def name(self) -> str: """Return the name of the generic device.""" name = CONST_ALARM_CONTROL_PANEL_NAME if self._home.name: - name = "{} {}".format(self._home.name, name) + name = f"{self._home.name} {name}" return name @property @@ -131,7 +131,7 @@ def available(self) -> bool: @property def unique_id(self) -> str: """Return a unique ID.""" - return "{}_{}".format(self.__class__.__name__, self._home.id) + return f"{self.__class__.__name__}_{self._home.id}" def _get_zone_alarm_state(security_zone) -> bool: diff --git a/homeassistant/components/homematicip_cloud/binary_sensor.py b/homeassistant/components/homematicip_cloud/binary_sensor.py index 97746f3f472b43..d6bc24d21edf18 100644 --- a/homeassistant/components/homematicip_cloud/binary_sensor.py +++ b/homeassistant/components/homematicip_cloud/binary_sensor.py @@ -291,7 +291,7 @@ class HomematicipSecurityZoneSensorGroup(HomematicipGenericDevice, BinarySensorD def __init__(self, home: AsyncHome, device, post: str = "SecurityZone") -> None: """Initialize security zone group.""" - device.modelType = "HmIP-{}".format(post) + device.modelType = f"HmIP-{post}" super().__init__(home, device, post) @property diff --git a/homeassistant/components/homematicip_cloud/device.py b/homeassistant/components/homematicip_cloud/device.py index 71855d7c3f5a4a..5eeb14b635946c 100644 --- a/homeassistant/components/homematicip_cloud/device.py +++ b/homeassistant/components/homematicip_cloud/device.py @@ -92,9 +92,9 @@ def name(self) -> str: """Return the name of the generic device.""" name = self._device.label if self._home.name is not None and self._home.name != "": - name = "{} {}".format(self._home.name, name) + name = f"{self._home.name} {name}" if self.post is not None and self.post != "": - name = "{} {}".format(name, self.post) + name = f"{name} {self.post}" return name @property @@ -110,7 +110,7 @@ def available(self) -> bool: @property def unique_id(self) -> str: """Return a unique ID.""" - return "{}_{}".format(self.__class__.__name__, self._device.id) + return f"{self.__class__.__name__}_{self._device.id}" @property def icon(self) -> Optional[str]: diff --git a/homeassistant/components/homematicip_cloud/light.py b/homeassistant/components/homematicip_cloud/light.py index c034b19bb3a860..bc7b12f9653ea5 100644 --- a/homeassistant/components/homematicip_cloud/light.py +++ b/homeassistant/components/homematicip_cloud/light.py @@ -205,7 +205,7 @@ def supported_features(self) -> int: @property def unique_id(self) -> str: """Return a unique ID.""" - return "{}_{}_{}".format(self.__class__.__name__, self.post, self._device.id) + return f"{self.__class__.__name__}_{self.post}_{self._device.id}" async def async_turn_on(self, **kwargs): """Turn the light on.""" diff --git a/homeassistant/components/homematicip_cloud/switch.py b/homeassistant/components/homematicip_cloud/switch.py index a9535736d0f23a..6d19087781daef 100644 --- a/homeassistant/components/homematicip_cloud/switch.py +++ b/homeassistant/components/homematicip_cloud/switch.py @@ -93,7 +93,7 @@ class HomematicipGroupSwitch(HomematicipGenericDevice, SwitchDevice): def __init__(self, home: AsyncHome, device, post: str = "Group") -> None: """Initialize switching group.""" - device.modelType = "HmIP-{}".format(post) + device.modelType = f"HmIP-{post}" super().__init__(home, device, post) @property @@ -149,12 +149,12 @@ class HomematicipMultiSwitch(HomematicipGenericDevice, SwitchDevice): def __init__(self, home: AsyncHome, device, channel: int): """Initialize the multi switch device.""" self.channel = channel - super().__init__(home, device, "Channel{}".format(channel)) + super().__init__(home, device, f"Channel{channel}") @property def unique_id(self) -> str: """Return a unique ID.""" - return "{}_{}_{}".format(self.__class__.__name__, self.post, self._device.id) + return f"{self.__class__.__name__}_{self.post}_{self._device.id}" @property def is_on(self) -> bool: diff --git a/homeassistant/components/homeworks/__init__.py b/homeassistant/components/homeworks/__init__.py index dcc2ce5dde62d1..bd40336b8ba894 100644 --- a/homeassistant/components/homeworks/__init__.py +++ b/homeassistant/components/homeworks/__init__.py @@ -106,7 +106,7 @@ def __init__(self, controller, addr, name): @property def unique_id(self): """Return a unique identifier.""" - return "homeworks.{}".format(self._addr) + return f"homeworks.{self._addr}" @property def name(self): diff --git a/homeassistant/components/honeywell/climate.py b/homeassistant/components/honeywell/climate.py index 62a370f60faa8e..84a816628c0626 100644 --- a/homeassistant/components/honeywell/climate.py +++ b/homeassistant/components/honeywell/climate.py @@ -318,7 +318,7 @@ def _set_temperature(self, **kwargs) -> None: # Get current mode mode = self._device.system_mode # Set hold if this is not the case - if getattr(self._device, "hold_{}".format(mode)) is False: + if getattr(self._device, f"hold_{mode}") is False: # Get next period key next_period_key = "{}NextPeriod".format(mode.capitalize()) # Get next period raw value @@ -326,11 +326,9 @@ def _set_temperature(self, **kwargs) -> None: # Get next period time hour, minute = divmod(next_period * 15, 60) # Set hold time - setattr( - self._device, "hold_{}".format(mode), datetime.time(hour, minute) - ) + setattr(self._device, f"hold_{mode}", datetime.time(hour, minute)) # Set temperature - setattr(self._device, "setpoint_{}".format(mode), temperature) + setattr(self._device, f"setpoint_{mode}", temperature) except somecomfort.SomeComfortError: _LOGGER.error("Temperature %.1f out of range", temperature) @@ -375,17 +373,14 @@ def _turn_away_mode_on(self) -> None: try: # Set permanent hold - setattr(self._device, "hold_{}".format(mode), True) + setattr(self._device, f"hold_{mode}", True) # Set temperature setattr( - self._device, - "setpoint_{}".format(mode), - getattr(self, "_{}_away_temp".format(mode)), + self._device, f"setpoint_{mode}", getattr(self, f"_{mode}_away_temp") ) except somecomfort.SomeComfortError: _LOGGER.error( - "Temperature %.1f out of range", - getattr(self, "_{}_away_temp".format(mode)), + "Temperature %.1f out of range", getattr(self, f"_{mode}_away_temp") ) def _turn_away_mode_off(self) -> None: diff --git a/homeassistant/components/hp_ilo/sensor.py b/homeassistant/components/hp_ilo/sensor.py index 1ad70c06397d52..cf95c21a8d1e7e 100644 --- a/homeassistant/components/hp_ilo/sensor.py +++ b/homeassistant/components/hp_ilo/sensor.py @@ -194,4 +194,4 @@ def update(self): hpilo.IloCommunicationError, hpilo.IloLoginFailed, ) as error: - raise ValueError("Unable to init HP ILO, {}".format(error)) + raise ValueError(f"Unable to init HP ILO, {error}") diff --git a/homeassistant/components/html5/notify.py b/homeassistant/components/html5/notify.py index 18882968cf900a..ac76911b9f63ea 100644 --- a/homeassistant/components/html5/notify.py +++ b/homeassistant/components/html5/notify.py @@ -570,8 +570,8 @@ def create_vapid_headers(vapid_email, subscription_info, vapid_private_key): if vapid_email and vapid_private_key and ATTR_ENDPOINT in subscription_info: url = urlparse(subscription_info.get(ATTR_ENDPOINT)) vapid_claims = { - "sub": "mailto:{}".format(vapid_email), - "aud": "{}://{}".format(url.scheme, url.netloc), + "sub": f"mailto:{vapid_email}", + "aud": f"{url.scheme}://{url.netloc}", } vapid = Vapid.from_string(private_key=vapid_private_key) return vapid.sign(vapid_claims) diff --git a/homeassistant/components/htu21d/sensor.py b/homeassistant/components/htu21d/sensor.py index c2223720eb5b2e..f94b11d5ada003 100644 --- a/homeassistant/components/htu21d/sensor.py +++ b/homeassistant/components/htu21d/sensor.py @@ -76,7 +76,7 @@ class HTU21DSensor(Entity): def __init__(self, htu21d_client, name, variable, unit): """Initialize the sensor.""" - self._name = "{}_{}".format(name, variable) + self._name = f"{name}_{variable}" self._variable = variable self._unit_of_measurement = unit self._client = htu21d_client diff --git a/homeassistant/components/huawei_lte/sensor.py b/homeassistant/components/huawei_lte/sensor.py index a2b52d1c164eb7..cb8f5fb5766aab 100644 --- a/homeassistant/components/huawei_lte/sensor.py +++ b/homeassistant/components/huawei_lte/sensor.py @@ -175,7 +175,7 @@ class HuaweiLteSensor(Entity): @property def unique_id(self) -> str: """Return unique ID for sensor.""" - return "{}-{}".format(self.data.mac, self.path) + return f"{self.data.mac}-{self.path}" @property def name(self) -> str: diff --git a/homeassistant/components/huawei_router/device_tracker.py b/homeassistant/components/huawei_router/device_tracker.py index 08b7c9ec859b9c..b7b5731dfd3b87 100644 --- a/homeassistant/components/huawei_router/device_tracker.py +++ b/homeassistant/components/huawei_router/device_tracker.py @@ -119,12 +119,12 @@ def _get_data(self): def _get_devices_response(self): """Get the raw string with the devices from the router.""" - cnt = requests.post("http://{}/asp/GetRandCount.asp".format(self.host)) + cnt = requests.post(f"http://{self.host}/asp/GetRandCount.asp") cnt_str = str(cnt.content, cnt.apparent_encoding, errors="replace") _LOGGER.debug("Logging in") cookie = requests.post( - "http://{}/login.cgi".format(self.host), + f"http://{self.host}/login.cgi", data=[ ("UserName", self.username), ("PassWord", self.password), @@ -136,13 +136,13 @@ def _get_devices_response(self): _LOGGER.debug("Requesting lan user info update") # this request is needed or else some devices' state won't be updated requests.get( - "http://{}/html/bbsp/common/lanuserinfo.asp".format(self.host), + f"http://{self.host}/html/bbsp/common/lanuserinfo.asp", cookies=cookie.cookies, ) _LOGGER.debug("Requesting lan user info data") devices = requests.get( - "http://{}/html/bbsp/common/GetLanUserDevInfo.asp".format(self.host), + f"http://{self.host}/html/bbsp/common/GetLanUserDevInfo.asp", cookies=cookie.cookies, ) diff --git a/homeassistant/components/hue/config_flow.py b/homeassistant/components/hue/config_flow.py index 0b0e3723b138a1..9c0e94bc3bdce0 100644 --- a/homeassistant/components/hue/config_flow.py +++ b/homeassistant/components/hue/config_flow.py @@ -160,7 +160,7 @@ async def async_step_ssdp(self, discovery_info): { "host": host, # This format is the legacy format that Hue used for discovery - "path": "phue-{}.conf".format(serial), + "path": f"phue-{serial}.conf", } ) diff --git a/homeassistant/components/hydroquebec/sensor.py b/homeassistant/components/hydroquebec/sensor.py index 79de222397b991..fd713e8b7a7937 100644 --- a/homeassistant/components/hydroquebec/sensor.py +++ b/homeassistant/components/hydroquebec/sensor.py @@ -104,7 +104,7 @@ ) HOST = "https://www.hydroquebec.com" -HOME_URL = "{}/portail/web/clientele/authentification".format(HOST) +HOME_URL = f"{HOST}/portail/web/clientele/authentification" PROFILE_URL = "{}/portail/fr/group/clientele/" "portrait-de-consommation".format(HOST) MONTHLY_MAP = ( ("period_total_bill", "montantFacturePeriode"), @@ -164,7 +164,7 @@ def __init__(self, hydroquebec_data, sensor_type, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/ialarm/alarm_control_panel.py b/homeassistant/components/ialarm/alarm_control_panel.py index e98e712bc6ff7a..845c6b9021f1e2 100644 --- a/homeassistant/components/ialarm/alarm_control_panel.py +++ b/homeassistant/components/ialarm/alarm_control_panel.py @@ -28,7 +28,7 @@ def no_application_protocol(value): """Validate that value is without the application protocol.""" protocol_separator = "://" if not value or protocol_separator in value: - raise vol.Invalid("Invalid host, {} is not allowed".format(protocol_separator)) + raise vol.Invalid(f"Invalid host, {protocol_separator} is not allowed") return value @@ -52,7 +52,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): password = config.get(CONF_PASSWORD) host = config.get(CONF_HOST) - url = "http://{}".format(host) + url = f"http://{host}" ialarm = IAlarmPanel(name, code, username, password, url) add_entities([ialarm], True) diff --git a/homeassistant/components/icloud/device_tracker.py b/homeassistant/components/icloud/device_tracker.py index dbd4f54bac6022..2ecf904314fe4b 100644 --- a/homeassistant/components/icloud/device_tracker.py +++ b/homeassistant/components/icloud/device_tracker.py @@ -281,10 +281,10 @@ def icloud_need_trusted_device(self): devicename = device.get( "deviceName", "SMS to %s" % device.get("phoneNumber") ) - devicesstring += "{}: {};".format(i, devicename) + devicesstring += f"{i}: {devicename};" _CONFIGURING[self.accountname] = configurator.request_config( - "iCloud {}".format(self.accountname), + f"iCloud {self.accountname}", self.icloud_trusted_device_callback, description=( "Please choose your trusted device by entering" @@ -327,7 +327,7 @@ def icloud_need_verification_code(self): return _CONFIGURING[self.accountname] = configurator.request_config( - "iCloud {}".format(self.accountname), + f"iCloud {self.accountname}", self.icloud_verification_callback, description=("Please enter the validation code:"), entity_picture="/static/images/config_icloud.png", @@ -528,7 +528,7 @@ def setinterval(self, interval=None, devicename=None): """Set the interval of the given devices.""" devs = [devicename] if devicename else self.devices for device in devs: - devid = "{}.{}".format(DOMAIN, device) + devid = f"{DOMAIN}.{device}" devicestate = self.hass.states.get(devid) if interval is not None: if devicestate is not None: diff --git a/homeassistant/components/ign_sismologia/geo_location.py b/homeassistant/components/ign_sismologia/geo_location.py index abba8749663d1d..44ba41ea7835fe 100644 --- a/homeassistant/components/ign_sismologia/geo_location.py +++ b/homeassistant/components/ign_sismologia/geo_location.py @@ -210,9 +210,9 @@ def source(self) -> str: def name(self) -> Optional[str]: """Return the name of the entity.""" if self._magnitude and self._region: - return "M {:.1f} - {}".format(self._magnitude, self._region) + return f"M {self._magnitude:.1f} - {self._region}" if self._magnitude: - return "M {:.1f}".format(self._magnitude) + return f"M {self._magnitude:.1f}" if self._region: return self._region return self._title diff --git a/homeassistant/components/ihc/__init__.py b/homeassistant/components/ihc/__init__.py index 3be40058fec13f..a55b94eb26a5eb 100644 --- a/homeassistant/components/ihc/__init__.py +++ b/homeassistant/components/ihc/__init__.py @@ -61,7 +61,7 @@ def validate_name(config): if CONF_NAME in config: return config ihcid = config[CONF_ID] - name = "ihc_{}".format(ihcid) + name = f"ihc_{ihcid}" config[CONF_NAME] = name return config @@ -312,7 +312,7 @@ def get_discovery_info(component_setup, groups, controller_id): if "setting" in node.attrib and node.attrib["setting"] == "yes": continue ihc_id = int(node.attrib["id"].strip("_"), 0) - name = "{}_{}".format(groupname, ihc_id) + name = f"{groupname}_{ihc_id}" device = { "ihc_id": ihc_id, "ctrl_id": controller_id, diff --git a/homeassistant/components/imap_email_content/sensor.py b/homeassistant/components/imap_email_content/sensor.py index b1bab09fdcbf79..c5171cde646f14 100644 --- a/homeassistant/components/imap_email_content/sensor.py +++ b/homeassistant/components/imap_email_content/sensor.py @@ -118,7 +118,7 @@ def read_next(self): if not self._unread_ids: search = "SINCE {0:%d-%b-%Y}".format(datetime.date.today()) if self._last_id is not None: - search = "UID {}:*".format(self._last_id) + search = f"UID {self._last_id}:*" _, data = self.connection.uid("search", None, search) self._unread_ids = deque(data[0].split()) diff --git a/homeassistant/components/incomfort/climate.py b/homeassistant/components/incomfort/climate.py index 0d13caca3b7426..cccb9d256444dc 100644 --- a/homeassistant/components/incomfort/climate.py +++ b/homeassistant/components/incomfort/climate.py @@ -30,7 +30,7 @@ def __init__(self, client, room): """Initialize the climate device.""" self._client = client self._room = room - self._name = "Room {}".format(room.room_no) + self._name = f"Room {room.room_no}" async def async_added_to_hass(self) -> None: """Set up a listener when this entity is added to HA.""" diff --git a/homeassistant/components/incomfort/water_heater.py b/homeassistant/components/incomfort/water_heater.py index 7eeb618c87488e..2449a1223ccc5f 100644 --- a/homeassistant/components/incomfort/water_heater.py +++ b/homeassistant/components/incomfort/water_heater.py @@ -96,7 +96,7 @@ def supported_features(self): def current_operation(self): """Return the current operation mode.""" if self._heater.is_failed: - return "Fault code: {}".format(self._heater.fault_code) + return f"Fault code: {self._heater.fault_code}" return self._heater.display_text diff --git a/homeassistant/components/influxdb/__init__.py b/homeassistant/components/influxdb/__init__.py index e8d2cc54bf1e1d..2bb5207aa85408 100644 --- a/homeassistant/components/influxdb/__init__.py +++ b/homeassistant/components/influxdb/__init__.py @@ -247,7 +247,7 @@ def event_to_json(event): try: json["fields"][key] = float(value) except (ValueError, TypeError): - new_key = "{}_str".format(key) + new_key = f"{key}_str" new_value = str(value) json["fields"][new_key] = new_value diff --git a/homeassistant/components/insteon/__init__.py b/homeassistant/components/insteon/__init__.py index 2dda073aa182db..4015d472ce8d42 100644 --- a/homeassistant/components/insteon/__init__.py +++ b/homeassistant/components/insteon/__init__.py @@ -314,7 +314,7 @@ def load_aldb(service): def _send_load_aldb_signal(entity_id, reload): """Send the load All-Link database signal to INSTEON entity.""" - signal = "{}_{}".format(entity_id, SIGNAL_LOAD_ALDB) + signal = f"{entity_id}_{SIGNAL_LOAD_ALDB}" dispatcher_send(hass, signal, reload) def print_aldb(service): @@ -322,7 +322,7 @@ def print_aldb(service): # For now this sends logs to the log file. # Furture direction is to create an INSTEON control panel. entity_id = service.data[CONF_ENTITY_ID] - signal = "{}_{}".format(entity_id, SIGNAL_PRINT_ALDB) + signal = f"{entity_id}_{SIGNAL_PRINT_ALDB}" dispatcher_send(hass, signal) def print_im_aldb(service): @@ -652,9 +652,9 @@ async def async_added_to_hass(self): ) self._insteon_device_state.register_updates(self.async_entity_update) self.hass.data[DOMAIN][INSTEON_ENTITIES][self.entity_id] = self - load_signal = "{}_{}".format(self.entity_id, SIGNAL_LOAD_ALDB) + load_signal = f"{self.entity_id}_{SIGNAL_LOAD_ALDB}" async_dispatcher_connect(self.hass, load_signal, self._load_aldb) - print_signal = "{}_{}".format(self.entity_id, SIGNAL_PRINT_ALDB) + print_signal = f"{self.entity_id}_{SIGNAL_PRINT_ALDB}" async_dispatcher_connect(self.hass, print_signal, self._print_aldb) def _load_aldb(self, reload=False): @@ -679,7 +679,7 @@ def _get_label(self): if self._insteon_device_state.name in STATE_NAME_LABEL_MAP: label = STATE_NAME_LABEL_MAP[self._insteon_device_state.name] else: - label = "Group {:d}".format(self.group) + label = f"Group {self.group:d}" return label diff --git a/homeassistant/components/ios/sensor.py b/homeassistant/components/ios/sensor.py index 4da0d148f9c718..47c54c3faceecd 100644 --- a/homeassistant/components/ios/sensor.py +++ b/homeassistant/components/ios/sensor.py @@ -67,7 +67,7 @@ def state(self): def unique_id(self): """Return the unique ID of this sensor.""" device_id = self._device[ios.ATTR_DEVICE_ID] - return "{}_{}".format(self.type, device_id) + return f"{self.type}_{device_id}" @property def unit_of_measurement(self): @@ -100,11 +100,11 @@ def icon(self): ios.ATTR_BATTERY_STATE_UNPLUGGED, ): charging = False - icon_state = "{}-off".format(DEFAULT_ICON_STATE) + icon_state = f"{DEFAULT_ICON_STATE}-off" elif battery_state == ios.ATTR_BATTERY_STATE_UNKNOWN: battery_level = None charging = False - icon_state = "{}-unknown".format(DEFAULT_ICON_LEVEL) + icon_state = f"{DEFAULT_ICON_LEVEL}-unknown" if self.type == "state": return icon_state diff --git a/homeassistant/components/iota/sensor.py b/homeassistant/components/iota/sensor.py index a34d6ed021421f..8a0b17aa63bdab 100644 --- a/homeassistant/components/iota/sensor.py +++ b/homeassistant/components/iota/sensor.py @@ -46,7 +46,7 @@ def __init__(self, wallet_config, iota_config): @property def name(self): """Return the name of the sensor.""" - return "{} Balance".format(self._name) + return f"{self._name} Balance" @property def state(self): diff --git a/homeassistant/components/iperf3/__init__.py b/homeassistant/components/iperf3/__init__.py index 1a68eccb312a1a..eda601b09de3f0 100644 --- a/homeassistant/components/iperf3/__init__.py +++ b/homeassistant/components/iperf3/__init__.py @@ -19,7 +19,7 @@ from homeassistant.helpers.event import async_track_time_interval DOMAIN = "iperf3" -DATA_UPDATED = "{}_data_updated".format(DOMAIN) +DATA_UPDATED = f"{DOMAIN}_data_updated" _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/ipma/weather.py b/homeassistant/components/ipma/weather.py index fdaf5904aa1ea6..9f1836c73896fd 100644 --- a/homeassistant/components/ipma/weather.py +++ b/homeassistant/components/ipma/weather.py @@ -132,7 +132,7 @@ async def async_update(self): @property def unique_id(self) -> str: """Return a unique id.""" - return "{}, {}".format(self._station.latitude, self._station.longitude) + return f"{self._station.latitude}, {self._station.longitude}" @property def attribution(self): diff --git a/homeassistant/components/iqvia/__init__.py b/homeassistant/components/iqvia/__init__.py index b6930e1070f92d..e3add21c3a41d0 100644 --- a/homeassistant/components/iqvia/__init__.py +++ b/homeassistant/components/iqvia/__init__.py @@ -234,7 +234,7 @@ def state(self): @property def unique_id(self): """Return a unique, HASS-friendly identifier for this entity.""" - return "{0}_{1}".format(self._zip_code, self._type) + return f"{self._zip_code}_{self._type}" @property def unit_of_measurement(self): diff --git a/homeassistant/components/iqvia/sensor.py b/homeassistant/components/iqvia/sensor.py index f2fd1143b6ac95..90aa89f06d1699 100644 --- a/homeassistant/components/iqvia/sensor.py +++ b/homeassistant/components/iqvia/sensor.py @@ -174,9 +174,9 @@ async def async_update(self): index = idx + 1 self._attrs.update( { - "{0}_{1}".format(ATTR_ALLERGEN_GENUS, index): attrs["Genus"], - "{0}_{1}".format(ATTR_ALLERGEN_NAME, index): attrs["Name"], - "{0}_{1}".format(ATTR_ALLERGEN_TYPE, index): attrs["PlantType"], + f"{ATTR_ALLERGEN_GENUS}_{index}": attrs["Genus"], + f"{ATTR_ALLERGEN_NAME}_{index}": attrs["Name"], + f"{ATTR_ALLERGEN_TYPE}_{index}": attrs["PlantType"], } ) elif self._type in (TYPE_ASTHMA_TODAY, TYPE_ASTHMA_TOMORROW): @@ -184,8 +184,8 @@ async def async_update(self): index = idx + 1 self._attrs.update( { - "{0}_{1}".format(ATTR_ALLERGEN_NAME, index): attrs["Name"], - "{0}_{1}".format(ATTR_ALLERGEN_AMOUNT, index): attrs["PPM"], + f"{ATTR_ALLERGEN_NAME}_{index}": attrs["Name"], + f"{ATTR_ALLERGEN_AMOUNT}_{index}": attrs["PPM"], } ) elif self._type == TYPE_DISEASE_TODAY: diff --git a/homeassistant/components/isy994/__init__.py b/homeassistant/components/isy994/__init__.py index 9ad0f6beef154c..407196532ef7fd 100644 --- a/homeassistant/components/isy994/__init__.py +++ b/homeassistant/components/isy994/__init__.py @@ -343,7 +343,7 @@ def _categorize_programs(hass: HomeAssistant, programs: dict) -> None: """Categorize the ISY994 programs.""" for domain in SUPPORTED_PROGRAM_DOMAINS: try: - folder = programs[KEY_MY_PROGRAMS]["HA.{}".format(domain)] + folder = programs[KEY_MY_PROGRAMS][f"HA.{domain}"] except KeyError: pass else: @@ -378,10 +378,10 @@ def _categorize_weather(hass: HomeAssistant, climate) -> None: WeatherNode( getattr(climate, attr), attr.replace("_", " "), - getattr(climate, "{}_units".format(attr)), + getattr(climate, f"{attr}_units"), ) for attr in climate_attrs - if "{}_units".format(attr) in climate_attrs + if f"{attr}_units" in climate_attrs ] hass.data[ISY994_WEATHER].extend(weather_nodes) diff --git a/homeassistant/components/isy994/sensor.py b/homeassistant/components/isy994/sensor.py index a382c2f0830499..a9746b004d0493 100644 --- a/homeassistant/components/isy994/sensor.py +++ b/homeassistant/components/isy994/sensor.py @@ -272,7 +272,7 @@ def state(self) -> str: int_prec = int(self._node.prec) decimal_part = str_val[-int_prec:] whole_part = str_val[: len(str_val) - int_prec] - val = float("{}.{}".format(whole_part, decimal_part)) + val = float(f"{whole_part}.{decimal_part}") raw_units = self.raw_unit_of_measurement if raw_units in (TEMP_CELSIUS, TEMP_FAHRENHEIT): val = self.hass.config.units.temperature(val, raw_units) diff --git a/homeassistant/components/itach/remote.py b/homeassistant/components/itach/remote.py index db646338f409eb..9895b54a50dd43 100644 --- a/homeassistant/components/itach/remote.py +++ b/homeassistant/components/itach/remote.py @@ -78,7 +78,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): cmddata = cmd[CONF_DATA].strip() if not cmddata: cmddata = '""' - cmddatas += "{}\n{}\n".format(cmdname, cmddata) + cmddatas += f"{cmdname}\n{cmddata}\n" itachip2ir.addDevice(name, modaddr, connaddr, cmddatas) devices.append(ITachIP2IRRemote(itachip2ir, name)) add_entities(devices, True) diff --git a/homeassistant/components/itunes/media_player.py b/homeassistant/components/itunes/media_player.py index df8ae7bd556ba4..aebe16ffa26616 100644 --- a/homeassistant/components/itunes/media_player.py +++ b/homeassistant/components/itunes/media_player.py @@ -84,13 +84,13 @@ def _base_url(self): uri_scheme = "http://" if self.port: - return "{}{}:{}".format(uri_scheme, self.host, self.port) + return f"{uri_scheme}{self.host}:{self.port}" - return "{}{}".format(uri_scheme, self.host) + return f"{uri_scheme}{self.host}" def _request(self, method, path, params=None): """Make the actual request and return the parsed response.""" - url = "{}{}".format(self._base_url, path) + url = f"{self._base_url}{path}" try: if method == "GET": diff --git a/homeassistant/components/jewish_calendar/sensor.py b/homeassistant/components/jewish_calendar/sensor.py index 7e119494a20ec7..d298aee91436b4 100644 --- a/homeassistant/components/jewish_calendar/sensor.py +++ b/homeassistant/components/jewish_calendar/sensor.py @@ -129,7 +129,7 @@ def __init__( @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def icon(self): From f48ab8d977b22b4b5a4626f8f5caa6cfcffc250c Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 17:28:47 +0200 Subject: [PATCH 58/72] Removes executable but from hassfest codeowners (#26381) --- script/hassfest/codeowners.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 script/hassfest/codeowners.py diff --git a/script/hassfest/codeowners.py b/script/hassfest/codeowners.py old mode 100755 new mode 100644 From 34c66ab6ab180ef2903626992b57ed18e1f79691 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 3 Sep 2019 17:56:41 +0200 Subject: [PATCH 59/72] Update translations_upload --- script/translations_upload | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/translations_upload b/script/translations_upload index 52045e41d60c81..22a2bbceba202f 100755 --- a/script/translations_upload +++ b/script/translations_upload @@ -26,8 +26,8 @@ LANG_ISO=en CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) -# Check Travis and CircleCI environment as well -if [ "${CURRENT_BRANCH-}" != "dev" ] && [ "${TRAVIS_BRANCH-}" != "dev" ] && [ "${CIRCLE_BRANCH-}" != "dev" ]; then +# Check Travis and Azure environment as well +if [ "${CURRENT_BRANCH-}" != "dev" ] && [ "${TRAVIS_BRANCH-}" != "dev" ] && [ "${AZURE_BRANCH-}" != "dev" ]; then echo "Please only run the translations upload script from a clean checkout of dev." exit 1 fi From 025bf5f75ae6a0b0cae0fc29d95cf07b6099aeda Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 3 Sep 2019 17:58:00 +0200 Subject: [PATCH 60/72] Update azure-pipelines-translation.yml for Azure Pipelines --- azure-pipelines-translation.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines-translation.yml b/azure-pipelines-translation.yml index ad536aa9068d1c..6c82bd578035c6 100644 --- a/azure-pipelines-translation.yml +++ b/azure-pipelines-translation.yml @@ -25,3 +25,4 @@ jobs: displayName: 'Upload Translation' env: LOKALISE_TOKEN: $(lokaliseToken) + AZURE_BRANCH: $(Build.SourceBranch) From 04e58ebf6fa8db30023de5b3ed6fdbc793132274 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 3 Sep 2019 18:05:59 +0200 Subject: [PATCH 61/72] Update azure-pipelines-translation.yml for Azure Pipelines --- azure-pipelines-translation.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines-translation.yml b/azure-pipelines-translation.yml index 6c82bd578035c6..fe4f70c5bf60c0 100644 --- a/azure-pipelines-translation.yml +++ b/azure-pipelines-translation.yml @@ -21,8 +21,8 @@ jobs: inputs: versionSpec: '3.7' - script: | + export LOKALISE_TOKEN="$(lokaliseToken)" + export AZURE_BRANCH="$(Build.SourceBranch)" + ./script/translations_upload displayName: 'Upload Translation' - env: - LOKALISE_TOKEN: $(lokaliseToken) - AZURE_BRANCH: $(Build.SourceBranch) From 01dd59e338888205d333ba498cc39f79234372b9 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 3 Sep 2019 18:07:23 +0200 Subject: [PATCH 62/72] Update azure-pipelines-release.yml for Azure Pipelines --- azure-pipelines-release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 510e16a351c14f..63ce5b707cf6b2 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -68,11 +68,11 @@ stages: - script: python setup.py sdist bdist_wheel displayName: 'Build package' - script: | + TWINE_USERNAME="$(twineUser)" + TWINE_PASSWORD="$(twinePassword)" + twine upload dist/* --skip-existing displayName: 'Upload pypi' - env: - TWINE_USERNAME: '$(twineUser)' - TWINE_PASSWORD: '$(twinePassword)' - job: 'ReleaseDocker' timeoutInMinutes: 240 pool: From 65cac5dab1830eaea75f776d02d5e8686963f377 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 3 Sep 2019 18:09:08 +0200 Subject: [PATCH 63/72] Update azure-pipelines-translation.yml for Azure Pipelines --- azure-pipelines-translation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines-translation.yml b/azure-pipelines-translation.yml index fe4f70c5bf60c0..05514ae3273485 100644 --- a/azure-pipelines-translation.yml +++ b/azure-pipelines-translation.yml @@ -22,7 +22,7 @@ jobs: versionSpec: '3.7' - script: | export LOKALISE_TOKEN="$(lokaliseToken)" - export AZURE_BRANCH="$(Build.SourceBranch)" + export AZURE_BRANCH="$(Build.SourceBranchName)" ./script/translations_upload displayName: 'Upload Translation' From 599f9cee09a10771b932af05b77cbae5e4e2f7fe Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 3 Sep 2019 19:09:25 +0200 Subject: [PATCH 64/72] Add support Slide cover (#25913) * Add support GoSlide cover * Fixed Parameters differ from overridden Fixed Removed other pylint warnings * Renamed GoSlide to Slide, because of Innovation in Motion rebranding * Fixed codeowners file * Fixed requirements file * Removed pylint: disable=unused-argument Removed DOMAIN not exist check Changed if to min/max Changed 3rd party import to top of the module Removed timeout/retry parameters Removed unused constants Added check for discovery_info is none Changed pass slide object instead of full hass object Changed pass api object instead of full hass object Added unique_id functionality Removed entity_id/name properties Removed supported_features/state functions * Fixed unused variables * Changed Slide API uses snake names Changed Improved exception handling Changed Updated Slide API to 0.50.0 * Changed moved exceptions into goslide-api Changed retry setup into coroutine * Changed str(err) to err Changed invert if result to if not result --- .coveragerc | 1 + CODEOWNERS | 1 + homeassistant/components/slide/__init__.py | 157 +++++++++++++++++++ homeassistant/components/slide/const.py | 7 + homeassistant/components/slide/cover.py | 124 +++++++++++++++ homeassistant/components/slide/manifest.json | 12 ++ requirements_all.txt | 3 + 7 files changed, 305 insertions(+) create mode 100755 homeassistant/components/slide/__init__.py create mode 100644 homeassistant/components/slide/const.py create mode 100644 homeassistant/components/slide/cover.py create mode 100644 homeassistant/components/slide/manifest.json diff --git a/.coveragerc b/.coveragerc index df87a5a1f71d70..6583f6e0ae5e1b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -564,6 +564,7 @@ omit = homeassistant/components/skybeacon/sensor.py homeassistant/components/skybell/* homeassistant/components/slack/notify.py + homeassistant/components/slide/* homeassistant/components/sma/sensor.py homeassistant/components/smappee/* homeassistant/components/smarty/* diff --git a/CODEOWNERS b/CODEOWNERS index 27c4f03ae93720..9c2c8673e6e365 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -236,6 +236,7 @@ homeassistant/components/shell_command/* @home-assistant/core homeassistant/components/shiftr/* @fabaff homeassistant/components/shodan/* @fabaff homeassistant/components/simplisafe/* @bachya +homeassistant/components/slide/* @ualex73 homeassistant/components/sma/* @kellerza homeassistant/components/smarthab/* @outadoc homeassistant/components/smartthings/* @andrewsayre diff --git a/homeassistant/components/slide/__init__.py b/homeassistant/components/slide/__init__.py new file mode 100755 index 00000000000000..54154ae863ee83 --- /dev/null +++ b/homeassistant/components/slide/__init__.py @@ -0,0 +1,157 @@ +"""Component for the Go Slide API.""" + +import logging +from datetime import timedelta + +import voluptuous as vol +from goslideapi import GoSlideCloud, goslideapi + +from homeassistant.const import ( + CONF_USERNAME, + CONF_PASSWORD, + CONF_SCAN_INTERVAL, + STATE_OPEN, + STATE_CLOSED, + STATE_OPENING, + STATE_CLOSING, +) +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.discovery import async_load_platform +from homeassistant.helpers.event import async_track_time_interval, async_call_later +from .const import DOMAIN, SLIDES, API, COMPONENT, DEFAULT_RETRY + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_SCAN_INTERVAL = timedelta(seconds=30) + +CONFIG_SCHEMA = vol.Schema( + { + DOMAIN: vol.Schema( + { + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional( + CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL + ): cv.time_period, + } + ) + }, + extra=vol.ALLOW_EXTRA, +) + + +async def async_setup(hass, config): + """Set up the Slide platform.""" + + async def update_slides(now=None): + """Update slide information.""" + result = await hass.data[DOMAIN][API].slides_overview() + + if result is None: + _LOGGER.error("Slide API does not work or returned an error") + return + + if result: + _LOGGER.debug("Slide API returned %d slide(s)", len(result)) + else: + _LOGGER.warning("Slide API returned 0 slides") + + for slide in result: + if "device_id" not in slide: + _LOGGER.error( + "Found invalid Slide entry, device_id is " "missing. Entry=%s", + slide, + ) + continue + + uid = slide["device_id"].replace("slide_", "") + slidenew = hass.data[DOMAIN][SLIDES].setdefault(uid, {}) + slidenew["mac"] = uid + slidenew["id"] = slide["id"] + slidenew["name"] = slide["device_name"] + slidenew["state"] = None + oldpos = slidenew.get("pos") + slidenew["pos"] = None + slidenew["online"] = False + + if "device_info" not in slide: + _LOGGER.error( + "Slide %s (%s) has no device_info Entry=%s", + slide["id"], + slidenew["mac"], + slide, + ) + continue + + # Check if we have pos (OK) or code (NOK) + if "pos" in slide["device_info"]: + slidenew["online"] = True + slidenew["pos"] = slide["device_info"]["pos"] + slidenew["pos"] = max(0, min(1, slidenew["pos"])) + + if oldpos is None or oldpos == slidenew["pos"]: + slidenew["state"] = ( + STATE_CLOSED if slidenew["pos"] > 0.95 else STATE_OPEN + ) + elif oldpos < slidenew["pos"]: + slidenew["state"] = ( + STATE_CLOSED if slidenew["pos"] >= 0.95 else STATE_CLOSING + ) + else: + slidenew["state"] = ( + STATE_OPEN if slidenew["pos"] <= 0.05 else STATE_OPENING + ) + elif "code" in slide["device_info"]: + _LOGGER.warning( + "Slide %s (%s) is offline with " "code=%s", + slide["id"], + slidenew["mac"], + slide["device_info"]["code"], + ) + else: + _LOGGER.error( + "Slide %s (%s) has invalid device_info %s", + slide["id"], + slidenew["mac"], + slide["device_info"], + ) + + _LOGGER.debug("Updated entry=%s", slidenew) + + async def retry_setup(now): + """Retry setup if a connection/timeout happens on Slide API.""" + await async_setup(hass, config) + + hass.data[DOMAIN] = {} + hass.data[DOMAIN][SLIDES] = {} + + username = config[DOMAIN][CONF_USERNAME] + password = config[DOMAIN][CONF_PASSWORD] + scaninterval = config[DOMAIN][CONF_SCAN_INTERVAL] + + hass.data[DOMAIN][API] = GoSlideCloud(username, password) + + try: + result = await hass.data[DOMAIN][API].login() + except (goslideapi.ClientConnectionError, goslideapi.ClientTimeoutError) as err: + _LOGGER.error( + "Error connecting to Slide Cloud: %s, going to retry in %s seconds", + err, + DEFAULT_RETRY, + ) + async_call_later(hass, DEFAULT_RETRY, retry_setup) + return True + + if not result: + _LOGGER.error("Slide API returned unknown error during authentication") + return False + + _LOGGER.debug("Slide API successfully authenticated") + + await update_slides() + + hass.async_create_task(async_load_platform(hass, COMPONENT, DOMAIN, {}, config)) + + async_track_time_interval(hass, update_slides, scaninterval) + + return True diff --git a/homeassistant/components/slide/const.py b/homeassistant/components/slide/const.py new file mode 100644 index 00000000000000..de3d2e560c1f2d --- /dev/null +++ b/homeassistant/components/slide/const.py @@ -0,0 +1,7 @@ +"""Define constants for the Go Slide component.""" + +API = "api" +COMPONENT = "cover" +DOMAIN = "slide" +SLIDES = "slides" +DEFAULT_RETRY = 120 diff --git a/homeassistant/components/slide/cover.py b/homeassistant/components/slide/cover.py new file mode 100644 index 00000000000000..1c4e6da5aaca6b --- /dev/null +++ b/homeassistant/components/slide/cover.py @@ -0,0 +1,124 @@ +"""Support for Go Slide slides.""" + +import logging + +from homeassistant.const import ATTR_ID +from homeassistant.components.cover import ( + ATTR_POSITION, + STATE_CLOSED, + STATE_OPENING, + STATE_CLOSING, + DEVICE_CLASS_CURTAIN, + CoverDevice, +) +from .const import API, DOMAIN, SLIDES + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): + """Set up cover(s) for Go Slide platform.""" + + if discovery_info is None: + return + + entities = [] + + for slide in hass.data[DOMAIN][SLIDES].values(): + _LOGGER.debug("Setting up Slide entity: %s", slide) + entities.append(SlideCover(hass.data[DOMAIN][API], slide)) + + async_add_entities(entities) + + +class SlideCover(CoverDevice): + """Representation of a Go Slide cover.""" + + def __init__(self, api, slide): + """Initialize the cover.""" + self._api = api + self._slide = slide + self._id = slide["id"] + self._unique_id = slide["mac"] + self._name = slide["name"] + + @property + def unique_id(self): + """Return the device unique id.""" + return self._unique_id + + @property + def name(self): + """Return the device name.""" + return self._name + + @property + def device_state_attributes(self): + """Return device specific state attributes.""" + return {ATTR_ID: self._id} + + @property + def is_opening(self): + """Return if the cover is opening or not.""" + return self._slide["state"] == STATE_OPENING + + @property + def is_closing(self): + """Return if the cover is closing or not.""" + return self._slide["state"] == STATE_CLOSING + + @property + def is_closed(self): + """Return None if status is unknown, True if closed, else False.""" + if self._slide["state"] is None: + return None + return self._slide["state"] == STATE_CLOSED + + @property + def available(self): + """Return False if state is not available.""" + return self._slide["online"] + + @property + def assumed_state(self): + """Let HA know the integration is assumed state.""" + return True + + @property + def device_class(self): + """Return the device class of the cover.""" + return DEVICE_CLASS_CURTAIN + + @property + def current_cover_position(self): + """Return the current position of cover shutter.""" + pos = self._slide["pos"] + if pos is not None: + pos = int(pos * 100) + return pos + + async def async_open_cover(self, **kwargs): + """Open the cover.""" + self._slide["state"] = STATE_OPENING + await self._api.slide_open(self._id) + + async def async_close_cover(self, **kwargs): + """Close the cover.""" + self._slide["state"] = STATE_CLOSING + await self._api.slide_close(self._id) + + async def async_stop_cover(self, **kwargs): + """Stop the cover.""" + await self._api.slide_stop(self._id) + + async def async_set_cover_position(self, **kwargs): + """Move the cover to a specific position.""" + position = kwargs[ATTR_POSITION] / 100 + + if self._slide["pos"] is not None: + if position > self._slide["pos"]: + self._slide["state"] = STATE_CLOSING + else: + self._slide["state"] = STATE_OPENING + + await self._api.slide_set_position(self._id, position) diff --git a/homeassistant/components/slide/manifest.json b/homeassistant/components/slide/manifest.json new file mode 100644 index 00000000000000..f9fd7f242b6332 --- /dev/null +++ b/homeassistant/components/slide/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "slide", + "name": "Slide", + "documentation": "https://www.home-assistant.io/components/slide", + "requirements": [ + "goslide-api==0.5.1" + ], + "dependencies": [], + "codeowners": [ + "@ualex73" + ] +} diff --git a/requirements_all.txt b/requirements_all.txt index 33367248372b06..349f46d47f1a8b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -567,6 +567,9 @@ google-cloud-texttospeech==0.4.0 # homeassistant.components.google_travel_time googlemaps==2.5.1 +# homeassistant.components.slide +goslide-api==0.5.1 + # homeassistant.components.remote_rpi_gpio gpiozero==1.4.1 From 9e12f94e7d83d67c32c00ab44e4ddfc25064dcda Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 20:35:00 +0200 Subject: [PATCH 65/72] Use literal string interpolation in integrations N-Q (f-strings) (#26391) --- homeassistant/components/neato/vacuum.py | 2 +- homeassistant/components/nello/lock.py | 2 +- homeassistant/components/nest/__init__.py | 2 +- homeassistant/components/nest/binary_sensor.py | 4 ++-- homeassistant/components/nest/local_auth.py | 2 +- homeassistant/components/netatmo/binary_sensor.py | 2 +- homeassistant/components/netatmo/camera.py | 4 ++-- homeassistant/components/netatmo/climate.py | 2 +- homeassistant/components/netdata/sensor.py | 2 +- homeassistant/components/netgear_lte/__init__.py | 4 ++-- homeassistant/components/nextbus/sensor.py | 6 ++---- homeassistant/components/nfandroidtv/notify.py | 2 +- homeassistant/components/niko_home_control/light.py | 2 +- homeassistant/components/nilu/air_quality.py | 2 +- homeassistant/components/nmbs/sensor.py | 8 ++++---- homeassistant/components/no_ip/__init__.py | 4 ++-- homeassistant/components/noaa_tides/sensor.py | 4 ++-- homeassistant/components/notify/__init__.py | 4 ++-- homeassistant/components/nsw_fuel_station/sensor.py | 2 +- .../components/nx584/alarm_control_panel.py | 2 +- homeassistant/components/nx584/binary_sensor.py | 2 +- homeassistant/components/nzbget/sensor.py | 2 +- homeassistant/components/octoprint/binary_sensor.py | 4 ++-- homeassistant/components/octoprint/sensor.py | 2 +- homeassistant/components/onboarding/views.py | 2 +- homeassistant/components/onvif/camera.py | 2 +- homeassistant/components/opengarage/cover.py | 7 ++----- homeassistant/components/opensky/sensor.py | 4 ++-- homeassistant/components/opentherm_gw/__init__.py | 6 +++--- .../components/opentherm_gw/binary_sensor.py | 2 +- homeassistant/components/opentherm_gw/sensor.py | 4 ++-- homeassistant/components/openuv/__init__.py | 2 +- homeassistant/components/openuv/binary_sensor.py | 2 +- homeassistant/components/openuv/sensor.py | 2 +- homeassistant/components/openweathermap/sensor.py | 2 +- homeassistant/components/owlet/__init__.py | 2 +- homeassistant/components/owntracks/__init__.py | 6 +++--- homeassistant/components/owntracks/messages.py | 4 ++-- homeassistant/components/pandora/media_player.py | 2 +- homeassistant/components/panel_custom/__init__.py | 2 +- homeassistant/components/philips_js/media_player.py | 2 +- homeassistant/components/pi_hole/sensor.py | 2 +- homeassistant/components/pjlink/media_player.py | 4 ++-- homeassistant/components/plaato/__init__.py | 6 +++--- homeassistant/components/plaato/sensor.py | 13 +++++-------- homeassistant/components/plant/__init__.py | 12 ++++++------ homeassistant/components/plex/media_player.py | 6 +++--- homeassistant/components/plex/sensor.py | 6 +++--- homeassistant/components/plum_lightpad/light.py | 2 +- homeassistant/components/point/__init__.py | 6 +++--- .../components/point/alarm_control_panel.py | 2 +- homeassistant/components/prezzibenzina/sensor.py | 2 +- homeassistant/components/proximity/__init__.py | 2 +- homeassistant/components/ps4/__init__.py | 2 +- homeassistant/components/pushetta/notify.py | 4 +--- homeassistant/components/pushsafer/notify.py | 2 +- homeassistant/components/pyload/sensor.py | 2 +- homeassistant/components/qbittorrent/sensor.py | 2 +- homeassistant/components/qnap/sensor.py | 8 ++++---- homeassistant/components/qwikswitch/__init__.py | 2 +- .../components/qwikswitch/binary_sensor.py | 2 +- homeassistant/components/qwikswitch/sensor.py | 4 ++-- 62 files changed, 103 insertions(+), 113 deletions(-) diff --git a/homeassistant/components/neato/vacuum.py b/homeassistant/components/neato/vacuum.py index d7d824c244c07a..93fe285dcfdb69 100644 --- a/homeassistant/components/neato/vacuum.py +++ b/homeassistant/components/neato/vacuum.py @@ -127,7 +127,7 @@ def __init__(self, hass, robot): """Initialize the Neato Connected Vacuum.""" self.robot = robot self.neato = hass.data[NEATO_LOGIN] - self._name = "{}".format(self.robot.name) + self._name = f"{self.robot.name}" self._status_state = None self._clean_state = None self._state = None diff --git a/homeassistant/components/nello/lock.py b/homeassistant/components/nello/lock.py index 5ae8bb6196855f..3efe0a9cc5fc1b 100644 --- a/homeassistant/components/nello/lock.py +++ b/homeassistant/components/nello/lock.py @@ -59,7 +59,7 @@ def update(self): location_id = self._nello_lock.location_id short_id = self._nello_lock.short_id address = self._nello_lock.address - self._name = "Nello {}".format(short_id) + self._name = f"Nello {short_id}" self._device_attrs = {ATTR_ADDRESS: address, ATTR_LOCATION_ID: location_id} # Process recent activity activity = self._nello_lock.activity diff --git a/homeassistant/components/nest/__init__.py b/homeassistant/components/nest/__init__.py index b7033bbfd63b6c..cf1ba36aa89320 100644 --- a/homeassistant/components/nest/__init__.py +++ b/homeassistant/components/nest/__init__.py @@ -405,7 +405,7 @@ def should_poll(self): @property def unique_id(self): """Return unique id based on device serial and variable.""" - return "{}-{}".format(self.device.serial, self.variable) + return f"{self.device.serial}-{self.variable}" @property def device_info(self): diff --git a/homeassistant/components/nest/binary_sensor.py b/homeassistant/components/nest/binary_sensor.py index d335acc2bf107c..0f3ae7da710edf 100644 --- a/homeassistant/components/nest/binary_sensor.py +++ b/homeassistant/components/nest/binary_sensor.py @@ -143,12 +143,12 @@ def __init__(self, structure, device, zone): """Initialize the sensor.""" super(NestActivityZoneSensor, self).__init__(structure, device, "") self.zone = zone - self._name = "{} {} activity".format(self._name, self.zone.name) + self._name = f"{self._name} {self.zone.name} activity" @property def unique_id(self): """Return unique id based on camera serial and zone id.""" - return "{}-{}".format(self.device.serial, self.zone.zone_id) + return f"{self.device.serial}-{self.zone.zone_id}" @property def device_class(self): diff --git a/homeassistant/components/nest/local_auth.py b/homeassistant/components/nest/local_auth.py index c60d09a60028d4..51d826c242fbd0 100644 --- a/homeassistant/components/nest/local_auth.py +++ b/homeassistant/components/nest/local_auth.py @@ -45,5 +45,5 @@ async def resolve_auth_code(hass, client_id, client_secret, code): if err.response.status_code == 401: raise config_flow.CodeInvalid() raise config_flow.NestAuthError( - "Unknown error: {} ({})".format(err, err.response.status_code) + f"Unknown error: {err} ({err.response.status_code})" ) diff --git a/homeassistant/components/netatmo/binary_sensor.py b/homeassistant/components/netatmo/binary_sensor.py index 2f2f3f9e182d97..591cd790ecf5d7 100644 --- a/homeassistant/components/netatmo/binary_sensor.py +++ b/homeassistant/components/netatmo/binary_sensor.py @@ -152,7 +152,7 @@ def __init__( self._home = home self._timeout = timeout if home: - self._name = "{} / {}".format(home, camera_name) + self._name = f"{home} / {camera_name}" else: self._name = camera_name if module_name: diff --git a/homeassistant/components/netatmo/camera.py b/homeassistant/components/netatmo/camera.py index ec55394105c9ea..d18ff9fc46c800 100644 --- a/homeassistant/components/netatmo/camera.py +++ b/homeassistant/components/netatmo/camera.py @@ -88,11 +88,11 @@ def camera_image(self): try: if self._localurl: response = requests.get( - "{0}/live/snapshot_720.jpg".format(self._localurl), timeout=10 + f"{self._localurl}/live/snapshot_720.jpg", timeout=10 ) elif self._vpnurl: response = requests.get( - "{0}/live/snapshot_720.jpg".format(self._vpnurl), + f"{self._vpnurl}/live/snapshot_720.jpg", timeout=10, verify=self._verify_ssl, ) diff --git a/homeassistant/components/netatmo/climate.py b/homeassistant/components/netatmo/climate.py index 9656d4a37a451c..1465058652dea2 100644 --- a/homeassistant/components/netatmo/climate.py +++ b/homeassistant/components/netatmo/climate.py @@ -154,7 +154,7 @@ def __init__(self, data, room_id): self._state = None self._room_id = room_id self._room_name = self._data.homedata.rooms[self._data.home_id][room_id]["name"] - self._name = "netatmo_{}".format(self._room_name) + self._name = f"netatmo_{self._room_name}" self._current_temperature = None self._target_temperature = None self._preset = None diff --git a/homeassistant/components/netdata/sensor.py b/homeassistant/components/netdata/sensor.py index 8fa18a7f19c034..aab901506a8f40 100644 --- a/homeassistant/components/netdata/sensor.py +++ b/homeassistant/components/netdata/sensor.py @@ -112,7 +112,7 @@ def __init__(self, netdata, name, sensor, sensor_name, element, icon, unit, inve @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._name, self._sensor_name) + return f"{self._name} {self._sensor_name}" @property def unit_of_measurement(self): diff --git a/homeassistant/components/netgear_lte/__init__.py b/homeassistant/components/netgear_lte/__init__.py index e4909ce68fc599..2514b37657fb05 100644 --- a/homeassistant/components/netgear_lte/__init__.py +++ b/homeassistant/components/netgear_lte/__init__.py @@ -350,7 +350,7 @@ class LTEEntity(Entity): @_unique_id.default def _init_unique_id(self): """Register unique_id while we know data is valid.""" - return "{}_{}".format(self.sensor_type, self.modem_data.data.serial_number) + return f"{self.sensor_type}_{self.modem_data.data.serial_number}" async def async_added_to_hass(self): """Register callback.""" @@ -380,4 +380,4 @@ def unique_id(self): @property def name(self): """Return the name of the sensor.""" - return "Netgear LTE {}".format(self.sensor_type) + return f"Netgear LTE {self.sensor_type}" diff --git a/homeassistant/components/nextbus/sensor.py b/homeassistant/components/nextbus/sensor.py index 3f9a5e01817b83..661eb75b732663 100644 --- a/homeassistant/components/nextbus/sensor.py +++ b/homeassistant/components/nextbus/sensor.py @@ -62,9 +62,7 @@ def validate_value(value_name, value, value_list): "Invalid %s tag `%s`. Please use one of the following: %s", value_name, value, - ", ".join( - "{}: {}".format(title, tag) for tag, title in valid_values.items() - ), + ", ".join(f"{title}: {tag}" for tag, title in valid_values.items()), ) return False @@ -126,7 +124,7 @@ def __init__(self, client, agency, route, stop, name=None): self.stop = stop self._custom_name = name # Maybe pull a more user friendly name from the API here - self._name = "{} {}".format(agency, route) + self._name = f"{agency} {route}" self._client = client # set up default state attributes diff --git a/homeassistant/components/nfandroidtv/notify.py b/homeassistant/components/nfandroidtv/notify.py index d828ed9d98aad8..36eed0a11db8a1 100644 --- a/homeassistant/components/nfandroidtv/notify.py +++ b/homeassistant/components/nfandroidtv/notify.py @@ -137,7 +137,7 @@ def __init__( is_allowed_path, ): """Initialize the service.""" - self._target = "http://{}:7676".format(remoteip) + self._target = f"http://{remoteip}:7676" self._default_duration = duration self._default_fontsize = fontsize self._default_position = position diff --git a/homeassistant/components/niko_home_control/light.py b/homeassistant/components/niko_home_control/light.py index af93ee0da69952..4cb8495600232a 100644 --- a/homeassistant/components/niko_home_control/light.py +++ b/homeassistant/components/niko_home_control/light.py @@ -46,7 +46,7 @@ def __init__(self, light, data): """Set up the Niko Home Control light platform.""" self._data = data self._light = light - self._unique_id = "light-{}".format(light.id) + self._unique_id = f"light-{light.id}" self._name = light.name self._state = light.is_on self._brightness = None diff --git a/homeassistant/components/nilu/air_quality.py b/homeassistant/components/nilu/air_quality.py index 246ff10b11711f..8d3d61befd5076 100644 --- a/homeassistant/components/nilu/air_quality.py +++ b/homeassistant/components/nilu/air_quality.py @@ -147,7 +147,7 @@ class NiluSensor(AirQualityEntity): def __init__(self, api_data: NiluData, name: str, show_on_map: bool): """Initialize the sensor.""" self._api = api_data - self._name = "{} {}".format(name, api_data.data.name) + self._name = f"{name} {api_data.data.name}" self._max_aqi = None self._attrs = {} diff --git a/homeassistant/components/nmbs/sensor.py b/homeassistant/components/nmbs/sensor.py index 59aa112622296e..8b2182665f64ef 100644 --- a/homeassistant/components/nmbs/sensor.py +++ b/homeassistant/components/nmbs/sensor.py @@ -124,7 +124,7 @@ def device_state_attributes(self): departure = get_time_until(self._attrs["time"]) attrs = { - "departure": "In {} minutes".format(departure), + "departure": f"In {departure} minutes", "extra_train": int(self._attrs["isExtra"]) > 0, "vehicle_id": self._attrs["vehicle"], "monitored_station": self._station, @@ -132,7 +132,7 @@ def device_state_attributes(self): } if delay > 0: - attrs["delay"] = "{} minutes".format(delay) + attrs["delay"] = f"{delay} minutes" return attrs @@ -194,7 +194,7 @@ def device_state_attributes(self): departure = get_time_until(self._attrs["departure"]["time"]) attrs = { - "departure": "In {} minutes".format(departure), + "departure": f"In {departure} minutes", "destination": self._station_to, "direction": self._attrs["departure"]["direction"]["name"], "platform_arriving": self._attrs["arrival"]["platform"], @@ -218,7 +218,7 @@ def device_state_attributes(self): ) + get_delay_in_minutes(via["departure"]["delay"]) if delay > 0: - attrs["delay"] = "{} minutes".format(delay) + attrs["delay"] = f"{delay} minutes" return attrs diff --git a/homeassistant/components/no_ip/__init__.py b/homeassistant/components/no_ip/__init__.py index 2fa9d45a8b2e41..70ac7099d30727 100644 --- a/homeassistant/components/no_ip/__init__.py +++ b/homeassistant/components/no_ip/__init__.py @@ -34,7 +34,7 @@ } UPDATE_URL = "https://dynupdate.noip.com/nic/update" -HA_USER_AGENT = "{} {}".format(SERVER_SOFTWARE, EMAIL) +HA_USER_AGENT = f"{SERVER_SOFTWARE} {EMAIL}" CONFIG_SCHEMA = vol.Schema( { @@ -58,7 +58,7 @@ async def async_setup(hass, config): password = config[DOMAIN].get(CONF_PASSWORD) timeout = config[DOMAIN].get(CONF_TIMEOUT) - auth_str = base64.b64encode("{}:{}".format(user, password).encode("utf-8")) + auth_str = base64.b64encode(f"{user}:{password}".encode("utf-8")) session = hass.helpers.aiohttp_client.async_get_clientsession() diff --git a/homeassistant/components/noaa_tides/sensor.py b/homeassistant/components/noaa_tides/sensor.py index 2b3d2e42d4d5fe..e5f31dba1568b3 100644 --- a/homeassistant/components/noaa_tides/sensor.py +++ b/homeassistant/components/noaa_tides/sensor.py @@ -101,10 +101,10 @@ def state(self): api_time = self.data.index[0] if self.data["hi_lo"][0] == "H": tidetime = api_time.strftime("%-I:%M %p") - return "High tide at {}".format(tidetime) + return f"High tide at {tidetime}" if self.data["hi_lo"][0] == "L": tidetime = api_time.strftime("%-I:%M %p") - return "Low tide at {}".format(tidetime) + return f"Low tide at {tidetime}" return None def update(self): diff --git a/homeassistant/components/notify/__init__.py b/homeassistant/components/notify/__init__.py index 773c08808c3056..6ede7f18da732b 100644 --- a/homeassistant/components/notify/__init__.py +++ b/homeassistant/components/notify/__init__.py @@ -124,7 +124,7 @@ async def async_notify_message(service): p_config.get(CONF_NAME) or discovery_info.get(CONF_NAME) or p_type ) for name, target in notify_service.targets.items(): - target_name = slugify("{}_{}".format(platform_name, name)) + target_name = slugify(f"{platform_name}_{name}") targets[target_name] = target hass.services.async_register( DOMAIN, @@ -145,7 +145,7 @@ async def async_notify_message(service): schema=NOTIFY_SERVICE_SCHEMA, ) - hass.config.components.add("{}.{}".format(DOMAIN, p_type)) + hass.config.components.add(f"{DOMAIN}.{p_type}") return True diff --git a/homeassistant/components/nsw_fuel_station/sensor.py b/homeassistant/components/nsw_fuel_station/sensor.py index 4c3258b6effc5e..a84aa554be910c 100644 --- a/homeassistant/components/nsw_fuel_station/sensor.py +++ b/homeassistant/components/nsw_fuel_station/sensor.py @@ -141,7 +141,7 @@ def get_station_name(self) -> str: None, ) - self._station_name = name or "station {}".format(self.station_id) + self._station_name = name or f"station {self.station_id}" return self._station_name diff --git a/homeassistant/components/nx584/alarm_control_panel.py b/homeassistant/components/nx584/alarm_control_panel.py index abe5f2a126e82b..d3d867ff378678 100644 --- a/homeassistant/components/nx584/alarm_control_panel.py +++ b/homeassistant/components/nx584/alarm_control_panel.py @@ -38,7 +38,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): host = config.get(CONF_HOST) port = config.get(CONF_PORT) - url = "http://{}:{}".format(host, port) + url = f"http://{host}:{port}" try: add_entities([NX584Alarm(hass, url, name)]) diff --git a/homeassistant/components/nx584/binary_sensor.py b/homeassistant/components/nx584/binary_sensor.py index e3af407a53dc1e..8b26a958a6ffa7 100644 --- a/homeassistant/components/nx584/binary_sensor.py +++ b/homeassistant/components/nx584/binary_sensor.py @@ -47,7 +47,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): zone_types = config.get(CONF_ZONE_TYPES) try: - client = nx584_client.Client("http://{}:{}".format(host, port)) + client = nx584_client.Client(f"http://{host}:{port}") zones = client.list_zones() except requests.exceptions.ConnectionError as ex: _LOGGER.error("Unable to connect to NX584: %s", str(ex)) diff --git a/homeassistant/components/nzbget/sensor.py b/homeassistant/components/nzbget/sensor.py index 50fdf004739a1d..73643a5383cea1 100644 --- a/homeassistant/components/nzbget/sensor.py +++ b/homeassistant/components/nzbget/sensor.py @@ -65,7 +65,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): password = config.get(CONF_PASSWORD) monitored_types = config.get(CONF_MONITORED_VARIABLES) - url = "http{}://{}:{}/jsonrpc".format(ssl, host, port) + url = f"http{ssl}://{host}:{port}/jsonrpc" try: nzbgetapi = NZBGetAPI(api_url=url, username=username, password=password) diff --git a/homeassistant/components/octoprint/binary_sensor.py b/homeassistant/components/octoprint/binary_sensor.py index ea457ee19c79a8..7ed1170c6a0f22 100644 --- a/homeassistant/components/octoprint/binary_sensor.py +++ b/homeassistant/components/octoprint/binary_sensor.py @@ -45,9 +45,9 @@ def __init__( """Initialize a new OctoPrint sensor.""" self.sensor_name = sensor_name if tool is None: - self._name = "{} {}".format(sensor_name, condition) + self._name = f"{sensor_name} {condition}" else: - self._name = "{} {}".format(sensor_name, condition) + self._name = f"{sensor_name} {condition}" self.sensor_type = sensor_type self.api = api self._state = False diff --git a/homeassistant/components/octoprint/sensor.py b/homeassistant/components/octoprint/sensor.py index 0233684c320b00..d21aac9ff650bc 100644 --- a/homeassistant/components/octoprint/sensor.py +++ b/homeassistant/components/octoprint/sensor.py @@ -89,7 +89,7 @@ def __init__( """Initialize a new OctoPrint sensor.""" self.sensor_name = sensor_name if tool is None: - self._name = "{} {}".format(sensor_name, condition) + self._name = f"{sensor_name} {condition}" else: self._name = "{} {} {} {}".format(sensor_name, condition, tool, "temp") self.sensor_type = sensor_type diff --git a/homeassistant/components/onboarding/views.py b/homeassistant/components/onboarding/views.py index df0f01bcff4d1f..2e79393fe4236d 100644 --- a/homeassistant/components/onboarding/views.py +++ b/homeassistant/components/onboarding/views.py @@ -122,7 +122,7 @@ async def post(self, request, data): for area in DEFAULT_AREAS: area_registry.async_create( - translations["component.onboarding.area.{}".format(area)] + translations[f"component.onboarding.area.{area}"] ) await self._async_mark_done(hass) diff --git a/homeassistant/components/onvif/camera.py b/homeassistant/components/onvif/camera.py index 6163453b4a527f..0635a2d1f11bb1 100644 --- a/homeassistant/components/onvif/camera.py +++ b/homeassistant/components/onvif/camera.py @@ -267,7 +267,7 @@ async def async_obtain_input_uri(self): uri_no_auth = stream_uri.Uri uri_for_log = uri_no_auth.replace("rtsp://", "rtsp://:@", 1) self._input = uri_no_auth.replace( - "rtsp://", "rtsp://{}:{}@".format(self._username, self._password), 1 + "rtsp://", f"rtsp://{self._username}:{self._password}@", 1 ) _LOGGER.debug( diff --git a/homeassistant/components/opengarage/cover.py b/homeassistant/components/opengarage/cover.py index ff85d182a22402..1243a9164fd26b 100644 --- a/homeassistant/components/opengarage/cover.py +++ b/homeassistant/components/opengarage/cover.py @@ -122,9 +122,7 @@ def open_cover(self, **kwargs): def update(self): """Get updated status from API.""" try: - status = requests.get( - "{}/jc".format(self.opengarage_url), timeout=10 - ).json() + status = requests.get(f"{self.opengarage_url}/jc", timeout=10).json() except requests.exceptions.RequestException as ex: _LOGGER.error( "Unable to connect to OpenGarage device: %(reason)s", dict(reason=ex) @@ -157,8 +155,7 @@ def _push_button(self): result = -1 try: result = requests.get( - "{}/cc?dkey={}&click=1".format(self.opengarage_url, self._device_key), - timeout=10, + f"{self.opengarage_url}/cc?dkey={self._device_key}&click=1", timeout=10 ).json()["result"] except requests.exceptions.RequestException as ex: _LOGGER.error( diff --git a/homeassistant/components/opensky/sensor.py b/homeassistant/components/opensky/sensor.py index a0cfaf5c2bef5d..0c17daa0ab4686 100644 --- a/homeassistant/components/opensky/sensor.py +++ b/homeassistant/components/opensky/sensor.py @@ -36,8 +36,8 @@ DEFAULT_ALTITUDE = 0 -EVENT_OPENSKY_ENTRY = "{}_entry".format(DOMAIN) -EVENT_OPENSKY_EXIT = "{}_exit".format(DOMAIN) +EVENT_OPENSKY_ENTRY = f"{DOMAIN}_entry" +EVENT_OPENSKY_EXIT = f"{DOMAIN}_exit" SCAN_INTERVAL = timedelta(seconds=12) # opensky public limit is 10 seconds OPENSKY_ATTRIBUTION = ( diff --git a/homeassistant/components/opentherm_gw/__init__.py b/homeassistant/components/opentherm_gw/__init__.py index b20d97dadce33a..0c145963653c3e 100644 --- a/homeassistant/components/opentherm_gw/__init__.py +++ b/homeassistant/components/opentherm_gw/__init__.py @@ -260,7 +260,7 @@ async def set_gpio_mode(call): gpio_id = call.data[ATTR_ID] gpio_mode = call.data[ATTR_MODE] mode = await gw_dev.gateway.set_gpio_mode(gpio_id, gpio_mode) - gpio_var = getattr(gw_vars, "OTGW_GPIO_{}".format(gpio_id)) + gpio_var = getattr(gw_vars, f"OTGW_GPIO_{gpio_id}") gw_dev.status.update({gpio_var: mode}) async_dispatcher_send(hass, gw_dev.update_signal, gw_dev.status) @@ -274,7 +274,7 @@ async def set_led_mode(call): led_id = call.data[ATTR_ID] led_mode = call.data[ATTR_MODE] mode = await gw_dev.gateway.set_led_mode(led_id, led_mode) - led_var = getattr(gw_vars, "OTGW_LED_{}".format(led_id)) + led_var = getattr(gw_vars, f"OTGW_LED_{led_id}") gw_dev.status.update({led_var: mode}) async_dispatcher_send(hass, gw_dev.update_signal, gw_dev.status) @@ -333,7 +333,7 @@ def __init__(self, hass, gw_id, config): self.name = config.get(CONF_NAME, gw_id) self.climate_config = config[CONF_CLIMATE] self.status = {} - self.update_signal = "{}_{}_update".format(DATA_OPENTHERM_GW, gw_id) + self.update_signal = f"{DATA_OPENTHERM_GW}_{gw_id}_update" self.gateway = pyotgw.pyotgw() async def connect_and_subscribe(self, device_path): diff --git a/homeassistant/components/opentherm_gw/binary_sensor.py b/homeassistant/components/opentherm_gw/binary_sensor.py index 2f4206b8e09fb8..614829265e2dcc 100644 --- a/homeassistant/components/opentherm_gw/binary_sensor.py +++ b/homeassistant/components/opentherm_gw/binary_sensor.py @@ -33,7 +33,7 @@ class OpenThermBinarySensor(BinarySensorDevice): def __init__(self, gw_dev, var, device_class, friendly_name_format): """Initialize the binary sensor.""" self.entity_id = async_generate_entity_id( - ENTITY_ID_FORMAT, "{}_{}".format(var, gw_dev.gw_id), hass=gw_dev.hass + ENTITY_ID_FORMAT, f"{var}_{gw_dev.gw_id}", hass=gw_dev.hass ) self._gateway = gw_dev self._var = var diff --git a/homeassistant/components/opentherm_gw/sensor.py b/homeassistant/components/opentherm_gw/sensor.py index 3727d907c9ad2c..1449caf5defdb9 100644 --- a/homeassistant/components/opentherm_gw/sensor.py +++ b/homeassistant/components/opentherm_gw/sensor.py @@ -34,7 +34,7 @@ class OpenThermSensor(Entity): def __init__(self, gw_dev, var, device_class, unit, friendly_name_format): """Initialize the OpenTherm Gateway sensor.""" self.entity_id = async_generate_entity_id( - ENTITY_ID_FORMAT, "{}_{}".format(var, gw_dev.gw_id), hass=gw_dev.hass + ENTITY_ID_FORMAT, f"{var}_{gw_dev.gw_id}", hass=gw_dev.hass ) self._gateway = gw_dev self._var = var @@ -55,7 +55,7 @@ def receive_report(self, status): """Handle status updates from the component.""" value = status.get(self._var) if isinstance(value, float): - value = "{:2.1f}".format(value) + value = f"{value:2.1f}" self._value = value self.async_schedule_update_ha_state() diff --git a/homeassistant/components/openuv/__init__.py b/homeassistant/components/openuv/__init__.py index c1a8873b9e0ce1..62a8c642bc8e4f 100644 --- a/homeassistant/components/openuv/__init__.py +++ b/homeassistant/components/openuv/__init__.py @@ -36,7 +36,7 @@ NOTIFICATION_ID = "openuv_notification" NOTIFICATION_TITLE = "OpenUV Component Setup" -TOPIC_UPDATE = "{0}_data_update".format(DOMAIN) +TOPIC_UPDATE = f"{DOMAIN}_data_update" TYPE_CURRENT_OZONE_LEVEL = "current_ozone_level" TYPE_CURRENT_UV_INDEX = "current_uv_index" diff --git a/homeassistant/components/openuv/binary_sensor.py b/homeassistant/components/openuv/binary_sensor.py index d081e09f853194..59f6e4d1c67e47 100644 --- a/homeassistant/components/openuv/binary_sensor.py +++ b/homeassistant/components/openuv/binary_sensor.py @@ -76,7 +76,7 @@ def should_poll(self): @property def unique_id(self) -> str: """Return a unique, HASS-friendly identifier for this entity.""" - return "{0}_{1}_{2}".format(self._latitude, self._longitude, self._sensor_type) + return f"{self._latitude}_{self._longitude}_{self._sensor_type}" async def async_added_to_hass(self): """Register callbacks.""" diff --git a/homeassistant/components/openuv/sensor.py b/homeassistant/components/openuv/sensor.py index e86bfdac35f479..de2688ab121655 100644 --- a/homeassistant/components/openuv/sensor.py +++ b/homeassistant/components/openuv/sensor.py @@ -98,7 +98,7 @@ def state(self): @property def unique_id(self) -> str: """Return a unique, HASS-friendly identifier for this entity.""" - return "{0}_{1}_{2}".format(self._latitude, self._longitude, self._sensor_type) + return f"{self._latitude}_{self._longitude}_{self._sensor_type}" @property def unit_of_measurement(self): diff --git a/homeassistant/components/openweathermap/sensor.py b/homeassistant/components/openweathermap/sensor.py index 85bd1ccb2c6eb0..51dc92623f3db1 100644 --- a/homeassistant/components/openweathermap/sensor.py +++ b/homeassistant/components/openweathermap/sensor.py @@ -108,7 +108,7 @@ def __init__(self, name, weather_data, sensor_type, temp_unit): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/owlet/__init__.py b/homeassistant/components/owlet/__init__.py index 1a49d92d1cfe89..f9543c7fa6e6d8 100644 --- a/homeassistant/components/owlet/__init__.py +++ b/homeassistant/components/owlet/__init__.py @@ -58,7 +58,7 @@ def setup(hass, config): device.update_properties() if not name: - name = "{}'s Owlet".format(device.baby_name) + name = f"{device.baby_name}'s Owlet" hass.data[DOMAIN] = OwletDevice(device, name, SENSOR_TYPES) diff --git a/homeassistant/components/owntracks/__init__.py b/homeassistant/components/owntracks/__init__.py index df9ae27b5ffd76..7e65ff3d51dba6 100644 --- a/homeassistant/components/owntracks/__init__.py +++ b/homeassistant/components/owntracks/__init__.py @@ -169,7 +169,7 @@ async def handle_webhook(hass, webhook_id, request): if user: topic_base = re.sub("/#$", "", context.mqtt_topic) - message["topic"] = "{}/{}/{}".format(topic_base, user, device) + message["topic"] = f"{topic_base}/{user}/{device}" elif message["_type"] != "encrypted": _LOGGER.warning( @@ -264,7 +264,7 @@ def async_see_beacons(self, hass, dev_id, kwargs_param): # Mobile beacons should always be set to the location of the # tracking device. I get the device state and make the necessary # changes to kwargs. - device_tracker_state = hass.states.get("device_tracker.{}".format(dev_id)) + device_tracker_state = hass.states.get(f"device_tracker.{dev_id}") if device_tracker_state is not None: acc = device_tracker_state.attributes.get("gps_accuracy") @@ -282,6 +282,6 @@ def async_see_beacons(self, hass, dev_id, kwargs_param): # kwargs location is the beacon's configured lat/lon kwargs.pop("battery", None) for beacon in self.mobile_beacons_active[dev_id]: - kwargs["dev_id"] = "{}_{}".format(BEACON_DEV_ID, beacon) + kwargs["dev_id"] = f"{BEACON_DEV_ID}_{beacon}" kwargs["host_name"] = beacon self.async_see(**kwargs) diff --git a/homeassistant/components/owntracks/messages.py b/homeassistant/components/owntracks/messages.py index 61cfb9e05f9b4f..7ef31be13272eb 100644 --- a/homeassistant/components/owntracks/messages.py +++ b/homeassistant/components/owntracks/messages.py @@ -60,7 +60,7 @@ def _parse_see_args(message, subscribe_topic): Async friendly. """ user, device = _parse_topic(message["topic"], subscribe_topic) - dev_id = slugify("{}_{}".format(user, device)) + dev_id = slugify(f"{user}_{device}") kwargs = {"dev_id": dev_id, "host_name": user, "attributes": {}} if message["lat"] is not None and message["lon"] is not None: kwargs["gps"] = (message["lat"], message["lon"]) @@ -253,7 +253,7 @@ async def async_handle_transition_message(hass, context, message): async def async_handle_waypoint(hass, name_base, waypoint): """Handle a waypoint.""" name = waypoint["desc"] - pretty_name = "{} - {}".format(name_base, name) + pretty_name = f"{name_base} - {name}" lat = waypoint["lat"] lon = waypoint["lon"] rad = waypoint["rad"] diff --git a/homeassistant/components/pandora/media_player.py b/homeassistant/components/pandora/media_player.py index 9ced5fc6cf4cae..c242670ba48b37 100644 --- a/homeassistant/components/pandora/media_player.py +++ b/homeassistant/components/pandora/media_player.py @@ -220,7 +220,7 @@ def select_source(self, source): return _LOGGER.debug("Setting station %s, %d", source, station_index) self._send_station_list_command() - self._pianobar.sendline("{}".format(station_index)) + self._pianobar.sendline(f"{station_index}") self._pianobar.expect("\r\n") self._player_state = STATE_PLAYING diff --git a/homeassistant/components/panel_custom/__init__.py b/homeassistant/components/panel_custom/__init__.py index d18d00ef841167..cf861992bd6e08 100644 --- a/homeassistant/components/panel_custom/__init__.py +++ b/homeassistant/components/panel_custom/__init__.py @@ -165,7 +165,7 @@ async def async_setup(hass, config): panel_path = panel.get(CONF_WEBCOMPONENT_PATH) if panel_path is None: - panel_path = hass.config.path(PANEL_DIR, "{}.html".format(name)) + panel_path = hass.config.path(PANEL_DIR, f"{name}.html") if CONF_JS_URL in panel: kwargs["js_url"] = panel[CONF_JS_URL] diff --git a/homeassistant/components/philips_js/media_player.py b/homeassistant/components/philips_js/media_player.py index 10d7fe8009d3b8..579dc253603263 100644 --- a/homeassistant/components/philips_js/media_player.py +++ b/homeassistant/components/philips_js/media_player.py @@ -286,7 +286,7 @@ def update(self): self._tv.update() self._sources = { - srcid: source["name"] or "Source {}".format(srcid) + srcid: source["name"] or f"Source {srcid}" for srcid, source in (self._tv.sources or {}).items() } diff --git a/homeassistant/components/pi_hole/sensor.py b/homeassistant/components/pi_hole/sensor.py index d60392373bc719..9c41c20fd637e9 100644 --- a/homeassistant/components/pi_hole/sensor.py +++ b/homeassistant/components/pi_hole/sensor.py @@ -117,7 +117,7 @@ def __init__(self, pi_hole, name, condition): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._name, self._condition_name) + return f"{self._name} {self._condition_name}" @property def icon(self): diff --git a/homeassistant/components/pjlink/media_player.py b/homeassistant/components/pjlink/media_player.py index 398e77ea5116fc..44b4055e032f92 100644 --- a/homeassistant/components/pjlink/media_player.py +++ b/homeassistant/components/pjlink/media_player.py @@ -54,7 +54,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): hass.data["pjlink"] = {} hass_data = hass.data["pjlink"] - device_label = "{}:{}".format(host, port) + device_label = f"{host}:{port}" if device_label in hass_data: return @@ -65,7 +65,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): def format_input_source(input_source_name, input_source_number): """Format input source for display in UI.""" - return "{} {}".format(input_source_name, input_source_number) + return f"{input_source_name} {input_source_number}" class PjLinkDevice(MediaPlayerDevice): diff --git a/homeassistant/components/plaato/__init__.py b/homeassistant/components/plaato/__init__.py index 7ca5de419e055a..49b749b8de6f54 100644 --- a/homeassistant/components/plaato/__init__.py +++ b/homeassistant/components/plaato/__init__.py @@ -37,8 +37,8 @@ ATTR_CO2_VOLUME = "co2_volume" ATTR_BATCH_VOLUME = "batch_volume" -SENSOR_UPDATE = "{}_sensor_update".format(DOMAIN) -SENSOR_DATA_KEY = "{}.{}".format(DOMAIN, SENSOR) +SENSOR_UPDATE = f"{DOMAIN}_sensor_update" +SENSOR_DATA_KEY = f"{DOMAIN}.{SENSOR}" WEBHOOK_SCHEMA = vol.Schema( { @@ -121,7 +121,7 @@ async def handle_webhook(hass, webhook_id, request): async_dispatcher_send(hass, SENSOR_UPDATE, device_id) - return web.Response(text="Saving status for {}".format(device_id), status=HTTP_OK) + return web.Response(text=f"Saving status for {device_id}", status=HTTP_OK) def _device_id(data): diff --git a/homeassistant/components/plaato/sensor.py b/homeassistant/components/plaato/sensor.py index bf128af931a4dd..f8e6a3e9fa7b48 100644 --- a/homeassistant/components/plaato/sensor.py +++ b/homeassistant/components/plaato/sensor.py @@ -54,9 +54,7 @@ async def _update_sensor(device_id): async_add_entities(entities, True) else: for entity in devices[device_id]: - async_dispatcher_send( - hass, "{}_{}".format(PLAATO_DOMAIN, entity.unique_id) - ) + async_dispatcher_send(hass, f"{PLAATO_DOMAIN}_{entity.unique_id}") hass.data[SENSOR_DATA_KEY] = async_dispatcher_connect( hass, SENSOR_UPDATE, _update_sensor @@ -73,18 +71,18 @@ def __init__(self, device_id, sensor_type): self._device_id = device_id self._type = sensor_type self._state = 0 - self._name = "{} {}".format(device_id, sensor_type) + self._name = f"{device_id} {sensor_type}" self._attributes = None @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(PLAATO_DOMAIN, self._name) + return f"{PLAATO_DOMAIN} {self._name}" @property def unique_id(self): """Return the unique ID of this sensor.""" - return "{}_{}".format(self._device_id, self._type) + return f"{self._device_id}_{self._type}" @property def device_info(self): @@ -157,6 +155,5 @@ def should_poll(self): async def async_added_to_hass(self): """Register callbacks.""" self.hass.helpers.dispatcher.async_dispatcher_connect( - "{}_{}".format(PLAATO_DOMAIN, self.unique_id), - self.async_schedule_update_ha_state, + f"{PLAATO_DOMAIN}_{self.unique_id}", self.async_schedule_update_ha_state ) diff --git a/homeassistant/components/plant/__init__.py b/homeassistant/components/plant/__init__.py index 5dff1d29e705a1..a516e06d55bce4 100644 --- a/homeassistant/components/plant/__init__.py +++ b/homeassistant/components/plant/__init__.py @@ -216,7 +216,7 @@ def state_changed(self, entity_id, _, new_state): ) else: raise HomeAssistantError( - "Unknown reading from sensor {}: {}".format(entity_id, value) + f"Unknown reading from sensor {entity_id}: {value}" ) if ATTR_UNIT_OF_MEASUREMENT in new_state.attributes: self._unit_of_measurement[reading] = new_state.attributes.get( @@ -229,10 +229,10 @@ def _update_state(self): result = [] for sensor_name in self._sensormap.values(): params = self.READINGS[sensor_name] - value = getattr(self, "_{}".format(sensor_name)) + value = getattr(self, f"_{sensor_name}") if value is not None: if value == STATE_UNAVAILABLE: - result.append("{} unavailable".format(sensor_name)) + result.append(f"{sensor_name} unavailable") else: if sensor_name == READING_BRIGHTNESS: result.append( @@ -260,14 +260,14 @@ def _check_min(self, sensor_name, value, params): if "min" in params and params["min"] in self._config: min_value = self._config[params["min"]] if value < min_value: - return "{} low".format(sensor_name) + return f"{sensor_name} low" def _check_max(self, sensor_name, value, params): """If configured, check the value against the defined maximum value.""" if "max" in params and params["max"] in self._config: max_value = self._config[params["max"]] if value > max_value: - return "{} high".format(sensor_name) + return f"{sensor_name} high" return None async def async_added_to_hass(self): @@ -352,7 +352,7 @@ def state_attributes(self): } for reading in self._sensormap.values(): - attrib[reading] = getattr(self, "_{}".format(reading)) + attrib[reading] = getattr(self, f"_{reading}") if self._brightness_history.max is not None: attrib[ATTR_MAX_BRIGHTNESS_HISTORY] = self._brightness_history.max diff --git a/homeassistant/components/plex/media_player.py b/homeassistant/components/plex/media_player.py index 98137897149f19..39694a061c4839 100644 --- a/homeassistant/components/plex/media_player.py +++ b/homeassistant/components/plex/media_player.py @@ -82,7 +82,7 @@ def setup_platform(hass, config, add_entities_callback, discovery_info=None): # Parse discovery data host = discovery_info.get("host") port = discovery_info.get("port") - host = "%s:%s" % (host, port) + host = f"{host}:{port}" _LOGGER.info("Discovered PLEX server: %s", host) if host in _CONFIGURING: @@ -113,7 +113,7 @@ def setup_plexserver( cert_session.verify = False try: plexserver = plexapi.server.PlexServer( - "%s://%s" % (http_prefix, host), token, cert_session + f"{http_prefix}://{host}", token, cert_session ) _LOGGER.info("Discovery configuration done (no token needed)") except ( @@ -847,7 +847,7 @@ def _get_tv_media(self, library_name, show_name, season_number, episode_number): show = self.device.server.library.section(library_name).get(show_name) if not season_number: - playlist_name = "{} - {} Episodes".format(self.entity_id, show_name) + playlist_name = f"{self.entity_id} - {show_name} Episodes" return self.device.server.createPlaylist(playlist_name, show.episodes()) for season in show.seasons(): diff --git a/homeassistant/components/plex/sensor.py b/homeassistant/components/plex/sensor.py index dbd0d9f8578167..d900b4de87c1d7 100644 --- a/homeassistant/components/plex/sensor.py +++ b/homeassistant/components/plex/sensor.py @@ -150,7 +150,7 @@ def update(self): for sess in sessions: user = sess.usernames[0] device = sess.players[0].title - now_playing_user = "{0} - {1}".format(user, device) + now_playing_user = f"{user} - {device}" now_playing_title = "" if sess.TYPE == "episode": @@ -161,7 +161,7 @@ def update(self): season_title += " ({0})".format(sess.show().year) season_episode = "S{0}".format(sess.parentIndex) if sess.index is not None: - season_episode += " · E{0}".format(sess.index) + season_episode += f" · E{sess.index}" episode_title = sess.title now_playing_title = "{0} - {1} - {2}".format( season_title, season_episode, episode_title @@ -181,7 +181,7 @@ def update(self): # "The Incredible Hulk (2008)" now_playing_title = sess.title if sess.year is not None: - now_playing_title += " ({0})".format(sess.year) + now_playing_title += f" ({sess.year})" now_playing.append((now_playing_user, now_playing_title)) self._state = len(sessions) diff --git a/homeassistant/components/plum_lightpad/light.py b/homeassistant/components/plum_lightpad/light.py index ecf423c500b0df..63fa67f4da54bb 100644 --- a/homeassistant/components/plum_lightpad/light.py +++ b/homeassistant/components/plum_lightpad/light.py @@ -94,7 +94,7 @@ class GlowRing(Light): def __init__(self, lightpad): """Initialize the light.""" self._lightpad = lightpad - self._name = "{} Glow Ring".format(lightpad.friendly_name) + self._name = f"{lightpad.friendly_name} Glow Ring" self._state = lightpad.glow_enabled self._brightness = lightpad.glow_intensity * 255.0 diff --git a/homeassistant/components/point/__init__.py b/homeassistant/components/point/__init__.py index f0931bc9e8fc24..e9885891553b9e 100644 --- a/homeassistant/components/point/__init__.py +++ b/homeassistant/components/point/__init__.py @@ -182,7 +182,7 @@ async def _sync(self): async def new_device(device_id, component): """Load new device.""" - config_entries_key = "{}.{}".format(component, DOMAIN) + config_entries_key = f"{component}.{DOMAIN}" async with self._hass.data[DATA_CONFIG_ENTRY_LOCK]: if config_entries_key not in self._hass.data[CONFIG_ENTRY_IS_SETUP]: await self._hass.config_entries.async_forward_entry_setup( @@ -247,7 +247,7 @@ def __init__(self, point_client, device_id, device_class): def __str__(self): """Return string representation of device.""" - return "MinutPoint {}".format(self.name) + return f"MinutPoint {self.name}" async def async_added_to_hass(self): """Call when entity is added to hass.""" @@ -333,7 +333,7 @@ def should_poll(self): @property def unique_id(self): """Return the unique id of the sensor.""" - return "point.{}-{}".format(self._id, self.device_class) + return f"point.{self._id}-{self.device_class}" @property def value(self): diff --git a/homeassistant/components/point/alarm_control_panel.py b/homeassistant/components/point/alarm_control_panel.py index 4a0db111b7d51f..f9e725f6c8e5c7 100644 --- a/homeassistant/components/point/alarm_control_panel.py +++ b/homeassistant/components/point/alarm_control_panel.py @@ -108,7 +108,7 @@ def alarm_arm_away(self, code=None): @property def unique_id(self): """Return the unique id of the sensor.""" - return "point.{}".format(self._home_id) + return f"point.{self._home_id}" @property def device_info(self): diff --git a/homeassistant/components/prezzibenzina/sensor.py b/homeassistant/components/prezzibenzina/sensor.py index 420cd448c1999f..f1f41ba46bad0a 100644 --- a/homeassistant/components/prezzibenzina/sensor.py +++ b/homeassistant/components/prezzibenzina/sensor.py @@ -77,7 +77,7 @@ def __init__(self, index, client, station, name, ft, srv): self._index = index self._data = None self._station = station - self._name = "{} {} {}".format(name, ft, srv) + self._name = f"{name} {ft} {srv}" @property def name(self): diff --git a/homeassistant/components/proximity/__init__.py b/homeassistant/components/proximity/__init__.py index e9b85f790848dd..b5856b7f78e921 100644 --- a/homeassistant/components/proximity/__init__.py +++ b/homeassistant/components/proximity/__init__.py @@ -71,7 +71,7 @@ def setup_proximity_component(hass, name, config): zone_id, unit_of_measurement, ) - proximity.entity_id = "{}.{}".format(DOMAIN, proximity_zone) + proximity.entity_id = f"{DOMAIN}.{proximity_zone}" proximity.schedule_update_ha_state() diff --git a/homeassistant/components/ps4/__init__.py b/homeassistant/components/ps4/__init__.py index 9baf1adbcc2c1b..60635bba525664 100644 --- a/homeassistant/components/ps4/__init__.py +++ b/homeassistant/components/ps4/__init__.py @@ -156,7 +156,7 @@ async def async_migrate_entry(hass, entry): def format_unique_id(creds, mac_address): """Use last 4 Chars of credential as suffix. Unique ID per PSN user.""" suffix = creds[-4:] - return "{}_{}".format(mac_address, suffix) + return f"{mac_address}_{suffix}" def load_games(hass: HomeAssistantType) -> dict: diff --git a/homeassistant/components/pushetta/notify.py b/homeassistant/components/pushetta/notify.py index 2bdd7d036ce71f..b8911039f3f050 100644 --- a/homeassistant/components/pushetta/notify.py +++ b/homeassistant/components/pushetta/notify.py @@ -61,9 +61,7 @@ def send_message(self, message="", **kwargs): title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) try: - self.pushetta.pushMessage( - self._channel_name, "{} {}".format(title, message) - ) + self.pushetta.pushMessage(self._channel_name, f"{title} {message}") except exceptions.TokenValidationError: _LOGGER.error("Please check your access token") self.is_valid = False diff --git a/homeassistant/components/pushsafer/notify.py b/homeassistant/components/pushsafer/notify.py index 461b2540beff45..758a3390286f65 100644 --- a/homeassistant/components/pushsafer/notify.py +++ b/homeassistant/components/pushsafer/notify.py @@ -132,7 +132,7 @@ def get_base64(cls, filebyte, mimetype): return None base64_image = base64.b64encode(filebyte).decode("utf8") - return "data:{};base64,{}".format(mimetype, base64_image) + return f"data:{mimetype};base64,{base64_image}" def load_from_url(self, url=None, username=None, password=None, auth=None): """Load image/document/etc from URL.""" diff --git a/homeassistant/components/pyload/sensor.py b/homeassistant/components/pyload/sensor.py index 07c23cd9e80b66..8ffe1ece4a2ab1 100644 --- a/homeassistant/components/pyload/sensor.py +++ b/homeassistant/components/pyload/sensor.py @@ -55,7 +55,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) monitored_types = config.get(CONF_MONITORED_VARIABLES) - url = "http{}://{}:{}/api/".format(ssl, host, port) + url = f"http{ssl}://{host}:{port}/api/" try: pyloadapi = PyLoadAPI(api_url=url, username=username, password=password) diff --git a/homeassistant/components/qbittorrent/sensor.py b/homeassistant/components/qbittorrent/sensor.py index 2900496a01e408..f00b392065cb7b 100644 --- a/homeassistant/components/qbittorrent/sensor.py +++ b/homeassistant/components/qbittorrent/sensor.py @@ -88,7 +88,7 @@ def __init__(self, sensor_type, qbittorrent_client, client_name, exception): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/qnap/sensor.py b/homeassistant/components/qnap/sensor.py index 8ab2ee575bfd01..efbb1ac26ca53a 100644 --- a/homeassistant/components/qnap/sensor.py +++ b/homeassistant/components/qnap/sensor.py @@ -215,8 +215,8 @@ def name(self): server_name = self._api.data["system_stats"]["system"]["name"] if self.monitor_device is not None: - return "{} {} ({})".format(server_name, self.var_name, self.monitor_device) - return "{} {}".format(server_name, self.var_name) + return f"{server_name} {self.var_name} ({self.monitor_device})" + return f"{server_name} {self.var_name}" @property def icon(self): @@ -270,7 +270,7 @@ def device_state_attributes(self): if self._api.data: data = self._api.data["system_stats"]["memory"] size = round_nicely(float(data["total"]) / 1024) - return {ATTR_MEMORY_SIZE: "{} GB".format(size)} + return {ATTR_MEMORY_SIZE: f"{size} GB"} class QNAPNetworkSensor(QNAPSensor): @@ -331,7 +331,7 @@ def device_state_attributes(self): ATTR_NAME: data["system"]["name"], ATTR_MODEL: data["system"]["model"], ATTR_SERIAL: data["system"]["serial_number"], - ATTR_UPTIME: "{:0>2d}d {:0>2d}h {:0>2d}m".format(days, hours, minutes), + ATTR_UPTIME: f"{days:0>2d}d {hours:0>2d}h {minutes:0>2d}m", } diff --git a/homeassistant/components/qwikswitch/__init__.py b/homeassistant/components/qwikswitch/__init__.py index 9e4c0658358e05..1ae92b0a18ad05 100644 --- a/homeassistant/components/qwikswitch/__init__.py +++ b/homeassistant/components/qwikswitch/__init__.py @@ -80,7 +80,7 @@ def poll(self): @property def unique_id(self): """Return a unique identifier for this sensor.""" - return "qs{}".format(self.qsid) + return f"qs{self.qsid}" @callback def update_packet(self, packet): diff --git a/homeassistant/components/qwikswitch/binary_sensor.py b/homeassistant/components/qwikswitch/binary_sensor.py index 36e8181cc47392..a5b142e19aede4 100644 --- a/homeassistant/components/qwikswitch/binary_sensor.py +++ b/homeassistant/components/qwikswitch/binary_sensor.py @@ -61,7 +61,7 @@ def is_on(self): @property def unique_id(self): """Return a unique identifier for this sensor.""" - return "qs{}:{}".format(self.qsid, self.channel) + return f"qs{self.qsid}:{self.channel}" @property def device_class(self): diff --git a/homeassistant/components/qwikswitch/sensor.py b/homeassistant/components/qwikswitch/sensor.py index 8e9a755d6dab12..01964fc7831e04 100644 --- a/homeassistant/components/qwikswitch/sensor.py +++ b/homeassistant/components/qwikswitch/sensor.py @@ -34,7 +34,7 @@ def __init__(self, sensor): self._decode, self.unit = SENSORS[sensor_type] if isinstance(self.unit, type): - self.unit = "{}:{}".format(sensor_type, self.channel) + self.unit = f"{sensor_type}:{self.channel}" @callback def update_packet(self, packet): @@ -60,7 +60,7 @@ def state(self): @property def unique_id(self): """Return a unique identifier for this sensor.""" - return "qs{}:{}".format(self.qsid, self.channel) + return f"qs{self.qsid}:{self.channel}" @property def unit_of_measurement(self): From eebd7488a4ae2f8a4c173695ba4178d12e90a19f Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 3 Sep 2019 21:04:38 +0200 Subject: [PATCH 66/72] Update OpenCV 4.1.1 / Numpy 1.17.1 (#26387) --- homeassistant/components/iqvia/manifest.json | 4 ++-- homeassistant/components/opencv/manifest.json | 6 +++--- homeassistant/components/tensorflow/manifest.json | 2 +- homeassistant/components/trend/manifest.json | 4 ++-- requirements_all.txt | 4 ++-- requirements_test_all.txt | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/iqvia/manifest.json b/homeassistant/components/iqvia/manifest.json index 357bfca607aece..7392c931f48339 100644 --- a/homeassistant/components/iqvia/manifest.json +++ b/homeassistant/components/iqvia/manifest.json @@ -4,11 +4,11 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/components/iqvia", "requirements": [ - "numpy==1.17.0", + "numpy==1.17.1", "pyiqvia==0.2.1" ], "dependencies": [], "codeowners": [ "@bachya" ] -} +} \ No newline at end of file diff --git a/homeassistant/components/opencv/manifest.json b/homeassistant/components/opencv/manifest.json index 68f14846af7a1e..e8ebeb102e67b1 100644 --- a/homeassistant/components/opencv/manifest.json +++ b/homeassistant/components/opencv/manifest.json @@ -3,9 +3,9 @@ "name": "Opencv", "documentation": "https://www.home-assistant.io/components/opencv", "requirements": [ - "numpy==1.17.0", - "opencv-python-headless==4.1.0.25" + "numpy==1.17.1", + "opencv-python-headless==4.1.1.26" ], "dependencies": [], "codeowners": [] -} +} \ No newline at end of file diff --git a/homeassistant/components/tensorflow/manifest.json b/homeassistant/components/tensorflow/manifest.json index f5bd981bad1dc4..9419cbaaefbede 100644 --- a/homeassistant/components/tensorflow/manifest.json +++ b/homeassistant/components/tensorflow/manifest.json @@ -4,7 +4,7 @@ "documentation": "https://www.home-assistant.io/components/tensorflow", "requirements": [ "tensorflow==1.13.2", - "numpy==1.17.0", + "numpy==1.17.1", "pillow==6.1.0", "protobuf==3.6.1" ], diff --git a/homeassistant/components/trend/manifest.json b/homeassistant/components/trend/manifest.json index b9c01c15d2004a..8719138f3ac213 100644 --- a/homeassistant/components/trend/manifest.json +++ b/homeassistant/components/trend/manifest.json @@ -3,8 +3,8 @@ "name": "Trend", "documentation": "https://www.home-assistant.io/components/trend", "requirements": [ - "numpy==1.17.0" + "numpy==1.17.1" ], "dependencies": [], "codeowners": [] -} +} \ No newline at end of file diff --git a/requirements_all.txt b/requirements_all.txt index 349f46d47f1a8b..ef162f19263b88 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -866,7 +866,7 @@ nuheat==0.3.0 # homeassistant.components.opencv # homeassistant.components.tensorflow # homeassistant.components.trend -numpy==1.17.0 +numpy==1.17.1 # homeassistant.components.oasa_telematics oasatelematics==0.3 @@ -884,7 +884,7 @@ onkyo-eiscp==1.2.4 onvif-zeep-async==0.2.0 # homeassistant.components.opencv -# opencv-python-headless==4.1.0.25 +# opencv-python-headless==4.1.1.26 # homeassistant.components.openevse openevsewifi==0.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 37e45278e33124..2ef8f0ca672595 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -226,7 +226,7 @@ nokia==1.2.0 # homeassistant.components.opencv # homeassistant.components.tensorflow # homeassistant.components.trend -numpy==1.17.0 +numpy==1.17.1 # homeassistant.components.google oauth2client==4.0.0 From 61550febe5549e5dc827451b19a954603d76e2e4 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 21:12:51 +0200 Subject: [PATCH 67/72] Use literal string interpolation in integrations T-W (f-strings) (#26394) --- homeassistant/components/tado/climate.py | 2 +- homeassistant/components/tado/sensor.py | 8 ++-- .../components/tapsaff/binary_sensor.py | 2 +- homeassistant/components/ted5000/sensor.py | 2 +- homeassistant/components/teksavvy/sensor.py | 2 +- .../components/telegram_bot/__init__.py | 4 +- .../components/telegram_bot/webhooks.py | 2 +- .../components/tellduslive/__init__.py | 2 +- homeassistant/components/tellstick/sensor.py | 2 +- homeassistant/components/tesla/sensor.py | 4 +- .../components/thermoworks_smoke/sensor.py | 4 +- .../components/thethingsnetwork/sensor.py | 7 +--- homeassistant/components/tibber/sensor.py | 4 +- homeassistant/components/time_date/sensor.py | 8 ++-- .../components/tplink/device_tracker.py | 38 +++++++++---------- homeassistant/components/traccar/__init__.py | 4 +- homeassistant/components/tradfri/light.py | 4 +- homeassistant/components/tradfri/switch.py | 2 +- .../trafikverket_weatherstation/sensor.py | 2 +- .../components/transmission/sensor.py | 2 +- homeassistant/components/travisci/sensor.py | 2 +- .../components/twentemilieu/sensor.py | 10 ++--- homeassistant/components/twilio/__init__.py | 2 +- .../components/ubus/device_tracker.py | 2 +- .../components/uk_transport/sensor.py | 10 ++--- .../components/unifi/device_tracker.py | 2 +- homeassistant/components/unifi/switch.py | 8 ++-- .../components/upc_connect/device_tracker.py | 9 ++--- homeassistant/components/upnp/sensor.py | 8 ++-- homeassistant/components/usps/camera.py | 2 +- homeassistant/components/usps/sensor.py | 4 +- homeassistant/components/vallox/__init__.py | 2 +- homeassistant/components/vallox/sensor.py | 16 ++++---- homeassistant/components/velbus/__init__.py | 2 +- .../components/volumio/media_player.py | 4 +- .../components/volvooncall/__init__.py | 6 +-- homeassistant/components/waqi/sensor.py | 2 +- .../components/watson_iot/__init__.py | 2 +- .../components/waze_travel_time/sensor.py | 2 +- homeassistant/components/wemo/__init__.py | 6 +-- homeassistant/components/wink/__init__.py | 8 ++-- .../components/wink/binary_sensor.py | 2 +- .../components/wirelesstag/__init__.py | 18 ++++----- .../components/wirelesstag/binary_sensor.py | 2 +- .../components/wirelesstag/switch.py | 2 +- homeassistant/components/withings/sensor.py | 2 +- .../components/worldtidesinfo/sensor.py | 4 +- .../components/worxlandroid/sensor.py | 4 +- .../components/wunderground/sensor.py | 10 ++--- homeassistant/components/wwlln/__init__.py | 2 +- 50 files changed, 128 insertions(+), 132 deletions(-) diff --git a/homeassistant/components/tado/climate.py b/homeassistant/components/tado/climate.py index 15e01db4082ee4..1108b32af4e07f 100644 --- a/homeassistant/components/tado/climate.py +++ b/homeassistant/components/tado/climate.py @@ -124,7 +124,7 @@ def create_climate_device(tado, hass, zone, name, zone_id): max_temp = float(temperatures["celsius"]["max"]) step = temperatures["celsius"].get("step", PRECISION_TENTHS) - data_id = "zone {} {}".format(name, zone_id) + data_id = f"zone {name} {zone_id}" device = TadoClimate( tado, name, diff --git a/homeassistant/components/tado/sensor.py b/homeassistant/components/tado/sensor.py index 5cfdbd1f30c06c..7b4bd643f3d123 100644 --- a/homeassistant/components/tado/sensor.py +++ b/homeassistant/components/tado/sensor.py @@ -80,7 +80,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): def create_zone_sensor(tado, zone, name, zone_id, variable): """Create a zone sensor.""" - data_id = "zone {} {}".format(name, zone_id) + data_id = f"zone {name} {zone_id}" tado.add_sensor( data_id, @@ -92,7 +92,7 @@ def create_zone_sensor(tado, zone, name, zone_id, variable): def create_device_sensor(tado, device, name, device_id, variable): """Create a device sensor.""" - data_id = "device {} {}".format(name, device_id) + data_id = f"device {name} {device_id}" tado.add_sensor( data_id, @@ -118,7 +118,7 @@ def __init__(self, store, zone_name, zone_id, zone_variable, data_id): self.zone_id = zone_id self.zone_variable = zone_variable - self._unique_id = "{} {}".format(zone_variable, zone_id) + self._unique_id = f"{zone_variable} {zone_id}" self._data_id = data_id self._state = None @@ -132,7 +132,7 @@ def unique_id(self): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.zone_name, self.zone_variable) + return f"{self.zone_name} {self.zone_variable}" @property def state(self): diff --git a/homeassistant/components/tapsaff/binary_sensor.py b/homeassistant/components/tapsaff/binary_sensor.py index 3b4bcfa8ea55a6..fe6b01ced4e170 100644 --- a/homeassistant/components/tapsaff/binary_sensor.py +++ b/homeassistant/components/tapsaff/binary_sensor.py @@ -45,7 +45,7 @@ def __init__(self, taps_aff_data, name): @property def name(self): """Return the name of the sensor.""" - return "{}".format(self._name) + return f"{self._name}" @property def is_on(self): diff --git a/homeassistant/components/ted5000/sensor.py b/homeassistant/components/ted5000/sensor.py index 922d88d44bf89a..ea0963a092e59a 100644 --- a/homeassistant/components/ted5000/sensor.py +++ b/homeassistant/components/ted5000/sensor.py @@ -32,7 +32,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): host = config.get(CONF_HOST) port = config.get(CONF_PORT) name = config.get(CONF_NAME) - url = "http://{}:{}/api/LiveData.xml".format(host, port) + url = f"http://{host}:{port}/api/LiveData.xml" gateway = Ted5000Gateway(url) diff --git a/homeassistant/components/teksavvy/sensor.py b/homeassistant/components/teksavvy/sensor.py index 51914d7a4fc49e..74c39a221ba0cf 100644 --- a/homeassistant/components/teksavvy/sensor.py +++ b/homeassistant/components/teksavvy/sensor.py @@ -90,7 +90,7 @@ def __init__(self, teksavvydata, sensor_type, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/telegram_bot/__init__.py b/homeassistant/components/telegram_bot/__init__.py index e73c25203e01a9..a36f41edf3b7d4 100644 --- a/homeassistant/components/telegram_bot/__init__.py +++ b/homeassistant/components/telegram_bot/__init__.py @@ -554,7 +554,7 @@ def _send_msg(self, func_send, msg_error, *args_msg, **kwargs_msg): def send_message(self, message="", target=None, **kwargs): """Send a message to one or multiple pre-allowed chat IDs.""" title = kwargs.get(ATTR_TITLE) - text = "{}\n{}".format(title, message) if title else message + text = f"{title}\n{message}" if title else message params = self._get_msg_kwargs(kwargs) for chat_id in self._get_target_chat_ids(target): _LOGGER.debug("Send message in chat ID %s with params: %s", chat_id, params) @@ -590,7 +590,7 @@ def edit_message(self, type_edit, chat_id=None, **kwargs): if type_edit == SERVICE_EDIT_MESSAGE: message = kwargs.get(ATTR_MESSAGE) title = kwargs.get(ATTR_TITLE) - text = "{}\n{}".format(title, message) if title else message + text = f"{title}\n{message}" if title else message _LOGGER.debug( "Editing message with ID %s.", message_id or inline_message_id ) diff --git a/homeassistant/components/telegram_bot/webhooks.py b/homeassistant/components/telegram_bot/webhooks.py index 166f48c4961296..c71510eddd90df 100644 --- a/homeassistant/components/telegram_bot/webhooks.py +++ b/homeassistant/components/telegram_bot/webhooks.py @@ -45,7 +45,7 @@ async def async_setup_platform(hass, config): else: _LOGGER.debug("telegram webhook Status: %s", current_status) - handler_url = "{0}{1}".format(base_url, TELEGRAM_HANDLER_URL) + handler_url = f"{base_url}{TELEGRAM_HANDLER_URL}" if not handler_url.startswith("https"): _LOGGER.error("Invalid telegram webhook %s must be https", handler_url) return False diff --git a/homeassistant/components/tellduslive/__init__.py b/homeassistant/components/tellduslive/__init__.py index 05662cc2b239cd..7234127a15231a 100644 --- a/homeassistant/components/tellduslive/__init__.py +++ b/homeassistant/components/tellduslive/__init__.py @@ -46,7 +46,7 @@ CONFIG_ENTRY_IS_SETUP = "telldus_config_entry_is_setup" NEW_CLIENT_TASK = "telldus_new_client_task" -INTERVAL_TRACKER = "{}_INTERVAL".format(DOMAIN) +INTERVAL_TRACKER = f"{DOMAIN}_INTERVAL" async def async_setup_entry(hass, entry): diff --git a/homeassistant/components/tellstick/sensor.py b/homeassistant/components/tellstick/sensor.py index 24c038f870aaa8..83b56c2cf394d8 100644 --- a/homeassistant/components/tellstick/sensor.py +++ b/homeassistant/components/tellstick/sensor.py @@ -107,7 +107,7 @@ def __init__(self, name, tellcore_sensor, datatype, sensor_info): self._unit_of_measurement = sensor_info.unit or None self._value = None - self._name = "{} {}".format(name, sensor_info.name) + self._name = f"{name} {sensor_info.name}" @property def name(self): diff --git a/homeassistant/components/tesla/sensor.py b/homeassistant/components/tesla/sensor.py index 98cf5e47fd930f..c737b2f0bba576 100644 --- a/homeassistant/components/tesla/sensor.py +++ b/homeassistant/components/tesla/sensor.py @@ -43,13 +43,13 @@ def __init__(self, tesla_device, controller, sensor_type=None): super().__init__(tesla_device, controller) if self.type: - self._name = "{} ({})".format(self.tesla_device.name, self.type) + self._name = f"{self.tesla_device.name} ({self.type})" @property def unique_id(self) -> str: """Return a unique ID.""" if self.type: - return "{}_{}".format(self.tesla_id, self.type) + return f"{self.tesla_id}_{self.type}" return self.tesla_id @property diff --git a/homeassistant/components/thermoworks_smoke/sensor.py b/homeassistant/components/thermoworks_smoke/sensor.py index 08e6afc3e568b6..70a16287fcc245 100644 --- a/homeassistant/components/thermoworks_smoke/sensor.py +++ b/homeassistant/components/thermoworks_smoke/sensor.py @@ -86,7 +86,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): add_entities(dev, True) except HTTPError as error: - msg = "{}".format(error.strerror) + msg = f"{error.strerror}" if "EMAIL_NOT_FOUND" in msg or "INVALID_PASSWORD" in msg: _LOGGER.error("Invalid email and password combination") else: @@ -105,7 +105,7 @@ def __init__(self, sensor_type, serial, mgr): self._state = None self._attributes = {} self._unit_of_measurement = TEMP_FAHRENHEIT - self._unique_id = "{serial}-{type}".format(serial=serial, type=sensor_type) + self._unique_id = f"{serial}-{sensor_type}" self.serial = serial self.mgr = mgr self.update_unit() diff --git a/homeassistant/components/thethingsnetwork/sensor.py b/homeassistant/components/thethingsnetwork/sensor.py index ccba2bc4b38399..3ba58a688fe179 100644 --- a/homeassistant/components/thethingsnetwork/sensor.py +++ b/homeassistant/components/thethingsnetwork/sensor.py @@ -65,7 +65,7 @@ def __init__(self, ttn_data_storage, device_id, value, unit_of_measurement): self._device_id = device_id self._unit_of_measurement = unit_of_measurement self._value = value - self._name = "{} {}".format(self._device_id, self._value) + self._name = f"{self._device_id} {self._value}" @property def name(self): @@ -116,10 +116,7 @@ def __init__(self, hass, app_id, device_id, access_key, values): self._url = TTN_DATA_STORAGE_URL.format( app_id=app_id, endpoint="api/v2/query", device_id=device_id ) - self._headers = { - ACCEPT: CONTENT_TYPE_JSON, - AUTHORIZATION: "key {}".format(access_key), - } + self._headers = {ACCEPT: CONTENT_TYPE_JSON, AUTHORIZATION: f"key {access_key}"} async def async_update(self): """Get the current state from The Things Network Data Storage.""" diff --git a/homeassistant/components/tibber/sensor.py b/homeassistant/components/tibber/sensor.py index aba6499ca6f336..3dfe0265bdeef5 100644 --- a/homeassistant/components/tibber/sensor.py +++ b/homeassistant/components/tibber/sensor.py @@ -149,7 +149,7 @@ def __init__(self, tibber_home): self._device_state_attributes = {} self._unit_of_measurement = "W" nickname = tibber_home.info["viewer"]["home"]["appNickname"] - self._name = "Real time consumption {}".format(nickname) + self._name = f"Real time consumption {nickname}" async def async_added_to_hass(self): """Start unavailability tracking.""" @@ -215,4 +215,4 @@ def unique_id(self): """Return a unique ID.""" home = self._tibber_home.info["viewer"]["home"] _id = home["meteringPointData"]["consumptionEan"] - return "{}_rt_consumption".format(_id) + return f"{_id}_rt_consumption" diff --git a/homeassistant/components/time_date/sensor.py b/homeassistant/components/time_date/sensor.py index 02cde06d76309f..cbe4c85ace31d1 100644 --- a/homeassistant/components/time_date/sensor.py +++ b/homeassistant/components/time_date/sensor.py @@ -118,15 +118,15 @@ def _update_internal_state(self, time_date): elif self.type == "date": self._state = date elif self.type == "date_time": - self._state = "{}, {}".format(date, time) + self._state = f"{date}, {time}" elif self.type == "time_date": - self._state = "{}, {}".format(time, date) + self._state = f"{time}, {date}" elif self.type == "time_utc": self._state = time_utc elif self.type == "beat": - self._state = "@{0:03d}".format(beat) + self._state = f"@{beat:03d}" elif self.type == "date_time_iso": - self._state = dt_util.parse_datetime("{} {}".format(date, time)).isoformat() + self._state = dt_util.parse_datetime(f"{date} {time}").isoformat() @callback def point_in_time_listener(self, time_date): diff --git a/homeassistant/components/tplink/device_tracker.py b/homeassistant/components/tplink/device_tracker.py index 6f1d9761fdf37a..60d495738338e7 100644 --- a/homeassistant/components/tplink/device_tracker.py +++ b/homeassistant/components/tplink/device_tracker.py @@ -168,8 +168,8 @@ def _update_info(self): """ _LOGGER.info("Loading wireless clients...") - url = "http://{}/userRpm/WlanStationRpm.htm".format(self.host) - referer = "http://{}".format(self.host) + url = f"http://{self.host}/userRpm/WlanStationRpm.htm" + referer = f"http://{self.host}" page = requests.get( url, auth=(self.username, self.password), @@ -205,16 +205,16 @@ def _update_info(self): """ _LOGGER.info("Loading wireless clients...") - url = "http://{}/data/map_access_wireless_client_grid.json".format(self.host) - referer = "http://{}".format(self.host) + url = f"http://{self.host}/data/map_access_wireless_client_grid.json" + referer = f"http://{self.host}" # Router uses Authorization cookie instead of header # Let's create the cookie - username_password = "{}:{}".format(self.username, self.password) + username_password = f"{self.username}:{self.password}" b64_encoded_username_password = base64.b64encode( username_password.encode("ascii") ).decode("ascii") - cookie = "Authorization=Basic {}".format(b64_encoded_username_password) + cookie = f"Authorization=Basic {b64_encoded_username_password}" response = requests.post( url, headers={REFERER: referer, COOKIE: cookie}, timeout=4 @@ -264,8 +264,8 @@ def _get_auth_tokens(self): """Retrieve auth tokens from the router.""" _LOGGER.info("Retrieving auth tokens...") - url = "http://{}/cgi-bin/luci/;stok=/login?form=login".format(self.host) - referer = "http://{}/webpages/login.html".format(self.host) + url = f"http://{self.host}/cgi-bin/luci/;stok=/login?form=login" + referer = f"http://{self.host}/webpages/login.html" # If possible implement RSA encryption of password here. response = requests.post( @@ -303,7 +303,7 @@ def _update_info(self): url = ( "http://{}/cgi-bin/luci/;stok={}/admin/wireless?" "form=statistics" ).format(self.host, self.stok) - referer = "http://{}/webpages/index.html".format(self.host) + referer = f"http://{self.host}/webpages/index.html" response = requests.post( url, @@ -346,7 +346,7 @@ def _log_out(self): url = ("http://{}/cgi-bin/luci/;stok={}/admin/system?" "form=logout").format( self.host, self.stok ) - referer = "http://{}/webpages/index.html".format(self.host) + referer = f"http://{self.host}/webpages/index.html" requests.post( url, @@ -379,19 +379,19 @@ def get_device_name(self, device): def _get_auth_tokens(self): """Retrieve auth tokens from the router.""" _LOGGER.info("Retrieving auth tokens...") - url = "http://{}/userRpm/LoginRpm.htm?Save=Save".format(self.host) + url = f"http://{self.host}/userRpm/LoginRpm.htm?Save=Save" # Generate md5 hash of password. The C7 appears to use the first 15 # characters of the password only, so we truncate to remove additional # characters from being hashed. password = hashlib.md5(self.password.encode("utf")[:15]).hexdigest() - credentials = "{}:{}".format(self.username, password).encode("utf") + credentials = f"{self.username}:{password}".encode("utf") # Encode the credentials to be sent as a cookie. self.credentials = base64.b64encode(credentials).decode("utf") # Create the authorization cookie. - cookie = "Authorization=Basic {}".format(self.credentials) + cookie = f"Authorization=Basic {self.credentials}" response = requests.get(url, headers={COOKIE: cookie}) @@ -423,9 +423,9 @@ def _update_info(self): # Check both the 2.4GHz and 5GHz client list URLs for clients_url in ("WlanStationRpm.htm", "WlanStationRpm_5g.htm"): - url = "http://{}/{}/userRpm/{}".format(self.host, self.token, clients_url) - referer = "http://{}".format(self.host) - cookie = "Authorization=Basic {}".format(self.credentials) + url = f"http://{self.host}/{self.token}/userRpm/{clients_url}" + referer = f"http://{self.host}" + cookie = f"Authorization=Basic {self.credentials}" page = requests.get(url, headers={COOKIE: cookie, REFERER: referer}) mac_results.extend(self.parse_macs.findall(page.text)) @@ -456,7 +456,7 @@ def _update_info(self): """ _LOGGER.info("Loading wireless clients...") - base_url = "http://{}".format(self.host) + base_url = f"http://{self.host}" header = { USER_AGENT: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12;" @@ -466,7 +466,7 @@ def _update_info(self): ACCEPT_ENCODING: "gzip, deflate", CONTENT_TYPE: "application/x-www-form-urlencoded; charset=UTF-8", HTTP_HEADER_X_REQUESTED_WITH: "XMLHttpRequest", - REFERER: "http://{}/".format(self.host), + REFERER: f"http://{self.host}/", CONNECTION: KEEP_ALIVE, PRAGMA: HTTP_HEADER_NO_CACHE, CACHE_CONTROL: HTTP_HEADER_NO_CACHE, @@ -484,7 +484,7 @@ def _update_info(self): # A timestamp is required to be sent as get parameter timestamp = int(datetime.now().timestamp() * 1e3) - client_list_url = "{}/data/monitor.client.client.json".format(base_url) + client_list_url = f"{base_url}/data/monitor.client.client.json" get_params = {"operation": "load", "_": timestamp} diff --git a/homeassistant/components/traccar/__init__.py b/homeassistant/components/traccar/__init__.py index 8e3f90fb66f666..5eb87de0db28f5 100644 --- a/homeassistant/components/traccar/__init__.py +++ b/homeassistant/components/traccar/__init__.py @@ -24,7 +24,7 @@ _LOGGER = logging.getLogger(__name__) -TRACKER_UPDATE = "{}_tracker_update".format(DOMAIN) +TRACKER_UPDATE = f"{DOMAIN}_tracker_update" DEFAULT_ACCURACY = 200 @@ -83,7 +83,7 @@ async def handle_webhook(hass, webhook_id, request): attrs, ) - return web.Response(text="Setting location for {}".format(device), status=HTTP_OK) + return web.Response(text=f"Setting location for {device}", status=HTTP_OK) async def async_setup_entry(hass, entry): diff --git a/homeassistant/components/tradfri/light.py b/homeassistant/components/tradfri/light.py index 7992bf459db78f..97fdfd9d36d885 100644 --- a/homeassistant/components/tradfri/light.py +++ b/homeassistant/components/tradfri/light.py @@ -57,7 +57,7 @@ class TradfriGroup(Light): def __init__(self, group, api, gateway_id): """Initialize a Group.""" self._api = api - self._unique_id = "group-{}-{}".format(gateway_id, group.id) + self._unique_id = f"group-{gateway_id}-{group.id}" self._group = group self._name = group.name @@ -152,7 +152,7 @@ class TradfriLight(Light): def __init__(self, light, api, gateway_id): """Initialize a Light.""" self._api = api - self._unique_id = "light-{}-{}".format(gateway_id, light.id) + self._unique_id = f"light-{gateway_id}-{light.id}" self._light = None self._light_control = None self._light_data = None diff --git a/homeassistant/components/tradfri/switch.py b/homeassistant/components/tradfri/switch.py index 2b1bb0d5c548de..4be72eb7359e64 100644 --- a/homeassistant/components/tradfri/switch.py +++ b/homeassistant/components/tradfri/switch.py @@ -34,7 +34,7 @@ class TradfriSwitch(SwitchDevice): def __init__(self, switch, api, gateway_id): """Initialize a switch.""" self._api = api - self._unique_id = "{}-{}".format(gateway_id, switch.id) + self._unique_id = f"{gateway_id}-{switch.id}" self._switch = None self._socket_control = None self._switch_data = None diff --git a/homeassistant/components/trafikverket_weatherstation/sensor.py b/homeassistant/components/trafikverket_weatherstation/sensor.py index 9c79aa5cda6054..cb80e8d441bfc4 100644 --- a/homeassistant/components/trafikverket_weatherstation/sensor.py +++ b/homeassistant/components/trafikverket_weatherstation/sensor.py @@ -147,7 +147,7 @@ def __init__(self, weather_api, name, sensor_type, sensor_station): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._client, self._name) + return f"{self._client} {self._name}" @property def icon(self): diff --git a/homeassistant/components/transmission/sensor.py b/homeassistant/components/transmission/sensor.py index 9e5397dd9fbaee..ac2e64ce92f390 100644 --- a/homeassistant/components/transmission/sensor.py +++ b/homeassistant/components/transmission/sensor.py @@ -63,7 +63,7 @@ def __init__( @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/travisci/sensor.py b/homeassistant/components/travisci/sensor.py index 546fe7606e7569..b86b62fc1e9518 100644 --- a/homeassistant/components/travisci/sensor.py +++ b/homeassistant/components/travisci/sensor.py @@ -84,7 +84,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): for repo in repositories: if "/" not in repo: - repo = "{0}/{1}".format(user.login, repo) + repo = f"{user.login}/{repo}" for sensor_type in config.get(CONF_MONITORED_CONDITIONS): sensors.append(TravisCISensor(travis, repo, user, branch, sensor_type)) diff --git a/homeassistant/components/twentemilieu/sensor.py b/homeassistant/components/twentemilieu/sensor.py index 9dc109c98ded7e..b1be9a071e4b4a 100644 --- a/homeassistant/components/twentemilieu/sensor.py +++ b/homeassistant/components/twentemilieu/sensor.py @@ -40,28 +40,28 @@ async def async_setup_entry( TwenteMilieuSensor( twentemilieu, unique_id=entry.data[CONF_ID], - name="{} Waste Pickup".format(WASTE_TYPE_NON_RECYCLABLE), + name=f"{WASTE_TYPE_NON_RECYCLABLE} Waste Pickup", waste_type=WASTE_TYPE_NON_RECYCLABLE, icon="mdi:delete-empty", ), TwenteMilieuSensor( twentemilieu, unique_id=entry.data[CONF_ID], - name="{} Waste Pickup".format(WASTE_TYPE_ORGANIC), + name=f"{WASTE_TYPE_ORGANIC} Waste Pickup", waste_type=WASTE_TYPE_ORGANIC, icon="mdi:delete-empty", ), TwenteMilieuSensor( twentemilieu, unique_id=entry.data[CONF_ID], - name="{} Waste Pickup".format(WASTE_TYPE_PAPER), + name=f"{WASTE_TYPE_PAPER} Waste Pickup", waste_type=WASTE_TYPE_PAPER, icon="mdi:delete-empty", ), TwenteMilieuSensor( twentemilieu, unique_id=entry.data[CONF_ID], - name="{} Waste Pickup".format(WASTE_TYPE_PLASTIC), + name=f"{WASTE_TYPE_PLASTIC} Waste Pickup", waste_type=WASTE_TYPE_PLASTIC, icon="mdi:delete-empty", ), @@ -110,7 +110,7 @@ def available(self) -> bool: @property def unique_id(self) -> str: """Return the unique ID for this sensor.""" - return "{}_{}_{}".format(DOMAIN, self._unique_id, self._waste_type) + return f"{DOMAIN}_{self._unique_id}_{self._waste_type}" @property def should_poll(self) -> bool: diff --git a/homeassistant/components/twilio/__init__.py b/homeassistant/components/twilio/__init__.py index 74264a31f0631c..ea5629e7cab6d9 100644 --- a/homeassistant/components/twilio/__init__.py +++ b/homeassistant/components/twilio/__init__.py @@ -11,7 +11,7 @@ DATA_TWILIO = DOMAIN -RECEIVED_DATA = "{}_data_received".format(DOMAIN) +RECEIVED_DATA = f"{DOMAIN}_data_received" CONFIG_SCHEMA = vol.Schema( { diff --git a/homeassistant/components/ubus/device_tracker.py b/homeassistant/components/ubus/device_tracker.py index 53cd900c0d499b..f14ea5af02cd43 100644 --- a/homeassistant/components/ubus/device_tracker.py +++ b/homeassistant/components/ubus/device_tracker.py @@ -80,7 +80,7 @@ def __init__(self, config): self.parse_api_pattern = re.compile(r"(?P\w*) = (?P.*);") self.last_results = {} - self.url = "http://{}/ubus".format(host) + self.url = f"http://{host}/ubus" self.session_id = _get_session_id(self.url, self.username, self.password) self.hostapd = [] diff --git a/homeassistant/components/uk_transport/sensor.py b/homeassistant/components/uk_transport/sensor.py index 38183d23a0ebc7..8e6e46531e2f41 100644 --- a/homeassistant/components/uk_transport/sensor.py +++ b/homeassistant/components/uk_transport/sensor.py @@ -157,10 +157,10 @@ def __init__(self, api_app_id, api_app_key, stop_atcocode, bus_direction, interv self._stop_atcocode = stop_atcocode self._bus_direction = bus_direction self._next_buses = [] - self._destination_re = re.compile("{}".format(bus_direction), re.IGNORECASE) + self._destination_re = re.compile(f"{bus_direction}", re.IGNORECASE) - sensor_name = "Next bus to {}".format(bus_direction) - stop_url = "bus/stop/{}/live.json".format(stop_atcocode) + sensor_name = f"Next bus to {bus_direction}" + stop_url = f"bus/stop/{stop_atcocode}/live.json" UkTransportSensor.__init__(self, sensor_name, api_app_id, api_app_key, stop_url) self.update = Throttle(interval)(self._update) @@ -220,8 +220,8 @@ def __init__(self, api_app_id, api_app_key, station_code, calling_at, interval): self._calling_at = calling_at self._next_trains = [] - sensor_name = "Next train to {}".format(calling_at) - query_url = "train/station/{}/live.json".format(station_code) + sensor_name = f"Next train to {calling_at}" + query_url = f"train/station/{station_code}/live.json" UkTransportSensor.__init__( self, sensor_name, api_app_id, api_app_key, query_url diff --git a/homeassistant/components/unifi/device_tracker.py b/homeassistant/components/unifi/device_tracker.py index 1f4aef754adc0b..ca6ddb6820660c 100644 --- a/homeassistant/components/unifi/device_tracker.py +++ b/homeassistant/components/unifi/device_tracker.py @@ -238,7 +238,7 @@ def name(self) -> str: @property def unique_id(self) -> str: """Return a unique identifier for this client.""" - return "{}-{}".format(self.client.mac, self.controller.site) + return f"{self.client.mac}-{self.controller.site}" @property def available(self) -> bool: diff --git a/homeassistant/components/unifi/switch.py b/homeassistant/components/unifi/switch.py index f46a55f671ea4f..4f757102d530e8 100644 --- a/homeassistant/components/unifi/switch.py +++ b/homeassistant/components/unifi/switch.py @@ -69,7 +69,7 @@ def update_items(controller, async_add_entities, switches, switches_off): # block client for client_id in controller.option_block_clients: - block_client_id = "block-{}".format(client_id) + block_client_id = f"block-{client_id}" if block_client_id in switches: LOGGER.debug( @@ -91,7 +91,7 @@ def update_items(controller, async_add_entities, switches, switches_off): # control poe for client_id in controller.api.clients: - poe_client_id = "poe-{}".format(client_id) + poe_client_id = f"poe-{client_id}" if poe_client_id in switches: LOGGER.debug( @@ -194,7 +194,7 @@ async def async_added_to_hass(self): @property def unique_id(self): """Return a unique identifier for this switch.""" - return "poe-{}".format(self.client.mac) + return f"poe-{self.client.mac}" @property def is_on(self): @@ -255,7 +255,7 @@ class UniFiBlockClientSwitch(UniFiClient, SwitchDevice): @property def unique_id(self): """Return a unique identifier for this switch.""" - return "block-{}".format(self.client.mac) + return f"block-{self.client.mac}" @property def is_on(self): diff --git a/homeassistant/components/upc_connect/device_tracker.py b/homeassistant/components/upc_connect/device_tracker.py index 3355c33ab2a182..384b82d139564c 100644 --- a/homeassistant/components/upc_connect/device_tracker.py +++ b/homeassistant/components/upc_connect/device_tracker.py @@ -48,7 +48,7 @@ def __init__(self, hass, config): self.headers = { HTTP_HEADER_X_REQUESTED_WITH: "XMLHttpRequest", - REFERER: "http://{}/index.html".format(self.host), + REFERER: f"http://{self.host}/index.html", USER_AGENT: ( "Mozilla/5.0 (Windows NT 10.0; WOW64) " "AppleWebKit/537.36 (KHTML, like Gecko) " @@ -88,8 +88,7 @@ async def async_initialize_token(self): # get first token with async_timeout.timeout(10): response = await self.websession.get( - "http://{}/common_page/login.html".format(self.host), - headers=self.headers, + f"http://{self.host}/common_page/login.html", headers=self.headers ) await response.text() @@ -109,8 +108,8 @@ async def _async_ws_function(self, function): # The 'token' parameter has to be first, and 'fun' second # or the UPC firmware will return an error response = await self.websession.post( - "http://{}/xml/getter.xml".format(self.host), - data="token={}&fun={}".format(self.token, function), + f"http://{self.host}/xml/getter.xml", + data=f"token={self.token}&fun={function}", headers=self.headers, allow_redirects=False, ) diff --git a/homeassistant/components/upnp/sensor.py b/homeassistant/components/upnp/sensor.py index 33ffa4d478af5e..e5746e088f866b 100644 --- a/homeassistant/components/upnp/sensor.py +++ b/homeassistant/components/upnp/sensor.py @@ -118,7 +118,7 @@ def name(self) -> str: @property def unique_id(self) -> str: """Return an unique ID.""" - return "{}_{}".format(self._device.udn, self._type_name) + return f"{self._device.udn}_{self._type_name}" @property def state(self) -> str: @@ -172,12 +172,12 @@ def _async_fetch_value(self): @property def unique_id(self) -> str: """Return an unique ID.""" - return "{}_{}/sec_{}".format(self._device.udn, self.unit, self._direction) + return f"{self._device.udn}_{self.unit}/sec_{self._direction}" @property def name(self) -> str: """Return the name of the sensor.""" - return "{} {}/sec {}".format(self._device.name, self.unit, self._direction) + return f"{self._device.name} {self.unit}/sec {self._direction}" @property def icon(self) -> str: @@ -187,7 +187,7 @@ def icon(self) -> str: @property def unit_of_measurement(self) -> str: """Return the unit of measurement of this entity, if any.""" - return "{}/sec".format(self.unit) + return f"{self.unit}/sec" def _is_overflowed(self, new_value) -> bool: """Check if value has overflowed.""" diff --git a/homeassistant/components/usps/camera.py b/homeassistant/components/usps/camera.py index 78af9c4feab0e2..3141314b049cb5 100644 --- a/homeassistant/components/usps/camera.py +++ b/homeassistant/components/usps/camera.py @@ -65,7 +65,7 @@ def camera_image(self): @property def name(self): """Return the name of this camera.""" - return "{} mail".format(self._name) + return f"{self._name} mail" @property def model(self): diff --git a/homeassistant/components/usps/sensor.py b/homeassistant/components/usps/sensor.py index a8aa6f6cc6f304..7e26e6c9e5c793 100644 --- a/homeassistant/components/usps/sensor.py +++ b/homeassistant/components/usps/sensor.py @@ -36,7 +36,7 @@ def __init__(self, usps): @property def name(self): """Return the name of the sensor.""" - return "{} packages".format(self._name) + return f"{self._name} packages" @property def state(self): @@ -85,7 +85,7 @@ def __init__(self, usps): @property def name(self): """Return the name of the sensor.""" - return "{} mail".format(self._name) + return f"{self._name} mail" @property def state(self): diff --git a/homeassistant/components/vallox/__init__.py b/homeassistant/components/vallox/__init__.py index 40ae0a8348251d..c107e4f8894551 100644 --- a/homeassistant/components/vallox/__init__.py +++ b/homeassistant/components/vallox/__init__.py @@ -152,7 +152,7 @@ def fetch_metric(self, metric_key): raise OSError("Device state out of sync.") if metric_key not in vlxDevConstants.__dict__: - raise KeyError("Unknown metric key: {}".format(metric_key)) + raise KeyError(f"Unknown metric key: {metric_key}") return self._metric_cache[metric_key] diff --git a/homeassistant/components/vallox/sensor.py b/homeassistant/components/vallox/sensor.py index 705ccd3103daf8..f7be502cecb18c 100644 --- a/homeassistant/components/vallox/sensor.py +++ b/homeassistant/components/vallox/sensor.py @@ -28,14 +28,14 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= sensors = [ ValloxProfileSensor( - name="{} Current Profile".format(name), + name=f"{name} Current Profile", state_proxy=state_proxy, device_class=None, unit_of_measurement=None, icon="mdi:gauge", ), ValloxFanSpeedSensor( - name="{} Fan Speed".format(name), + name=f"{name} Fan Speed", state_proxy=state_proxy, metric_key="A_CYC_FAN_SPEED", device_class=None, @@ -43,7 +43,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= icon="mdi:fan", ), ValloxSensor( - name="{} Extract Air".format(name), + name=f"{name} Extract Air", state_proxy=state_proxy, metric_key="A_CYC_TEMP_EXTRACT_AIR", device_class=DEVICE_CLASS_TEMPERATURE, @@ -51,7 +51,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= icon=None, ), ValloxSensor( - name="{} Exhaust Air".format(name), + name=f"{name} Exhaust Air", state_proxy=state_proxy, metric_key="A_CYC_TEMP_EXHAUST_AIR", device_class=DEVICE_CLASS_TEMPERATURE, @@ -59,7 +59,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= icon=None, ), ValloxSensor( - name="{} Outdoor Air".format(name), + name=f"{name} Outdoor Air", state_proxy=state_proxy, metric_key="A_CYC_TEMP_OUTDOOR_AIR", device_class=DEVICE_CLASS_TEMPERATURE, @@ -67,7 +67,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= icon=None, ), ValloxSensor( - name="{} Supply Air".format(name), + name=f"{name} Supply Air", state_proxy=state_proxy, metric_key="A_CYC_TEMP_SUPPLY_AIR", device_class=DEVICE_CLASS_TEMPERATURE, @@ -75,7 +75,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= icon=None, ), ValloxSensor( - name="{} Humidity".format(name), + name=f"{name} Humidity", state_proxy=state_proxy, metric_key="A_CYC_RH_VALUE", device_class=DEVICE_CLASS_HUMIDITY, @@ -83,7 +83,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= icon=None, ), ValloxFilterRemainingSensor( - name="{} Remaining Time For Filter".format(name), + name=f"{name} Remaining Time For Filter", state_proxy=state_proxy, metric_key="A_CYC_REMAINING_TIME_FOR_FILTER", device_class=DEVICE_CLASS_TIMESTAMP, diff --git a/homeassistant/components/velbus/__init__.py b/homeassistant/components/velbus/__init__.py index 76018dcf54844d..9946f06446f059 100644 --- a/homeassistant/components/velbus/__init__.py +++ b/homeassistant/components/velbus/__init__.py @@ -119,7 +119,7 @@ def unique_id(self): serial = self._module.get_module_address() else: serial = self._module.serial - return "{}-{}".format(serial, self._channel) + return f"{serial}-{self._channel}" @property def name(self): diff --git a/homeassistant/components/volumio/media_player.py b/homeassistant/components/volumio/media_player.py index 96e1d883646361..8bd1952a6507d0 100644 --- a/homeassistant/components/volumio/media_player.py +++ b/homeassistant/components/volumio/media_player.py @@ -125,7 +125,7 @@ def __init__(self, name, host, port, hass): async def send_volumio_msg(self, method, params=None): """Send message.""" - url = "http://{}:{}/api/v1/{}/".format(self.host, self.port, method) + url = f"http://{self.host}:{self.port}/api/v1/{method}/" _LOGGER.debug("URL: %s params: %s", url, params) @@ -202,7 +202,7 @@ def media_image_url(self): if str(url[0:2]).lower() == "ht": mediaurl = url else: - mediaurl = "http://{}:{}{}".format(self.host, self.port, url) + mediaurl = f"http://{self.host}:{self.port}{url}" return mediaurl @property diff --git a/homeassistant/components/volvooncall/__init__.py b/homeassistant/components/volvooncall/__init__.py index b007628dbd85b1..c41c72020c42aa 100644 --- a/homeassistant/components/volvooncall/__init__.py +++ b/homeassistant/components/volvooncall/__init__.py @@ -36,7 +36,7 @@ CONF_SCANDINAVIAN_MILES = "scandinavian_miles" CONF_MUTABLE = "mutable" -SIGNAL_STATE_UPDATED = "{}.updated".format(DOMAIN) +SIGNAL_STATE_UPDATED = f"{DOMAIN}.updated" COMPONENTS = { "sensor": "sensor", @@ -261,7 +261,7 @@ def _vehicle_name(self): @property def name(self): """Return full name of the entity.""" - return "{} {}".format(self._vehicle_name, self._entity_name) + return f"{self._vehicle_name} {self._entity_name}" @property def should_poll(self): @@ -278,5 +278,5 @@ def device_state_attributes(self): """Return device specific state attributes.""" return dict( self.instrument.attributes, - model="{}/{}".format(self.vehicle.vehicle_type, self.vehicle.model_year), + model=f"{self.vehicle.vehicle_type}/{self.vehicle.model_year}", ) diff --git a/homeassistant/components/waqi/sensor.py b/homeassistant/components/waqi/sensor.py index a2b9e69e002460..dbfe6de1a60b46 100644 --- a/homeassistant/components/waqi/sensor.py +++ b/homeassistant/components/waqi/sensor.py @@ -113,7 +113,7 @@ def __init__(self, client, station): def name(self): """Return the name of the sensor.""" if self.station_name: - return "WAQI {}".format(self.station_name) + return f"WAQI {self.station_name}" return "WAQI {}".format(self.url if self.url else self.uid) @property diff --git a/homeassistant/components/watson_iot/__init__.py b/homeassistant/components/watson_iot/__init__.py index 54c11506b29a8e..aef2cc8ccce274 100644 --- a/homeassistant/components/watson_iot/__init__.py +++ b/homeassistant/components/watson_iot/__init__.py @@ -126,7 +126,7 @@ def event_to_json(event): if key != "unit_of_measurement": # If the key is already in fields if key in out_event["fields"]: - key = "{}_".format(key) + key = f"{key}_" # For each value we try to cast it as float # But if we can not do it we store the value # as string diff --git a/homeassistant/components/waze_travel_time/sensor.py b/homeassistant/components/waze_travel_time/sensor.py index 3fc44f90d4268e..340c0adbc9705e 100644 --- a/homeassistant/components/waze_travel_time/sensor.py +++ b/homeassistant/components/waze_travel_time/sensor.py @@ -175,7 +175,7 @@ def _get_location_from_entity(self, entity_id): return _get_location_from_attributes(state) # Check if device is inside a zone. - zone_state = self.hass.states.get("zone.{}".format(state.state)) + zone_state = self.hass.states.get(f"zone.{state.state}") if location.has_location(zone_state): _LOGGER.debug( "%s is in %s, getting zone location", entity_id, zone_state.entity_id diff --git a/homeassistant/components/wemo/__init__.py b/homeassistant/components/wemo/__init__.py index 3cdc5afd4a0063..9e479991d15548 100644 --- a/homeassistant/components/wemo/__init__.py +++ b/homeassistant/components/wemo/__init__.py @@ -108,7 +108,7 @@ def stop_wemo(event): def setup_url_for_device(device): """Determine setup.xml url for given device.""" - return "http://{}:{}/setup.xml".format(device.host, device.port) + return f"http://{device.host}:{device.port}/setup.xml" def setup_url_for_address(host, port): """Determine setup.xml url for given host and port pair.""" @@ -118,7 +118,7 @@ def setup_url_for_address(host, port): if not port: return None - return "http://{}:{}/setup.xml".format(host, port) + return f"http://{host}:{port}/setup.xml" def discovery_dispatch(service, discovery_info): """Dispatcher for incoming WeMo discovery events.""" @@ -150,7 +150,7 @@ def discover_wemo_devices(now): if not url: _LOGGER.error( "Unable to get description url for WeMo at: %s", - "{}:{}".format(host, port) if port else host, + f"{host}:{port}" if port else host, ) continue diff --git a/homeassistant/components/wink/__init__.py b/homeassistant/components/wink/__init__.py index 710adfd734d294..5af784359d83db 100644 --- a/homeassistant/components/wink/__init__.py +++ b/homeassistant/components/wink/__init__.py @@ -52,7 +52,7 @@ WINK_AUTH_CALLBACK_PATH = "/auth/wink/callback" WINK_AUTH_START = "/auth/wink" WINK_CONFIG_FILE = ".wink.conf" -USER_AGENT = "Manufacturer/Home-Assistant{} python/3 Wink/3".format(__version__) +USER_AGENT = f"Manufacturer/Home-Assistant{__version__} python/3 Wink/3" DEFAULT_CONFIG = {"client_id": "CLIENT_ID_HERE", "client_secret": "CLIENT_SECRET_HERE"} @@ -228,7 +228,7 @@ def wink_configuration_callback(callback_data): _configurator = hass.data[DOMAIN]["configuring"][DOMAIN] configurator.notify_errors(_configurator, error_msg) - start_url = "{}{}".format(hass.config.api.base_url, WINK_AUTH_CALLBACK_PATH) + start_url = f"{hass.config.api.base_url}{WINK_AUTH_CALLBACK_PATH}" description = """Please create a Wink developer app at https://developer.wink.com. @@ -268,9 +268,9 @@ def wink_configuration_callback(callback_data): """Call setup again.""" setup(hass, config) - start_url = "{}{}".format(hass.config.api.base_url, WINK_AUTH_START) + start_url = f"{hass.config.api.base_url}{WINK_AUTH_START}" - description = "Please authorize Wink by visiting {}".format(start_url) + description = f"Please authorize Wink by visiting {start_url}" hass.data[DOMAIN]["configuring"][DOMAIN] = configurator.request_config( DOMAIN, wink_configuration_callback, description=description diff --git a/homeassistant/components/wink/binary_sensor.py b/homeassistant/components/wink/binary_sensor.py index ad1800b4223c9a..e82a767fde8315 100644 --- a/homeassistant/components/wink/binary_sensor.py +++ b/homeassistant/components/wink/binary_sensor.py @@ -140,7 +140,7 @@ def device_state_attributes(self): # The service call to set the Kidde code # takes a string of 1s and 0s so it makes # sense to display it to the user that way - _formatted_kidde_code = "{:b}".format(_kidde_code).zfill(8) + _formatted_kidde_code = f"{_kidde_code:b}".zfill(8) _attributes["kidde_radio_code"] = _formatted_kidde_code return _attributes diff --git a/homeassistant/components/wirelesstag/__init__.py b/homeassistant/components/wirelesstag/__init__.py index 331b88894def67..5e0da881076f65 100644 --- a/homeassistant/components/wirelesstag/__init__.py +++ b/homeassistant/components/wirelesstag/__init__.py @@ -74,14 +74,14 @@ def load_tags(self): def arm(self, switch): """Arm entity sensor monitoring.""" - func_name = "arm_{}".format(switch.sensor_type) + func_name = f"arm_{switch.sensor_type}" arm_func = getattr(self.api, func_name) if arm_func is not None: arm_func(switch.tag_id, switch.tag_manager_mac) def disarm(self, switch): """Disarm entity sensor monitoring.""" - func_name = "disarm_{}".format(switch.sensor_type) + func_name = f"disarm_{switch.sensor_type}" disarm_func = getattr(self.api, func_name) if disarm_func is not None: disarm_func(switch.tag_id, switch.tag_manager_mac) @@ -132,18 +132,18 @@ def local_base_url(self): port = self.hass.config.api.port if port is not None: - self._local_base_url += ":{}".format(port) + self._local_base_url += f":{port}" return self._local_base_url @property def update_callback_url(self): """Return url for local push notifications(update event).""" - return "{}/api/events/wirelesstag_update_tags".format(self.local_base_url) + return f"{self.local_base_url}/api/events/wirelesstag_update_tags" @property def binary_event_callback_url(self): """Return url for local push notifications(binary event).""" - return "{}/api/events/wirelesstag_binary_event".format(self.local_base_url) + return f"{self.local_base_url}/api/events/wirelesstag_binary_event" def handle_update_tags_event(self, event): """Handle push event from wireless tag manager.""" @@ -254,7 +254,7 @@ def updated_state_value(self): # pylint: disable=no-self-use def decorate_value(self, value): """Decorate input value to be well presented for end user.""" - return "{:.1f}".format(value) + return f"{value:.1f}" @property def available(self): @@ -280,8 +280,8 @@ def device_state_attributes(self): """Return the state attributes.""" return { ATTR_BATTERY_LEVEL: int(self._tag.battery_remaining * 100), - ATTR_VOLTAGE: "{:.2f}V".format(self._tag.battery_volts), - ATTR_TAG_SIGNAL_STRENGTH: "{}dBm".format(self._tag.signal_strength), + ATTR_VOLTAGE: f"{self._tag.battery_volts:.2f}V", + ATTR_TAG_SIGNAL_STRENGTH: f"{self._tag.signal_strength}dBm", ATTR_TAG_OUT_OF_RANGE: not self._tag.is_in_range, - ATTR_TAG_POWER_CONSUMPTION: "{:.2f}%".format(self._tag.power_consumption), + ATTR_TAG_POWER_CONSUMPTION: f"{self._tag.power_consumption:.2f}%", } diff --git a/homeassistant/components/wirelesstag/binary_sensor.py b/homeassistant/components/wirelesstag/binary_sensor.py index 72b68a8762ff65..4fcebe73478c78 100644 --- a/homeassistant/components/wirelesstag/binary_sensor.py +++ b/homeassistant/components/wirelesstag/binary_sensor.py @@ -95,7 +95,7 @@ def __init__(self, api, tag, sensor_type): """Initialize a binary sensor for a Wireless Sensor Tags.""" super().__init__(api, tag) self._sensor_type = sensor_type - self._name = "{0} {1}".format(self._tag.name, self.event.human_readable_name) + self._name = f"{self._tag.name} {self.event.human_readable_name}" async def async_added_to_hass(self): """Register callbacks.""" diff --git a/homeassistant/components/wirelesstag/switch.py b/homeassistant/components/wirelesstag/switch.py index 37f97e3a1e695a..1bc806d9e32390 100644 --- a/homeassistant/components/wirelesstag/switch.py +++ b/homeassistant/components/wirelesstag/switch.py @@ -79,5 +79,5 @@ def updated_state_value(self): @property def principal_value(self): """Provide actual value of switch.""" - attr_name = "is_{}_sensor_armed".format(self.sensor_type) + attr_name = f"is_{self.sensor_type}_sensor_armed" return getattr(self._tag, attr_name, False) diff --git a/homeassistant/components/withings/sensor.py b/homeassistant/components/withings/sensor.py index 3328808295f36e..67cf966c1bcd4a 100644 --- a/homeassistant/components/withings/sensor.py +++ b/homeassistant/components/withings/sensor.py @@ -325,7 +325,7 @@ def __init__( @property def name(self) -> str: """Return the name of the sensor.""" - return "Withings {} {}".format(self._attribute.measurement, self._slug) + return f"Withings {self._attribute.measurement} {self._slug}" @property def unique_id(self) -> str: diff --git a/homeassistant/components/worldtidesinfo/sensor.py b/homeassistant/components/worldtidesinfo/sensor.py index bd20431d70630c..aaa9f2d1585919 100644 --- a/homeassistant/components/worldtidesinfo/sensor.py +++ b/homeassistant/components/worldtidesinfo/sensor.py @@ -96,12 +96,12 @@ def state(self): tidetime = time.strftime( "%I:%M %p", time.localtime(self.data["extremes"][0]["dt"]) ) - return "High tide at {}".format(tidetime) + return f"High tide at {tidetime}" if "Low" in str(self.data["extremes"][0]["type"]): tidetime = time.strftime( "%I:%M %p", time.localtime(self.data["extremes"][0]["dt"]) ) - return "Low tide at {}".format(tidetime) + return f"Low tide at {tidetime}" return None return None diff --git a/homeassistant/components/worxlandroid/sensor.py b/homeassistant/components/worxlandroid/sensor.py index 69e2813e7d1c16..4e9bf0a6a4a913 100644 --- a/homeassistant/components/worxlandroid/sensor.py +++ b/homeassistant/components/worxlandroid/sensor.py @@ -63,12 +63,12 @@ def __init__(self, sensor, config): self.pin = config.get(CONF_PIN) self.timeout = config.get(CONF_TIMEOUT) self.allow_unreachable = config.get(CONF_ALLOW_UNREACHABLE) - self.url = "http://{}/jsondata.cgi".format(self.host) + self.url = f"http://{self.host}/jsondata.cgi" @property def name(self): """Return the name of the sensor.""" - return "worxlandroid-{}".format(self.sensor) + return f"worxlandroid-{self.sensor}" @property def state(self): diff --git a/homeassistant/components/wunderground/sensor.py b/homeassistant/components/wunderground/sensor.py index 21f87d9ce0b510..5272b33ccb5673 100644 --- a/homeassistant/components/wunderground/sensor.py +++ b/homeassistant/components/wunderground/sensor.py @@ -968,7 +968,7 @@ async def async_setup_platform( ) if pws_id is None: - unique_id_base = "@{:06f},{:06f}".format(longitude, latitude) + unique_id_base = f"@{longitude:06f},{latitude:06f}" else: # Manually specified weather station, use that for unique_id unique_id_base = pws_id @@ -999,7 +999,7 @@ def __init__(self, hass: HomeAssistantType, rest, condition, unique_id_base: str # This is only the suggested entity id, it might get changed by # the entity registry later. self.entity_id = sensor.ENTITY_ID_FORMAT.format("pws_" + condition) - self._unique_id = "{},{}".format(unique_id_base, condition) + self._unique_id = f"{unique_id_base},{condition}" self._device_class = self._cfg_expand("device_class") def _cfg_expand(self, what, default=None): @@ -1106,7 +1106,7 @@ def __init__(self, hass, api_key, pws_id, lang, latitude, longitude): self._hass = hass self._api_key = api_key self._pws_id = pws_id - self._lang = "lang:{}".format(lang) + self._lang = f"lang:{lang}" self._latitude = latitude self._longitude = longitude self._features = set() @@ -1122,9 +1122,9 @@ def _build_url(self, baseurl=_RESOURCE): self._api_key, "/".join(sorted(self._features)), self._lang ) if self._pws_id: - url = url + "pws:{}".format(self._pws_id) + url = url + f"pws:{self._pws_id}" else: - url = url + "{},{}".format(self._latitude, self._longitude) + url = url + f"{self._latitude},{self._longitude}" return url + ".json" diff --git a/homeassistant/components/wwlln/__init__.py b/homeassistant/components/wwlln/__init__.py index ca3711490e7fad..412efc904dbf52 100644 --- a/homeassistant/components/wwlln/__init__.py +++ b/homeassistant/components/wwlln/__init__.py @@ -47,7 +47,7 @@ async def async_setup(hass, config): latitude = conf.get(CONF_LATITUDE, hass.config.latitude) longitude = conf.get(CONF_LONGITUDE, hass.config.longitude) - identifier = "{0}, {1}".format(latitude, longitude) + identifier = f"{latitude}, {longitude}" if identifier in configured_instances(hass): return True From e16f2c3e6b1dfdfa76ffcc642d420acb0cb35c50 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 21:14:00 +0200 Subject: [PATCH 68/72] Use literal string interpolation in integrations K-M (f-strings) (#26389) --- homeassistant/components/kankun/switch.py | 8 +++---- homeassistant/components/kira/__init__.py | 2 +- homeassistant/components/kodi/media_player.py | 12 +++++----- homeassistant/components/kodi/notify.py | 2 +- .../components/konnected/__init__.py | 2 +- homeassistant/components/kwb/sensor.py | 2 +- homeassistant/components/lastfm/sensor.py | 6 ++--- homeassistant/components/lcn/helpers.py | 2 +- .../components/life360/config_flow.py | 2 +- .../components/life360/device_tracker.py | 10 ++++----- homeassistant/components/lifx/light.py | 2 +- homeassistant/components/lifx_cloud/scene.py | 2 +- homeassistant/components/light/__init__.py | 10 ++++----- .../linksys_smart/device_tracker.py | 2 +- .../components/linux_battery/sensor.py | 2 +- .../components/liveboxplaytv/media_player.py | 2 +- homeassistant/components/locative/__init__.py | 10 ++++----- homeassistant/components/logbook/__init__.py | 14 ++++++------ .../components/logentries/__init__.py | 2 +- .../components/logi_circle/__init__.py | 2 +- .../components/logi_circle/config_flow.py | 2 +- .../components/logi_circle/sensor.py | 2 +- .../components/luftdaten/__init__.py | 2 +- homeassistant/components/lutron/__init__.py | 4 ++-- homeassistant/components/lyft/sensor.py | 2 +- .../components/magicseaweed/sensor.py | 6 ++--- homeassistant/components/mailgun/__init__.py | 4 ++-- homeassistant/components/marytts/tts.py | 2 +- homeassistant/components/metoffice/weather.py | 2 +- homeassistant/components/microsoft/tts.py | 4 ++-- .../components/microsoft_face/__init__.py | 22 ++++++++----------- .../microsoft_face_detect/image_processing.py | 2 +- homeassistant/components/miflora/sensor.py | 2 +- homeassistant/components/minio/__init__.py | 2 +- homeassistant/components/mitemp_bt/sensor.py | 2 +- .../components/mobile_app/binary_sensor.py | 2 +- homeassistant/components/mobile_app/entity.py | 2 +- homeassistant/components/mobile_app/sensor.py | 2 +- .../components/mobile_app/webhook.py | 8 +++---- homeassistant/components/mochad/light.py | 8 +++---- homeassistant/components/modbus/climate.py | 2 +- homeassistant/components/modbus/sensor.py | 2 +- homeassistant/components/mopar/__init__.py | 2 +- .../components/mpchc/media_player.py | 8 +++---- homeassistant/components/mpd/media_player.py | 2 +- homeassistant/components/mqtt/discovery.py | 6 ++--- .../components/mqtt/vacuum/schema_legacy.py | 8 +++---- .../components/mysensors/__init__.py | 4 ++-- homeassistant/components/mysensors/gateway.py | 2 +- homeassistant/components/mysensors/notify.py | 2 +- .../components/mystrom/binary_sensor.py | 9 +++----- 51 files changed, 104 insertions(+), 121 deletions(-) diff --git a/homeassistant/components/kankun/switch.py b/homeassistant/components/kankun/switch.py index 5d41b2360e93e1..63f289862f636e 100644 --- a/homeassistant/components/kankun/switch.py +++ b/homeassistant/components/kankun/switch.py @@ -66,7 +66,7 @@ def __init__(self, hass, name, host, port, path, user, passwd): self._hass = hass self._name = name self._state = False - self._url = "http://{}:{}{}".format(host, port, path) + self._url = f"http://{host}:{port}{path}" if user is not None: self._auth = (user, passwd) else: @@ -78,7 +78,7 @@ def _switch(self, newstate): try: req = requests.get( - "{}?set={}".format(self._url, newstate), auth=self._auth, timeout=5 + f"{self._url}?set={newstate}", auth=self._auth, timeout=5 ) return req.json()["ok"] except requests.RequestException: @@ -89,9 +89,7 @@ def _query_state(self): _LOGGER.info("Querying state from: %s", self._url) try: - req = requests.get( - "{}?get=state".format(self._url), auth=self._auth, timeout=5 - ) + req = requests.get(f"{self._url}?get=state", auth=self._auth, timeout=5) return req.json()["state"] == "on" except requests.RequestException: _LOGGER.error("State query failed") diff --git a/homeassistant/components/kira/__init__.py b/homeassistant/components/kira/__init__.py index 24eb8b06aef620..77f91a50dfad04 100644 --- a/homeassistant/components/kira/__init__.py +++ b/homeassistant/components/kira/__init__.py @@ -32,7 +32,7 @@ CONF_SENSOR = "sensor" CONF_REMOTE = "remote" -CODES_YAML = "{}_codes.yaml".format(DOMAIN) +CODES_YAML = f"{DOMAIN}_codes.yaml" CODE_SCHEMA = vol.Schema( { diff --git a/homeassistant/components/kodi/media_player.py b/homeassistant/components/kodi/media_player.py index 14ef0292eccfc6..9f0aab6c00c7d8 100644 --- a/homeassistant/components/kodi/media_player.py +++ b/homeassistant/components/kodi/media_player.py @@ -140,7 +140,7 @@ def _check_deprecated_turn_off(hass, turn_off_action): method = DEPRECATED_TURN_OFF_ACTIONS[turn_off_action] new_config = OrderedDict( [ - ("service", "{}.{}".format(DOMAIN, SERVICE_CALL_METHOD)), + ("service", f"{DOMAIN}.{SERVICE_CALL_METHOD}"), ( "data_template", OrderedDict([("entity_id", "{{ entity_id }}"), ("method", method)]), @@ -281,18 +281,18 @@ def __init__( if username is not None: kwargs["auth"] = aiohttp.BasicAuth(username, password) - image_auth_string = "{}:{}@".format(username, password) + image_auth_string = f"{username}:{password}@" else: image_auth_string = "" http_protocol = "https" if encryption else "http" ws_protocol = "wss" if encryption else "ws" - self._http_url = "{}://{}:{}/jsonrpc".format(http_protocol, host, port) + self._http_url = f"{http_protocol}://{host}:{port}/jsonrpc" self._image_url = "{}://{}{}:{}/image".format( http_protocol, image_auth_string, host, port ) - self._ws_url = "{}://{}:{}/jsonrpc".format(ws_protocol, host, tcp_port) + self._ws_url = f"{ws_protocol}://{host}:{tcp_port}/jsonrpc" self._http_server = jsonrpc_async.Server(self._http_url, **kwargs) if websocket: @@ -326,14 +326,14 @@ def on_hass_stop(event): turn_on_action = script.Script( self.hass, turn_on_action, - "{} turn ON script".format(self.name), + f"{self.name} turn ON script", self.async_update_ha_state(True), ) if turn_off_action is not None: turn_off_action = script.Script( self.hass, _check_deprecated_turn_off(hass, turn_off_action), - "{} turn OFF script".format(self.name), + f"{self.name} turn OFF script", ) self._turn_on_action = turn_on_action self._turn_off_action = turn_off_action diff --git a/homeassistant/components/kodi/notify.py b/homeassistant/components/kodi/notify.py index 70c8669019cd85..41dfc42b5deda5 100644 --- a/homeassistant/components/kodi/notify.py +++ b/homeassistant/components/kodi/notify.py @@ -62,7 +62,7 @@ async def async_get_service(hass, config, discovery_info=None): ) http_protocol = "https" if encryption else "http" - url = "{}://{}:{}/jsonrpc".format(http_protocol, host, port) + url = f"{http_protocol}://{host}:{port}/jsonrpc" if username is not None: auth = aiohttp.BasicAuth(username, password) diff --git a/homeassistant/components/konnected/__init__.py b/homeassistant/components/konnected/__init__.py index d98f44bd3d9f4d..4cc872fb78b2a2 100644 --- a/homeassistant/components/konnected/__init__.py +++ b/homeassistant/components/konnected/__init__.py @@ -538,7 +538,7 @@ async def put(self, request: Request, device_id) -> Response: ) auth = request.headers.get(AUTHORIZATION, None) - if not hmac.compare_digest("Bearer {}".format(self.auth_token), auth): + if not hmac.compare_digest(f"Bearer {self.auth_token}", auth): return self.json_message("unauthorized", status_code=HTTP_UNAUTHORIZED) pin_num = int(pin_num) device = data[CONF_DEVICES].get(device_id) diff --git a/homeassistant/components/kwb/sensor.py b/homeassistant/components/kwb/sensor.py index 911884d2a9e3ad..49815faf7aed44 100644 --- a/homeassistant/components/kwb/sensor.py +++ b/homeassistant/components/kwb/sensor.py @@ -92,7 +92,7 @@ def __init__(self, easyfire, sensor, client_name): @property def name(self): """Return the name.""" - return "{} {}".format(self._client_name, self._name) + return f"{self._client_name} {self._name}" @property def available(self) -> bool: diff --git a/homeassistant/components/lastfm/sensor.py b/homeassistant/components/lastfm/sensor.py index ce92cffee53d39..736792aefd8123 100644 --- a/homeassistant/components/lastfm/sensor.py +++ b/homeassistant/components/lastfm/sensor.py @@ -72,7 +72,7 @@ def name(self): @property def entity_id(self): """Return the entity ID.""" - return "sensor.lastfm_{}".format(self._name) + return f"sensor.lastfm_{self._name}" @property def state(self): @@ -84,7 +84,7 @@ def update(self): self._cover = self._user.get_image() self._playcount = self._user.get_playcount() last = self._user.get_recent_tracks(limit=2)[0] - self._lastplayed = "{} - {}".format(last.track.artist, last.track.title) + self._lastplayed = f"{last.track.artist} - {last.track.title}" top = self._user.get_top_tracks(limit=1)[0] toptitle = re.search("', '(.+?)',", str(top)) topartist = re.search("'(.+?)',", str(top)) @@ -93,7 +93,7 @@ def update(self): self._state = "Not Scrobbling" return now = self._user.get_now_playing() - self._state = "{} - {}".format(now.artist, now.title) + self._state = f"{now.artist} - {now.title}" @property def device_state_attributes(self): diff --git a/homeassistant/components/lcn/helpers.py b/homeassistant/components/lcn/helpers.py index 92d515127269c7..236035b0400eb7 100644 --- a/homeassistant/components/lcn/helpers.py +++ b/homeassistant/components/lcn/helpers.py @@ -38,7 +38,7 @@ def has_unique_connection_names(connections): if suffix == 0: connection[CONF_NAME] = DEFAULT_NAME else: - connection[CONF_NAME] = "{}{:d}".format(DEFAULT_NAME, suffix) + connection[CONF_NAME] = f"{DEFAULT_NAME}{suffix:d}" schema = vol.Schema(vol.Unique()) schema([connection.get(CONF_NAME) for connection in connections]) diff --git a/homeassistant/components/life360/config_flow.py b/homeassistant/components/life360/config_flow.py index be84d276422109..6af999a575d5c8 100644 --- a/homeassistant/components/life360/config_flow.py +++ b/homeassistant/components/life360/config_flow.py @@ -99,7 +99,7 @@ async def async_step_import(self, user_input): ) return self.async_abort(reason="unexpected") return self.async_create_entry( - title="{} (from configuration)".format(username), + title=f"{username} (from configuration)", data={ CONF_USERNAME: username, CONF_PASSWORD: password, diff --git a/homeassistant/components/life360/device_tracker.py b/homeassistant/components/life360/device_tracker.py index dc5645a5216770..ddd562ebfac8e9 100644 --- a/homeassistant/components/life360/device_tracker.py +++ b/homeassistant/components/life360/device_tracker.py @@ -159,7 +159,7 @@ def _err(self, key, err_msg): _errs = self._errs.get(key, 0) if _errs < self._max_errs: self._errs[key] = _errs = _errs + 1 - msg = "{}: {}".format(key, err_msg) + msg = f"{key}: {err_msg}" if _errs >= self._error_threshold: if _errs == self._max_errs: msg = "Suppressing further errors until OK: " + msg @@ -233,14 +233,12 @@ def _update_member(self, member, dev_id): convert(float(gps_accuracy), LENGTH_FEET, LENGTH_METERS) ) except (TypeError, ValueError): - self._err( - dev_id, "GPS data invalid: {}, {}, {}".format(lat, lon, gps_accuracy) - ) + self._err(dev_id, f"GPS data invalid: {lat}, {lon}, {gps_accuracy}") return self._ok(dev_id) - msg = "Updating {}".format(dev_id) + msg = f"Updating {dev_id}" if prev_seen: msg += "; Time since last update: {}".format(last_seen - prev_seen) _LOGGER.debug(msg) @@ -401,7 +399,7 @@ def _update_life360(self, now=None): except (Life360Error, KeyError): pass if incl_circle: - err_key = 'get_circle_members "{}"'.format(circle_name) + err_key = f'get_circle_members "{circle_name}"' try: members = api.get_circle_members(circle_id) except Life360Error as exc: diff --git a/homeassistant/components/lifx/light.py b/homeassistant/components/lifx/light.py index b3ec9ed288ff16..ed26db3d49e535 100644 --- a/homeassistant/components/lifx/light.py +++ b/homeassistant/components/lifx/light.py @@ -509,7 +509,7 @@ def name(self): @property def who(self): """Return a string identifying the bulb.""" - return "%s (%s)" % (self.bulb.ip_addr, self.name) + return f"{self.bulb.ip_addr} ({self.name})" @property def min_mireds(self): diff --git a/homeassistant/components/lifx_cloud/scene.py b/homeassistant/components/lifx_cloud/scene.py index 6fc9fac126762a..ac4e0201fb87f5 100644 --- a/homeassistant/components/lifx_cloud/scene.py +++ b/homeassistant/components/lifx_cloud/scene.py @@ -31,7 +31,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= token = config.get(CONF_TOKEN) timeout = config.get(CONF_TIMEOUT) - headers = {AUTHORIZATION: "Bearer {}".format(token)} + headers = {AUTHORIZATION: f"Bearer {token}"} url = LIFX_API_URL.format("scenes") diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 94ba43b85458d9..ed61d961d881df 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -237,16 +237,16 @@ async def async_handle(self, intent_obj): response = intent_obj.create_response() if not speech_parts: # No attributes changed - speech = "Turned on {}".format(state.name) + speech = f"Turned on {state.name}" else: - parts = ["Changed {} to".format(state.name)] + parts = [f"Changed {state.name} to"] for index, part in enumerate(speech_parts): if index == 0: - parts.append(" {}".format(part)) + parts.append(f" {part}") elif index != len(speech_parts) - 1: - parts.append(", {}".format(part)) + parts.append(f", {part}") else: - parts.append(" and {}".format(part)) + parts.append(f" and {part}") speech = "".join(parts) response.async_set_speech(speech) diff --git a/homeassistant/components/linksys_smart/device_tracker.py b/homeassistant/components/linksys_smart/device_tracker.py index 9877f6ed09174e..1af84a4c4ab216 100644 --- a/homeassistant/components/linksys_smart/device_tracker.py +++ b/homeassistant/components/linksys_smart/device_tracker.py @@ -100,7 +100,7 @@ def _make_request(self): ] headers = {"X-JNAP-Action": "http://linksys.com/jnap/core/Transaction"} return requests.post( - "http://{}/JNAP/".format(self.host), + f"http://{self.host}/JNAP/", timeout=DEFAULT_TIMEOUT, headers=headers, json=data, diff --git a/homeassistant/components/linux_battery/sensor.py b/homeassistant/components/linux_battery/sensor.py index 9eb7090e957f74..9256c3ad18dc47 100644 --- a/homeassistant/components/linux_battery/sensor.py +++ b/homeassistant/components/linux_battery/sensor.py @@ -59,7 +59,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): if system == "android": os.listdir(os.path.join(DEFAULT_PATH, "battery")) else: - os.listdir(os.path.join(DEFAULT_PATH, "BAT{}".format(battery_id))) + os.listdir(os.path.join(DEFAULT_PATH, f"BAT{battery_id}")) except FileNotFoundError: _LOGGER.error("No battery found") return False diff --git a/homeassistant/components/liveboxplaytv/media_player.py b/homeassistant/components/liveboxplaytv/media_player.py index 3c3c8bb9b38ce0..98418d6be81895 100644 --- a/homeassistant/components/liveboxplaytv/media_player.py +++ b/homeassistant/components/liveboxplaytv/media_player.py @@ -178,7 +178,7 @@ def media_title(self): """Title of current playing media.""" if self._current_channel: if self._current_program: - return "{}: {}".format(self._current_channel, self._current_program) + return f"{self._current_channel}: {self._current_program}" return self._current_channel @property diff --git a/homeassistant/components/locative/__init__.py b/homeassistant/components/locative/__init__.py index e1df5b980a9e39..61e0b1f7474949 100644 --- a/homeassistant/components/locative/__init__.py +++ b/homeassistant/components/locative/__init__.py @@ -22,7 +22,7 @@ _LOGGER = logging.getLogger(__name__) DOMAIN = "locative" -TRACKER_UPDATE = "{}_tracker_update".format(DOMAIN) +TRACKER_UPDATE = f"{DOMAIN}_tracker_update" ATTR_DEVICE_ID = "device" @@ -76,12 +76,10 @@ async def handle_webhook(hass, webhook_id, request): if direction == "enter": async_dispatcher_send(hass, TRACKER_UPDATE, device, gps_location, location_name) - return web.Response( - text="Setting location to {}".format(location_name), status=HTTP_OK - ) + return web.Response(text=f"Setting location to {location_name}", status=HTTP_OK) if direction == "exit": - current_state = hass.states.get("{}.{}".format(DEVICE_TRACKER, device)) + current_state = hass.states.get(f"{DEVICE_TRACKER}.{device}") if current_state is None or current_state.state == location_name: location_name = STATE_NOT_HOME @@ -108,7 +106,7 @@ async def handle_webhook(hass, webhook_id, request): _LOGGER.error("Received unidentified message from Locative: %s", direction) return web.Response( - text="Received unidentified message: {}".format(direction), + text=f"Received unidentified message: {direction}", status=HTTP_UNPROCESSABLE_ENTITY, ) diff --git a/homeassistant/components/logbook/__init__.py b/homeassistant/components/logbook/__init__.py index 0383e73105b714..3c5e828765c98d 100644 --- a/homeassistant/components/logbook/__init__.py +++ b/homeassistant/components/logbook/__init__.py @@ -188,7 +188,7 @@ def humanify(hass, events): - if 2+ sensor updates in GROUP_BY_MINUTES, show last - if home assistant stop and start happen in same minute call it restarted """ - domain_prefixes = tuple("{}.".format(dom) for dom in CONTINUOUS_DOMAINS) + domain_prefixes = tuple(f"{dom}." for dom in CONTINUOUS_DOMAINS) # Group events in batches of GROUP_BY_MINUTES for _, g_events in groupby( @@ -332,7 +332,7 @@ def humanify(hass, events): entity_id = data.get(ATTR_ENTITY_ID) value = data.get(ATTR_VALUE) - value_msg = " to {}".format(value) if value else "" + value_msg = f" to {value}" if value else "" message = "send command {}{} for {}".format( data[ATTR_SERVICE], value_msg, data[ATTR_DISPLAY_NAME] ) @@ -519,7 +519,7 @@ def _keep_event(event, entities_filter): domain = DOMAIN_HOMEKIT if not entity_id and domain: - entity_id = "%s." % (domain,) + entity_id = f"{domain}." return not entity_id or entities_filter(entity_id) @@ -530,7 +530,7 @@ def _entry_message_from_state(domain, state): if domain in ["device_tracker", "person"]: if state.state == STATE_NOT_HOME: return "is away" - return "is at {}".format(state.state) + return f"is at {state.state}" if domain == "sun": if state.state == sun.STATE_ABOVE_HORIZON: @@ -596,9 +596,9 @@ def _entry_message_from_state(domain, state): "vibration", ]: if state.state == STATE_ON: - return "detected {}".format(device_class) + return f"detected {device_class}" if state.state == STATE_OFF: - return "cleared (no {} detected)".format(device_class) + return f"cleared (no {device_class} detected)" if state.state == STATE_ON: # Future: combine groups and its entity entries ? @@ -607,4 +607,4 @@ def _entry_message_from_state(domain, state): if state.state == STATE_OFF: return "turned off" - return "changed to {}".format(state.state) + return f"changed to {state.state}" diff --git a/homeassistant/components/logentries/__init__.py b/homeassistant/components/logentries/__init__.py index ba92fb8a6726b7..3601ee275b852b 100644 --- a/homeassistant/components/logentries/__init__.py +++ b/homeassistant/components/logentries/__init__.py @@ -24,7 +24,7 @@ def setup(hass, config): """Set up the Logentries component.""" conf = config[DOMAIN] token = conf.get(CONF_TOKEN) - le_wh = "{}{}".format(DEFAULT_HOST, token) + le_wh = f"{DEFAULT_HOST}{token}" def logentries_event_listener(event): """Listen for new messages on the bus and sends them to Logentries.""" diff --git a/homeassistant/components/logi_circle/__init__.py b/homeassistant/components/logi_circle/__init__.py index 6f073a064f16f6..12484a655d635f 100644 --- a/homeassistant/components/logi_circle/__init__.py +++ b/homeassistant/components/logi_circle/__init__.py @@ -156,7 +156,7 @@ async def async_setup_entry(hass, entry): except asyncio.TimeoutError: # The TimeoutError exception object returns nothing when casted to a # string, so we'll handle it separately. - err = "{}s timeout exceeded when connecting to Logi Circle API".format(_TIMEOUT) + err = f"{_TIMEOUT}s timeout exceeded when connecting to Logi Circle API" hass.components.persistent_notification.create( "Error: {}
" "You will need to restart hass after fixing." diff --git a/homeassistant/components/logi_circle/config_flow.py b/homeassistant/components/logi_circle/config_flow.py index f81db9ba17139d..2a25c5f00a49fd 100644 --- a/homeassistant/components/logi_circle/config_flow.py +++ b/homeassistant/components/logi_circle/config_flow.py @@ -179,7 +179,7 @@ async def _async_create_session(self, code): account_id = (await logi_session.account)["accountId"] await logi_session.close() return self.async_create_entry( - title="Logi Circle ({})".format(account_id), + title=f"Logi Circle ({account_id})", data={ CONF_CLIENT_ID: client_id, CONF_CLIENT_SECRET: client_secret, diff --git a/homeassistant/components/logi_circle/sensor.py b/homeassistant/components/logi_circle/sensor.py index f229250ea09e0c..fc5ad7155b44ca 100644 --- a/homeassistant/components/logi_circle/sensor.py +++ b/homeassistant/components/logi_circle/sensor.py @@ -49,7 +49,7 @@ def __init__(self, camera, time_zone, sensor_type): """Initialize a sensor for Logi Circle camera.""" self._sensor_type = sensor_type self._camera = camera - self._id = "{}-{}".format(self._camera.mac_address, self._sensor_type) + self._id = f"{self._camera.mac_address}-{self._sensor_type}" self._icon = "mdi:{}".format(SENSOR_TYPES.get(self._sensor_type)[2]) self._name = "{0} {1}".format( self._camera.name, SENSOR_TYPES.get(self._sensor_type)[0] diff --git a/homeassistant/components/luftdaten/__init__.py b/homeassistant/components/luftdaten/__init__.py index e05967a91fd958..86129eafc0295e 100644 --- a/homeassistant/components/luftdaten/__init__.py +++ b/homeassistant/components/luftdaten/__init__.py @@ -34,7 +34,7 @@ SENSOR_PRESSURE = "pressure" SENSOR_TEMPERATURE = "temperature" -TOPIC_UPDATE = "{0}_data_update".format(DOMAIN) +TOPIC_UPDATE = f"{DOMAIN}_data_update" VOLUME_MICROGRAMS_PER_CUBIC_METER = "µg/m3" diff --git a/homeassistant/components/lutron/__init__.py b/homeassistant/components/lutron/__init__.py index 9f4d81df044d47..de3ca40fd1d9c3 100644 --- a/homeassistant/components/lutron/__init__.py +++ b/homeassistant/components/lutron/__init__.py @@ -114,7 +114,7 @@ def _update_callback(self, _device, _context, _event, _params): @property def name(self): """Return the name of the device.""" - return "{} {}".format(self._area_name, self._lutron_device.name) + return f"{self._area_name} {self._lutron_device.name}" @property def should_poll(self): @@ -132,7 +132,7 @@ class LutronButton: def __init__(self, hass, keypad, button): """Register callback for activity on the button.""" - name = "{}: {}".format(keypad.name, button.name) + name = f"{keypad.name}: {button.name}" self._hass = hass self._has_release_event = ( button.button_type is not None and "RaiseLower" in button.button_type diff --git a/homeassistant/components/lyft/sensor.py b/homeassistant/components/lyft/sensor.py index 0bf739b040c32c..339b996c5d847b 100644 --- a/homeassistant/components/lyft/sensor.py +++ b/homeassistant/components/lyft/sensor.py @@ -85,7 +85,7 @@ def __init__(self, sensorType, products, product_id, product): self._sensortype = sensorType self._name = "{} {}".format(self._product["display_name"], self._sensortype) if "lyft" not in self._name.lower(): - self._name = "Lyft{}".format(self._name) + self._name = f"Lyft{self._name}" if self._sensortype == "time": self._unit_of_measurement = "min" elif self._sensortype == "price": diff --git a/homeassistant/components/magicseaweed/sensor.py b/homeassistant/components/magicseaweed/sensor.py index 61abb9788c53d5..66ab87a6569ffa 100644 --- a/homeassistant/components/magicseaweed/sensor.py +++ b/homeassistant/components/magicseaweed/sensor.py @@ -108,10 +108,10 @@ def __init__(self, forecast_data, sensor_type, name, unit_system, hour=None): def name(self): """Return the name of the sensor.""" if self.hour is None and "forecast" in self.type: - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" if self.hour is None: - return "Current {} {}".format(self.client_name, self._name) - return "{} {} {}".format(self.hour, self.client_name, self._name) + return f"Current {self.client_name} {self._name}" + return f"{self.hour} {self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/mailgun/__init__.py b/homeassistant/components/mailgun/__init__.py index 87bbe6bee076c7..4bcca0848f43f9 100644 --- a/homeassistant/components/mailgun/__init__.py +++ b/homeassistant/components/mailgun/__init__.py @@ -19,7 +19,7 @@ DEFAULT_SANDBOX = False -MESSAGE_RECEIVED = "{}_message_received".format(DOMAIN) +MESSAGE_RECEIVED = f"{DOMAIN}_message_received" CONFIG_SCHEMA = vol.Schema( { @@ -75,7 +75,7 @@ async def verify_webhook(hass, token=None, timestamp=None, signature=None): hmac_digest = hmac.new( key=bytes(hass.data[DOMAIN][CONF_API_KEY], "utf-8"), - msg=bytes("{}{}".format(timestamp, token), "utf-8"), + msg=bytes(f"{timestamp}{token}", "utf-8"), digestmod=hashlib.sha256, ).hexdigest() diff --git a/homeassistant/components/marytts/tts.py b/homeassistant/components/marytts/tts.py index 9f64c088b4a0b8..e5088c5b2df3c3 100644 --- a/homeassistant/components/marytts/tts.py +++ b/homeassistant/components/marytts/tts.py @@ -74,7 +74,7 @@ async def async_get_tts_audio(self, message, language, options=None): try: with async_timeout.timeout(10): - url = "http://{}:{}/process?".format(self._host, self._port) + url = f"http://{self._host}:{self._port}/process?" audio = self._codec.upper() if audio == "WAV": diff --git a/homeassistant/components/metoffice/weather.py b/homeassistant/components/metoffice/weather.py index e90d6fdc4c2e82..bb7a64005ce287 100644 --- a/homeassistant/components/metoffice/weather.py +++ b/homeassistant/components/metoffice/weather.py @@ -83,7 +83,7 @@ def update(self): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._name, self.site.name) + return f"{self._name} {self.site.name}" @property def condition(self): diff --git a/homeassistant/components/microsoft/tts.py b/homeassistant/components/microsoft/tts.py index ff06e8815ed1d7..3536c788bb9d4e 100644 --- a/homeassistant/components/microsoft/tts.py +++ b/homeassistant/components/microsoft/tts.py @@ -115,8 +115,8 @@ def __init__(self, apikey, lang, gender, ttype, rate, volume, pitch, contour): self._gender = gender self._type = ttype self._output = DEFAULT_OUTPUT - self._rate = "{}%".format(rate) - self._volume = "{}%".format(volume) + self._rate = f"{rate}%" + self._volume = f"{volume}%" self._pitch = pitch self._contour = contour self.name = "Microsoft" diff --git a/homeassistant/components/microsoft_face/__init__.py b/homeassistant/components/microsoft_face/__init__.py index 6c2fc5ae6bf2ad..5d0c50e536a554 100644 --- a/homeassistant/components/microsoft_face/__init__.py +++ b/homeassistant/components/microsoft_face/__init__.py @@ -92,7 +92,7 @@ async def async_create_group(service): g_id = slugify(name) try: - await face.call_api("put", "persongroups/{0}".format(g_id), {"name": name}) + await face.call_api("put", f"persongroups/{g_id}", {"name": name}) face.store[g_id] = {} entities[g_id] = MicrosoftFaceGroupEntity(hass, face, g_id, name) @@ -109,7 +109,7 @@ async def async_delete_group(service): g_id = slugify(service.data[ATTR_NAME]) try: - await face.call_api("delete", "persongroups/{0}".format(g_id)) + await face.call_api("delete", f"persongroups/{g_id}") face.store.pop(g_id) entity = entities.pop(g_id) @@ -126,7 +126,7 @@ async def async_train_group(service): g_id = service.data[ATTR_GROUP] try: - await face.call_api("post", "persongroups/{0}/train".format(g_id)) + await face.call_api("post", f"persongroups/{g_id}/train") except HomeAssistantError as err: _LOGGER.error("Can't train group '%s' with error: %s", g_id, err) @@ -141,7 +141,7 @@ async def async_create_person(service): try: user_data = await face.call_api( - "post", "persongroups/{0}/persons".format(g_id), {"name": name} + "post", f"persongroups/{g_id}/persons", {"name": name} ) face.store[g_id][name] = user_data["personId"] @@ -160,9 +160,7 @@ async def async_delete_person(service): p_id = face.store[g_id].get(name) try: - await face.call_api( - "delete", "persongroups/{0}/persons/{1}".format(g_id, p_id) - ) + await face.call_api("delete", f"persongroups/{g_id}/persons/{p_id}") face.store[g_id].pop(name) await entities[g_id].async_update_ha_state() @@ -186,7 +184,7 @@ async def async_face_person(service): await face.call_api( "post", - "persongroups/{0}/persons/{1}/persistedFaces".format(g_id, p_id), + f"persongroups/{g_id}/persons/{p_id}/persistedFaces", image.content, binary=True, ) @@ -218,7 +216,7 @@ def name(self): @property def entity_id(self): """Return entity id.""" - return "{0}.{1}".format(DOMAIN, self._id) + return f"{DOMAIN}.{self._id}" @property def state(self): @@ -249,7 +247,7 @@ def __init__(self, hass, server_loc, api_key, timeout, entities): self.websession = async_get_clientsession(hass) self.timeout = timeout self._api_key = api_key - self._server_url = "https://{0}.{1}".format(server_loc, FACE_API_URL) + self._server_url = f"https://{server_loc}.{FACE_API_URL}" self._store = {} self._entities = entities @@ -270,9 +268,7 @@ async def update_store(self): self.hass, self, g_id, group["name"] ) - persons = await self.call_api( - "get", "persongroups/{0}/persons".format(g_id) - ) + persons = await self.call_api("get", f"persongroups/{g_id}/persons") for person in persons: self._store[g_id][person["name"]] = person["personId"] diff --git a/homeassistant/components/microsoft_face_detect/image_processing.py b/homeassistant/components/microsoft_face_detect/image_processing.py index 243b4533938191..c10f7edf9dbe3d 100644 --- a/homeassistant/components/microsoft_face_detect/image_processing.py +++ b/homeassistant/components/microsoft_face_detect/image_processing.py @@ -30,7 +30,7 @@ def validate_attributes(list_attributes): """Validate face attributes.""" for attr in list_attributes: if attr not in SUPPORTED_ATTRIBUTES: - raise vol.Invalid("Invalid attribute {0}".format(attr)) + raise vol.Invalid(f"Invalid attribute {attr}") return list_attributes diff --git a/homeassistant/components/miflora/sensor.py b/homeassistant/components/miflora/sensor.py index 999dc473c604a7..86f1462e2cca55 100644 --- a/homeassistant/components/miflora/sensor.py +++ b/homeassistant/components/miflora/sensor.py @@ -85,7 +85,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= prefix = config.get(CONF_NAME) if prefix: - name = "{} {}".format(prefix, name) + name = f"{prefix} {name}" devs.append( MiFloraSensor(poller, parameter, name, unit, icon, force_update, median) diff --git a/homeassistant/components/minio/__init__.py b/homeassistant/components/minio/__init__.py index cede3a7aad53c2..d411d913082f89 100644 --- a/homeassistant/components/minio/__init__.py +++ b/homeassistant/components/minio/__init__.py @@ -166,7 +166,7 @@ def remove_file(service): def get_minio_endpoint(host: str, port: int) -> str: """Create minio endpoint from host and port.""" - return "{}:{}".format(host, port) + return f"{host}:{port}" class QueueListener(threading.Thread): diff --git a/homeassistant/components/mitemp_bt/sensor.py b/homeassistant/components/mitemp_bt/sensor.py index c9b7837c683710..9cd1f1cebc29be 100644 --- a/homeassistant/components/mitemp_bt/sensor.py +++ b/homeassistant/components/mitemp_bt/sensor.py @@ -94,7 +94,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): prefix = config.get(CONF_NAME) if prefix: - name = "{} {}".format(prefix, name) + name = f"{prefix} {name}" devs.append( MiTempBtSensor(poller, parameter, device, name, unit, force_update, median) diff --git a/homeassistant/components/mobile_app/binary_sensor.py b/homeassistant/components/mobile_app/binary_sensor.py index c0ea297edc1b1a..975c4c16c32cd9 100644 --- a/homeassistant/components/mobile_app/binary_sensor.py +++ b/homeassistant/components/mobile_app/binary_sensor.py @@ -53,7 +53,7 @@ def handle_sensor_registration(webhook_id, data): async_dispatcher_connect( hass, - "{}_{}_register".format(DOMAIN, ENTITY_TYPE), + f"{DOMAIN}_{ENTITY_TYPE}_register", partial(handle_sensor_registration, webhook_id), ) diff --git a/homeassistant/components/mobile_app/entity.py b/homeassistant/components/mobile_app/entity.py index c207475dc3c842..27cb9934b18ef8 100644 --- a/homeassistant/components/mobile_app/entity.py +++ b/homeassistant/components/mobile_app/entity.py @@ -21,7 +21,7 @@ def sensor_id(webhook_id, unique_id): """Return a unique sensor ID.""" - return "{}_{}".format(webhook_id, unique_id) + return f"{webhook_id}_{unique_id}" class MobileAppEntity(Entity): diff --git a/homeassistant/components/mobile_app/sensor.py b/homeassistant/components/mobile_app/sensor.py index d6d2247736c3cc..b96a6f1e2f0496 100644 --- a/homeassistant/components/mobile_app/sensor.py +++ b/homeassistant/components/mobile_app/sensor.py @@ -53,7 +53,7 @@ def handle_sensor_registration(webhook_id, data): async_dispatcher_connect( hass, - "{}_{}_register".format(DOMAIN, ENTITY_TYPE), + f"{DOMAIN}_{ENTITY_TYPE}_register", partial(handle_sensor_registration, webhook_id), ) diff --git a/homeassistant/components/mobile_app/webhook.py b/homeassistant/components/mobile_app/webhook.py index ecbd08375e0c1e..f95d5b993f083a 100644 --- a/homeassistant/components/mobile_app/webhook.py +++ b/homeassistant/components/mobile_app/webhook.py @@ -220,13 +220,13 @@ async def handle_webhook( unique_id = data[ATTR_SENSOR_UNIQUE_ID] - unique_store_key = "{}_{}".format(webhook_id, unique_id) + unique_store_key = f"{webhook_id}_{unique_id}" if unique_store_key in hass.data[DOMAIN][entity_type]: _LOGGER.error("Refusing to re-register existing sensor %s!", unique_id) return error_response( ERR_SENSOR_DUPLICATE_UNIQUE_ID, - "{} {} already exists!".format(entity_type, unique_id), + f"{entity_type} {unique_id} already exists!", status=409, ) @@ -257,13 +257,13 @@ async def handle_webhook( unique_id = sensor[ATTR_SENSOR_UNIQUE_ID] - unique_store_key = "{}_{}".format(webhook_id, unique_id) + unique_store_key = f"{webhook_id}_{unique_id}" if unique_store_key not in hass.data[DOMAIN][entity_type]: _LOGGER.error( "Refusing to update non-registered sensor: %s", unique_store_key ) - err_msg = "{} {} is not registered".format(entity_type, unique_id) + err_msg = f"{entity_type} {unique_id} is not registered" resp[unique_id] = { "success": False, "error": {"code": ERR_SENSOR_NOT_REGISTERED, "message": err_msg}, diff --git a/homeassistant/components/mochad/light.py b/homeassistant/components/mochad/light.py index a7b0b8c2d0faa2..899908c34bdfc4 100644 --- a/homeassistant/components/mochad/light.py +++ b/homeassistant/components/mochad/light.py @@ -50,7 +50,7 @@ def __init__(self, hass, ctrl, dev): self._controller = ctrl self._address = dev[CONF_ADDRESS] - self._name = dev.get(CONF_NAME, "x10_light_dev_{}".format(self._address)) + self._name = dev.get(CONF_NAME, f"x10_light_dev_{self._address}") self._comm_type = dev.get(mochad.CONF_COMM_TYPE, "pl") self.light = device.Device(ctrl, self._address, comm_type=self._comm_type) self._brightness = 0 @@ -95,12 +95,12 @@ def _adjust_brightness(self, brightness): if self._brightness > brightness: bdelta = self._brightness - brightness mochad_brightness = self._calculate_brightness_value(bdelta) - self.light.send_cmd("dim {}".format(mochad_brightness)) + self.light.send_cmd(f"dim {mochad_brightness}") self._controller.read_data() elif self._brightness < brightness: bdelta = brightness - self._brightness mochad_brightness = self._calculate_brightness_value(bdelta) - self.light.send_cmd("bright {}".format(mochad_brightness)) + self.light.send_cmd(f"bright {mochad_brightness}") self._controller.read_data() def turn_on(self, **kwargs): @@ -109,7 +109,7 @@ def turn_on(self, **kwargs): with mochad.REQ_LOCK: if self._brightness_levels > 32: out_brightness = self._calculate_brightness_value(brightness) - self.light.send_cmd("xdim {}".format(out_brightness)) + self.light.send_cmd(f"xdim {out_brightness}") self._controller.read_data() else: self.light.send_cmd("on") diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 22b871cea20f65..64b45b03c95994 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -170,7 +170,7 @@ def read_register(self, register): [x.to_bytes(2, byteorder="big") for x in result.registers] ) val = struct.unpack(self._structure, byte_string)[0] - register_value = format(val, ".{}f".format(self._precision)) + register_value = format(val, f".{self._precision}f") return register_value def write_register(self, register, value): diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 4fc9fb808c6c53..1a5c71812d610b 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -54,7 +54,7 @@ def number(value: Any) -> Union[int, float]: value = float(value) return value except (TypeError, ValueError): - raise vol.Invalid("invalid number {}".format(value)) + raise vol.Invalid(f"invalid number {value}") PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( diff --git a/homeassistant/components/mopar/__init__.py b/homeassistant/components/mopar/__init__.py index 686b927b515f7d..857dbab2a3b08a 100644 --- a/homeassistant/components/mopar/__init__.py +++ b/homeassistant/components/mopar/__init__.py @@ -19,7 +19,7 @@ from homeassistant.helpers.event import track_time_interval DOMAIN = "mopar" -DATA_UPDATED = "{}_data_updated".format(DOMAIN) +DATA_UPDATED = f"{DOMAIN}_data_updated" _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/mpchc/media_player.py b/homeassistant/components/mpchc/media_player.py index d616ec6d1e842f..ae96704be589e9 100644 --- a/homeassistant/components/mpchc/media_player.py +++ b/homeassistant/components/mpchc/media_player.py @@ -56,7 +56,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): host = config.get(CONF_HOST) port = config.get(CONF_PORT) - url = "{}:{}".format(host, port) + url = f"{host}:{port}" add_entities([MpcHcDevice(name, url)], True) @@ -73,9 +73,7 @@ def __init__(self, name, url): def update(self): """Get the latest details.""" try: - response = requests.get( - "{}/variables.html".format(self._url), data=None, timeout=3 - ) + response = requests.get(f"{self._url}/variables.html", data=None, timeout=3) mpchc_variables = re.findall(r'

(.+?)

', response.text) @@ -88,7 +86,7 @@ def _send_command(self, command_id): """Send a command to MPC-HC via its window message ID.""" try: params = {"wm_command": command_id} - requests.get("{}/command.html".format(self._url), params=params, timeout=3) + requests.get(f"{self._url}/command.html", params=params, timeout=3) except requests.exceptions.RequestException: _LOGGER.error( "Could not send command %d to MPC-HC at: %s", command_id, self._url diff --git a/homeassistant/components/mpd/media_player.py b/homeassistant/components/mpd/media_player.py index 0d924cdd1d29f8..c19f8f49226d9f 100644 --- a/homeassistant/components/mpd/media_player.py +++ b/homeassistant/components/mpd/media_player.py @@ -211,7 +211,7 @@ def media_title(self): if title is None: return name - return "{}: {}".format(name, title) + return f"{name}: {title}" @property def media_artist(self): diff --git a/homeassistant/components/mqtt/discovery.py b/homeassistant/components/mqtt/discovery.py index d611b8db13e430..f393c3157932a5 100644 --- a/homeassistant/components/mqtt/discovery.py +++ b/homeassistant/components/mqtt/discovery.py @@ -86,7 +86,7 @@ async def async_device_message_received(msg): """Process the received message.""" payload = msg.payload topic = msg.topic - topic_trimmed = topic.replace("{}/".format(discovery_topic), "", 1) + topic_trimmed = topic.replace(f"{discovery_topic}/", "", 1) match = TOPIC_MATCHER.match(topic_trimmed) if not match: @@ -134,9 +134,7 @@ async def async_device_message_received(msg): if payload: # Attach MQTT topic to the payload, used for debug prints - setattr( - payload, "__configuration_source__", "MQTT (topic: '{}')".format(topic) - ) + setattr(payload, "__configuration_source__", f"MQTT (topic: '{topic}')") if CONF_PLATFORM in payload and "schema" not in payload: platform = payload[CONF_PLATFORM] diff --git a/homeassistant/components/mqtt/vacuum/schema_legacy.py b/homeassistant/components/mqtt/vacuum/schema_legacy.py index 20be0dcf89cfb7..f2fa8f8da6622f 100644 --- a/homeassistant/components/mqtt/vacuum/schema_legacy.py +++ b/homeassistant/components/mqtt/vacuum/schema_legacy.py @@ -339,7 +339,7 @@ def message_received(msg): elif self._cleaning: self._status = "Cleaning" elif self._error: - self._status = "Error: {}".format(self._error) + self._status = f"Error: {self._error}" else: self._status = "Stopped" @@ -360,7 +360,7 @@ def message_received(msg): self.hass, self._sub_state, { - "topic{}".format(i): { + f"topic{i}": { "topic": topic, "msg_callback": message_received, "qos": self._qos, @@ -550,7 +550,7 @@ async def async_set_fan_speed(self, fan_speed, **kwargs): mqtt.async_publish( self.hass, self._set_fan_speed_topic, fan_speed, self._qos, self._retain ) - self._status = "Setting fan to {}...".format(fan_speed) + self._status = f"Setting fan to {fan_speed}..." self.async_write_ha_state() async def async_send_command(self, command, params=None, **kwargs): @@ -566,5 +566,5 @@ async def async_send_command(self, command, params=None, **kwargs): mqtt.async_publish( self.hass, self._send_command_topic, message, self._qos, self._retain ) - self._status = "Sending command {}...".format(message) + self._status = f"Sending command {message}..." self.async_write_ha_state() diff --git a/homeassistant/components/mysensors/__init__.py b/homeassistant/components/mysensors/__init__.py index 2bde87976bc222..cbedd947843c38 100644 --- a/homeassistant/components/mysensors/__init__.py +++ b/homeassistant/components/mysensors/__init__.py @@ -56,7 +56,7 @@ def is_persistence_file(value): """Validate that persistence file path ends in either .pickle or .json.""" if value.endswith((".json", ".pickle")): return value - raise vol.Invalid("{} does not end in either `.json` or `.pickle`".format(value)) + raise vol.Invalid(f"{value} does not end in either `.json` or `.pickle`") def deprecated(key): @@ -138,7 +138,7 @@ def _get_mysensors_name(gateway, node_id, child_id): ), node_name, ) - return "{} {}".format(node_name, child_id) + return f"{node_name} {child_id}" @callback diff --git a/homeassistant/components/mysensors/gateway.py b/homeassistant/components/mysensors/gateway.py index 28d49303835aab..366692205a761a 100644 --- a/homeassistant/components/mysensors/gateway.py +++ b/homeassistant/components/mysensors/gateway.py @@ -44,7 +44,7 @@ def is_serial_port(value): ports = ("COM{}".format(idx + 1) for idx in range(256)) if value in ports: return value - raise vol.Invalid("{} is not a serial port".format(value)) + raise vol.Invalid(f"{value} is not a serial port") return cv.isdevice(value) diff --git a/homeassistant/components/mysensors/notify.py b/homeassistant/components/mysensors/notify.py index ac94a8559a19a0..99e731762df5c8 100644 --- a/homeassistant/components/mysensors/notify.py +++ b/homeassistant/components/mysensors/notify.py @@ -26,7 +26,7 @@ def send_msg(self, msg): def __repr__(self): """Return the representation.""" - return "".format(self.name) + return f"" class MySensorsNotificationService(BaseNotificationService): diff --git a/homeassistant/components/mystrom/binary_sensor.py b/homeassistant/components/mystrom/binary_sensor.py index 20d32be199edde..ff0063a380ed7d 100644 --- a/homeassistant/components/mystrom/binary_sensor.py +++ b/homeassistant/components/mystrom/binary_sensor.py @@ -41,19 +41,16 @@ async def _handle(self, hass, data): if button_action is None: _LOGGER.error("Received unidentified message from myStrom button: %s", data) - return ( - "Received unidentified message: {}".format(data), - HTTP_UNPROCESSABLE_ENTITY, - ) + return (f"Received unidentified message: {data}", HTTP_UNPROCESSABLE_ENTITY) button_id = data[button_action] - entity_id = "{}.{}_{}".format(DOMAIN, button_id, button_action) + entity_id = f"{DOMAIN}.{button_id}_{button_action}" if entity_id not in self.buttons: _LOGGER.info( "New myStrom button/action detected: %s/%s", button_id, button_action ) self.buttons[entity_id] = MyStromBinarySensor( - "{}_{}".format(button_id, button_action) + f"{button_id}_{button_action}" ) self.add_entities([self.buttons[entity_id]]) else: From 3e1d2834ad0bfb8ec59761922ac4615581ca3f23 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 21:14:39 +0200 Subject: [PATCH 69/72] Use literal string interpolation in integrations R-S (f-strings) (#26392) --- homeassistant/components/rachio/__init__.py | 2 +- .../components/rachio/binary_sensor.py | 4 +-- homeassistant/components/rachio/switch.py | 8 ++--- homeassistant/components/rainbird/switch.py | 2 +- .../components/rainmachine/__init__.py | 6 ++-- .../components/recollect_waste/sensor.py | 2 +- homeassistant/components/reddit/sensor.py | 2 +- .../components/rejseplanen/sensor.py | 2 +- .../components/remember_the_milk/__init__.py | 6 ++-- homeassistant/components/repetier/__init__.py | 2 +- homeassistant/components/rflink/light.py | 2 +- homeassistant/components/rfxtrx/__init__.py | 4 +-- .../components/rfxtrx/binary_sensor.py | 2 +- homeassistant/components/rfxtrx/sensor.py | 4 +-- .../components/ring/binary_sensor.py | 2 +- homeassistant/components/ring/light.py | 2 +- homeassistant/components/ring/sensor.py | 2 +- homeassistant/components/ring/switch.py | 4 +-- homeassistant/components/roku/__init__.py | 2 +- homeassistant/components/roku/media_player.py | 2 +- homeassistant/components/roku/remote.py | 2 +- homeassistant/components/roomba/vacuum.py | 2 +- homeassistant/components/route53/__init__.py | 2 +- homeassistant/components/rova/sensor.py | 2 +- homeassistant/components/rtorrent/sensor.py | 2 +- homeassistant/components/sabnzbd/sensor.py | 2 +- .../components/samsungtv/media_player.py | 2 +- homeassistant/components/scsgate/__init__.py | 6 ++-- homeassistant/components/sense/sensor.py | 2 +- homeassistant/components/serial_pm/sensor.py | 2 +- .../components/seventeentrack/sensor.py | 4 +-- homeassistant/components/shiftr/__init__.py | 5 +-- .../components/shopping_list/__init__.py | 2 +- homeassistant/components/sigfox/sensor.py | 6 ++-- .../components/sky_hub/device_tracker.py | 2 +- homeassistant/components/skybell/camera.py | 2 +- homeassistant/components/sma/sensor.py | 6 ++-- homeassistant/components/smappee/sensor.py | 2 +- .../components/smartthings/binary_sensor.py | 4 +-- .../components/smartthings/sensor.py | 4 +-- .../components/smartthings/smartapp.py | 2 +- .../components/smarty/binary_sensor.py | 12 ++----- homeassistant/components/smarty/sensor.py | 12 +++---- homeassistant/components/smhi/weather.py | 2 +- homeassistant/components/smtp/notify.py | 12 +++---- .../components/snapcast/media_player.py | 14 ++++---- .../components/solaredge_local/sensor.py | 2 +- homeassistant/components/solax/sensor.py | 4 +-- homeassistant/components/somfy/config_flow.py | 4 +-- .../components/sonos/media_player.py | 2 +- .../components/speedtestdotnet/const.py | 2 +- homeassistant/components/spotcrime/sensor.py | 2 +- .../components/spotify/media_player.py | 2 +- .../components/squeezebox/media_player.py | 6 ++-- homeassistant/components/srp_energy/sensor.py | 2 +- homeassistant/components/startca/sensor.py | 2 +- .../components/steam_online/sensor.py | 2 +- .../components/stiebel_eltron/climate.py | 2 +- homeassistant/components/stream/__init__.py | 8 ++--- homeassistant/components/stream/hls.py | 7 ++-- .../streamlabswater/binary_sensor.py | 2 +- .../components/streamlabswater/sensor.py | 6 ++-- .../swiss_hydrological_data/sensor.py | 2 +- .../swiss_public_transport/sensor.py | 2 +- .../components/swisscom/device_tracker.py | 2 +- .../components/switcher_kis/switch.py | 2 +- homeassistant/components/syncthru/sensor.py | 34 +++++++++---------- .../components/synologydsm/sensor.py | 2 +- homeassistant/components/sytadin/sensor.py | 2 +- 69 files changed, 129 insertions(+), 149 deletions(-) diff --git a/homeassistant/components/rachio/__init__.py b/homeassistant/components/rachio/__init__.py index 0d582b0c2e99f1..2030512ab3136e 100644 --- a/homeassistant/components/rachio/__init__.py +++ b/homeassistant/components/rachio/__init__.py @@ -226,7 +226,7 @@ def _deinit_webhooks(event) -> None: def __str__(self) -> str: """Display the controller as a string.""" - return 'Rachio controller "{}"'.format(self.name) + return f'Rachio controller "{self.name}"' @property def controller_id(self) -> str: diff --git a/homeassistant/components/rachio/binary_sensor.py b/homeassistant/components/rachio/binary_sensor.py index 01d38a931c474d..f74e3ca1802181 100644 --- a/homeassistant/components/rachio/binary_sensor.py +++ b/homeassistant/components/rachio/binary_sensor.py @@ -87,12 +87,12 @@ def __init__(self, hass, controller): @property def name(self) -> str: """Return the name of this sensor including the controller name.""" - return "{} online".format(self._controller.name) + return f"{self._controller.name} online" @property def unique_id(self) -> str: """Return a unique id for this entity.""" - return "{}-online".format(self._controller.controller_id) + return f"{self._controller.controller_id}-online" @property def device_class(self) -> str: diff --git a/homeassistant/components/rachio/switch.py b/homeassistant/components/rachio/switch.py index b65e6bf6044295..80c227a6df6977 100644 --- a/homeassistant/components/rachio/switch.py +++ b/homeassistant/components/rachio/switch.py @@ -72,7 +72,7 @@ def should_poll(self) -> bool: @property def name(self) -> str: """Get a name for this switch.""" - return "Switch on {}".format(self._controller.name) + return f"Switch on {self._controller.name}" @property def is_on(self) -> bool: @@ -113,12 +113,12 @@ def __init__(self, hass, controller): @property def name(self) -> str: """Return the name of the standby switch.""" - return "{} in standby mode".format(self._controller.name) + return f"{self._controller.name} in standby mode" @property def unique_id(self) -> str: """Return a unique id by combining controller id and purpose.""" - return "{}-standby".format(self._controller.controller_id) + return f"{self._controller.controller_id}-standby" @property def icon(self) -> str: @@ -183,7 +183,7 @@ def name(self) -> str: @property def unique_id(self) -> str: """Return a unique id by combining controller id and zone number.""" - return "{}-zone-{}".format(self._controller.controller_id, self.zone_id) + return f"{self._controller.controller_id}-zone-{self.zone_id}" @property def icon(self) -> str: diff --git a/homeassistant/components/rainbird/switch.py b/homeassistant/components/rainbird/switch.py index 55a9f4007cbaaf..9fb19bc620654d 100644 --- a/homeassistant/components/rainbird/switch.py +++ b/homeassistant/components/rainbird/switch.py @@ -54,7 +54,7 @@ def __init__(self, rb: RainbirdController, dev, dev_id): self._rainbird = rb self._devid = dev_id self._zone = int(dev.get(CONF_ZONE)) - self._name = dev.get(CONF_FRIENDLY_NAME, "Sprinkler {}".format(self._zone)) + self._name = dev.get(CONF_FRIENDLY_NAME, f"Sprinkler {self._zone}") self._state = None self._duration = dev.get(CONF_TRIGGER_TIME) self._attributes = {"duration": self._duration, "zone": self._zone} diff --git a/homeassistant/components/rainmachine/__init__.py b/homeassistant/components/rainmachine/__init__.py index b04384dc81dda3..183872087a7240 100644 --- a/homeassistant/components/rainmachine/__init__.py +++ b/homeassistant/components/rainmachine/__init__.py @@ -41,9 +41,9 @@ DATA_LISTENER = "listener" -PROGRAM_UPDATE_TOPIC = "{0}_program_update".format(DOMAIN) -SENSOR_UPDATE_TOPIC = "{0}_data_update".format(DOMAIN) -ZONE_UPDATE_TOPIC = "{0}_zone_update".format(DOMAIN) +PROGRAM_UPDATE_TOPIC = f"{DOMAIN}_program_update" +SENSOR_UPDATE_TOPIC = f"{DOMAIN}_data_update" +ZONE_UPDATE_TOPIC = f"{DOMAIN}_zone_update" CONF_CONTROLLERS = "controllers" CONF_PROGRAM_ID = "program_id" diff --git a/homeassistant/components/recollect_waste/sensor.py b/homeassistant/components/recollect_waste/sensor.py index 0c3833528dc6f4..118b6fb370979a 100644 --- a/homeassistant/components/recollect_waste/sensor.py +++ b/homeassistant/components/recollect_waste/sensor.py @@ -66,7 +66,7 @@ def name(self): @property def unique_id(self) -> str: """Return a unique ID.""" - return "{}{}".format(self.client.place_id, self.client.service_id) + return f"{self.client.place_id}{self.client.service_id}" @property def state(self): diff --git a/homeassistant/components/reddit/sensor.py b/homeassistant/components/reddit/sensor.py index 0e95bea9091d7e..f9c8140f60db71 100644 --- a/homeassistant/components/reddit/sensor.py +++ b/homeassistant/components/reddit/sensor.py @@ -94,7 +94,7 @@ def __init__(self, reddit, subreddit: str, limit: int, sort_by: str): @property def name(self): """Return the name of the sensor.""" - return "reddit_{}".format(self._subreddit) + return f"reddit_{self._subreddit}" @property def state(self): diff --git a/homeassistant/components/rejseplanen/sensor.py b/homeassistant/components/rejseplanen/sensor.py index 3172e614166bec..61cb319fd11ed6 100644 --- a/homeassistant/components/rejseplanen/sensor.py +++ b/homeassistant/components/rejseplanen/sensor.py @@ -220,7 +220,7 @@ def intersection(lst1, lst2): and due_at_time is not None and route is not None ): - due_at = "{} {}".format(due_at_date, due_at_time) + due_at = f"{due_at_date} {due_at_time}" departure_data = { ATTR_DUE_IN: due_in_minutes(due_at), diff --git a/homeassistant/components/remember_the_milk/__init__.py b/homeassistant/components/remember_the_milk/__init__.py index 3d340d9c07e612..c92a246da14789 100644 --- a/homeassistant/components/remember_the_milk/__init__.py +++ b/homeassistant/components/remember_the_milk/__init__.py @@ -87,13 +87,13 @@ def _create_instance( component.add_entities([entity]) hass.services.register( DOMAIN, - "{}_create_task".format(account_name), + f"{account_name}_create_task", entity.create_task, schema=SERVICE_SCHEMA_CREATE_TASK, ) hass.services.register( DOMAIN, - "{}_complete_task".format(account_name), + f"{account_name}_complete_task", entity.complete_task, schema=SERVICE_SCHEMA_COMPLETE_TASK, ) @@ -137,7 +137,7 @@ def register_account_callback(_): configurator.request_done(request_id) request_id = configurator.async_request_config( - "{} - {}".format(DOMAIN, account_name), + f"{DOMAIN} - {account_name}", callback=register_account_callback, description="You need to log in to Remember The Milk to" + "connect your account. \n\n" diff --git a/homeassistant/components/repetier/__init__.py b/homeassistant/components/repetier/__init__.py index 1643966b33eef6..6f72a6b7ddc545 100644 --- a/homeassistant/components/repetier/__init__.py +++ b/homeassistant/components/repetier/__init__.py @@ -239,7 +239,7 @@ def _load_entities(self): info["name"] = printer.slug info["printer_name"] = self.conf_name - known = "{}-{}".format(printer.slug, sensor_type) + known = f"{printer.slug}-{sensor_type}" if known in self._known_entities: continue diff --git a/homeassistant/components/rflink/light.py b/homeassistant/components/rflink/light.py index 56ae6f8675fb3a..682d45f8f420b2 100644 --- a/homeassistant/components/rflink/light.py +++ b/homeassistant/components/rflink/light.py @@ -300,7 +300,7 @@ class ToggleRflinkLight(SwitchableRflinkDevice, Light): @property def entity_id(self): """Return entity id.""" - return "light.{}".format(self.name) + return f"light.{self.name}" def _handle_event(self, event): """Adjust state if Rflink picks up a remote command for this device.""" diff --git a/homeassistant/components/rfxtrx/__init__.py b/homeassistant/components/rfxtrx/__init__.py index 0c9a98143c800c..79b3054ecf2750 100644 --- a/homeassistant/components/rfxtrx/__init__.py +++ b/homeassistant/components/rfxtrx/__init__.py @@ -106,7 +106,7 @@ def handle_receive(event): slugify(event.device.id_string.lower()), event.device.__class__.__name__, event.device.subtype, - "".join("{0:02x}".format(x) for x in event.data), + "".join(f"{x:02x}" for x in event.data), ) # Callback to HA registered components. @@ -270,7 +270,7 @@ def get_new_device(event, config, device): if not config[ATTR_AUTOMATIC_ADD]: return - pkt_id = "".join("{0:02x}".format(x) for x in event.data) + pkt_id = "".join(f"{x:02x}" for x in event.data) _LOGGER.debug( "Automatic add %s rfxtrx device (Class: %s Sub: %s Packet_id: %s)", device_id, diff --git a/homeassistant/components/rfxtrx/binary_sensor.py b/homeassistant/components/rfxtrx/binary_sensor.py index d4ed874156e9a1..8f1c7e6fa55f3d 100644 --- a/homeassistant/components/rfxtrx/binary_sensor.py +++ b/homeassistant/components/rfxtrx/binary_sensor.py @@ -116,7 +116,7 @@ def binary_sensor_update(event): poss_id = slugify(poss_dev.event.device.id_string.lower()) _LOGGER.debug("Found possible matching device ID: %s", poss_id) - pkt_id = "".join("{0:02x}".format(x) for x in event.data) + pkt_id = "".join(f"{x:02x}" for x in event.data) sensor = RfxtrxBinarySensor(event, pkt_id) sensor.hass = hass rfxtrx.RFX_DEVICES[device_id] = sensor diff --git a/homeassistant/components/rfxtrx/sensor.py b/homeassistant/components/rfxtrx/sensor.py index 69397263a627e4..5941b00764b8ce 100644 --- a/homeassistant/components/rfxtrx/sensor.py +++ b/homeassistant/components/rfxtrx/sensor.py @@ -98,7 +98,7 @@ def sensor_update(event): if not config[CONF_AUTOMATIC_ADD]: return - pkt_id = "".join("{0:02x}".format(x) for x in event.data) + pkt_id = "".join(f"{x:02x}" for x in event.data) _LOGGER.info("Automatic add rfxtrx.sensor: %s", pkt_id) data_type = "" @@ -141,7 +141,7 @@ def state(self): @property def name(self): """Get the name of the sensor.""" - return "{} {}".format(self._name, self.data_type) + return f"{self._name} {self.data_type}" @property def device_state_attributes(self): diff --git a/homeassistant/components/ring/binary_sensor.py b/homeassistant/components/ring/binary_sensor.py index 1b06a1d47d1086..6806df0408fb78 100644 --- a/homeassistant/components/ring/binary_sensor.py +++ b/homeassistant/components/ring/binary_sensor.py @@ -73,7 +73,7 @@ def __init__(self, hass, data, sensor_type): ) self._device_class = SENSOR_TYPES.get(self._sensor_type)[2] self._state = None - self._unique_id = "{}-{}".format(self._data.id, self._sensor_type) + self._unique_id = f"{self._data.id}-{self._sensor_type}" @property def name(self): diff --git a/homeassistant/components/ring/light.py b/homeassistant/components/ring/light.py index bd7ea3a36797a1..5805114252e09a 100644 --- a/homeassistant/components/ring/light.py +++ b/homeassistant/components/ring/light.py @@ -56,7 +56,7 @@ def _update_callback(self): @property def name(self): """Name of the light.""" - return "{} light".format(self._device.name) + return f"{self._device.name} light" @property def unique_id(self): diff --git a/homeassistant/components/ring/sensor.py b/homeassistant/components/ring/sensor.py index 9950609c10fddf..af661f4571c210 100644 --- a/homeassistant/components/ring/sensor.py +++ b/homeassistant/components/ring/sensor.py @@ -121,7 +121,7 @@ def __init__(self, hass, data, sensor_type): ) self._state = None self._tz = str(hass.config.time_zone) - self._unique_id = "{}-{}".format(self._data.id, self._sensor_type) + self._unique_id = f"{self._data.id}-{self._sensor_type}" async def async_added_to_hass(self): """Register callbacks.""" diff --git a/homeassistant/components/ring/switch.py b/homeassistant/components/ring/switch.py index 3b6bd4ea0243b5..cbbecb1a40398b 100644 --- a/homeassistant/components/ring/switch.py +++ b/homeassistant/components/ring/switch.py @@ -38,7 +38,7 @@ def __init__(self, device, device_type): """Initialize the switch.""" self._device = device self._device_type = device_type - self._unique_id = "{}-{}".format(self._device.id, self._device_type) + self._unique_id = f"{self._device.id}-{self._device_type}" async def async_added_to_hass(self): """Register callbacks.""" @@ -53,7 +53,7 @@ def _update_callback(self): @property def name(self): """Name of the device.""" - return "{} {}".format(self._device.name, self._device_type) + return f"{self._device.name} {self._device_type}" @property def unique_id(self): diff --git a/homeassistant/components/roku/__init__.py b/homeassistant/components/roku/__init__.py index e6dd05b9328647..aa13814ee6b7a3 100644 --- a/homeassistant/components/roku/__init__.py +++ b/homeassistant/components/roku/__init__.py @@ -78,7 +78,7 @@ def scan_for_rokus(hass): "Name: {0}
Host: {1}
".format( r_info.userdevicename if r_info.userdevicename - else "{} {}".format(r_info.modelname, r_info.serial_num), + else f"{r_info.modelname} {r_info.serial_num}", roku.host, ) ) diff --git a/homeassistant/components/roku/media_player.py b/homeassistant/components/roku/media_player.py index 03060361020c1d..d69b0eddb71d52 100644 --- a/homeassistant/components/roku/media_player.py +++ b/homeassistant/components/roku/media_player.py @@ -92,7 +92,7 @@ def name(self): """Return the name of the device.""" if self._device_info.user_device_name: return self._device_info.user_device_name - return "Roku {}".format(self._device_info.serial_num) + return f"Roku {self._device_info.serial_num}" @property def state(self): diff --git a/homeassistant/components/roku/remote.py b/homeassistant/components/roku/remote.py index 0bb840e953135a..f443b7e8e74edc 100644 --- a/homeassistant/components/roku/remote.py +++ b/homeassistant/components/roku/remote.py @@ -36,7 +36,7 @@ def name(self): """Return the name of the device.""" if self._device_info.user_device_name: return self._device_info.user_device_name - return "Roku {}".format(self._device_info.serial_num) + return f"Roku {self._device_info.serial_num}" @property def unique_id(self): diff --git a/homeassistant/components/roomba/vacuum.py b/homeassistant/components/roomba/vacuum.py index 766fd72cdbab15..291658e19f4b2a 100644 --- a/homeassistant/components/roomba/vacuum.py +++ b/homeassistant/components/roomba/vacuum.py @@ -327,7 +327,7 @@ async def async_update(self): pos_y = pos_state.get("point", {}).get("y") theta = pos_state.get("theta") if all(item is not None for item in [pos_x, pos_y, theta]): - position = "({}, {}, {})".format(pos_x, pos_y, theta) + position = f"({pos_x}, {pos_y}, {theta})" self._state_attrs[ATTR_POSITION] = position # Not all Roombas have a bin full sensor diff --git a/homeassistant/components/route53/__init__.py b/homeassistant/components/route53/__init__.py index 906f09a56491f1..3dffc3ffd9e381 100644 --- a/homeassistant/components/route53/__init__.py +++ b/homeassistant/components/route53/__init__.py @@ -104,7 +104,7 @@ def _update_route53( { "Action": "UPSERT", "ResourceRecordSet": { - "Name": "{}.{}".format(record, domain), + "Name": f"{record}.{domain}", "Type": "A", "TTL": ttl, "ResourceRecords": [{"Value": ipaddress}], diff --git a/homeassistant/components/rova/sensor.py b/homeassistant/components/rova/sensor.py index c39bf5ca4f3f18..fe0b5dead84d15 100644 --- a/homeassistant/components/rova/sensor.py +++ b/homeassistant/components/rova/sensor.py @@ -96,7 +96,7 @@ def __init__(self, platform_name, sensor_key, data_service): @property def name(self): """Return the name.""" - return "{}_{}".format(self.platform_name, self.sensor_key) + return f"{self.platform_name}_{self.sensor_key}" @property def icon(self): diff --git a/homeassistant/components/rtorrent/sensor.py b/homeassistant/components/rtorrent/sensor.py index f2533e3dc86261..ed16331e91288b 100644 --- a/homeassistant/components/rtorrent/sensor.py +++ b/homeassistant/components/rtorrent/sensor.py @@ -79,7 +79,7 @@ def __init__(self, sensor_type, rtorrent_client, client_name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/sabnzbd/sensor.py b/homeassistant/components/sabnzbd/sensor.py index 642dd27b1d82e3..58624c758d9c83 100644 --- a/homeassistant/components/sabnzbd/sensor.py +++ b/homeassistant/components/sabnzbd/sensor.py @@ -42,7 +42,7 @@ async def async_added_to_hass(self): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._client_name, self._name) + return f"{self._client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/samsungtv/media_player.py b/homeassistant/components/samsungtv/media_player.py index 934ee94e65df3b..2821a05261b337 100644 --- a/homeassistant/components/samsungtv/media_player.py +++ b/homeassistant/components/samsungtv/media_player.py @@ -84,7 +84,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): tv_name = discovery_info.get("name") model = discovery_info.get("model_name") host = discovery_info.get("host") - name = "{} ({})".format(tv_name, model) + name = f"{tv_name} ({model})" port = DEFAULT_PORT timeout = DEFAULT_TIMEOUT mac = None diff --git a/homeassistant/components/scsgate/__init__.py b/homeassistant/components/scsgate/__init__.py index acb7f78a2aafc2..739a2949d17a5d 100644 --- a/homeassistant/components/scsgate/__init__.py +++ b/homeassistant/components/scsgate/__init__.py @@ -77,11 +77,11 @@ def handle_message(self, message): """Handle a messages seen on the bus.""" from scsgate.messages import StateMessage, ScenarioTriggeredMessage - self._logger.debug("Received message {}".format(message)) + self._logger.debug(f"Received message {message}") if not isinstance(message, StateMessage) and not isinstance( message, ScenarioTriggeredMessage ): - msg = "Ignored message {} - not relevant type".format(message) + msg = f"Ignored message {message} - not relevant type" self._logger.debug(msg) return @@ -97,7 +97,7 @@ def handle_message(self, message): try: self._devices[message.entity].process_event(message) except Exception as exception: # pylint: disable=broad-except - msg = "Exception while processing event: {}".format(exception) + msg = f"Exception while processing event: {exception}" self._logger.error(msg) else: self._logger.info( diff --git a/homeassistant/components/sense/sensor.py b/homeassistant/components/sense/sensor.py index 8ad289b92000df..36474620b03f2b 100644 --- a/homeassistant/components/sense/sensor.py +++ b/homeassistant/components/sense/sensor.py @@ -80,7 +80,7 @@ class Sense(Entity): def __init__(self, data, name, sensor_type, is_production, update_call): """Initialize the Sense sensor.""" name_type = PRODUCTION_NAME if is_production else CONSUMPTION_NAME - self._name = "{} {}".format(name, name_type) + self._name = f"{name} {name_type}" self._data = data self._sensor_type = sensor_type self.update_sensor = update_call diff --git a/homeassistant/components/serial_pm/sensor.py b/homeassistant/components/serial_pm/sensor.py index 80952672487783..1d46b05d46e0d6 100644 --- a/homeassistant/components/serial_pm/sensor.py +++ b/homeassistant/components/serial_pm/sensor.py @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): if config.get(CONF_NAME) is not None: name = "{} PM{}".format(config.get(CONF_NAME), pmname) else: - name = "PM{}".format(pmname) + name = f"PM{pmname}" dev.append(ParticulateMatterSensor(coll, name, pmname)) add_entities(dev) diff --git a/homeassistant/components/seventeentrack/sensor.py b/homeassistant/components/seventeentrack/sensor.py index 14539e342f18c4..33abe2f1f861df 100644 --- a/homeassistant/components/seventeentrack/sensor.py +++ b/homeassistant/components/seventeentrack/sensor.py @@ -120,7 +120,7 @@ def icon(self): @property def name(self): """Return the name.""" - return "Seventeentrack Packages {0}".format(self._status) + return f"Seventeentrack Packages {self._status}" @property def state(self): @@ -203,7 +203,7 @@ def name(self): name = self._friendly_name if not name: name = self._tracking_number - return "Seventeentrack Package: {0}".format(name) + return f"Seventeentrack Package: {name}" @property def state(self): diff --git a/homeassistant/components/shiftr/__init__.py b/homeassistant/components/shiftr/__init__.py index a7e82ef66cf623..8e698d283cfcaa 100644 --- a/homeassistant/components/shiftr/__init__.py +++ b/homeassistant/components/shiftr/__init__.py @@ -69,10 +69,7 @@ def shiftr_event_listener(event): if state.attributes: for attribute, data in state.attributes.items(): mqttc.publish( - "/{}/{}".format(topic, attribute), - str(data), - qos=0, - retain=False, + f"/{topic}/{attribute}", str(data), qos=0, retain=False ) except RuntimeError: pass diff --git a/homeassistant/components/shopping_list/__init__.py b/homeassistant/components/shopping_list/__init__.py index 075d819655b395..3c9cb4391a73af 100644 --- a/homeassistant/components/shopping_list/__init__.py +++ b/homeassistant/components/shopping_list/__init__.py @@ -196,7 +196,7 @@ def async_handle(self, intent_obj): intent_obj.hass.data[DOMAIN].async_add(item) response = intent_obj.create_response() - response.async_set_speech("I've added {} to your shopping list".format(item)) + response.async_set_speech(f"I've added {item} to your shopping list") intent_obj.hass.bus.async_fire(EVENT) return response diff --git a/homeassistant/components/sigfox/sensor.py b/homeassistant/components/sigfox/sensor.py index 0961017b65c153..b890880389c232 100644 --- a/homeassistant/components/sigfox/sensor.py +++ b/homeassistant/components/sigfox/sensor.py @@ -90,7 +90,7 @@ def get_devices(self, device_types): """Get the device_id of each device registered.""" devices = [] for unique_type in device_types: - location_url = "devicetypes/{}/devices".format(unique_type) + location_url = f"devicetypes/{unique_type}/devices" url = urljoin(API_URL, location_url) response = requests.get(url, auth=self._auth, timeout=10) devices_data = json.loads(response.text)["data"] @@ -117,12 +117,12 @@ def __init__(self, device_id, auth, name): self._device_id = device_id self._auth = auth self._message_data = {} - self._name = "{}_{}".format(name, device_id) + self._name = f"{name}_{device_id}" self._state = None def get_last_message(self): """Return the last message from a device.""" - device_url = "devices/{}/messages?limit=1".format(self._device_id) + device_url = f"devices/{self._device_id}/messages?limit=1" url = urljoin(API_URL, device_url) response = requests.get(url, auth=self._auth, timeout=10) data = json.loads(response.text)["data"][0] diff --git a/homeassistant/components/sky_hub/device_tracker.py b/homeassistant/components/sky_hub/device_tracker.py index eea97fb37fb021..c8969add244a19 100644 --- a/homeassistant/components/sky_hub/device_tracker.py +++ b/homeassistant/components/sky_hub/device_tracker.py @@ -34,7 +34,7 @@ def __init__(self, config): _LOGGER.info("Initialising Sky Hub") self.host = config.get(CONF_HOST, "192.168.1.254") self.last_results = {} - self.url = "http://{}/".format(self.host) + self.url = f"http://{self.host}/" # Test the router is accessible data = _get_skyhub_data(self.url) diff --git a/homeassistant/components/skybell/camera.py b/homeassistant/components/skybell/camera.py index 87cfdce6dfcaca..87dc3c0bf8d75b 100644 --- a/homeassistant/components/skybell/camera.py +++ b/homeassistant/components/skybell/camera.py @@ -57,7 +57,7 @@ def __init__(self, device, camera_type, name=None): SkybellDevice.__init__(self, device) Camera.__init__(self) if name is not None: - self._name = "{} {}".format(self._device.name, name) + self._name = f"{self._device.name} {name}" else: self._name = self._device.name self._url = None diff --git a/homeassistant/components/sma/sensor.py b/homeassistant/components/sma/sensor.py index 5b6bc57be9d6dc..56e10b03d2adca 100644 --- a/homeassistant/components/sma/sensor.py +++ b/homeassistant/components/sma/sensor.py @@ -50,7 +50,7 @@ def _check_sensor_schema(conf): sensor, ) elif sensor not in valid: - raise vol.Invalid("{} does not exist".format(sensor)) + raise vol.Invalid(f"{sensor} does not exist") return conf @@ -217,7 +217,7 @@ def async_update_values(self): update = False for sens in self._sub_sensors: # Can be remove from 0.99 - newval = "{} {}".format(sens.value, sens.unit) + newval = f"{sens.value} {sens.unit}" if self._attr[sens.name] != newval: update = True self._attr[sens.name] = newval @@ -231,4 +231,4 @@ def async_update_values(self): @property def unique_id(self): """Return a unique identifier for this sensor.""" - return "sma-{}-{}".format(self._sensor.key, self._sensor.name) + return f"sma-{self._sensor.key}-{self._sensor.name}" diff --git a/homeassistant/components/smappee/sensor.py b/homeassistant/components/smappee/sensor.py index cdbd1d18c2990a..28abf759d098f6 100644 --- a/homeassistant/components/smappee/sensor.py +++ b/homeassistant/components/smappee/sensor.py @@ -139,7 +139,7 @@ def name(self): else: location_name = "Local" - return "{} {} {}".format(SENSOR_PREFIX, location_name, self._name) + return f"{SENSOR_PREFIX} {location_name} {self._name}" @property def icon(self): diff --git a/homeassistant/components/smartthings/binary_sensor.py b/homeassistant/components/smartthings/binary_sensor.py index 1ddbee6b827ca5..1e90709fc82c43 100644 --- a/homeassistant/components/smartthings/binary_sensor.py +++ b/homeassistant/components/smartthings/binary_sensor.py @@ -66,12 +66,12 @@ def __init__(self, device, attribute): @property def name(self) -> str: """Return the name of the binary sensor.""" - return "{} {}".format(self._device.label, self._attribute) + return f"{self._device.label} {self._attribute}" @property def unique_id(self) -> str: """Return a unique ID.""" - return "{}.{}".format(self._device.device_id, self._attribute) + return f"{self._device.device_id}.{self._attribute}" @property def is_on(self): diff --git a/homeassistant/components/smartthings/sensor.py b/homeassistant/components/smartthings/sensor.py index 423c141e4dab0b..3a6f9167054a04 100644 --- a/homeassistant/components/smartthings/sensor.py +++ b/homeassistant/components/smartthings/sensor.py @@ -283,12 +283,12 @@ def __init__( @property def name(self) -> str: """Return the name of the binary sensor.""" - return "{} {}".format(self._device.label, self._name) + return f"{self._device.label} {self._name}" @property def unique_id(self) -> str: """Return a unique ID.""" - return "{}.{}".format(self._device.device_id, self._attribute) + return f"{self._device.device_id}.{self._attribute}" @property def state(self): diff --git a/homeassistant/components/smartthings/smartapp.py b/homeassistant/components/smartthings/smartapp.py index b64ba690d41dbc..d205c1d245cb1b 100644 --- a/homeassistant/components/smartthings/smartapp.py +++ b/homeassistant/components/smartthings/smartapp.py @@ -112,7 +112,7 @@ def _get_app_template(hass: HomeAssistantType): cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL] if cloudhook_url is not None: endpoint = "via Nabu Casa" - description = "{} {}".format(hass.config.location_name, endpoint) + description = f"{hass.config.location_name} {endpoint}" return { "app_name": APP_NAME_PREFIX + str(uuid4()), diff --git a/homeassistant/components/smarty/binary_sensor.py b/homeassistant/components/smarty/binary_sensor.py index 2d79700db78507..8723f0248d34a8 100644 --- a/homeassistant/components/smarty/binary_sensor.py +++ b/homeassistant/components/smarty/binary_sensor.py @@ -69,9 +69,7 @@ class BoostSensor(SmartyBinarySensor): def __init__(self, name, smarty): """Alarm Sensor Init.""" - super().__init__( - name="{} Boost State".format(name), device_class=None, smarty=smarty - ) + super().__init__(name=f"{name} Boost State", device_class=None, smarty=smarty) def update(self) -> None: """Update state.""" @@ -84,9 +82,7 @@ class AlarmSensor(SmartyBinarySensor): def __init__(self, name, smarty): """Alarm Sensor Init.""" - super().__init__( - name="{} Alarm".format(name), device_class="problem", smarty=smarty - ) + super().__init__(name=f"{name} Alarm", device_class="problem", smarty=smarty) def update(self) -> None: """Update state.""" @@ -99,9 +95,7 @@ class WarningSensor(SmartyBinarySensor): def __init__(self, name, smarty): """Warning Sensor Init.""" - super().__init__( - name="{} Warning".format(name), device_class="problem", smarty=smarty - ) + super().__init__(name=f"{name} Warning", device_class="problem", smarty=smarty) def update(self) -> None: """Update state.""" diff --git a/homeassistant/components/smarty/sensor.py b/homeassistant/components/smarty/sensor.py index 16d910beeb5b57..bf647777b52801 100644 --- a/homeassistant/components/smarty/sensor.py +++ b/homeassistant/components/smarty/sensor.py @@ -88,7 +88,7 @@ class SupplyAirTemperatureSensor(SmartySensor): def __init__(self, name, smarty): """Supply Air Temperature Init.""" super().__init__( - name="{} Supply Air Temperature".format(name), + name=f"{name} Supply Air Temperature", device_class=DEVICE_CLASS_TEMPERATURE, unit_of_measurement=TEMP_CELSIUS, smarty=smarty, @@ -106,7 +106,7 @@ class ExtractAirTemperatureSensor(SmartySensor): def __init__(self, name, smarty): """Supply Air Temperature Init.""" super().__init__( - name="{} Extract Air Temperature".format(name), + name=f"{name} Extract Air Temperature", device_class=DEVICE_CLASS_TEMPERATURE, unit_of_measurement=TEMP_CELSIUS, smarty=smarty, @@ -124,7 +124,7 @@ class OutdoorAirTemperatureSensor(SmartySensor): def __init__(self, name, smarty): """Outdoor Air Temperature Init.""" super().__init__( - name="{} Outdoor Air Temperature".format(name), + name=f"{name} Outdoor Air Temperature", device_class=DEVICE_CLASS_TEMPERATURE, unit_of_measurement=TEMP_CELSIUS, smarty=smarty, @@ -142,7 +142,7 @@ class SupplyFanSpeedSensor(SmartySensor): def __init__(self, name, smarty): """Supply Fan Speed RPM Init.""" super().__init__( - name="{} Supply Fan Speed".format(name), + name=f"{name} Supply Fan Speed", device_class=None, unit_of_measurement=None, smarty=smarty, @@ -160,7 +160,7 @@ class ExtractFanSpeedSensor(SmartySensor): def __init__(self, name, smarty): """Extract Fan Speed RPM Init.""" super().__init__( - name="{} Extract Fan Speed".format(name), + name=f"{name} Extract Fan Speed", device_class=None, unit_of_measurement=None, smarty=smarty, @@ -178,7 +178,7 @@ class FilterDaysLeftSensor(SmartySensor): def __init__(self, name, smarty): """Filter Days Left Init.""" super().__init__( - name="{} Filter Days Left".format(name), + name=f"{name} Filter Days Left", device_class=DEVICE_CLASS_TIMESTAMP, unit_of_measurement=None, smarty=smarty, diff --git a/homeassistant/components/smhi/weather.py b/homeassistant/components/smhi/weather.py index 29a8c300944585..5f6722b72a6df3 100644 --- a/homeassistant/components/smhi/weather.py +++ b/homeassistant/components/smhi/weather.py @@ -102,7 +102,7 @@ def __init__( @property def unique_id(self) -> str: """Return a unique id.""" - return "{}, {}".format(self._latitude, self._longitude) + return f"{self._latitude}, {self._longitude}" @Throttle(MIN_TIME_BETWEEN_UPDATES) async def async_update(self) -> None: diff --git a/homeassistant/components/smtp/notify.py b/homeassistant/components/smtp/notify.py index 7336b4577fa3d8..8a96865ab8db63 100644 --- a/homeassistant/components/smtp/notify.py +++ b/homeassistant/components/smtp/notify.py @@ -182,7 +182,7 @@ def send_message(self, message="", **kwargs): msg["Subject"] = subject msg["To"] = ",".join(self.recipients) if self._sender_name: - msg["From"] = "{} <{}>".format(self._sender_name, self._sender) + msg["From"] = f"{self._sender_name} <{self._sender}>" else: msg["From"] = self._sender msg["X-Mailer"] = "HomeAssistant" @@ -225,18 +225,18 @@ def _build_multipart_msg(message, images): msg.attach(msg_alt) body_txt = MIMEText(message) msg_alt.attach(body_txt) - body_text = ["

{}


".format(message)] + body_text = [f"

{message}


"] for atch_num, atch_name in enumerate(images): - cid = "image{}".format(atch_num) - body_text.append('
'.format(cid)) + cid = f"image{atch_num}" + body_text.append(f'
') try: with open(atch_name, "rb") as attachment_file: file_bytes = attachment_file.read() try: attachment = MIMEImage(file_bytes) msg.attach(attachment) - attachment.add_header("Content-ID", "<{}>".format(cid)) + attachment.add_header("Content-ID", f"<{cid}>") except TypeError: _LOGGER.warning( "Attachment %s has an unknown MIME type. " @@ -271,7 +271,7 @@ def _build_html_msg(text, html, images): with open(atch_name, "rb") as attachment_file: attachment = MIMEImage(attachment_file.read(), filename=name) msg.attach(attachment) - attachment.add_header("Content-ID", "<{}>".format(name)) + attachment.add_header("Content-ID", f"<{name}>") except FileNotFoundError: _LOGGER.warning( "Attachment %s [#%s] not found. Skipping", atch_name, atch_num diff --git a/homeassistant/components/snapcast/media_player.py b/homeassistant/components/snapcast/media_player.py index 454201319adfd3..81cd6538578c0b 100644 --- a/homeassistant/components/snapcast/media_player.py +++ b/homeassistant/components/snapcast/media_player.py @@ -98,7 +98,7 @@ async def async_service_handle(service_event, service, data): return # Note: Host part is needed, when using multiple snapservers - hpid = "{}:{}".format(host, port) + hpid = f"{host}:{port}" groups = [SnapcastGroupDevice(group, hpid) for group in server.groups] clients = [SnapcastClientDevice(client, hpid) for client in server.clients] @@ -114,7 +114,7 @@ def __init__(self, group, uid_part): """Initialize the Snapcast group device.""" group.set_callback(self.schedule_update_ha_state) self._group = group - self._uid = "{}{}_{}".format(GROUP_PREFIX, uid_part, self._group.identifier) + self._uid = f"{GROUP_PREFIX}{uid_part}_{self._group.identifier}" @property def state(self): @@ -133,7 +133,7 @@ def unique_id(self): @property def name(self): """Return the name of the device.""" - return "{}{}".format(GROUP_PREFIX, self._group.identifier) + return f"{GROUP_PREFIX}{self._group.identifier}" @property def source(self): @@ -163,7 +163,7 @@ def source_list(self): @property def device_state_attributes(self): """Return the state attributes.""" - name = "{} {}".format(self._group.friendly_name, GROUP_SUFFIX) + name = f"{self._group.friendly_name} {GROUP_SUFFIX}" return {"friendly_name": name} @property @@ -204,7 +204,7 @@ def __init__(self, client, uid_part): """Initialize the Snapcast client device.""" client.set_callback(self.schedule_update_ha_state) self._client = client - self._uid = "{}{}_{}".format(CLIENT_PREFIX, uid_part, self._client.identifier) + self._uid = f"{CLIENT_PREFIX}{uid_part}_{self._client.identifier}" @property def unique_id(self): @@ -223,7 +223,7 @@ def identifier(self): @property def name(self): """Return the name of the device.""" - return "{}{}".format(CLIENT_PREFIX, self._client.identifier) + return f"{CLIENT_PREFIX}{self._client.identifier}" @property def source(self): @@ -260,7 +260,7 @@ def state(self): @property def device_state_attributes(self): """Return the state attributes.""" - name = "{} {}".format(self._client.friendly_name, CLIENT_SUFFIX) + name = f"{self._client.friendly_name} {CLIENT_SUFFIX}" return {"friendly_name": name} @property diff --git a/homeassistant/components/solaredge_local/sensor.py b/homeassistant/components/solaredge_local/sensor.py index 80bd8e1f61ed8c..8586d950e39cdb 100644 --- a/homeassistant/components/solaredge_local/sensor.py +++ b/homeassistant/components/solaredge_local/sensor.py @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): platform_name = config[CONF_NAME] # Create new SolarEdge object to retrieve data - api = SolarEdge("http://{}/".format(ip_address)) + api = SolarEdge(f"http://{ip_address}/") # Check if api can be reached and site is active try: diff --git a/homeassistant/components/solax/sensor.py b/homeassistant/components/solax/sensor.py index 62c6a2a3a514b8..0c1cfcf21da32a 100644 --- a/homeassistant/components/solax/sensor.py +++ b/homeassistant/components/solax/sensor.py @@ -35,7 +35,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= idx, unit = solax.INVERTER_SENSORS[sensor] if unit == "C": unit = TEMP_CELSIUS - uid = "{}-{}".format(serial, idx) + uid = f"{serial}-{idx}" devices.append(Inverter(uid, serial, sensor, unit)) endpoint.sensors = devices async_add_entities(devices) @@ -97,7 +97,7 @@ def unique_id(self): @property def name(self): """Name of this inverter attribute.""" - return "Solax {} {}".format(self.serial, self.key) + return f"Solax {self.serial} {self.key}" @property def unit_of_measurement(self): diff --git a/homeassistant/components/somfy/config_flow.py b/homeassistant/components/somfy/config_flow.py index 7e6645c31e2f52..9f3c58c8ffba70 100644 --- a/homeassistant/components/somfy/config_flow.py +++ b/homeassistant/components/somfy/config_flow.py @@ -73,7 +73,7 @@ async def _get_authorization_url(self): client_id = self.hass.data[DOMAIN][CLIENT_ID] client_secret = self.hass.data[DOMAIN][CLIENT_SECRET] - redirect_uri = "{}{}".format(self.hass.config.api.base_url, AUTH_CALLBACK_PATH) + redirect_uri = f"{self.hass.config.api.base_url}{AUTH_CALLBACK_PATH}" api = SomfyApi(client_id, client_secret, redirect_uri) self.hass.http.register_view(SomfyAuthCallbackView()) @@ -95,7 +95,7 @@ async def async_step_creation(self, user_input=None): code = self.code from pymfy.api.somfy_api import SomfyApi - redirect_uri = "{}{}".format(self.hass.config.api.base_url, AUTH_CALLBACK_PATH) + redirect_uri = f"{self.hass.config.api.base_url}{AUTH_CALLBACK_PATH}" api = SomfyApi(client_id, client_secret, redirect_uri) token = await self.hass.async_add_executor_job(api.request_token, None, code) _LOGGER.info("Successfully authenticated Somfy") diff --git a/homeassistant/components/sonos/media_player.py b/homeassistant/components/sonos/media_player.py index 70461ad15d2fa6..41472413a077b6 100644 --- a/homeassistant/components/sonos/media_player.py +++ b/homeassistant/components/sonos/media_player.py @@ -606,7 +606,7 @@ def update_media_radio(self, variables, track_info): # media_artist = "Station - Artist - Title" # detect this case and trim from the front of # media_artist for cosmetics - trim = "{title} - ".format(title=self._media_title) + trim = f"{self._media_title} - " chars = min(len(self._media_artist), len(trim)) if self._media_artist[:chars].upper() == trim[:chars].upper(): diff --git a/homeassistant/components/speedtestdotnet/const.py b/homeassistant/components/speedtestdotnet/const.py index 90a89fcda2c60a..69aadb7ac6c8d2 100644 --- a/homeassistant/components/speedtestdotnet/const.py +++ b/homeassistant/components/speedtestdotnet/const.py @@ -1,7 +1,7 @@ """Consts used by Speedtest.net.""" DOMAIN = "speedtestdotnet" -DATA_UPDATED = "{}_data_updated".format(DOMAIN) +DATA_UPDATED = f"{DOMAIN}_data_updated" SENSOR_TYPES = { "ping": ["Ping", "ms"], diff --git a/homeassistant/components/spotcrime/sensor.py b/homeassistant/components/spotcrime/sensor.py index 4498fd47e694e8..fc3a7592af3130 100644 --- a/homeassistant/components/spotcrime/sensor.py +++ b/homeassistant/components/spotcrime/sensor.py @@ -29,7 +29,7 @@ DEFAULT_DAYS = 1 NAME = "spotcrime" -EVENT_INCIDENT = "{}_incident".format(NAME) +EVENT_INCIDENT = f"{NAME}_incident" SCAN_INTERVAL = timedelta(minutes=30) diff --git a/homeassistant/components/spotify/media_player.py b/homeassistant/components/spotify/media_player.py index 74a0dc0c9c0cca..31fdc09af80371 100644 --- a/homeassistant/components/spotify/media_player.py +++ b/homeassistant/components/spotify/media_player.py @@ -99,7 +99,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Spotify platform.""" import spotipy.oauth2 - callback_url = "{}{}".format(hass.config.api.base_url, AUTH_CALLBACK_PATH) + callback_url = f"{hass.config.api.base_url}{AUTH_CALLBACK_PATH}" cache = config.get(CONF_CACHE_PATH, hass.config.path(DEFAULT_CACHE_PATH)) oauth = spotipy.oauth2.SpotifyOAuth( config.get(CONF_CLIENT_ID), diff --git a/homeassistant/components/squeezebox/media_player.py b/homeassistant/components/squeezebox/media_player.py index 5f3a91bcf2f9d2..9e62e7ee0dbc83 100644 --- a/homeassistant/components/squeezebox/media_player.py +++ b/homeassistant/components/squeezebox/media_player.py @@ -208,7 +208,7 @@ async def async_query(self, *command, player=""): if self._username is None else aiohttp.BasicAuth(self._username, self._password) ) - url = "http://{}:{}/jsonrpc.js".format(self.host, self.port) + url = f"http://{self.host}:{self.port}/jsonrpc.js" data = json.dumps( {"id": "1", "method": "slim.request", "params": [player, command]} ) @@ -288,9 +288,7 @@ def async_query(self, *parameters): async def async_update(self): """Retrieve the current state of the player.""" tags = "adKl" - response = await self.async_query( - "status", "-", "1", "tags:{tags}".format(tags=tags) - ) + response = await self.async_query("status", "-", "1", f"tags:{tags}") if response is False: return diff --git a/homeassistant/components/srp_energy/sensor.py b/homeassistant/components/srp_energy/sensor.py index a9873c76afe79f..f1d1787b7b48c5 100644 --- a/homeassistant/components/srp_energy/sensor.py +++ b/homeassistant/components/srp_energy/sensor.py @@ -87,7 +87,7 @@ def state(self): if self._state is None: return None - return "{0:.2f}".format(self._state) + return f"{self._state:.2f}" @property def name(self): diff --git a/homeassistant/components/startca/sensor.py b/homeassistant/components/startca/sensor.py index d4104dd3dcf47c..5e370ed7b63290 100644 --- a/homeassistant/components/startca/sensor.py +++ b/homeassistant/components/startca/sensor.py @@ -86,7 +86,7 @@ def __init__(self, startcadata, sensor_type, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): diff --git a/homeassistant/components/steam_online/sensor.py b/homeassistant/components/steam_online/sensor.py index 924afedfbd5f3b..6c9c5ac6079eb9 100644 --- a/homeassistant/components/steam_online/sensor.py +++ b/homeassistant/components/steam_online/sensor.py @@ -80,7 +80,7 @@ def name(self): @property def entity_id(self): """Return the entity ID.""" - return "sensor.steam_{}".format(self._account) + return f"sensor.steam_{self._account}" @property def state(self): diff --git a/homeassistant/components/stiebel_eltron/climate.py b/homeassistant/components/stiebel_eltron/climate.py index f2e6209d21db70..ce16b10f548856 100644 --- a/homeassistant/components/stiebel_eltron/climate.py +++ b/homeassistant/components/stiebel_eltron/climate.py @@ -139,7 +139,7 @@ def max_temp(self): @property def current_humidity(self): """Return the current humidity.""" - return float("{0:.1f}".format(self._current_humidity)) + return float(f"{self._current_humidity:.1f}") @property def hvac_modes(self): diff --git a/homeassistant/components/stream/__init__.py b/homeassistant/components/stream/__init__.py index 50cc1d8169d6e4..2ae8dd5f71405b 100644 --- a/homeassistant/components/stream/__init__.py +++ b/homeassistant/components/stream/__init__.py @@ -217,9 +217,7 @@ async def async_handle_record_service(hass, call): # Check for file access if not hass.config.is_allowed_path(video_path): - raise HomeAssistantError( - "Can't write {}, no access to path!".format(video_path) - ) + raise HomeAssistantError(f"Can't write {video_path}, no access to path!") # Check for active stream streams = hass.data[DOMAIN][ATTR_STREAMS] @@ -231,9 +229,7 @@ async def async_handle_record_service(hass, call): # Add recorder recorder = stream.outputs.get("recorder") if recorder: - raise HomeAssistantError( - "Stream already recording to {}!".format(recorder.video_path) - ) + raise HomeAssistantError(f"Stream already recording to {recorder.video_path}!") recorder = stream.add_provider("recorder") recorder.video_path = video_path diff --git a/homeassistant/components/stream/hls.py b/homeassistant/components/stream/hls.py index ab8779151588a3..c9e62f53a5788b 100644 --- a/homeassistant/components/stream/hls.py +++ b/homeassistant/components/stream/hls.py @@ -64,10 +64,7 @@ def __init__(self, stream): @staticmethod def render_preamble(track): """Render preamble.""" - return [ - "#EXT-X-VERSION:3", - "#EXT-X-TARGETDURATION:{}".format(track.target_duration), - ] + return ["#EXT-X-VERSION:3", f"#EXT-X-TARGETDURATION:{track.target_duration}"] @staticmethod def render_playlist(track, start_time): @@ -84,7 +81,7 @@ def render_playlist(track, start_time): playlist.extend( [ "#EXTINF:{:.04f},".format(float(segment.duration)), - "./segment/{}.ts".format(segment.sequence), + f"./segment/{segment.sequence}.ts", ] ) diff --git a/homeassistant/components/streamlabswater/binary_sensor.py b/homeassistant/components/streamlabswater/binary_sensor.py index fd0ccb57aa6018..78b2ceb40441d0 100644 --- a/homeassistant/components/streamlabswater/binary_sensor.py +++ b/homeassistant/components/streamlabswater/binary_sensor.py @@ -58,7 +58,7 @@ def __init__(self, location_name, streamlabs_location_data): @property def name(self): """Return the name for away mode.""" - return "{} {}".format(self._location_name, NAME_AWAY_MODE) + return f"{self._location_name} {NAME_AWAY_MODE}" @property def is_on(self): diff --git a/homeassistant/components/streamlabswater/sensor.py b/homeassistant/components/streamlabswater/sensor.py index 69196c288f6077..e7168f8ec0b536 100644 --- a/homeassistant/components/streamlabswater/sensor.py +++ b/homeassistant/components/streamlabswater/sensor.py @@ -79,7 +79,7 @@ def __init__(self, location_name, streamlabs_usage_data): @property def name(self): """Return the name for daily usage.""" - return "{} {}".format(self._location_name, NAME_DAILY_USAGE) + return f"{self._location_name} {NAME_DAILY_USAGE}" @property def icon(self): @@ -107,7 +107,7 @@ class StreamLabsMonthlyUsage(StreamLabsDailyUsage): @property def name(self): """Return the name for monthly usage.""" - return "{} {}".format(self._location_name, NAME_MONTHLY_USAGE) + return f"{self._location_name} {NAME_MONTHLY_USAGE}" @property def state(self): @@ -121,7 +121,7 @@ class StreamLabsYearlyUsage(StreamLabsDailyUsage): @property def name(self): """Return the name for yearly usage.""" - return "{} {}".format(self._location_name, NAME_YEARLY_USAGE) + return f"{self._location_name} {NAME_YEARLY_USAGE}" @property def state(self): diff --git a/homeassistant/components/swiss_hydrological_data/sensor.py b/homeassistant/components/swiss_hydrological_data/sensor.py index bbac046d62ef97..2d5d0e8de3f3af 100644 --- a/homeassistant/components/swiss_hydrological_data/sensor.py +++ b/homeassistant/components/swiss_hydrological_data/sensor.py @@ -101,7 +101,7 @@ def name(self): @property def unique_id(self) -> str: """Return a unique, friendly identifier for this entity.""" - return "{0}_{1}".format(self._station, self._condition) + return f"{self._station}_{self._condition}" @property def unit_of_measurement(self): diff --git a/homeassistant/components/swiss_public_transport/sensor.py b/homeassistant/components/swiss_public_transport/sensor.py index fedcb3003b05c5..3cf8babf554889 100644 --- a/homeassistant/components/swiss_public_transport/sensor.py +++ b/homeassistant/components/swiss_public_transport/sensor.py @@ -110,7 +110,7 @@ def device_state_attributes(self): ATTR_DEPARTURE_TIME2: self._opendata.connections[2]["departure"], ATTR_START: self._opendata.from_name, ATTR_TARGET: self._opendata.to_name, - ATTR_REMAINING_TIME: "{}".format(self._remaining_time), + ATTR_REMAINING_TIME: f"{self._remaining_time}", ATTR_ATTRIBUTION: ATTRIBUTION, } return attr diff --git a/homeassistant/components/swisscom/device_tracker.py b/homeassistant/components/swisscom/device_tracker.py index 3775854fade01e..98965af15136b8 100644 --- a/homeassistant/components/swisscom/device_tracker.py +++ b/homeassistant/components/swisscom/device_tracker.py @@ -74,7 +74,7 @@ def _update_info(self): def get_swisscom_data(self): """Retrieve data from Swisscom and return parsed result.""" - url = "http://{}/ws".format(self.host) + url = f"http://{self.host}/ws" headers = {CONTENT_TYPE: "application/x-sah-ws-4-call+json"} data = """ {"service":"Devices", "method":"get", diff --git a/homeassistant/components/switcher_kis/switch.py b/homeassistant/components/switcher_kis/switch.py index f52935c02ec8f6..a758a5843472cb 100644 --- a/homeassistant/components/switcher_kis/switch.py +++ b/homeassistant/components/switcher_kis/switch.py @@ -65,7 +65,7 @@ def should_poll(self) -> bool: @property def unique_id(self) -> str: """Return a unique ID.""" - return "{}-{}".format(self._device_data.device_id, self._device_data.mac_addr) + return f"{self._device_data.device_id}-{self._device_data.mac_addr}" @property def is_on(self) -> bool: diff --git a/homeassistant/components/syncthru/sensor.py b/homeassistant/components/syncthru/sensor.py index 0a50eec75c2696..1258732223b01c 100644 --- a/homeassistant/components/syncthru/sensor.py +++ b/homeassistant/components/syncthru/sensor.py @@ -18,12 +18,10 @@ TRAYS = range(1, 6) OUTPUT_TRAYS = range(0, 6) DEFAULT_MONITORED_CONDITIONS = [] -DEFAULT_MONITORED_CONDITIONS.extend(["toner_{}".format(key) for key in TONER_COLORS]) -DEFAULT_MONITORED_CONDITIONS.extend(["drum_{}".format(key) for key in DRUM_COLORS]) -DEFAULT_MONITORED_CONDITIONS.extend(["tray_{}".format(key) for key in TRAYS]) -DEFAULT_MONITORED_CONDITIONS.extend( - ["output_tray_{}".format(key) for key in OUTPUT_TRAYS] -) +DEFAULT_MONITORED_CONDITIONS.extend([f"toner_{key}" for key in TONER_COLORS]) +DEFAULT_MONITORED_CONDITIONS.extend([f"drum_{key}" for key in DRUM_COLORS]) +DEFAULT_MONITORED_CONDITIONS.extend([f"tray_{key}" for key in TRAYS]) +DEFAULT_MONITORED_CONDITIONS.extend([f"output_tray_{key}" for key in OUTPUT_TRAYS]) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { @@ -81,16 +79,16 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= devices = [SyncThruMainSensor(printer, name)] for key in supp_toner: - if "toner_{}".format(key) in monitored: + if f"toner_{key}" in monitored: devices.append(SyncThruTonerSensor(printer, name, key)) for key in supp_drum: - if "drum_{}".format(key) in monitored: + if f"drum_{key}" in monitored: devices.append(SyncThruDrumSensor(printer, name, key)) for key in supp_tray: - if "tray_{}".format(key) in monitored: + if f"tray_{key}" in monitored: devices.append(SyncThruInputTraySensor(printer, name, key)) for key in supp_output_tray: - if "output_tray_{}".format(key) in monitored: + if f"output_tray_{key}" in monitored: devices.append(SyncThruOutputTraySensor(printer, name, key)) async_add_entities(devices, True) @@ -173,10 +171,10 @@ class SyncThruTonerSensor(SyncThruSensor): def __init__(self, syncthru, name, color): """Initialize the sensor.""" super().__init__(syncthru, name) - self._name = "{} Toner {}".format(name, color) + self._name = f"{name} Toner {color}" self._color = color self._unit_of_measurement = "%" - self._id_suffix = "_toner_{}".format(color) + self._id_suffix = f"_toner_{color}" def update(self): """Get the latest data from SyncThru and update the state.""" @@ -193,10 +191,10 @@ class SyncThruDrumSensor(SyncThruSensor): def __init__(self, syncthru, name, color): """Initialize the sensor.""" super().__init__(syncthru, name) - self._name = "{} Drum {}".format(name, color) + self._name = f"{name} Drum {color}" self._color = color self._unit_of_measurement = "%" - self._id_suffix = "_drum_{}".format(color) + self._id_suffix = f"_drum_{color}" def update(self): """Get the latest data from SyncThru and update the state.""" @@ -213,9 +211,9 @@ class SyncThruInputTraySensor(SyncThruSensor): def __init__(self, syncthru, name, number): """Initialize the sensor.""" super().__init__(syncthru, name) - self._name = "{} Tray {}".format(name, number) + self._name = f"{name} Tray {number}" self._number = number - self._id_suffix = "_tray_{}".format(number) + self._id_suffix = f"_tray_{number}" def update(self): """Get the latest data from SyncThru and update the state.""" @@ -234,9 +232,9 @@ class SyncThruOutputTraySensor(SyncThruSensor): def __init__(self, syncthru, name, number): """Initialize the sensor.""" super().__init__(syncthru, name) - self._name = "{} Output Tray {}".format(name, number) + self._name = f"{name} Output Tray {number}" self._number = number - self._id_suffix = "_output_tray_{}".format(number) + self._id_suffix = f"_output_tray_{number}" def update(self): """Get the latest data from SyncThru and update the state.""" diff --git a/homeassistant/components/synologydsm/sensor.py b/homeassistant/components/synologydsm/sensor.py index 17295f15250619..e19f6ada809706 100644 --- a/homeassistant/components/synologydsm/sensor.py +++ b/homeassistant/components/synologydsm/sensor.py @@ -184,7 +184,7 @@ def __init__(self, api, name, variable, variable_info, monitor_device=None): def name(self): """Return the name of the sensor, if any.""" if self.monitor_device is not None: - return "{} ({})".format(self.var_name, self.monitor_device) + return f"{self.var_name} ({self.monitor_device})" return self.var_name @property diff --git a/homeassistant/components/sytadin/sensor.py b/homeassistant/components/sytadin/sensor.py index 4296f2d5b05b39..b7c94933a39974 100644 --- a/homeassistant/components/sytadin/sensor.py +++ b/homeassistant/components/sytadin/sensor.py @@ -86,7 +86,7 @@ def __init__(self, data, name, sensor_type, option, unit): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._name, self._option) + return f"{self._name} {self._option}" @property def state(self): From d13210ef54e1962c9d7ffd117fc04f36cde7a7b4 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 3 Sep 2019 21:15:31 +0200 Subject: [PATCH 70/72] Use literal string interpolation in integrations X-Z (f-strings) (#26395) --- .../components/xiaomi/device_tracker.py | 2 +- .../components/xiaomi_aqara/__init__.py | 6 +- homeassistant/components/xiaomi_miio/fan.py | 2 +- homeassistant/components/xiaomi_miio/light.py | 4 +- .../components/xiaomi_miio/remote.py | 2 +- .../components/xiaomi_miio/sensor.py | 2 +- .../components/xiaomi_miio/switch.py | 4 +- homeassistant/components/xmpp/notify.py | 4 +- .../components/yamaha/media_player.py | 6 +- .../yamaha_musiccast/media_player.py | 2 +- homeassistant/components/yeelight/__init__.py | 2 +- .../components/yeelight/binary_sensor.py | 2 +- homeassistant/components/yeelight/light.py | 4 +- .../components/yeelightsunflower/light.py | 2 +- homeassistant/components/yr/sensor.py | 4 +- homeassistant/components/yweather/sensor.py | 2 +- homeassistant/components/zamg/sensor.py | 4 +- homeassistant/components/zestimate/sensor.py | 4 +- homeassistant/components/zha/api.py | 70 +++++++++---------- .../components/zha/core/channels/__init__.py | 6 +- .../components/zha/core/channels/closures.py | 8 +-- .../components/zha/core/channels/general.py | 10 +-- .../zha/core/channels/homeautomation.py | 4 +- .../components/zha/core/channels/hvac.py | 8 +-- .../components/zha/core/channels/security.py | 8 +-- homeassistant/components/zha/core/device.py | 24 +++---- .../components/zha/core/discovery.py | 6 +- homeassistant/components/zha/core/gateway.py | 12 ++-- homeassistant/components/zha/entity.py | 2 +- .../ziggo_mediabox_xl/media_player.py | 2 +- .../components/zoneminder/__init__.py | 2 +- homeassistant/components/zoneminder/sensor.py | 4 +- homeassistant/components/zoneminder/switch.py | 2 +- homeassistant/components/zwave/__init__.py | 18 +++-- homeassistant/components/zwave/node_entity.py | 2 +- homeassistant/components/zwave/util.py | 6 +- 36 files changed, 115 insertions(+), 137 deletions(-) diff --git a/homeassistant/components/xiaomi/device_tracker.py b/homeassistant/components/xiaomi/device_tracker.py index 36ce4589396f7b..dbc647f49827d1 100644 --- a/homeassistant/components/xiaomi/device_tracker.py +++ b/homeassistant/components/xiaomi/device_tracker.py @@ -143,7 +143,7 @@ def _retrieve_list(host, token, **kwargs): def _get_token(host, username, password): """Get authentication token for the given host+username+password.""" - url = "http://{}/cgi-bin/luci/api/xqsystem/login".format(host) + url = f"http://{host}/cgi-bin/luci/api/xqsystem/login" data = {"username": username, "password": password} try: res = requests.post(url, data=data, timeout=5) diff --git a/homeassistant/components/xiaomi_aqara/__init__.py b/homeassistant/components/xiaomi_aqara/__init__.py index cf2411ccda50ac..6e2298e05b9782 100644 --- a/homeassistant/components/xiaomi_aqara/__init__.py +++ b/homeassistant/components/xiaomi_aqara/__init__.py @@ -232,7 +232,7 @@ def __init__(self, device, device_type, xiaomi_hub): self._state = None self._is_available = True self._sid = device["sid"] - self._name = "{}_{}".format(device_type, self._sid) + self._name = f"{device_type}_{self._sid}" self._type = device_type self._write_to_hub = xiaomi_hub.write_to_hub self._get_from_hub = xiaomi_hub.get_from_hub @@ -247,7 +247,7 @@ def __init__(self, device, device_type, xiaomi_hub): self._data_key, self._sid # pylint: disable=no-member ) else: - self._unique_id = "{}{}".format(self._type, self._sid) + self._unique_id = f"{self._type}{self._sid}" def _add_push_data_job(self, *args): self.hass.add_job(self.push_data, *args) @@ -345,7 +345,7 @@ def gateway(sid): if gateway.sid == sid: return gateway - raise vol.Invalid("Unknown gateway sid {}".format(sid)) + raise vol.Invalid(f"Unknown gateway sid {sid}") gateways = list(xiaomi.gateways.values()) kwargs = {} diff --git a/homeassistant/components/xiaomi_miio/fan.py b/homeassistant/components/xiaomi_miio/fan.py index 93ca7e4bde0c6b..c6ca6db32fbce6 100644 --- a/homeassistant/components/xiaomi_miio/fan.py +++ b/homeassistant/components/xiaomi_miio/fan.py @@ -440,7 +440,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model - unique_id = "{}-{}".format(model, device_info.mac_address) + unique_id = f"{model}-{device_info.mac_address}" _LOGGER.info( "%s %s %s detected", model, diff --git a/homeassistant/components/xiaomi_miio/light.py b/homeassistant/components/xiaomi_miio/light.py index ebb5be2cc06219..3d23f1dfc98c48 100644 --- a/homeassistant/components/xiaomi_miio/light.py +++ b/homeassistant/components/xiaomi_miio/light.py @@ -136,7 +136,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model - unique_id = "{}-{}".format(model, device_info.mac_address) + unique_id = f"{model}-{device_info.mac_address}" _LOGGER.info( "%s %s %s detected", model, @@ -731,7 +731,7 @@ class XiaomiPhilipsEyecareLampAmbientLight(XiaomiPhilipsAbstractLight): def __init__(self, name, light, model, unique_id): """Initialize the light device.""" - name = "{} Ambient Light".format(name) + name = f"{name} Ambient Light" if unique_id is not None: unique_id = "{}-{}".format(unique_id, "ambient") super().__init__(name, light, model, unique_id) diff --git a/homeassistant/components/xiaomi_miio/remote.py b/homeassistant/components/xiaomi_miio/remote.py index d66d8ce39b1cf2..311a356870c828 100644 --- a/homeassistant/components/xiaomi_miio/remote.py +++ b/homeassistant/components/xiaomi_miio/remote.py @@ -90,7 +90,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= try: device_info = device.info() model = device_info.model - unique_id = "{}-{}".format(model, device_info.mac_address) + unique_id = f"{model}-{device_info.mac_address}" _LOGGER.info( "%s %s %s detected", model, diff --git a/homeassistant/components/xiaomi_miio/sensor.py b/homeassistant/components/xiaomi_miio/sensor.py index ffbdf281843b08..0ebffb06fcd87e 100644 --- a/homeassistant/components/xiaomi_miio/sensor.py +++ b/homeassistant/components/xiaomi_miio/sensor.py @@ -52,7 +52,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= air_quality_monitor = AirQualityMonitor(host, token) device_info = air_quality_monitor.info() model = device_info.model - unique_id = "{}-{}".format(model, device_info.mac_address) + unique_id = f"{model}-{device_info.mac_address}" _LOGGER.info( "%s %s %s detected", model, diff --git a/homeassistant/components/xiaomi_miio/switch.py b/homeassistant/components/xiaomi_miio/switch.py index 8188d7911889ca..5f79652621bab3 100644 --- a/homeassistant/components/xiaomi_miio/switch.py +++ b/homeassistant/components/xiaomi_miio/switch.py @@ -117,7 +117,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model - unique_id = "{}-{}".format(model, device_info.mac_address) + unique_id = f"{model}-{device_info.mac_address}" _LOGGER.info( "%s %s %s detected", model, @@ -426,7 +426,7 @@ class ChuangMiPlugSwitch(XiaomiPlugGenericSwitch): def __init__(self, name, plug, model, unique_id, channel_usb): """Initialize the plug switch.""" - name = "{} USB".format(name) if channel_usb else name + name = f"{name} USB" if channel_usb else name if unique_id is not None and channel_usb: unique_id = "{}-{}".format(unique_id, "usb") diff --git a/homeassistant/components/xmpp/notify.py b/homeassistant/components/xmpp/notify.py index ce22bf7a953d8b..3719113f7c9d18 100644 --- a/homeassistant/components/xmpp/notify.py +++ b/homeassistant/components/xmpp/notify.py @@ -87,12 +87,12 @@ def __init__(self, sender, resource, password, recipient, tls, verify, room, has async def async_send_message(self, message="", **kwargs): """Send a message to a user.""" title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) - text = "{}: {}".format(title, message) if title else message + text = f"{title}: {message}" if title else message data = kwargs.get(ATTR_DATA) timeout = data.get(ATTR_TIMEOUT, XEP_0363_TIMEOUT) if data else None await async_send_message( - "{}/{}".format(self._sender, self._resource), + f"{self._sender}/{self._resource}", self._password, self._recipient, self._tls, diff --git a/homeassistant/components/yamaha/media_player.py b/homeassistant/components/yamaha/media_player.py index ff976c6b12fe59..e699ab74e680d9 100644 --- a/homeassistant/components/yamaha/media_player.py +++ b/homeassistant/components/yamaha/media_player.py @@ -114,7 +114,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): for recv in rxv.find(): receivers.extend(recv.zone_controllers()) else: - ctrl_url = "http://{}:80/YamahaRemoteControl/ctrl".format(host) + ctrl_url = f"http://{host}:80/YamahaRemoteControl/ctrl" receivers = rxv.RXV(ctrl_url, name).zone_controllers() devices = [] @@ -276,7 +276,7 @@ def source_list(self): @property def zone_id(self): """Return a zone_id to ensure 1 media player per zone.""" - return "{0}:{1}".format(self.receiver.ctrl_url, self._zone) + return f"{self.receiver.ctrl_url}:{self._zone}" @property def supported_features(self): @@ -410,6 +410,6 @@ def media_title(self): # If both song and station is available, print both, otherwise # just the one we have. if song and station: - return "{}: {}".format(station, song) + return f"{station}: {song}" return song or station diff --git a/homeassistant/components/yamaha_musiccast/media_player.py b/homeassistant/components/yamaha_musiccast/media_player.py index d82b093ca7e8e0..38e606a0962cd1 100644 --- a/homeassistant/components/yamaha_musiccast/media_player.py +++ b/homeassistant/components/yamaha_musiccast/media_player.py @@ -128,7 +128,7 @@ def __init__(self, recv, zone): @property def name(self): """Return the name of the device.""" - return "{} ({})".format(self._name, self._zone.zone_id) + return f"{self._name} ({self._zone.zone_id})" @property def state(self): diff --git a/homeassistant/components/yeelight/__init__.py b/homeassistant/components/yeelight/__init__.py index 172d66f9bf5c0d..431c34aa06ef80 100644 --- a/homeassistant/components/yeelight/__init__.py +++ b/homeassistant/components/yeelight/__init__.py @@ -26,7 +26,7 @@ DOMAIN = "yeelight" DATA_YEELIGHT = DOMAIN DATA_UPDATED = "yeelight_{}_data_updated" -DEVICE_INITIALIZED = "{}_device_initialized".format(DOMAIN) +DEVICE_INITIALIZED = f"{DOMAIN}_device_initialized" DEFAULT_NAME = "Yeelight" DEFAULT_TRANSITION = 350 diff --git a/homeassistant/components/yeelight/binary_sensor.py b/homeassistant/components/yeelight/binary_sensor.py index 0a6e021df94aa0..da39152e9cae63 100644 --- a/homeassistant/components/yeelight/binary_sensor.py +++ b/homeassistant/components/yeelight/binary_sensor.py @@ -48,7 +48,7 @@ def should_poll(self): @property def name(self): """Return the name of the sensor.""" - return "{} nightlight".format(self._device.name) + return f"{self._device.name} nightlight" @property def is_on(self): diff --git a/homeassistant/components/yeelight/light.py b/homeassistant/components/yeelight/light.py index a3d5d2dec2e863..8601e0e16322c1 100644 --- a/homeassistant/components/yeelight/light.py +++ b/homeassistant/components/yeelight/light.py @@ -165,7 +165,7 @@ def _wrap(self, *args, **kwargs): def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Yeelight bulbs.""" - data_key = "{}_lights".format(DATA_YEELIGHT) + data_key = f"{DATA_YEELIGHT}_lights" if not discovery_info: return @@ -673,7 +673,7 @@ def __init__(self, *args, **kwargs): @property def name(self) -> str: """Return the name of the device if any.""" - return "{} ambilight".format(self.device.name) + return f"{self.device.name} ambilight" def _get_property(self, prop, default=None): bg_prop = self.PROPERTIES_MAPPING.get(prop) diff --git a/homeassistant/components/yeelightsunflower/light.py b/homeassistant/components/yeelightsunflower/light.py index 896daac96c40de..fa836f2776ffa5 100644 --- a/homeassistant/components/yeelightsunflower/light.py +++ b/homeassistant/components/yeelightsunflower/light.py @@ -50,7 +50,7 @@ def __init__(self, light): @property def name(self): """Return the display name of this light.""" - return "sunflower_{}".format(self._light.zid) + return f"sunflower_{self._light.zid}" @property def available(self): diff --git a/homeassistant/components/yr/sensor.py b/homeassistant/components/yr/sensor.py index 15d966d1354f41..3d8c63621be977 100644 --- a/homeassistant/components/yr/sensor.py +++ b/homeassistant/components/yr/sensor.py @@ -106,7 +106,7 @@ def __init__(self, name, sensor_type): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self._name) + return f"{self.client_name} {self._name}" @property def state(self): @@ -168,7 +168,7 @@ def try_again(err: str): with async_timeout.timeout(10): resp = await websession.get(self._url, params=self._urlparams) if resp.status != 200: - try_again("{} returned {}".format(resp.url, resp.status)) + try_again(f"{resp.url} returned {resp.status}") return text = await resp.text() diff --git a/homeassistant/components/yweather/sensor.py b/homeassistant/components/yweather/sensor.py index d23b49a0230624..4dc236998724ee 100644 --- a/homeassistant/components/yweather/sensor.py +++ b/homeassistant/components/yweather/sensor.py @@ -108,7 +108,7 @@ def __init__(self, weather_data, name, forecast, sensor_type): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._client, self._name) + return f"{self._client} {self._name}" @property def state(self): diff --git a/homeassistant/components/zamg/sensor.py b/homeassistant/components/zamg/sensor.py index 52f6617c397a76..9eea1f6612c8d1 100644 --- a/homeassistant/components/zamg/sensor.py +++ b/homeassistant/components/zamg/sensor.py @@ -124,7 +124,7 @@ def __init__(self, probe, variable, name): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self.client_name, self.variable) + return f"{self.client_name} {self.variable}" @property def state(self): @@ -212,7 +212,7 @@ def update(self): } break else: - raise ValueError("No weather data for station {}".format(self._station_id)) + raise ValueError(f"No weather data for station {self._station_id}") def get_data(self, variable): """Get the data.""" diff --git a/homeassistant/components/zestimate/sensor.py b/homeassistant/components/zestimate/sensor.py index 0b5c75934b6bdb..703e3bf25a0cee 100644 --- a/homeassistant/components/zestimate/sensor.py +++ b/homeassistant/components/zestimate/sensor.py @@ -19,7 +19,7 @@ DEFAULT_NAME = "Zestimate" NAME = "zestimate" -ZESTIMATE = "{}:{}".format(DEFAULT_NAME, NAME) +ZESTIMATE = f"{DEFAULT_NAME}:{NAME}" ICON = "mdi:home-variant" @@ -74,7 +74,7 @@ def unique_id(self): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._name, self.address) + return f"{self._name} {self.address}" @property def state(self): diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index 77b1b36fa36d6c..be079e83fa6bb0 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -283,10 +283,10 @@ async def websocket_device_cluster_attributes(hass, connection, msg): ) _LOGGER.debug( "Requested attributes for: %s %s %s %s", - "{}: [{}]".format(ATTR_CLUSTER_ID, cluster_id), - "{}: [{}]".format(ATTR_CLUSTER_TYPE, cluster_type), - "{}: [{}]".format(ATTR_ENDPOINT_ID, endpoint_id), - "{}: [{}]".format(RESPONSE, cluster_attributes), + f"{ATTR_CLUSTER_ID}: [{cluster_id}]", + f"{ATTR_CLUSTER_TYPE}: [{cluster_type}]", + f"{ATTR_ENDPOINT_ID}: [{endpoint_id}]", + f"{RESPONSE}: [{cluster_attributes}]", ) connection.send_result(msg[ID], cluster_attributes) @@ -337,10 +337,10 @@ async def websocket_device_cluster_commands(hass, connection, msg): ) _LOGGER.debug( "Requested commands for: %s %s %s %s", - "{}: [{}]".format(ATTR_CLUSTER_ID, cluster_id), - "{}: [{}]".format(ATTR_CLUSTER_TYPE, cluster_type), - "{}: [{}]".format(ATTR_ENDPOINT_ID, endpoint_id), - "{}: [{}]".format(RESPONSE, cluster_commands), + f"{ATTR_CLUSTER_ID}: [{cluster_id}]", + f"{ATTR_CLUSTER_TYPE}: [{cluster_type}]", + f"{ATTR_ENDPOINT_ID}: [{endpoint_id}]", + f"{RESPONSE}: [{cluster_commands}]", ) connection.send_result(msg[ID], cluster_commands) @@ -381,11 +381,11 @@ async def websocket_read_zigbee_cluster_attributes(hass, connection, msg): ) _LOGGER.debug( "Read attribute for: %s %s %s %s %s %s %s", - "{}: [{}]".format(ATTR_CLUSTER_ID, cluster_id), - "{}: [{}]".format(ATTR_CLUSTER_TYPE, cluster_type), - "{}: [{}]".format(ATTR_ENDPOINT_ID, endpoint_id), - "{}: [{}]".format(ATTR_ATTRIBUTE, attribute), - "{}: [{}]".format(ATTR_MANUFACTURER, manufacturer), + f"{ATTR_CLUSTER_ID}: [{cluster_id}]", + f"{ATTR_CLUSTER_TYPE}: [{cluster_type}]", + f"{ATTR_ENDPOINT_ID}: [{endpoint_id}]", + f"{ATTR_ATTRIBUTE}: [{attribute}]", + f"{ATTR_MANUFACTURER}: [{manufacturer}]", "{}: [{}]".format(RESPONSE, str(success.get(attribute))), "{}: [{}]".format("failure", failure), ) @@ -411,7 +411,7 @@ async def websocket_get_bindable_devices(hass, connection, msg): _LOGGER.debug( "Get bindable devices: %s %s", - "{}: [{}]".format(ATTR_SOURCE_IEEE, source_ieee), + f"{ATTR_SOURCE_IEEE}: [{source_ieee}]", "{}: [{}]".format("bindable devices:", devices), ) @@ -435,8 +435,8 @@ async def websocket_bind_devices(hass, connection, msg): await async_binding_operation(zha_gateway, source_ieee, target_ieee, BIND_REQUEST) _LOGGER.info( "Issue bind devices: %s %s", - "{}: [{}]".format(ATTR_SOURCE_IEEE, source_ieee), - "{}: [{}]".format(ATTR_TARGET_IEEE, target_ieee), + f"{ATTR_SOURCE_IEEE}: [{source_ieee}]", + f"{ATTR_TARGET_IEEE}: [{target_ieee}]", ) @@ -457,8 +457,8 @@ async def websocket_unbind_devices(hass, connection, msg): await async_binding_operation(zha_gateway, source_ieee, target_ieee, UNBIND_REQUEST) _LOGGER.info( "Issue unbind devices: %s %s", - "{}: [{}]".format(ATTR_SOURCE_IEEE, source_ieee), - "{}: [{}]".format(ATTR_TARGET_IEEE, target_ieee), + f"{ATTR_SOURCE_IEEE}: [{source_ieee}]", + f"{ATTR_TARGET_IEEE}: [{target_ieee}]", ) @@ -482,8 +482,8 @@ async def async_binding_operation(zha_gateway, source_ieee, target_ieee, operati _LOGGER.debug( "processing binding operation for: %s %s %s", - "{}: [{}]".format(ATTR_SOURCE_IEEE, source_ieee), - "{}: [{}]".format(ATTR_TARGET_IEEE, target_ieee), + f"{ATTR_SOURCE_IEEE}: [{source_ieee}]", + f"{ATTR_TARGET_IEEE}: [{target_ieee}]", "{}: {}".format("cluster", cluster_pair.source_cluster.cluster_id), ) bind_tasks.append( @@ -551,13 +551,13 @@ async def set_zigbee_cluster_attributes(service): ) _LOGGER.debug( "Set attribute for: %s %s %s %s %s %s %s", - "{}: [{}]".format(ATTR_CLUSTER_ID, cluster_id), - "{}: [{}]".format(ATTR_CLUSTER_TYPE, cluster_type), - "{}: [{}]".format(ATTR_ENDPOINT_ID, endpoint_id), - "{}: [{}]".format(ATTR_ATTRIBUTE, attribute), - "{}: [{}]".format(ATTR_VALUE, value), - "{}: [{}]".format(ATTR_MANUFACTURER, manufacturer), - "{}: [{}]".format(RESPONSE, response), + f"{ATTR_CLUSTER_ID}: [{cluster_id}]", + f"{ATTR_CLUSTER_TYPE}: [{cluster_type}]", + f"{ATTR_ENDPOINT_ID}: [{endpoint_id}]", + f"{ATTR_ATTRIBUTE}: [{attribute}]", + f"{ATTR_VALUE}: [{value}]", + f"{ATTR_MANUFACTURER}: [{manufacturer}]", + f"{RESPONSE}: [{response}]", ) hass.helpers.service.async_register_admin_service( @@ -593,14 +593,14 @@ async def issue_zigbee_cluster_command(service): ) _LOGGER.debug( "Issue command for: %s %s %s %s %s %s %s %s", - "{}: [{}]".format(ATTR_CLUSTER_ID, cluster_id), - "{}: [{}]".format(ATTR_CLUSTER_TYPE, cluster_type), - "{}: [{}]".format(ATTR_ENDPOINT_ID, endpoint_id), - "{}: [{}]".format(ATTR_COMMAND, command), - "{}: [{}]".format(ATTR_COMMAND_TYPE, command_type), - "{}: [{}]".format(ATTR_ARGS, args), - "{}: [{}]".format(ATTR_MANUFACTURER, manufacturer), - "{}: [{}]".format(RESPONSE, response), + f"{ATTR_CLUSTER_ID}: [{cluster_id}]", + f"{ATTR_CLUSTER_TYPE}: [{cluster_type}]", + f"{ATTR_ENDPOINT_ID}: [{endpoint_id}]", + f"{ATTR_COMMAND}: [{command}]", + f"{ATTR_COMMAND_TYPE}: [{command_type}]", + f"{ATTR_ARGS}: [{args}]", + f"{ATTR_MANUFACTURER}: [{manufacturer}]", + f"{RESPONSE}: [{response}]", ) hass.helpers.service.async_register_admin_service( diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py index 20756f26b729f7..9e3b69a80df07c 100644 --- a/homeassistant/components/zha/core/channels/__init__.py +++ b/homeassistant/components/zha/core/channels/__init__.py @@ -87,7 +87,7 @@ def __init__(self, cluster, device): self._channel_name = cluster.ep_attribute if self.CHANNEL_NAME: self._channel_name = self.CHANNEL_NAME - self._generic_id = "channel_0x{:04x}".format(cluster.cluster_id) + self._generic_id = f"channel_0x{cluster.cluster_id:04x}" self._cluster = cluster self._zha_device = device self._unique_id = "{}:{}:0x{:04x}".format( @@ -299,9 +299,7 @@ def attribute_updated(self, attrid, value): """Handle attribute updates on this cluster.""" if attrid == self.value_attribute: async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - value, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", value ) async def async_initialize(self, from_cache): diff --git a/homeassistant/components/zha/core/channels/closures.py b/homeassistant/components/zha/core/channels/closures.py index 0559c4a1f76056..378be778e6f565 100644 --- a/homeassistant/components/zha/core/channels/closures.py +++ b/homeassistant/components/zha/core/channels/closures.py @@ -30,9 +30,7 @@ async def async_update(self): result = await self.get_attribute_value("lock_state", from_cache=True) async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - result, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", result ) @callback @@ -44,9 +42,7 @@ def attribute_updated(self, attrid, value): ) if attrid == self._value_attribute: async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - value, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", value ) async def async_initialize(self, from_cache): diff --git a/homeassistant/components/zha/core/channels/general.py b/homeassistant/components/zha/core/channels/general.py index 6a828ef1ad8a94..f67ee2fb75ac77 100644 --- a/homeassistant/components/zha/core/channels/general.py +++ b/homeassistant/components/zha/core/channels/general.py @@ -198,7 +198,7 @@ def attribute_updated(self, attrid, value): def dispatch_level_change(self, command, level): """Dispatch level change.""" async_dispatcher_send( - self._zha_device.hass, "{}_{}".format(self.unique_id, command), level + self._zha_device.hass, f"{self.unique_id}_{command}", level ) async def async_initialize(self, from_cache): @@ -284,9 +284,7 @@ def attribute_updated(self, attrid, value): """Handle attribute updates on this cluster.""" if attrid == self.ON_OFF: async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - value, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", value ) self._state = bool(value) @@ -355,9 +353,7 @@ def attribute_updated(self, attrid, value): attr_id = attr if attrid == attr_id: async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - value, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", value ) async def async_initialize(self, from_cache): diff --git a/homeassistant/components/zha/core/channels/homeautomation.py b/homeassistant/components/zha/core/channels/homeautomation.py index 198eec67a469ca..7a5f0161fb4385 100644 --- a/homeassistant/components/zha/core/channels/homeautomation.py +++ b/homeassistant/components/zha/core/channels/homeautomation.py @@ -72,9 +72,7 @@ async def async_update(self): # This is a polling channel. Don't allow cache. result = await self.get_attribute_value("active_power", from_cache=False) async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - result, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", result ) async def async_initialize(self, from_cache): diff --git a/homeassistant/components/zha/core/channels/hvac.py b/homeassistant/components/zha/core/channels/hvac.py index 46d9ffb52e5e7f..2f6e6c1b3e8390 100644 --- a/homeassistant/components/zha/core/channels/hvac.py +++ b/homeassistant/components/zha/core/channels/hvac.py @@ -48,9 +48,7 @@ async def async_update(self): result = await self.get_attribute_value("fan_mode", from_cache=True) async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - result, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", result ) @callback @@ -62,9 +60,7 @@ def attribute_updated(self, attrid, value): ) if attrid == self._value_attribute: async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - value, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", value ) async def async_initialize(self, from_cache): diff --git a/homeassistant/components/zha/core/channels/security.py b/homeassistant/components/zha/core/channels/security.py index cac93ea7214b22..cd407cfc416b68 100644 --- a/homeassistant/components/zha/core/channels/security.py +++ b/homeassistant/components/zha/core/channels/security.py @@ -43,9 +43,7 @@ def cluster_command(self, tsn, command_id, args): if command_id == 0: state = args[0] & 3 async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - state, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", state ) self.debug("Updated alarm state: %s", state) elif command_id == 1: @@ -91,9 +89,7 @@ def attribute_updated(self, attrid, value): if attrid == 2: value = value & 3 async_dispatcher_send( - self._zha_device.hass, - "{}_{}".format(self.unique_id, SIGNAL_ATTR_UPDATED), - value, + self._zha_device.hass, f"{self.unique_id}_{SIGNAL_ATTR_UPDATED}", value ) async def async_initialize(self, from_cache): diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index 1c22b41ce86af7..1db4aafeeb9a80 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -102,7 +102,7 @@ def __init__(self, hass, zigpy_device, zha_gateway): @property def name(self): """Return device name.""" - return "{} {}".format(self.manufacturer, self.model) + return f"{self.manufacturer} {self.model}" @property def ieee(self): @@ -461,10 +461,10 @@ async def write_zigbee_attribute( except DeliveryError as exc: self.debug( "failed to set attribute: %s %s %s %s %s", - "{}: {}".format(ATTR_VALUE, value), - "{}: {}".format(ATTR_ATTRIBUTE, attribute), - "{}: {}".format(ATTR_CLUSTER_ID, cluster_id), - "{}: {}".format(ATTR_ENDPOINT_ID, endpoint_id), + f"{ATTR_VALUE}: {value}", + f"{ATTR_ATTRIBUTE}: {attribute}", + f"{ATTR_CLUSTER_ID}: {cluster_id}", + f"{ATTR_ENDPOINT_ID}: {endpoint_id}", exc, ) return None @@ -493,13 +493,13 @@ async def issue_cluster_command( self.debug( "Issued cluster command: %s %s %s %s %s %s %s", - "{}: {}".format(ATTR_CLUSTER_ID, cluster_id), - "{}: {}".format(ATTR_COMMAND, command), - "{}: {}".format(ATTR_COMMAND_TYPE, command_type), - "{}: {}".format(ATTR_ARGS, args), - "{}: {}".format(ATTR_CLUSTER_ID, cluster_type), - "{}: {}".format(ATTR_MANUFACTURER, manufacturer), - "{}: {}".format(ATTR_ENDPOINT_ID, endpoint_id), + f"{ATTR_CLUSTER_ID}: {cluster_id}", + f"{ATTR_COMMAND}: {command}", + f"{ATTR_COMMAND_TYPE}: {command_type}", + f"{ATTR_ARGS}: {args}", + f"{ATTR_CLUSTER_ID}: {cluster_type}", + f"{ATTR_MANUFACTURER}: {manufacturer}", + f"{ATTR_ENDPOINT_ID}: {endpoint_id}", ) return response diff --git a/homeassistant/components/zha/core/discovery.py b/homeassistant/components/zha/core/discovery.py index c4489164b0c481..5a5ffb34ab13ea 100644 --- a/homeassistant/components/zha/core/discovery.py +++ b/homeassistant/components/zha/core/discovery.py @@ -62,7 +62,7 @@ def async_process_endpoint( component = None profile_clusters = [] - device_key = "{}-{}".format(device.ieee, endpoint_id) + device_key = f"{device.ieee}-{endpoint_id}" node_config = {} if CONF_DEVICE_CONFIG in config: node_config = config[CONF_DEVICE_CONFIG].get(device_key, {}) @@ -281,12 +281,12 @@ def _async_handle_single_cluster_match( channels = [] _async_create_cluster_channel(cluster, zha_device, is_new_join, channels=channels) - cluster_key = "{}-{}".format(device_key, cluster.cluster_id) + cluster_key = f"{device_key}-{cluster.cluster_id}" discovery_info = { "unique_id": cluster_key, "zha_device": zha_device, "channels": channels, - "entity_suffix": "_{}".format(cluster.cluster_id), + "entity_suffix": f"_{cluster.cluster_id}", "component": component, } diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 3d8c3e8fd9086b..be09312f6931cb 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -339,7 +339,7 @@ async def async_device_initialized(self, device): _LOGGER.debug( "device - %s entering async_device_initialized - is_new_join: %s", - "0x{:04x}:{}".format(device.nwk, device.ieee), + f"0x{device.nwk:04x}:{device.ieee}", zha_device.status is not DeviceStatus.INITIALIZED, ) @@ -348,13 +348,13 @@ async def async_device_initialized(self, device): # new nwk or device was physically reset and added again without being removed _LOGGER.debug( "device - %s has been reset and readded or its nwk address changed", - "0x{:04x}:{}".format(device.nwk, device.ieee), + f"0x{device.nwk:04x}:{device.ieee}", ) await self._async_device_rejoined(zha_device) else: _LOGGER.debug( "device - %s has joined the ZHA zigbee network", - "0x{:04x}:{}".format(device.nwk, device.ieee), + f"0x{device.nwk:04x}:{device.ieee}", ) await self._async_device_joined(device, zha_device) @@ -413,9 +413,9 @@ async def async_device_restored(self, device): # to update it now _LOGGER.debug( "attempting to request fresh state for device - %s %s %s", - "0x{:04x}:{}".format(zha_device.nwk, zha_device.ieee), + f"0x{zha_device.nwk:04x}:{zha_device.ieee}", zha_device.name, - "with power source: {}".format(zha_device.power_source), + f"with power source: {zha_device.power_source}", ) await zha_device.async_initialize(from_cache=False) else: @@ -427,7 +427,7 @@ async def async_device_restored(self, device): async def _async_device_rejoined(self, zha_device): _LOGGER.debug( "skipping discovery for previously discovered device - %s", - "0x{:04x}:{}".format(zha_device.nwk, zha_device.ieee), + f"0x{zha_device.nwk:04x}:{zha_device.ieee}", ) # we don't have to do this on a nwk swap but we don't have a way to tell currently await zha_device.async_configure() diff --git a/homeassistant/components/zha/entity.py b/homeassistant/components/zha/entity.py index 694f7b25695258..00c3942358e1fe 100644 --- a/homeassistant/components/zha/entity.py +++ b/homeassistant/components/zha/entity.py @@ -189,7 +189,7 @@ async def async_accept_signal(self, channel, signal, func, signal_override=False unsub = async_dispatcher_connect(self.hass, signal, func) else: unsub = async_dispatcher_connect( - self.hass, "{}_{}".format(channel.unique_id, signal), func + self.hass, f"{channel.unique_id}_{signal}", func ) self._unsubs.append(unsub) diff --git a/homeassistant/components/ziggo_mediabox_xl/media_player.py b/homeassistant/components/ziggo_mediabox_xl/media_player.py index f9e4e1ac49dbee..a5f8b38ac3775a 100644 --- a/homeassistant/components/ziggo_mediabox_xl/media_player.py +++ b/homeassistant/components/ziggo_mediabox_xl/media_player.py @@ -206,5 +206,5 @@ def select_source(self, source): if digits is None: return - self.send_keys(["NUM_{}".format(digit) for digit in str(digits)]) + self.send_keys([f"NUM_{digit}" for digit in str(digits)]) self._state = STATE_PLAYING diff --git a/homeassistant/components/zoneminder/__init__.py b/homeassistant/components/zoneminder/__init__.py index 1ce6b87a88f912..a116cc31891e5d 100644 --- a/homeassistant/components/zoneminder/__init__.py +++ b/homeassistant/components/zoneminder/__init__.py @@ -64,7 +64,7 @@ def setup(hass, config): schema = "http" host_name = conf[CONF_HOST] - server_origin = "{}://{}".format(schema, host_name) + server_origin = f"{schema}://{host_name}" zm_client = ZoneMinder( server_origin, conf.get(CONF_USERNAME), diff --git a/homeassistant/components/zoneminder/sensor.py b/homeassistant/components/zoneminder/sensor.py index e2ab4b0905fc20..bfcfcb8f907a8e 100644 --- a/homeassistant/components/zoneminder/sensor.py +++ b/homeassistant/components/zoneminder/sensor.py @@ -68,7 +68,7 @@ def __init__(self, monitor): @property def name(self): """Return the name of the sensor.""" - return "{} Status".format(self._monitor.name) + return f"{self._monitor.name} Status" @property def state(self): @@ -105,7 +105,7 @@ def __init__(self, monitor, include_archived, sensor_type): @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._monitor.name, self.time_period.title) + return f"{self._monitor.name} {self.time_period.title}" @property def unit_of_measurement(self): diff --git a/homeassistant/components/zoneminder/switch.py b/homeassistant/components/zoneminder/switch.py index d22ef611b35303..d2d761aab1e60c 100644 --- a/homeassistant/components/zoneminder/switch.py +++ b/homeassistant/components/zoneminder/switch.py @@ -53,7 +53,7 @@ def __init__(self, monitor, on_state, off_state): @property def name(self): """Return the name of the switch.""" - return "{} State".format(self._monitor.name) + return f"{self._monitor.name} State" def update(self): """Update the switch value.""" diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index bc40d46b8ba6ef..223ce810d7cefe 100644 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -478,10 +478,10 @@ def _on_timeout(sec): def node_removed(node): node_id = node.node_id - node_key = "node-{}".format(node_id) + node_key = f"node-{node_id}" _LOGGER.info("Node Removed: %s", hass.data[DATA_DEVICES][node_key]) for key in list(hass.data[DATA_DEVICES]): - if not key.startswith("{}-".format(node_id)): + if not key.startswith(f"{node_id}-"): continue entity = hass.data[DATA_DEVICES][key] @@ -586,11 +586,11 @@ async def rename_node(service): update_ids = service.data.get(const.ATTR_UPDATE_IDS) # We want to rename the device, the node entity, # and all the contained entities - node_key = "node-{}".format(node_id) + node_key = f"node-{node_id}" entity = hass.data[DATA_DEVICES][node_key] await entity.node_renamed(update_ids) for key in list(hass.data[DATA_DEVICES]): - if not key.startswith("{}-".format(node_id)): + if not key.startswith(f"{node_id}-"): continue entity = hass.data[DATA_DEVICES][key] await entity.value_renamed(update_ids) @@ -607,7 +607,7 @@ async def rename_value(service): "Renamed Z-Wave value (Node %d Value %d) to %s", node_id, value_id, name ) update_ids = service.data.get(const.ATTR_UPDATE_IDS) - value_key = "{}-{}".format(node_id, value_id) + value_key = f"{node_id}-{value_id}" entity = hass.data[DATA_DEVICES][value_key] await entity.value_renamed(update_ids) @@ -1109,7 +1109,7 @@ def _check_entity_ready(self): if polling_intensity: self.primary.enable_poll(polling_intensity) - platform = import_module(".{}".format(component), __name__) + platform = import_module(f".{component}", __name__) device = platform.get_device( node=self._node, values=self, node_config=node_config, hass=self._hass @@ -1149,9 +1149,7 @@ async def discover_device(component, device): self._hass.data[DATA_DEVICES][device.unique_id] = device if component in SUPPORTED_PLATFORMS: - async_dispatcher_send( - self._hass, "zwave_new_{}".format(component), device - ) + async_dispatcher_send(self._hass, f"zwave_new_{component}", device) else: await discovery.async_load_platform( self._hass, @@ -1316,4 +1314,4 @@ def _compute_unique_id(self): def compute_value_unique_id(node, value): """Compute unique_id a value would get if it were to get one.""" - return "{}-{}".format(node.node_id, value.object_id) + return f"{node.node_id}-{value.object_id}" diff --git a/homeassistant/components/zwave/node_entity.py b/homeassistant/components/zwave/node_entity.py index c60314d35798a5..66c3452f7c881d 100644 --- a/homeassistant/components/zwave/node_entity.py +++ b/homeassistant/components/zwave/node_entity.py @@ -348,5 +348,5 @@ def device_state_attributes(self): def _compute_unique_id(self): if is_node_parsed(self.node) or self.node.is_ready: - return "node-{}".format(self.node_id) + return f"node-{self.node_id}" return None diff --git a/homeassistant/components/zwave/util.py b/homeassistant/components/zwave/util.py index 1e7b77d2b38b02..da8fa37f44fbdc 100644 --- a/homeassistant/components/zwave/util.py +++ b/homeassistant/components/zwave/util.py @@ -91,8 +91,8 @@ def check_value_schema(value, schema): def node_name(node): """Return the name of the node.""" if is_node_parsed(node): - return node.name or "{} {}".format(node.manufacturer_name, node.product_name) - return "Unknown Node {}".format(node.node_id) + return node.name or f"{node.manufacturer_name} {node.product_name}" + return f"Unknown Node {node.node_id}" def node_device_id_and_name(node, instance=1): @@ -100,7 +100,7 @@ def node_device_id_and_name(node, instance=1): name = node_name(node) if instance == 1: return ((const.DOMAIN, node.node_id), name) - name = "{} ({})".format(name, instance) + name = f"{name} ({instance})" return ((const.DOMAIN, node.node_id, instance), name) From ea4f927f9a0876d259c9909a905abb91b4d55454 Mon Sep 17 00:00:00 2001 From: Peter Nijssen Date: Tue, 3 Sep 2019 22:56:34 +0200 Subject: [PATCH 71/72] add irrigation service to rain bird, which allows you to set the duration --- .../components/rainbird/services.yaml | 9 +++ homeassistant/components/rainbird/switch.py | 60 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 homeassistant/components/rainbird/services.yaml diff --git a/homeassistant/components/rainbird/services.yaml b/homeassistant/components/rainbird/services.yaml new file mode 100644 index 00000000000000..160e86cff12324 --- /dev/null +++ b/homeassistant/components/rainbird/services.yaml @@ -0,0 +1,9 @@ +start_irrigation: + description: Start the irrigation + fields: + entity_id: + description: Name(s) of irrigations to turn on + example: 'switch.sprinkler_1' + duration: + description: Duration for this sprinkler to be turned on + example: 1 \ No newline at end of file diff --git a/homeassistant/components/rainbird/switch.py b/homeassistant/components/rainbird/switch.py index 9fb19bc620654d..2d4f2a6bdceefc 100644 --- a/homeassistant/components/rainbird/switch.py +++ b/homeassistant/components/rainbird/switch.py @@ -7,6 +7,7 @@ from homeassistant.components.switch import PLATFORM_SCHEMA, SwitchDevice from homeassistant.const import ( + ATTR_ENTITY_ID, CONF_FRIENDLY_NAME, CONF_SCAN_INTERVAL, CONF_SWITCHES, @@ -20,6 +21,12 @@ DOMAIN = "rainbird" _LOGGER = logging.getLogger(__name__) +ATTR_DURATION = "duration" + +SERVICE_START_IRRIGATION = "start_irrigation" + +SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.entity_ids}) + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Required(CONF_SWITCHES, default={}): vol.Schema( @@ -35,6 +42,17 @@ } ) +SERVICE_SCHEMA_IRRIGATION = SERVICE_SCHEMA.extend( + {vol.Required(ATTR_DURATION): vol.All(vol.Coerce(float), vol.Range(min=0))} +) + +SERVICE_TO_METHOD = { + SERVICE_START_IRRIGATION: { + "method": "start_irrigation", + "schema": SERVICE_SCHEMA_IRRIGATION, + } +} + def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Rain Bird switches over a Rain Bird controller.""" @@ -45,6 +63,31 @@ def setup_platform(hass, config, add_entities, discovery_info=None): devices.append(RainBirdSwitch(controller, switch, dev_id)) add_entities(devices, True) + def start_irrigation(service): + """Set IR code as device state attribute.""" + entity_ids = service.data.get(ATTR_ENTITY_ID) + duration = service.data.get(ATTR_DURATION) + + if entity_ids: + _devices = [ + device + for device in devices + if isinstance(device, RainBirdSwitch) and device.entity_id in entity_ids + ] + else: + _devices = [ + device for device in devices if isinstance(device, RainBirdSwitch) + ] + for device in _devices: + device.start_irrigation(duration) + + hass.services.async_register( + DOMAIN, + SERVICE_START_IRRIGATION, + start_irrigation, + schema=SERVICE_SCHEMA_IRRIGATION, + ) + class RainBirdSwitch(SwitchDevice): """Representation of a Rain Bird switch.""" @@ -79,6 +122,23 @@ def turn_off(self, **kwargs): if self._rainbird.stop_irrigation(): self._state = False +<<<<<<< HEAD +======= + def start_irrigation(self, duration: int): + """Turn the irrigation on.""" + response = self._rainbird.startIrrigation(int(self._zone), int(duration)) + if response and response["type"] == "AcknowledgeResponse": + self._state = True + + def get_device_status(self): + """Get the status of the switch from Rain Bird Controller.""" + response = self._rainbird.currentIrrigation() + if response is None: + return None + if isinstance(response, dict) and "sprinklers" in response: + return response["sprinklers"][self._zone] + +>>>>>>> add irrigation service to rain bird, which allows you to set the duration def update(self): """Update switch status.""" self._state = self._rainbird.zone_state(self._zone) From 539d84c0b051bb9ad33d3352576f4d956d418ebe Mon Sep 17 00:00:00 2001 From: Peter Nijssen Date: Thu, 5 Sep 2019 23:36:15 +0200 Subject: [PATCH 72/72] rebased on konikvranik and solved some feedback --- .../components/rainbird/services.yaml | 2 +- homeassistant/components/rainbird/switch.py | 55 +++++-------------- 2 files changed, 14 insertions(+), 43 deletions(-) diff --git a/homeassistant/components/rainbird/services.yaml b/homeassistant/components/rainbird/services.yaml index 160e86cff12324..3ed79b2a9cbf6f 100644 --- a/homeassistant/components/rainbird/services.yaml +++ b/homeassistant/components/rainbird/services.yaml @@ -2,7 +2,7 @@ start_irrigation: description: Start the irrigation fields: entity_id: - description: Name(s) of irrigations to turn on + description: Name of a single irrigation to turn on example: 'switch.sprinkler_1' duration: description: Duration for this sprinkler to be turned on diff --git a/homeassistant/components/rainbird/switch.py b/homeassistant/components/rainbird/switch.py index 2d4f2a6bdceefc..ca17dd141ebe4a 100644 --- a/homeassistant/components/rainbird/switch.py +++ b/homeassistant/components/rainbird/switch.py @@ -16,17 +16,14 @@ ) from homeassistant.helpers import config_validation as cv -from . import DATA_RAINBIRD +from . import DATA_RAINBIRD, DOMAIN -DOMAIN = "rainbird" _LOGGER = logging.getLogger(__name__) ATTR_DURATION = "duration" SERVICE_START_IRRIGATION = "start_irrigation" -SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.entity_ids}) - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Required(CONF_SWITCHES, default={}): vol.Schema( @@ -42,16 +39,12 @@ } ) -SERVICE_SCHEMA_IRRIGATION = SERVICE_SCHEMA.extend( - {vol.Required(ATTR_DURATION): vol.All(vol.Coerce(float), vol.Range(min=0))} -) - -SERVICE_TO_METHOD = { - SERVICE_START_IRRIGATION: { - "method": "start_irrigation", - "schema": SERVICE_SCHEMA_IRRIGATION, +SERVICE_SCHEMA_IRRIGATION = vol.Schema( + { + vol.Required(ATTR_ENTITY_ID): cv.entity_id, + vol.Required(ATTR_DURATION): vol.All(vol.Coerce(float), vol.Range(min=0)), } -} +) def setup_platform(hass, config, add_entities, discovery_info=None): @@ -64,22 +57,13 @@ def setup_platform(hass, config, add_entities, discovery_info=None): add_entities(devices, True) def start_irrigation(service): - """Set IR code as device state attribute.""" - entity_ids = service.data.get(ATTR_ENTITY_ID) + """Set the duration device state attribute and start the irrigation.""" + entity_id = service.data.get(ATTR_ENTITY_ID) duration = service.data.get(ATTR_DURATION) - if entity_ids: - _devices = [ - device - for device in devices - if isinstance(device, RainBirdSwitch) and device.entity_id in entity_ids - ] - else: - _devices = [ - device for device in devices if isinstance(device, RainBirdSwitch) - ] - for device in _devices: - device.start_irrigation(duration) + for device in devices: + if isinstance(device, RainBirdSwitch) and device.entity_id == entity_id: + device.start_irrigation(duration) hass.services.async_register( DOMAIN, @@ -114,31 +98,18 @@ def name(self): def turn_on(self, **kwargs): """Turn the switch on.""" - if self._rainbird.irrigate_zone(int(self._zone), int(self._duration)): - self._state = True + self.start_irrigation(self._duration) def turn_off(self, **kwargs): """Turn the switch off.""" if self._rainbird.stop_irrigation(): self._state = False -<<<<<<< HEAD -======= def start_irrigation(self, duration: int): """Turn the irrigation on.""" - response = self._rainbird.startIrrigation(int(self._zone), int(duration)) - if response and response["type"] == "AcknowledgeResponse": + if self._rainbird.irrigate_zone(int(self._zone), duration): self._state = True - def get_device_status(self): - """Get the status of the switch from Rain Bird Controller.""" - response = self._rainbird.currentIrrigation() - if response is None: - return None - if isinstance(response, dict) and "sprinklers" in response: - return response["sprinklers"][self._zone] - ->>>>>>> add irrigation service to rain bird, which allows you to set the duration def update(self): """Update switch status.""" self._state = self._rainbird.zone_state(self._zone)