Compare commits

...

297 Commits

Author SHA1 Message Date
Paulus Schoutsen
e715c43e0d Merge pull request #26912 from home-assistant/rc
0.99.3
2019-09-25 11:25:29 -07:00
Paulus Schoutsen
4bab1612a3 Bumped version to 0.99.3 2019-09-25 10:28:20 -07:00
MajestyIV
7566a38f01 HM-CC-TC was not recognized (#26623)
* HM-CC-TC was not recognized

* guard instead of exception
2019-09-25 10:28:08 -07:00
Sébastien RAMAGE
9919f5f924 Bump zigpy-zigate to 0.3.1 (#26600)
* Bump zigpy-zigate to 0.3.1

Bump zigpy-zigate to 0.3.1 (fix Rpi.GPIO dependency)

* Bump zigpy-zigate to 0.3.1

Bump zigpy-zigate to 0.3.1 (fix Rpi.GPIO dependency)
2019-09-23 14:19:34 -07:00
Paulus Schoutsen
7bed79255e Updated frontend to 20190919.1 2019-09-23 13:35:06 -07:00
Paulus Schoutsen
b3420cbf93 Merge pull request #26751 from home-assistant/rc
0.99.2
2019-09-19 15:29:19 -07:00
Paulus Schoutsen
616b36527b Bumped version to 0.99.2 2019-09-19 15:26:49 -07:00
Paulus Schoutsen
794c26a66e Updated frontend to 20190919.0 2019-09-19 15:23:42 -07:00
Paulus Schoutsen
1892ae5bfc Merge pull request #26748 from home-assistant/rc
0.99.1
2019-09-19 15:22:01 -07:00
Paulus Schoutsen
8439329b04 Bumped version to 0.99.1 2019-09-19 14:29:43 -07:00
Daniel Shokouhi
3551c39bad Bump pyobihai to fix issue with user account (#26736) 2019-09-19 14:28:34 -07:00
Paulus Schoutsen
66405d5651 Bump TRADFRI (#26731)
* Bump TRADFRI

* Fix test
2019-09-19 14:28:33 -07:00
Andrew Rowson
120c8bad50 Encode prometheus metric names per the prom spec (#26639)
Referencing issue #26418.

Prometheus metric names can only contain chars a-zA-Z0-9, : and _
(https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels).

HA currently generates invalid prometheus names, e.g. if the unit for a
sensor is a non-ASCII character containing  ° or μ. To resolve, we need
to sanitize the name before creating, replacing non-valid characters
with a valid representation. In this case, I've used
"u{unicode-hex-code}".

Also updated the test case to make sure that the ° case is handled.
2019-09-19 14:28:30 -07:00
Paulus Schoutsen
88154074c1 Update translations 2019-09-18 17:29:34 -07:00
Paulus Schoutsen
884591a105 Merge pull request #26710 from home-assistant/rc
0.99.0
2019-09-18 15:29:01 -07:00
Paulus Schoutsen
9f08e2b718 Bumped version to 0.99.0 2019-09-18 14:47:50 -07:00
zewelor
e3f25eb730 Fix yeelight inheritance order (#26706) 2019-09-18 14:47:42 -07:00
Paulus Schoutsen
1af5d20601 Updated frontend to 20190918.1 2019-09-18 13:40:28 -07:00
Bram Kragten
1a9b4b82f5 Bump version to 0.99.0b4 2019-09-18 18:44:57 +02:00
Bram Kragten
e7d5e08780 Updated frontend to 20190918.0 (#26704) 2019-09-18 18:43:34 +02:00
Paulus Schoutsen
ef9b3321c1 Verify withings config (#26698) 2019-09-18 18:43:33 +02:00
Bram Kragten
46a55ed723 Updated frontend to 20190917.2 (#26696) 2019-09-18 18:43:33 +02:00
Pascal Vizeli
7d525ff2f3 Fix release access for bram (#26693) 2019-09-18 18:43:32 +02:00
Maikel Punie
5b0cbad953 Fix cert expiry config flow check and update (#26638)
* Fix typo in translations

* Work on bug #26619

* readd the homeassistant.start event

* Remove the callback

* Added the executor_job for _test_connection

* Update test_config_flow.py
2019-09-18 18:43:31 +02:00
Erik Montnemery
bc7ff8323c Fix translation, adjust trigger names (#26635) 2019-09-18 18:43:31 +02:00
Erik Montnemery
4a30c1023c Rename MockToggleDevice to MockToggleEntity (#26644)
* Rename MockToggleDevice to MockToggleEntity

* Fix tests
2019-09-18 18:41:58 +02:00
Bram Kragten
e9fe90a873 Bump version to 0.99.0b3 2019-09-17 15:47:39 +02:00
Bram Kragten
7d79d281c1 Updated frontend to 20190917.1 (#26691) 2019-09-17 15:43:14 +02:00
Pascal Vizeli
d8ccc7751f Bump connect-box library to fix logging (#26690) 2019-09-17 15:43:14 +02:00
Pascal Vizeli
6853f99e30 Fix Nuki issues (#26689)
* Fix Nuki issues

* remove stale code

* Add comments

* Fix lint
2019-09-17 15:43:13 +02:00
Pascal Vizeli
1b57ea51be Bump version to 0.99.0b2 2019-09-17 07:43:09 +00:00
Bram Kragten
8d44e0cc0c Updated frontend to 20190917.0 (#26686) 2019-09-17 07:41:41 +00:00
Paulus Schoutsen
fe8ff200bc Use Nabu Casa url if no https url set (#26682)
* Use Nabu Casa url if no https url set

* Update test_home_assistant_cast.py
2019-09-17 07:38:43 +00:00
Pascal Vizeli
36ab3d3421 Bumped version to 0.99.0b1 2019-09-14 11:53:52 +00:00
Paulus Schoutsen
a1a44d47b9 Update PyChromecast (#26594) 2019-09-14 11:52:36 +00:00
Gerard
ffee50bd7a Fix CCM messages (#26589) 2019-09-14 11:52:34 +00:00
Pascal Vizeli
dfcffa14fb Update azure-pipelines-release.yml 2019-09-12 08:30:57 +02:00
Paulus Schoutsen
2ec86a2349 Bumped version to 0.99.0b0 2019-09-11 13:36:12 -06:00
Robert Svensson
0221d136de Remove support of UniFi device tracker configuration import (#26587) 2019-09-11 13:35:30 -06:00
Paulus Schoutsen
0f204b34fa Merge remote-tracking branch 'origin/master' into dev 2019-09-11 13:32:41 -06:00
Paulus Schoutsen
df390bc9ab Check if git is dirty before committing (#26588) 2019-09-11 13:30:51 -06:00
Paulus Schoutsen
3fbdc89db1 Updated frontend to 20190911.1 2019-09-11 13:21:22 -06:00
Pascal Vizeli
182bf1edef Deprecate Python 3.6.0 (#26575)
* Deprecate Python 3.6.1

* Update msg
2019-09-11 12:42:54 -06:00
Paulus Schoutsen
adaa200935 Home Assistant Cast (#26566)
* Add backend support for Home Assistant Cast

* Update test reqs
2019-09-11 12:34:10 -06:00
jjlawren
6eeb01edc4 Remove default host for Plex config (#26583)
* Remove default host, allow config with token(+server)

* Require one of host or token

* Oops

* Adjust schema

* Fix schema

* Add self as codeowner

* Update CODEOWNERS
2019-09-11 20:21:08 +02:00
Daniel Shokouhi
2b30f47f4b Add Obihai integration (#26537)
* Add Obihai integration

* Lint

* Lint and bump library for multiple ports fix

* Review comments

* Review comments

* Correct errors

* Review comments

* Review comments
2019-09-11 19:26:50 +02:00
Florent Thoumie
1a73e6b44e Add switch platform to iaqualink integration (#26545)
* Add switch platform to iaqualink component

* Remove unnecessary call to constructor
2019-09-11 19:24:41 +02:00
Tsvi Mostovicz
7dfdec531c Fix GTFS sensor wrong timezone (#26580) 2019-09-11 18:00:18 +02:00
Tsvi Mostovicz
f53fcacf49 Make uk_transport sensor timezone/DST aware (#26577)
* Make uk_transport sensor timezone/DST aware

* Fix offset-naive and offset-aware datetime comparison
2019-09-11 16:37:09 +02:00
Bram Kragten
faeb95581a Updated frontend to 20190911.0 (#26578) 2019-09-11 15:28:06 +02:00
David F. Mulcahey
c31efe50ca bump dependencies (#26576) 2019-09-11 09:18:31 -04:00
Pascal Vizeli
f3fa073045 Bump UPC connect / fix auth issue (#26570)
* Bump UPC connect / fix auth issue

* Fix lint

* Fix platform schema

* Fix config value

* Address comment / add session cleanup

* Fix device handling
2019-09-11 13:17:07 +02:00
Pascal Vizeli
e6ecabd6e1 Cleanup stale script stuff (#26573) 2019-09-11 11:33:35 +02:00
Pascal Vizeli
702a524b55 Improve startup of devcontainer (#26572) 2019-09-11 11:20:21 +02:00
Pascal Vizeli
02466ed8ab Ignore test output 2019-09-11 08:28:57 +02:00
HomeAssistant Azure
53a3f2e83d [ci skip] Translation update 2019-09-11 00:33:50 +00:00
Robert Svensson
c680c07c65 deCONZ device automations (#26366)
* Early draft

* Getting there

* Working fully with Hue dimmer remote

* Fix Balloobs comments

* No side effects in constructor

* Improve hue dimmer

* Add Ikea remote control

* Add xiaomi button support

* Refactor getting deconz event

* Added xiaomi devices and tradfri wireless dimmer

* Resolve unique id from device id

* Add Hue Tap and Tradfri on off switch

* More triggers for ikea on off switch and Aqara double wall switch

* Add support for Tradfri open close remote

* Fix changes after rebase

* Initial test

* Change id to event_id

* Fix translations and add subtypes

* Try if tests pass without the new tests

* Revert disabling tests
Add new exception InvalidDeviceAutomationConfig

* Ignore places calling remotes

* Enable all gateway tests

* Found the issue, now to identify which test creates it

* Remove block till done

* See if device automation test passes in azure

* Register event to device registry

* Enable test sensors

* Skip deconz event tests currently failing

* Added reason why skipping tests
2019-09-10 16:56:28 -07:00
Pascal Vizeli
bee566f893 Nuki less strict (#26542) 2019-09-10 23:23:27 +02:00
David F. Mulcahey
1cea3a6abc osram cluster (#26555) 2019-09-10 13:44:41 -07:00
David F. Mulcahey
4f3a2c0443 fix events for smartthings acceleration cluster (#26557) 2019-09-10 13:14:22 -07:00
Paulus Schoutsen
6f27c5ae46 Fix tests 2019-09-10 13:07:55 -07:00
Paulus Schoutsen
7468cc21be Refactor Cast (#26550)
* Refactor Cast

* Fix tests & address comments

* Update reqs
2019-09-10 13:05:46 -07:00
Florent Thoumie
a7830bc2d2 Add sensor platform to iaqualink component (#26544)
* Add sensor platform to iaqualink component

* Remove unnecessary icon, fix case where value is 0
2019-09-10 22:01:12 +02:00
David Bonnes
fbc3376c32 Bump geniushub-client to 0.6.13 (#26554)
* bump geniushub client
2019-09-10 16:19:08 +01:00
Pascal Vizeli
b321ed2fdb Update azure-pipelines-ci.yml for Azure Pipelines 2019-09-10 17:15:35 +02:00
Quentame
d746035a91 Add Météo France icons + device_class (#26441)
* Add Météo France icons

* Add Météo France device_class (temperature) + use constants

* Fix weather alert info log

* Use new f"{...} {...}" format for sensor name
2019-09-10 13:17:10 +02:00
Florent Thoumie
adf6852acc Remove unnecessary force_refresh=True, clarify system behavior (#26543)
* Remove unnecessary force_refresh=True, clarify system behavior

* Fix lint.
2019-09-10 13:12:20 +02:00
HomeAssistant Azure
9df5c0ab86 [ci skip] Translation update 2019-09-10 00:32:37 +00:00
lifeisafractal
5d5102e1a2 Add zwave application version (#26205)
* Set application version in zwave

* update tests for more coverage
2019-09-09 23:59:40 +02:00
indykoning
a4fd991ab5 Add growatt server integration (#25635)
* Added growatt server integration

* Ran black formatter

* Processed feedback.

* Made attributes more readable.

* Create a sensor for each property.

* Added unique_ids

* Accidentally flipped functions

* Added dynamic device classes.

* Fixed stale session.
2019-09-09 23:47:44 +02:00
Hans Oischinger
051639b6ad Add more attributes to vicare climate entity (#26521)
Add some device information as attributes to the climate device:
 - room_temperature
 - supply_temperature
 - outside_temperature
 - active_vicare_program
 - active_vicare_mode
 - heating_curve_slope
 - heating_curve_shift
 - month_since_last_service
 - date_last_service
 - error_history
 - active_error
 - circulationpump_active
2019-09-09 23:46:11 +02:00
Tsvi Mostovicz
f3123ee0ca Fix radiotherm local time (#26526)
We want to use our own dt_util.now() which takes into consideration the globally set DEFAULT_TIME_ZONE
2019-09-09 23:41:47 +02:00
jjlawren
30fb4ddc98 Move config and connections to Plex component (#26488)
* Move config and connections to component

* Separate imports

* Set a unique_id on sensor

* Set a platforms const

* Add SERVERS dict, hardcode to single server

* Move to debug

* Return false

* More debug

* Import at top to fix lint

* Guard against legacy setup attempts

* Refactor to add setup callback

* Review comments

* Log levels

* Return result of callback

* Store CONFIGURING in hass.data

* Set up discovery if no config data

* Use schema to set defaults

* Remove media_player options to remove entities

* Improve error handling
2019-09-09 23:28:20 +02:00
Florent Thoumie
3c629db096 Add light platform to iaqualink integration (#26484)
* Add light platform to iaqualink component.

* Style changes.

* Polling moved to timer in the component
2019-09-09 23:10:25 +02:00
SukramJ
ff136a19d9 Add Delta Counter of HmIP-SPDR to Homematic IP Cloud (#26538) 2019-09-09 22:02:53 +02:00
tyjtyj
702e63e6e8 Fix Tuya Light without brightness (#26534)
Return none if there is brightness data from tuya

https://github.com/home-assistant/home-assistant/issues/25896
2019-09-09 21:44:00 +02:00
Paulus Schoutsen
7d71976e01 Do not complain about automatic generated files (#26540)
* Do not complain about automatic generated files

* Update generated files
2019-09-09 12:01:49 -07:00
Florent Thoumie
f167914951 Move iaqualink update from climate to component (#26505)
* Move iaqualink update from climate to component

* Typing fix
2019-09-09 20:06:05 +02:00
Erik Montnemery
02ded7a4a8 Remove device from device action schema (#26536) 2019-09-09 10:40:22 -07:00
Erik Montnemery
b14b14c3c9 Add device automation support to switch entities (#26466)
* Add device automation support to switch entities

* Update switch translations

* Address review comments
2019-09-09 16:55:47 +02:00
Pascal Vizeli
5f13cdf760 Update azure-pipelines-wheels.yml for Azure Pipelines 2019-09-09 16:24:24 +02:00
David F. Mulcahey
fec6706bf7 use newly added is_server for cluster reporting (#26533) 2019-09-09 09:21:34 -04:00
Maikel Punie
28beebac61 Enable SolarEdge config entries (#26282)
* Initial commit for the solaredge configflow

* rerun the hassfest script

* Adding testcases

* Rerun hassfest, problem with black?

* Requirements for the tests

* Remove CONF_MONITORED_CONDITIONS from configuration.yaml

* Remove the options flow strings

* Resolve some comments

* Comments

* More comments

* Move the config from the sensor platform to the component itself

* More comments

* More comments

* Added solaredge __init__

* Added more test to increase coverage
2019-09-08 21:49:20 +02:00
Kevin McCormack
0983367abe Add vivotek camera component (#26071)
* Add vivotek camera component

* Update vivotek camera compontent

Use async request to enable/disable motion detection

* Update Vivotek camera

- Use HTTPS
- Use IP address for still and stream

* Update vivotek component

- Add brand and model properties
- Add state property
- Use attribute to save motion detection status

* Add vivotek camera to .coveragerc

* Update vivotek camera

Fix lint errors

* Update vivotek camera

Remove unused method

* Update Vivotek integration to use libpyvivotek

Use libpyvivotek instead of directly making HTTPS API calls.

* Update Vivotek component

Address code review.

- Remove unused code
- Replace async methods with synchronous methods
- Update docstrings

* Linter fixes for Vivotek component

* Update Vivotek camera component

- Add SSL option
- Remove authentication options as only basic authentication
  is currently working

* Update Vivotek camera component

- Make frame rate configurable
- Require username and password

* Remove unused constants in Vivotek component

* Update Vivotek camera integration

- Use libpyvivotek v0.2.1 with better response parsing
- Use add_entities instead of async_add_entities

* Update Vivotek camera component

- Build camera and stream source ouside VivotekCam
- Remove unnecessary _stream_source attribute

* Update Vivotek camera component

- Move brand to constant
- Move _supported_features to property

* Update Vivotek camera compontent to remove unused property
2019-09-08 21:36:48 +02:00
Bram Kragten
036e0ade1f Updated frontend to 20190908.0 (#26524) 2019-09-08 20:59:09 +02:00
Steven Looman
4390ccfd4d Update to async_upnp_client==0.14.11 (#26515) 2019-09-08 16:02:31 +02:00
David Bonnes
7614f9f3fb Bump geniushubclient (#26519)
* bump client

* bump again
2019-09-08 15:11:40 +02:00
Alexei Chetroi
3544f3d7e0 Bump ZHA dependencies. (#26504) 2019-09-07 21:14:32 -05:00
HomeAssistant Azure
e204d22a9e [ci skip] Translation update 2019-09-08 00:32:16 +00:00
Erik Montnemery
28b9416b0c Device automations: Rename name to entity_name in translations (#26491) 2019-09-07 19:07:11 -05:00
Jeff Irion
da88be3827 Bump androidtv to 0.0.27 (#26497) 2019-09-07 20:47:24 +02:00
David F. Mulcahey
5237bd3fd1 fix cluster configuration (#26494) 2019-09-07 10:39:56 -04:00
Santobert
ece023bfee Restructure Z-Wave Climate (#25724) 2019-09-07 09:35:51 -04:00
Ville Skyttä
33e1b44b3a Use PEP 526 type annotations, add some type hints (#26464)
* Add some more type hints to helpers.event

* Change most type comments to variable types

* Remove some superfluous type hints
2019-09-07 09:48:58 +03:00
Paulus Schoutsen
c07227a53f Merge pull request #26487 from home-assistant/rc
0.98.5
2019-09-06 18:44:42 -07:00
Paulus Schoutsen
6ad87e52a8 Bumped version to 0.98.5 2019-09-06 18:01:30 -07:00
Paulus Schoutsen
c1671bbb28 Updated frontend to 20190828.1 2019-09-06 17:56:18 -07:00
Hans Oischinger
5b3004c7b0 Vicare: Avoid invalid temperature values (#26485)
The PyVicare API can return the string "error" in case of connection
or authentication errors.
The current_temperature value could be set to "error" instead of a
nueric value or None which breaks the climate component.

This commit sets the current_temperature to None instead.
2019-09-06 19:41:34 -05:00
Aaron Bach
078a72d102 Bump aiowwlln to 2.0.1 (#26486) 2019-09-06 19:41:19 -05:00
HomeAssistant Azure
0b1f389c76 [ci skip] Translation update 2019-09-07 00:32:45 +00:00
Matthias Alphart
a5ccb03e2e Fix KNX light tunable white rounding error (#26364)
* KNX light - tunable white rounding error

mitigate rounding errors in kelvin - mired conversion for lights with relative color temperature
fixes https://github.com/home-assistant/home-assistant/issues/26357

* typo _min_kelvin <> _max_kelvin

* black
2019-09-07 01:38:09 +02:00
Magnus Brange
48dea59517 Add protocol and model as an optional restriction for tellstick sensors (#26026)
* Add protocl and model as restriction for tellstick sensors

A tellstick sensors is uniq identified by id, protocol and model, not
just the id.

This will add an optional restriction for "named sensors" for protocol
and model.

* Don't default config to empty string

* Compare None with 'is not'
2019-09-06 22:28:31 +02:00
Florent Thoumie
0abb2f3eb8 Add new integration for Jandy iAqualink pool control (#26034)
* Import new iaqualink component with climate platform.

* Style and unittest changes, fix async_step_import.

* Reorder imports.

* Fix stale doctstrings and add unittest.
2019-09-06 22:21:56 +02:00
Hans Oischinger
a72d9da9f4 Add Viessmann ViCare Climate platform (#26151)
* Add Viessmann ViCare Climate platform

* Add water_heater and fix review comments
Update to latest PyVicare (0.1.0)

* Move PyVicare API creation to component

* More review fixes

* Return false if api creation fails

* Fix logging format

* Update PyVicare 0.1.1 to fix json issues

* Formatting fixes
2019-09-06 22:09:03 +02:00
dieselrabbit
f9445c9488 Update radiotherm climate attributes (#26465)
* Update radiotherm for lovelace

-Adds hvac_action property to better support the Lovelace Climate card.
-Clean up "fan" attribute. Now called "fan_action", as "mode" is supported via hvac_action.
-Update current operation label from "Off" to "Idle".

* black formatting
2019-09-06 22:05:46 +02:00
Quentame
b3e574d5b2 Add device_info to Linky integration (#26477)
* Add device_info to Linky integration

* Remove useless SENSORS const

* Review: remove DOMAIN from the unique_id
2019-09-06 22:01:23 +02:00
zewelor
9e8f4a589f Add set scene service calls to yeelight (#26255)
* Add set scene service calls to yeelight

* Simplify code

* DRY valid brightness validation

* Fix services description

* PR fixes
2019-09-06 14:46:14 -04:00
zewelor
c847cc20fc Add yeelight nightlight support via separate light entity (#26224)
* Add yeelight nightligh support via separate light entity

* Fix lint too many ancestors

* PR fixes
2019-09-06 14:33:03 -04:00
SukramJ
f540d74b65 Unify device_state_attributes handling for Homematic IP Cloud (#26449)
*  unifi DSA for Homematic IP Cloud

* sabotage is not relevant for state

* TODAY_SUNSHINE_DURATION is not a group attribute

* Separated the words as requested

* add missing underscores
2019-09-06 15:28:24 +02:00
David Bonnes
a202afcac2 bump geniushub client (#26476)
fixes #26440
2019-09-06 12:25:46 +01:00
Tsvi Mostovicz
815e7a70e9 Jewish calendar binary sensor (#26200)
* Move jewish calendar to its own platform

* Fix tests for Jewish Calendar platform

As part of this, move tests to use async_setup_component instead of
testing JewishCalendarSensor as suggested by @MartinHjelmare here:

https://github.com/home-assistant/home-assistant/pull/24958#pullrequestreview-259394226

* Get sensors to update during test

* Use hass.config.set_time_zone instead of directly calling set_default_time_zone in tests

* Cleanup log messages

* Rename result from weekly_portion to parshat_hashavua

* Fix english/hebrew tests

* Fix updating of issue melacha binary sensor

* Fix docstrings of binary sensor

* Reset timezones before and after each test

* Use correct entity_id for day of the omer tests

* Fix omer tests

* Cleanup and rearrange tests

* Remove the old issur_melacha_in_effect sensor

* Rename variables to make the code clearer

Instead of using lagging_date, use after_tzais and after_shkia

* Use dt_util.set_default_time_zone instead of hass.config.set_time_zone so as not to break other tests

* Remove should_poll set to false (accidental copy/paste)

* Remove _LOGGER messaging during init and impossible cases

* Move binary tests to standalone test functions

Move sensor tests to standalone test functions

* Collect entities before calling add_entities

* Fix pylint errors

* Simplify logic in binary sensor until a future a PR adds more sensors

* Rename test_id holyness to holiday_type

* Fix time zone for binary sensor tests

Fix time zone for sensor tests

* Don't use unnecessary alter_time in sensors

Don't use unnecessary alter time in binary sensor

Remove unused alter_time

* Simply set hass.config.time_zone instead of murking around with global values

* Use async_fire_time_changed instead of directly calling async_update_entity

* Removing debug messaging during init of integration

* Capitalize constants

* Collect all Entities before calling async_add_entities

* Revert "Don't use unnecessary alter_time in sensors"

This reverts commit 74371740eaeb6e73c1a374725b05207071648ee1.

* Use test time instead of utc_now

* Remove superfluous testing

* Fix triggering of time changed

* Fix failing tests due to side-effects

* Use dt_util.as_utc instead of reimplementing it's functionality

* Use dict[key] for default values

* Move 3rd party imports to the top of the module

* Fix imports
2019-09-06 13:24:10 +02:00
Marius
50cec91cf0 Change darksky icon for clear night (#26452)
* change icon for clear night

change mdi:weather-sunny to mdi:night for condition clear night

* changed erroneous mdi:night to mdi:weather-night
2019-09-06 11:19:31 +02:00
Paulus Schoutsen
b870980456 Merge pull request #26463 from home-assistant/rc
0.98.4
2019-09-05 22:19:39 -07:00
Paulus Schoutsen
f23ab2af8c Bumped version to 0.98.4 2019-09-05 22:10:37 -07:00
Johann Kellerman
5994f82fc5 Add person to device_sun_light_trigger (#25877)
* Add person to device_sun_light_trigger

* tests

* fix test
2019-09-05 20:41:57 -07:00
HomeAssistant Azure
3714cdaa6d [ci skip] Translation update 2019-09-06 00:33:40 +00:00
Robert Svensson
518d2c31bb deCONZ - use entity registry disabled_by to control available entities (#26219)
* First draft

* Support enabling disabled entities

* Clean up

* Move import

* Local entity enabled replaced during rebase

* Add option flow test

* Mark options properties with option
2019-09-05 16:38:00 -07:00
Erik Montnemery
b1c2a5fa08 Add device automation action (#26455)
* Add support for device actions, with light as example.

* Add translation; return list
2019-09-05 16:26:22 -07:00
jjlawren
23fdc04554 Add plex server config options to media_player platform (#26458)
* Add server config options to media_player platform

* Unnecessary else

* Default host

* No need to try for default values

* Use const
2019-09-05 22:20:58 +02:00
jjlawren
2cd845fb25 Standardize Plex server connections (#26444)
* Common connection class

* Omit tests for new Plex files

* Oops

* Add missing properties

* Remove redundant log message

* Stopgap to avoid duplicate setups

* Cleaner check for server setup

Co-Authored-By: Martin Hjelmare <marhje52@kth.se>

* Cleaner check for server setup

Co-Authored-By: Martin Hjelmare <marhje52@kth.se>

* Not needed with previous setup check

* Remove username/password support

* Reduce log level

Co-Authored-By: Martin Hjelmare <marhje52@kth.se>

* Don't do setup in __init__

* Oops

* Committing too fast...

* Connect after init

* Catch update exceptions like media_player

* Pass in validated PlexServer instance

* Remove unnecessary check

* Counter should be unknown on init

* Remove servername config option
2019-09-05 19:50:26 +02:00
Malte Franken
a000125729 Queensland Bushfire Alert icon for geolocation entities (#26439)
* define icon

* reordered const imports
2019-09-05 17:11:48 +02:00
Erik Montnemery
f7dc537275 Add device automation condition (#26313)
* Add support for device conditions

* Lint

* Update test case

* Make and+or conditions async, adjust tests

* Cleanup tests

* Remove non callback versions of conditions, correct typing

* Correct typing

* Update light/strings.json

* Address review comments

* Make device automation lists simple lists, not dicts

* Add device_automation/const.py

* Use IS_ON/IS_OFF everywhere for conditions
2019-09-05 16:49:32 +02:00
Pascal Vizeli
c50faaef3c Cleanup Dockerfile.dev (#26451) 2019-09-05 14:20:08 +02:00
HomeAssistant Azure
1cbb895d20 [ci skip] Translation update 2019-09-05 10:11:41 +00:00
Pascal Vizeli
a85f89c5a6 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-05 12:09:21 +02:00
HomeAssistant Azure
1bd22a129b [ci skip] Translation update 2019-09-05 00:32:29 +00:00
Pierre
6acfede512 Add atome sensor platform (#26197)
* Atome sensor platform - provides live data from Linky energy meters with Atome device from Total/Direct energie

* Proper requirements, added code ownership

* Do not cover atome component

* Proper PEP8 import, proper use of const, added missing docstring etc

* Proper PEP8 import, proper use of const, added missing docstring etc

* Integrate recommendations from MartinHjelmare

* Init shall remain as clean as possible, we don't want side effect

* Add daily,weekly,monthly,yearly sensors. Now depends on pyatome 0.1

* Requirements regenerated for atome component

* Refactored the way we update sensors

* Removed some un-necessary returns and unused variable
2019-09-04 20:20:20 +02:00
Franck Nijhof
0df1b4c7a1 Replaces IOError by OSError (#26428) 2019-09-04 19:09:24 +02:00
Penny Wood
4004879ae0 Entity registry doesn't overwrite with None (#24275) 2019-09-04 09:49:22 -07:00
Paulus Schoutsen
79045f2da1 Undo accidental Tuya change 2019-09-04 09:23:56 -07:00
Paulus Schoutsen
fba06049d2 Merge remote-tracking branch 'origin/master' into dev 2019-09-04 09:18:32 -07:00
zewelor
c4c21d3e99 Add device to mqtt camera (#26238)
* Add device to mqtt camera

* Support discovery device info update and add tests
2019-09-04 16:15:40 +02:00
Bram Kragten
2c65e02491 Updated frontend to 20190904.0 (#26421)
* Updated frontend to 20190904.0

* Updated frontend to 20190904.0
2019-09-04 15:51:15 +02:00
Pascal Vizeli
6bef5a98fe Add prettier to vscode (#26417) 2019-09-04 11:47:13 +02:00
Malte Franken
d1bc0c1dd9 NSW Rural Fire Service icon for geolocation entities (#26416)
* define icon

* add myself as codeowner
2019-09-04 11:33:29 +02:00
Pascal Vizeli
c191551091 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-04 09:56:25 +02:00
HomeAssistant Azure
3b1a4a52e9 [ci skip] Translation update 2019-09-04 07:41:09 +00:00
Pascal Vizeli
e59eea3044 Merge pull request #26414 from home-assistant/rc
0.98.3
2019-09-04 09:33:30 +02:00
Pascal Vizeli
9e9859a959 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-04 09:02:35 +02:00
Pascal Vizeli
6ae2aacdb2 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-04 08:57:09 +02:00
Pascal Vizeli
90aaa36206 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-04 08:49:34 +02:00
Pascal Vizeli
7995bf9e66 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-04 08:36:49 +02:00
Paulus Schoutsen
b8f9319cb0 Bumped version to 0.98.3 2019-09-03 23:20:25 -07:00
Greg Laabs
860843ada1 Bump ISY994's PyISY dependency to 1.1.2 (#26413)
Fixed a major bug that was responsible for ISY events getting seemingly random delays up to 24 seconds
2019-09-03 23:20:17 -07:00
Paulus Schoutsen
7bccbcbcc3 Fix state report (#26406)
* Fix state report

* Update test
2019-09-03 23:20:17 -07:00
ehendrix23
8cf02e0b22 Update to 0.1.13 (#26402)
Update to 0.1.13
2019-09-03 23:20:16 -07:00
Daniel Høyer Iversen
93e4cd6bb2 Met, check for existing location (#26400) 2019-09-03 23:20:15 -07:00
Paulus Schoutsen
d4905477b8 Allow core config updated (#26398) 2019-09-03 23:20:15 -07:00
Anders Melchiorsen
a980eedd22 Fix race during initial Sonos group construction (#26371)
* Fix race during initial Sonos group construction

* Update homeassistant/components/sonos/media_player.py
2019-09-03 23:20:14 -07:00
Robert Svensson
a74bb3fd5e String has nothing to do with class method naming (#26368) 2019-09-03 23:20:14 -07:00
Fabian Affolter
b50ac6f486 Upgrade pyhaversion to 3.1.0 (#26232) 2019-09-03 23:20:13 -07:00
David Bonnes
4661f2a6df Initial commit (#26383) 2019-09-03 23:16:31 -07:00
David Bonnes
d5c61be651 Initial commit (#26385) 2019-09-03 23:15:40 -07:00
David Bonnes
525a434511 Use literal string interpolation in honeywell (#26386)
* Initial commit

* fix lint hints
2019-09-03 23:14:29 -07:00
Franck Nijhof
60ef41cc69 Correct file permissions in slide integration (#26390) 2019-09-03 23:13:53 -07:00
Paulus Schoutsen
92f8362883 Allow core config updated (#26398) 2019-09-03 23:13:34 -07:00
Daniel Høyer Iversen
b9923ca109 Met, check for existing location (#26400) 2019-09-03 23:13:17 -07:00
Greg Laabs
22d3cf4117 Bump ISY994's PyISY dependency to 1.1.2 (#26413)
Fixed a major bug that was responsible for ISY events getting seemingly random delays up to 24 seconds
2019-09-03 23:11:30 -07:00
Quentame
b4058b5c7f Add config flow to linky (#26076)
* Linky: setup ConfigFlow

* async_track_time_interval

* Review from @MartinHjelmare 1

* Review from @MartinHjelmare 2

* Review from @MartinHjelmare 3

* Review from @MartinHjelmare 4

* black --fast homeassistant tests

* Bump pylinky to 0.4.0 and add error user feedback

* Fix .coveragerc

* Linky platform moved to integration in config.yml and with multiple accounts

* Remove useless logs

* Review from @MartinHjelmare 5

* Add config flow tests

* Add config flow tests : login + fetch on failed
2019-09-04 07:04:26 +02:00
Taylor Silva
ca97bba4b4 Add X10 devices as ISY994 switches (#26342)
* Add X10 devices as switches

Signed-off-by: Taylor Silva <taylorsilva@outlook.com>

* Add logging message for when unsupported device is found.

This will help a user figure out why they aren't seeing all devices.

Signed-off-by: Taylor Silva <taylorsilva@outlook.com>

* Update homeassistant/components/isy994/__init__.py

Co-Authored-By: Martin Hjelmare <marhje52@kth.se>

* Update homeassistant/components/isy994/__init__.py

100 is too generic of an ISY uom. We don't want to accidentally add non-switch devices.
2019-09-04 07:00:19 +02:00
Franck Nijhof
2f0eb07624 Migrate legacy typehints in core to PEP-526 (#26403)
* Migrate legacy typehints in core to PEP-526

* Fix one type
2019-09-03 20:36:04 -07:00
ehendrix23
2dc90be94f Update to 0.1.13 (#26402)
Update to 0.1.13
2019-09-03 21:00:05 -05:00
Malte Franken
2f9de2a5a5 IGN Sismologia icon for geolocation entities (#26408)
* define icon

* fixed tests
2019-09-03 20:58:40 -05:00
Paulus Schoutsen
4e2fcdb9a3 Fix state report (#26406)
* Fix state report

* Update test
2019-09-03 20:57:32 -05:00
Paulus Schoutsen
53720c5c48 Allow passing None as input_text config (#26409) 2019-09-03 20:55:58 -05:00
croghostrider
b968b53e38 Fix Emulated Hue AttributeError: 'NoneType' object has no attribute '… (#26018)
* Fix Emulated Hue AttributeError: 'NoneType' object has no attribute 'lower'

* Fix debug

* Update error message
2019-09-03 17:33:48 -07:00
Sriram Vaidyanathan
f7a58cc19e Change xiaomi camera conf_host to template (#25799)
* changed conf_host to template

Changed conf_host to template to accommodate dynamic ips

* Update camera.py

* Updated per comment

* update for black formatter

* black changes
2019-09-03 17:06:11 -07:00
John Luetke
757482ee85 Refactor pihole integration (#25837)
* Adds tests for pi_hole integration

* Refactor pi_hole component to an integration supporting multiple platforms

* Adds mock of Hole dependency

* Aborts platform setup when discovery_info is none

* Removes use of monitored_conditions

* Adds integration setup test

* Removes PlatformNotReady check

* Adds sensor test

* Code review updates

* Refactor tests to assert state through hass

* Reorder imports
2019-09-03 16:18:06 -07:00
Franck Nijhof
9035efee10 Fixes invalid JSON files and whitespace corrections in YAML files (#26396) 2019-09-03 16:02:42 -07:00
Pascal Vizeli
b6cd5ab27b Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-03 22:15:25 +02:00
Pascal Vizeli
e7ccb6f047 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-03 22:09:21 +02:00
Franck Nijhof
dae6895a95 Use literal string interpolation in integrations X-Z (f-strings) (#26395) 2019-09-03 21:15:31 +02:00
Franck Nijhof
445c741b30 Use literal string interpolation in integrations R-S (f-strings) (#26392) 2019-09-03 21:14:39 +02:00
Franck Nijhof
7203027cbf Use literal string interpolation in integrations K-M (f-strings) (#26389) 2019-09-03 21:14:00 +02:00
Franck Nijhof
ef0e9431b6 Use literal string interpolation in integrations T-W (f-strings) (#26394) 2019-09-03 21:12:51 +02:00
Pascal Vizeli
cde09062c4 Update OpenCV 4.1.1 / Numpy 1.17.1 (#26387) 2019-09-03 21:04:38 +02:00
Franck Nijhof
1c5e0123c9 Use literal string interpolation in integrations N-Q (f-strings) (#26391) 2019-09-03 11:35:00 -07:00
Alexander
330ae0d885 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
2019-09-03 10:09:25 -07:00
Pascal Vizeli
7d1e3af701 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-03 18:09:08 +02:00
Pascal Vizeli
7d27b4d2ab Update azure-pipelines-release.yml for Azure Pipelines 2019-09-03 18:07:23 +02:00
Pascal Vizeli
09a4a81d09 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-03 18:05:59 +02:00
Pascal Vizeli
fcbc2fda49 Update azure-pipelines-translation.yml for Azure Pipelines 2019-09-03 17:58:00 +02:00
Pascal Vizeli
12d470331c Update translations_upload 2019-09-03 17:56:41 +02:00
Franck Nijhof
09a350ba26 Removes executable but from hassfest codeowners (#26381) 2019-09-03 17:28:47 +02:00
Franck Nijhof
f9edec19ad Use literal string interpolation in integrations H-J (f-strings) (#26380) 2019-09-03 17:27:14 +02:00
Malte Franken
13bb2ea35a 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
2019-09-03 17:16:13 +02:00
Franck Nijhof
fa79ef1220 Use literal string interpolation in integrations E-G (f-strings) (#26379) 2019-09-03 17:10:56 +02:00
Franck Nijhof
6a24d893c8 Use literal string interpolation in integrations B-D (f-strings) (#26378) 2019-09-03 17:09:59 +02:00
ThaStealth
105461edb5 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
2019-09-03 17:05:23 +02:00
Franck Nijhof
ad51615718 Use literal string interpolation in integrations A (f-strings) (#26377)
* Use literal string interpolation in integrations A (f-strings)

* Black
2019-09-03 09:11:36 -05:00
Anders Melchiorsen
3534b8a977 Fix race during initial Sonos group construction (#26371)
* Fix race during initial Sonos group construction

* Update homeassistant/components/sonos/media_player.py
2019-09-03 14:14:33 +02:00
Franck Nijhof
617133e465 Correct file permissions, removing executable bits (#26376) 2019-09-03 14:13:44 +02:00
Pascal Vizeli
950f8343d3 Update azure-pipelines-wheels.yml 2019-09-03 10:39:23 +02:00
ruohan.chen
c2a752e34f 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
2019-09-03 10:18:08 +02:00
Fabian Affolter
245450a402 Upgrade pyhaversion to 3.1.0 (#26232) 2019-09-03 10:17:03 +02:00
Paulus Schoutsen
0cffd61481 Allow passing dictionaries to async_register_entity_service (#26370) 2019-09-03 09:50:24 +02:00
Pascal Vizeli
df9703d814 Add token support 2019-09-03 09:35:03 +02:00
Robert Svensson
c6d839f8ae String has nothing to do with class method naming (#26368) 2019-09-02 22:12:10 -07:00
Sébastien RAMAGE
6a5f7bd8e4 Update zigpy_zigate to 0.2.0 (#26327)
* Update zigpy_zigate to 0.2.0

* Update requirements_all.txt
2019-09-02 22:21:09 +02:00
Costas
df90e9c4fd 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.
2019-09-02 22:17:34 +02:00
Jeff Irion
85473d2c98 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
2019-09-02 22:08:01 +02:00
Oliver
64465f0fbe Push to version 0.7.10 of denonavr (#26362) 2019-09-02 14:15:00 -05:00
Ville Skyttä
ed5d3dba0e Test with 3.6.1 in Travis (#26347)
https://github.com/home-assistant/architecture/issues/278
2019-09-02 15:51:59 +02:00
Malte Franken
ecaadfed3a USGS Earthquakes icon for geolocation entities (#26353)
* define icon

* updated tests

* added codeowner

* updated codeowners
2019-09-02 13:37:11 +02:00
Paulus Schoutsen
7a171dae33 Updated frontend to 20190901.0 2019-09-01 22:30:21 -07:00
Paulus Schoutsen
385a496944 Update translations 2019-09-01 22:30:09 -07:00
ChristianKuehnel
1b13c49541 added missing bluepy dependency for miflora (#26297)
fixes dependency issue #19362 (only part of the solution)
2019-09-01 21:44:50 -07:00
Paulus Schoutsen
aa7513bc5c Expose current direction properly on state machine (#26298)
* Expose current direction properly on state machine

* Fix template fan
2019-09-01 21:42:57 -07:00
Erik Montnemery
3aa2729716 Add improvements of device_automation from frontend PR 3514 (#26295)
* Add improvements from frontend PR 3514

* Fix test

* Tweak
2019-09-01 21:40:18 -07:00
Steven Rollason
79488daddf 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
2019-09-01 18:12:55 +02:00
Aleix Murtra
1617c2cd64 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
2019-09-01 18:05:46 +02:00
Robert Svensson
b5426761f4 UniFi - Simplify getting controller from config entry (#26335)
* Simplify getting controller from config entry

* Lint ignore no longer needed

* Fix tests
2019-09-01 17:57:25 +02:00
fmartens
5b77a357e6 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'
2019-09-01 17:52:43 +02:00
Daniel Høyer Iversen
597cd3e886 Upgrade tibber library (#26332) 2019-09-01 14:22:50 +02:00
Robert Svensson
6102eb9f1c 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
2019-09-01 13:15:48 +02:00
Josef Schlehofer
a80d26f0dc Upgrade sqlalchemy to 1.3.8 (#26331) 2019-09-01 14:10:58 +03:00
David Bonnes
f91dd4f5f8 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)
2019-09-01 11:45:41 +01:00
Rocik
298aafc79d Add support for Supla switches (#26188)
* add support for Supla switches

* remove blank line at the end of file

* Add comma on last element of a list

* Remove unnecessary supla dependencies variable
2019-09-01 10:42:17 +02:00
Jonathan Keljo
5ba436e3d8 Add a keypress service for AlarmDecoder (#26100)
* Add a keypress service for AlarmDecoder (like Envisalink has)

* Feedback

* Import DOMAIN
2019-09-01 10:38:58 +02:00
tyjtyj
fade2e991b Fix google_maps scan interval (#26328)
Reported on 
https://github.com/home-assistant/home-assistant/issues/26275
2019-09-01 10:24:54 +02:00
Josef Schlehofer
b31fde6255 Upgrade youtube_dl to 2019.09.01 (#26330) 2019-09-01 10:20:08 +02:00
Balazs Sandor
baa30aec9d Fix onvif camera setup error (#24585)
* fix: onvif setup error

* refactor: onvif camera init process

* onvif/camera: review fixes

* onvif/camera: review fixes

* onvif/camera: fix pydoc

* onvif: remove unrelated async-await

* Onvif review fix

* onvif/camera: remove log
2019-08-31 22:29:42 +02:00
Robert Svensson
d9ef92f6d2 UniFi - use entity registry disabled_by to control available entities (#26141)
* Move ignoring logic to entity registry enabled default

* Handle config to option import better

* Properly enable and disable entity registry entries on changes from config entry options

* Fix balloobs comments

* Fix some tests

* Fix tests

* Simplify updating disable on entities

* Simplify device tracker update function

* Local entity disabled replaced on rebase

* Only alter entities with changed options

* Proper tracking of changed options

* Back to straightforward updating of disabled
2019-08-31 22:04:04 +02:00
Pawel
922522b089 Fetch Onkyo current radio preset (#26211)
* atribute to show which preset is currently on in radio

* add attribute for onkyo zone

* change format string to f-strings
2019-08-31 21:56:29 +02:00
Diogo Gomes
9df2c3f8c9 Add precision argument to the Range Filter (#25874)
* add precision argument

* add precision testing to range_filter
2019-08-31 19:24:17 +02:00
Paulus Schoutsen
46b5b0cac7 Fix alexa bad temp sensors (#26307) 2019-08-31 09:46:26 -05:00
Robert Svensson
d1874d148a deCONZ - Dont update entry if data is equal 2019-08-31 15:56:43 +02:00
Robert Van Gorkom
614cf74225 Add Withings support (#25154)
* Rebasing with a clean branch.
Addressing PR feedback.
Cleaning up some static code checks.
Fixing bug with saving credentials.

* Removing unecessary change.

* Caching data manager.

* Removing configurable measures.

* Using import step in config flow.

* Updating config flows.

* Addressing PR feedback.

* Formatting source.

* Addressing PR feedback and rebasing.
2019-08-31 14:30:59 +02:00
Jc2k
944b544b2e Add support for Homekit accessory battery sensors (#26210)
* Add simple battery sensor
* Add test for battery sensor based on a real device
* Vary icon based on battery state
* Add test for battery sensory
* Read other battery related states from accessory
* Add a device class to the battery sensor
* Respect the low battery flag from the device
2019-08-31 13:18:18 +01:00
Paulus Schoutsen
7b05ede297 Fix Alexa Report State (#26305)
* Fix Alexa Report State

* Forgot to save a file
2019-08-30 20:34:40 -05:00
Paulus Schoutsen
37a3d5fd85 Add HEAD and PUT support to webhooks (#26299) 2019-08-30 20:32:38 -05:00
Paul Annekov
f01e106e6d bump tuyaha 0.0.4 (#26303) 2019-08-30 17:30:18 -07:00
Paulus Schoutsen
2f6bdc8643 Remove deprecated SMA config (#26306) 2019-08-30 16:41:07 -07:00
Pascal Vizeli
299695ca24 Update azure-pipelines-wheels.yml 2019-08-30 15:56:52 +02:00
Pascal Vizeli
b074337b9c Update azure-pipelines-wheels.yml 2019-08-30 15:50:49 +02:00
Pascal Vizeli
4d08e73e3e Enable py_noaa 2019-08-30 14:48:08 +02:00
5mauggy
62338dd28e Fix deConz thermostat integration (#26267)
* Fixed logger name to allow selective logging

* Fixed thermostat mode ('off' and 'heat' modes were not consistent with Eurotronic Spirit Zigbee Thermostat state) and added 'auto' to supported mode

* Added required blank lines in code

* Black formatting

* Revert logging code added to each files. Instead, only replaced "." by __package__ in const.py

* Added a test on self._device.state_on to determine hvac_mode

* Black formatting

* Added debug message when unsupported hvac_mode is encountered

* Applied formatting recommandations

* Updated tests for 'auto' hvac_mode
2019-08-30 14:28:39 +02:00
Paulus Schoutsen
ad6ede9ef7 Merge remote-tracking branch 'origin/master' into dev 2019-08-29 16:06:24 -07:00
Robert Svensson
0d7326168e UniFi - dont schedule updates on disabled entities (#26278)
* Dont schedule updates on disabled entities

* Use entity enabled since it is available
2019-08-29 14:04:01 -07:00
mbo18
6a02fd51b8 Fix missing DarkSky mdi icon (#26274)
* Fix missing DarkSky mdi icon

Fix mdi icon for DarkSky

* fix icon

* Update weather.py
2019-08-29 13:22:52 -07:00
Paulus Schoutsen
66b905776b Fix partly cloudy (#26277) 2019-08-29 13:22:29 -07:00
David F. Mulcahey
25961df548 Fix ZHA state restore by always restoring last seen on devices (#26271)
* fix state restore by always restoring last seen

* cleanup
2019-08-29 12:44:53 -07:00
Eliseo Martelli
24a4a42664 Update sensor.py (#26209) 2019-08-29 12:36:21 -07:00
Paulus Schoutsen
36312bdef1 Add translations 2019-08-29 12:32:15 -07:00
Andrew Sayre
955bed8df4 Clean up HEOS strings (#26242)
* Clean up strings

* Shorten lines to ~ 88
2019-08-29 14:23:42 -05:00
StephenWetzel
16fff16082 Add two new methods to the OpenUV component that consume only a singl… (#26207)
* Add two new methods to the OpenUV component that consume only a single API call

* Two lines after class

* Rename methods to better reflect what they do, and DRY copy and pasted code

* More error handling down into methods, run api calls in parallel

* Fix import order

* Add new methods to services.yaml, and update error messages
2019-08-29 09:56:12 -06:00
Jeff Irion
789ad38c38 Bump androidtv to 0.0.25 and add tests (#26202)
* Add tests for androidtv

* 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

* Clarify comment

* Add test for when the ADB shell command returns None

* Bump androidtv to 0.0.25
2019-08-29 12:03:03 +02:00
Maikel Punie
ec3d83c0cc Velbus config entries remove decorator (#26256) 2019-08-29 08:45:01 +02:00
Paulus Schoutsen
d652bb23de Updated frontend to 20190828.0 2019-08-28 13:43:45 -07:00
SukramJ
cf3bb300e6 Fix for 0.98: Don't update disabled entities (Homematic IP Cloud) (#26236)
* Homematic IP Cloud Fix: Don't update disabled entities

* Added enabled to entity.py

* Update test for enabled

* Update entity.py
2019-08-28 13:38:20 -07:00
Paulus Schoutsen
e69953fe2d Update translations 2019-08-28 12:45:48 -07:00
Maikel Punie
33bd9c83fb Enable cert_expiry config entries (#25624)
* Enable cert_expiry config entries

* add black

* lint fixes

* Rerun black

* Black on json files is a bad idea

* Work on comments

* Forgot the lint

* More comment work

* Correctly set defaults

* More comments

* Add codeowner

* Fix black

* More comments implemented

* Removed the catch

* Add helper.py from cert_expiry to .coveragerc
2019-08-28 19:35:09 +02:00
Malte Franken
49ad527a37 Fix WWLLN entity management (#26250)
* added debug logging

* fixed manager to keep track of managed external ids
2019-08-28 08:42:39 -06:00
Johann Kellerman
a28e644def SMA beta fix #26225 (#26244) 2019-08-28 09:21:21 +02:00
Andrew Sayre
3c07a9b4c7 Cleanup strings (#26243) 2019-08-27 17:08:09 -06:00
Matt Schmitt
6525f8704a Bump dependency to add PLAY_STATE_STOPPED (#26239) 2019-08-27 14:30:19 -05:00
Robert Svensson
1f2e0d3949 deCONZ normalizes cover values to follow zigbee spec (#26240) 2019-08-27 21:06:14 +02:00
michaeldavie
d9ae63e239 Remove throttle from update (#26216) 2019-08-27 16:00:54 +02:00
Andrew Sayre
9dc40197e9 Fix flaky updater tests (#26221) 2019-08-27 10:30:41 +02:00
Florian Klien
c185c015ef luci device-tracker dependency fix (#26215)
* luci device-tracker dependency fix

fixes issue #25758

* luci device-tracker fix, requirements_all
2019-08-27 00:34:57 -05:00
presslab-us
8e5d272b5f Support formatting and scaling with ZHA Metering cluster (#26201)
* Support formatting and scaling with Metering cluster

* fix lint

* run black formatter
2019-08-26 23:16:54 -04:00
newbee112
03cfe7247b Update sensor.py (#26218)
Added more options for CPU temp.
2019-08-27 00:14:38 +02:00
Pascal Vizeli
193881c4d1 Update azure-pipelines-release.yml for Azure Pipelines 2019-08-26 21:08:21 +02:00
Pascal Vizeli
055eb69e2d Update azure-pipelines-wheels.yml for Azure Pipelines 2019-08-26 17:12:57 +02:00
Pascal Vizeli
54d85fa3dd Update azure-pipelines-release.yml for Azure Pipelines 2019-08-26 16:10:40 +02:00
David F. Mulcahey
6f2ac705eb Add web socket API command to get a single ZHA device (#26196)
* get single device web socket command

* test get single device

* add not found error

* fix handling when device doesn't exist

* add test for zha device not found
2019-08-26 09:54:19 -04:00
Pascal Vizeli
7a111bf863 Nightly builds (#26204)
* Nightly docker builds / Hass.io dev HA

* use same style

* Finish nightly build

* Update builder version

* Fix style

* fix style part 2

* Last one

* Fix order
2019-08-26 11:46:46 +02:00
Ville Skyttä
0c49c82015 Huawei LTE misc improvements (#26203)
* Constant and whitespace cleanups

* Upgrade huawei_lte_api to 1.3.0

https://github.com/Salamek/huawei-lte-api/releases

* Hush traceback if device does not support logout
2019-08-26 10:32:50 +02:00
David F. Mulcahey
bde572c91a bump quirks version (#26198) 2019-08-25 22:34:43 -07:00
Paulus Schoutsen
2db9542338 Updated frontend to 20190825.0 2019-08-25 22:24:46 -07:00
Bram Kragten
248619a036 Speed up history get_states (#23881)
* Speed up history `get_states`

Adding a boundary of the start of the recorder run the point is in, significantly increases the time of the query. This speeds up the fetching of the history of 1 entity.

* Make single entity query easier

no need for joins with single entity

* Lint
2019-08-25 21:11:12 +02:00
Andrew Sayre
7bfb365f62 Update pyheos to 0.6.0 (#26191) 2019-08-25 20:57:43 +02:00
Daniel Høyer Iversen
d4bd5a180c Refactor open garage (#26179)
* Use defined constant in open garage

* refactor open garage

* style

* style

* refactor

* refactor

* refactor

* remove vehicle state
2019-08-25 12:05:42 +02:00
Aaron Bach
7238eb9bac Fix possible KeyError in SimpliSafe (#26190) 2019-08-25 02:18:31 +02:00
Daniel Høyer Iversen
059ae2bb68 Update ambiclimate library (#26182) 2019-08-24 11:15:21 -05:00
Paulus Schoutsen
691e3f6141 Allow bumping version for nightly builds (#26167) 2019-08-23 10:32:54 -07:00
Chao
3deeac6bf7 fix issue setting scan_interval (#26165)
I was getting the following error when i set the scan_interval
```
    self.scan_interval = timedelta(seconds=config.get(CONF_SCAN_INTERVAL, 60))
TypeError: unsupported type for timedelta seconds component: datetime.timedelta
```
it turns out `config.get(CONF_SCAN_INTERVAL)` already returns `timedelta`

```('scan_interval', datetime.timedelta(seconds=180))```
2019-08-23 10:14:18 -07:00
Franck Nijhof
decf13b948 Use literal string interpolation in core (f-strings) (#26166) 2019-08-23 09:53:33 -07:00
On Freund
1efa29d6ff CoolMaster: Change auto to heat_cool (#26144) 2019-08-23 15:59:25 +02:00
Jeff Irion
55031e6ea4 Bump androidtv to 0.0.24 (#26158)
* Bump androidtv to 0.0.24

* Add unique ID for Fire TV (not just Android TV)
2019-08-23 15:58:24 +02:00
MatthewFlamm
17750a604e Add NWS weather (#23647)
* Add nws weather.

* Hassfest

* Address multiple comments

* Add NWS icon weather code link

* Add metar fallback.

Use metar code from nws observation if normal api is missing data.

* only get 1 observation - we dont use more than 1

* add mocked metar for tests

* lint

* mock metar package for all tests

* add check for metar attributes

* catch errors in setup

* add timeout error

* handle request exceptions

* check and test for missing observations

* refactor to new pynws

* change to simpler api

* Make py3.5 compatible

Remove f string

* bump pynws version

* gen_requirements

* fix wind bearing observation

* Revert "Make py3.5 compatible"

This reverts commit 4946d91779.

* Precommit black missed a file?

* black test

* add exceptional weather condition

* bump pynws version

* update requirements_all

* address comments

* move observation and forecast outside try-except-else

* Revert "move observation and forecast outside try-except-else"

This reverts commit 53b78b3283.

* remove else from update forecast block

* remove unneeded ConfigEntryNotReady import

* add scan_interval, reduce min_time_between_updates

* pytest tests

* lint test docstring

* use async await

* lat and lon inclusive in config
2019-08-23 14:13:06 +02:00
Pascal Vizeli
2b6c5eeb1d Update azure-pipelines-release.yml for Azure Pipelines 2019-08-23 13:54:44 +02:00
Tyler Page
432f6569ad Venstar: define success for all branches of set_temperature() (#26148)
* define success for all branches

* add operation_mode to error when unexpected value

* fix black linting

* black linting

* fix weird black linting result
2019-08-23 10:23:19 +02:00
Paulus Schoutsen
f704a8e90e Reload config entry when entity enabled in entity registry, remove entity if disabled. (#26120)
* Reload config entry when disabled_by updated in entity registry

* Add types

* Remove entities that get disabled

* Remove unnecessary domain checks.

* Attach handler in async_setup

* Remove unused var

* Type

* Fix test

* Fix tests
2019-08-22 19:32:43 -05:00
Paulus Schoutsen
a4eeaac24c Updated frontend to 20190822.0 2019-08-22 15:05:57 -07:00
Paulus Schoutsen
aa56b4dd30 Log warning if disabled entities receive updates. (#26143)
* Log warning if disabled entities receive updates.

* Fix test

* Always set entity ID on disabled entities
2019-08-22 14:12:24 -07:00
Phil Cole
bff5b00a09 Nissanleaf login fix (#26139)
* Upgrade to pycarwings2.9 per 25 July 2019 API change

* Remove rest of location tracker. Fix get_status_from_update call.
2019-08-22 12:40:48 -07:00
Paul Annekov
bc17170f95 Fix tuya switch state (#26145)
* bump tuyaha 0.0.3

* bump tuyaha 0.0.3
2019-08-22 12:26:08 -07:00
Jeff Irion
aff151c90a Load user-provided descriptions for python_scripts (#26069)
* Load user-provided descriptions for python_scripts

* Import SERVICE_DESCRIPTION_CACHE

* Use async_set_service_schema to register service descriptions

* Add python_script tests for loading service descriptions

* Use async/await in test
2019-08-22 11:01:56 -07:00
Johann Kellerman
2d432da14c DuckDNS setup backoff (#25899) 2019-08-22 18:19:27 +02:00
SukramJ
82b1b10c28 Splitt device_state_attributes between device and group for Homematic IP Cloud (#26137)
* splitt device_state_attributes between device and group

* readd device_state_attributes for access point
2019-08-22 09:02:35 -07:00
SukramJ
bc5cec97f4 Add myself as codeowner to HmIP Cloud (#26140) 2019-08-22 09:00:15 -07:00
Pascal Vizeli
be0739626b Update azure-pipelines-release.yml for Azure Pipelines 2019-08-22 17:49:17 +02:00
Pascal Vizeli
2b78bfaf78 Update azure-pipelines-release.yml for Azure Pipelines 2019-08-22 17:47:35 +02:00
Pascal Vizeli
f793c71f52 Update azure-pipelines-release.yml for Azure Pipelines 2019-08-22 17:34:54 +02:00
Pascal Vizeli
b3ae6a20ba Update azure-pipelines-release.yml for Azure Pipelines 2019-08-22 09:28:46 +02:00
Pascal Vizeli
9a16b7b0f6 Update azure-pipelines-release.yml for Azure Pipelines (#26128)
* Update azure-pipelines-release.yml for Azure Pipelines

* Update azure-pipelines-release.yml
2019-08-22 08:58:41 +02:00
1262 changed files with 25976 additions and 6549 deletions

View File

@@ -31,7 +31,6 @@ omit =
homeassistant/components/amcrest/*
homeassistant/components/ampio/*
homeassistant/components/android_ip_webcam/*
homeassistant/components/androidtv/*
homeassistant/components/anel_pwrctrl/switch.py
homeassistant/components/anthemav/media_player.py
homeassistant/components/apache_kafka/*
@@ -51,6 +50,7 @@ omit =
homeassistant/components/asterisk_cdr/mailbox.py
homeassistant/components/asterisk_mbox/*
homeassistant/components/asuswrt/device_tracker.py
homeassistant/components/atome/*
homeassistant/components/august/*
homeassistant/components/aurora_abb_powerone/sensor.py
homeassistant/components/automatic/device_tracker.py
@@ -58,6 +58,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
@@ -93,6 +94,7 @@ omit =
homeassistant/components/canary/camera.py
homeassistant/components/cast/*
homeassistant/components/cert_expiry/sensor.py
homeassistant/components/cert_expiry/helper.py
homeassistant/components/channels/media_player.py
homeassistant/components/cisco_ios/device_tracker.py
homeassistant/components/cisco_mobility_express/device_tracker.py
@@ -247,6 +249,7 @@ omit =
homeassistant/components/greeneye_monitor/sensor.py
homeassistant/components/greenwave/light.py
homeassistant/components/group/notify.py
homeassistant/components/growatt_server/sensor.py
homeassistant/components/gstreamer/media_player.py
homeassistant/components/gtfs/sensor.py
homeassistant/components/gtt/sensor.py
@@ -285,6 +288,10 @@ omit =
homeassistant/components/hydrawise/*
homeassistant/components/hyperion/light.py
homeassistant/components/ialarm/alarm_control_panel.py
homeassistant/components/iaqualink/climate.py
homeassistant/components/iaqualink/light.py
homeassistant/components/iaqualink/sensor.py
homeassistant/components/iaqualink/switch.py
homeassistant/components/icloud/device_tracker.py
homeassistant/components/idteck_prox/*
homeassistant/components/ifttt/*
@@ -338,6 +345,7 @@ omit =
homeassistant/components/limitlessled/light.py
homeassistant/components/linksys_ap/device_tracker.py
homeassistant/components/linksys_smart/device_tracker.py
homeassistant/components/linky/__init__.py
homeassistant/components/linky/sensor.py
homeassistant/components/linode/*
homeassistant/components/linux_battery/sensor.py
@@ -427,6 +435,7 @@ omit =
homeassistant/components/nut/sensor.py
homeassistant/components/nx584/alarm_control_panel.py
homeassistant/components/nzbget/sensor.py
homeassistant/components/obihai/*
homeassistant/components/octoprint/*
homeassistant/components/oem/climate.py
homeassistant/components/oasa_telematics/sensor.py
@@ -467,8 +476,7 @@ omit =
homeassistant/components/pioneer/media_player.py
homeassistant/components/pjlink/media_player.py
homeassistant/components/plaato/*
homeassistant/components/plex/media_player.py
homeassistant/components/plex/sensor.py
homeassistant/components/plex/*
homeassistant/components/plugwise/*
homeassistant/components/plum_lightpad/*
homeassistant/components/pocketcasts/sensor.py
@@ -563,6 +571,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/*
@@ -572,6 +581,7 @@ omit =
homeassistant/components/snmp/*
homeassistant/components/sochain/sensor.py
homeassistant/components/socialblade/sensor.py
homeassistant/components/solaredge/__init__.py
homeassistant/components/solaredge/sensor.py
homeassistant/components/solaredge_local/sensor.py
homeassistant/components/solax/sensor.py
@@ -667,6 +677,7 @@ omit =
homeassistant/components/ue_smart_radio/media_player.py
homeassistant/components/upcloud/*
homeassistant/components/upnp/*
homeassistant/components/upc_connect/*
homeassistant/components/ups/sensor.py
homeassistant/components/uptimerobot/binary_sensor.py
homeassistant/components/uscis/sensor.py
@@ -689,6 +700,8 @@ omit =
homeassistant/components/vesync/const.py
homeassistant/components/vesync/switch.py
homeassistant/components/viaggiatreno/sensor.py
homeassistant/components/vicare/*
homeassistant/components/vivotek/camera.py
homeassistant/components/vizio/media_player.py
homeassistant/components/vlc/media_player.py
homeassistant/components/vlc_telnet/media_player.py

View File

@@ -1,35 +1,33 @@
// See https://aka.ms/vscode-remote/devcontainer.json for format details.
{
"name": "Home Assistant Dev",
"context": "..",
"dockerFile": "../Dockerfile.dev",
"postCreateCommand": "pip3 install -e .",
"appPort": 8123,
"runArgs": [
"-e",
"GIT_EDITOR=\"code --wait\""
],
"extensions": [
"ms-python.python",
"ms-azure-devops.azure-pipelines",
"redhat.vscode-yaml"
],
"settings": {
"python.pythonPath": "/usr/local/bin/python",
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true,
"terminal.integrated.shell.linux": "/bin/bash",
"yaml.customTags": [
"!secret scalar",
"!include_dir_named scalar",
"!include_dir_list scalar",
"!include_dir_merge_list scalar",
"!include_dir_merge_named scalar"
]
}
}
"name": "Home Assistant Dev",
"context": "..",
"dockerFile": "../Dockerfile.dev",
"postCreateCommand": "mkdir -p config && pip3 install -e .",
"appPort": 8123,
"runArgs": ["-e", "GIT_EDITOR=\"code --wait\""],
"extensions": [
"ms-python.python",
"ms-azure-devops.azure-pipelines",
"redhat.vscode-yaml",
"esbenp.prettier-vscode"
],
"settings": {
"python.pythonPath": "/usr/local/bin/python",
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true,
"terminal.integrated.shell.linux": "/bin/bash",
"yaml.customTags": [
"!secret scalar",
"!include_dir_named scalar",
"!include_dir_list scalar",
"!include_dir_merge_list scalar",
"!include_dir_merge_named scalar"
]
}
}

1
.gitignore vendored
View File

@@ -64,6 +64,7 @@ nosetests.xml
htmlcov/
test-reports/
test-results.xml
test-output.xml
# Translations
*.mo

View File

@@ -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

193
.vscode/tasks.json vendored
View File

@@ -1,92 +1,105 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Preview",
"type": "shell",
"command": "hass -c ./config",
"group": {
"kind": "test",
"isDefault": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Pytest",
"type": "shell",
"command": "pytest --timeout=10 tests",
"group": {
"kind": "test",
"isDefault": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Flake8",
"type": "shell",
"command": "flake8 homeassistant tests",
"group": {
"kind": "test",
"isDefault": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Pylint",
"type": "shell",
"command": "pylint homeassistant",
"dependsOn": [
"Install all Requirements"
],
"group": {
"kind": "test",
"isDefault": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Generate Requirements",
"type": "shell",
"command": "./script/gen_requirements_all.py",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Install all Requirements",
"type": "shell",
"command": "pip3 install -r requirements_all.txt -c homeassistant/package_constraints.txt",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
}
]
"version": "2.0.0",
"tasks": [
{
"label": "Preview",
"type": "shell",
"command": "hass -c ./config",
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Pytest",
"type": "shell",
"command": "pytest --timeout=10 tests",
"dependsOn": ["Install all Test Requirements"],
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Flake8",
"type": "shell",
"command": "flake8 homeassistant tests",
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Pylint",
"type": "shell",
"command": "pylint homeassistant",
"dependsOn": ["Install all Requirements"],
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Generate Requirements",
"type": "shell",
"command": "./script/gen_requirements_all.py",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Install all Requirements",
"type": "shell",
"command": "pip3 install -r requirements_all.txt -c homeassistant/package_constraints.txt",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Install all Test Requirements",
"type": "shell",
"command": "pip3 install -r requirements_test_all.txt -c homeassistant/package_constraints.txt",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
}
]
}

View File

@@ -28,6 +28,7 @@ homeassistant/components/arcam_fmj/* @elupus
homeassistant/components/arduino/* @fabaff
homeassistant/components/arest/* @fabaff
homeassistant/components/asuswrt/* @kennedyshead
homeassistant/components/atome/* @baqs
homeassistant/components/aurora_abb_powerone/* @davet2001
homeassistant/components/auth/* @home-assistant/core
homeassistant/components/automatic/* @armills
@@ -37,6 +38,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
@@ -46,6 +48,7 @@ homeassistant/components/broadlink/* @danielhiversen
homeassistant/components/brunt/* @eavanvalkenburg
homeassistant/components/bt_smarthub/* @jxwolstenholme
homeassistant/components/buienradar/* @mjj4791 @ties
homeassistant/components/cert_expiry/* @cereal2nd
homeassistant/components/cisco_ios/* @fbradyirl
homeassistant/components/cisco_mobility_express/* @fbradyirl
homeassistant/components/cisco_webex_teams/* @fbradyirl
@@ -107,6 +110,7 @@ homeassistant/components/google_translate/* @awarecan
homeassistant/components/google_travel_time/* @robbiet480
homeassistant/components/gpsd/* @fabaff
homeassistant/components/group/* @home-assistant/core
homeassistant/components/growatt_server/* @indykoning
homeassistant/components/gtfs/* @robbiet480
homeassistant/components/harmony/* @ehendrix23
homeassistant/components/hassio/* @home-assistant/hass-io
@@ -119,12 +123,14 @@ homeassistant/components/hive/* @Rendili @KJonline
homeassistant/components/homeassistant/* @home-assistant/core
homeassistant/components/homekit_controller/* @Jc2k
homeassistant/components/homematic/* @pvizeli @danielperna84
homeassistant/components/homematicip_cloud/* @SukramJ
homeassistant/components/honeywell/* @zxdavb
homeassistant/components/html5/* @robbiet480
homeassistant/components/http/* @home-assistant/core
homeassistant/components/huawei_lte/* @scop
homeassistant/components/huawei_router/* @abmantis
homeassistant/components/hue/* @balloob
homeassistant/components/iaqualink/* @flz
homeassistant/components/ign_sismologia/* @exxamalte
homeassistant/components/incomfort/* @zxdavb
homeassistant/components/influxdb/* @fabaff
@@ -150,7 +156,7 @@ homeassistant/components/life360/* @pnbruckner
homeassistant/components/lifx/* @amelchio
homeassistant/components/lifx_cloud/* @amelchio
homeassistant/components/lifx_legacy/* @amelchio
homeassistant/components/linky/* @tiste @Quentame
homeassistant/components/linky/* @Quentame
homeassistant/components/linux_battery/* @fabaff
homeassistant/components/liveboxplaytv/* @pschmitt
homeassistant/components/logger/* @home-assistant/core
@@ -188,7 +194,10 @@ homeassistant/components/no_ip/* @fabaff
homeassistant/components/notify/* @home-assistant/core
homeassistant/components/notion/* @bachya
homeassistant/components/nsw_fuel_station/* @nickw444
homeassistant/components/nuki/* @pschmitt
homeassistant/components/nsw_rural_fire_service_feed/* @exxamalte
homeassistant/components/nuki/* @pvizeli
homeassistant/components/nws/* @MatthewFlamm
homeassistant/components/obihai/* @dshokouhi
homeassistant/components/ohmconnect/* @robbiet480
homeassistant/components/onboarding/* @home-assistant/core
homeassistant/components/opentherm_gw/* @mvn23
@@ -203,6 +212,7 @@ homeassistant/components/philips_js/* @elupus
homeassistant/components/pi_hole/* @fabaff
homeassistant/components/plaato/* @JohNan
homeassistant/components/plant/* @ChristianKuehnel
homeassistant/components/plex/* @jjlawren
homeassistant/components/plugwise/* @laetificat @CoMPaTech
homeassistant/components/point/* @fredrike
homeassistant/components/ps4/* @ktnrg45
@@ -232,6 +242,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
@@ -281,15 +292,18 @@ homeassistant/components/twentemilieu/* @frenck
homeassistant/components/twilio_call/* @robbiet480
homeassistant/components/twilio_sms/* @robbiet480
homeassistant/components/unifi/* @kane610
homeassistant/components/upc_connect/* @pvizeli
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
homeassistant/components/version/* @fabaff
homeassistant/components/vesync/* @markperdue @webdjoe
homeassistant/components/vicare/* @oischinger
homeassistant/components/vizio/* @raman325
homeassistant/components/vlc_telnet/* @rodripf
homeassistant/components/waqi/* @andrey-git
@@ -298,6 +312,7 @@ homeassistant/components/weather/* @fabaff
homeassistant/components/weblink/* @home-assistant/core
homeassistant/components/websocket_api/* @home-assistant/core
homeassistant/components/wemo/* @sqldiablo
homeassistant/components/withings/* @vangorra
homeassistant/components/worldclock/* @fabaff
homeassistant/components/wwlln/* @bachya
homeassistant/components/xfinity/* @cisasteelersfan

View File

@@ -23,9 +23,10 @@ RUN git clone --depth 1 https://github.com/home-assistant/hass-release \
WORKDIR /workspaces
# Install Python dependencies from requirements.txt if it exists
COPY requirements_test_all.txt homeassistant/package_constraints.txt /workspaces/
RUN pip3 install -r requirements_test_all.txt -c package_constraints.txt
# Install Python dependencies from requirements
COPY requirements_test.txt homeassistant/package_constraints.txt ./
RUN pip3 install -r requirements_test.txt -c package_constraints.txt \
&& rm -f requirements_test.txt package_constraints.txt
# Set the default shell to bash instead of sh
ENV SHELL /bin/bash

View File

@@ -113,7 +113,7 @@ stages:
pip uninstall -y typing
- script: |
. venv/bin/activate
pytest --timeout=9 --durations=10 --junitxml=test-results.xml -qq -o console_output_style=count -p no:sugar tests
pytest --timeout=9 --durations=10 -qq -o console_output_style=count -p no:sugar tests
script/check_dirty
displayName: 'Run pytest for python $(python.container)'
condition: and(succeeded(), ne(variables['python.container'], variables['PythonMain']))
@@ -121,22 +121,11 @@ stages:
set -e
. venv/bin/activate
pytest --timeout=9 --durations=10 --junitxml=test-results.xml --cov --cov-report=xml -qq -o console_output_style=count -p no:sugar tests
pytest --timeout=9 --durations=10 --cov homeassistant --cov-report html -qq -o console_output_style=count -p no:sugar tests
codecov --token $(codecovToken)
script/check_dirty
displayName: 'Run pytest for python $(python.container) / coverage'
condition: and(succeeded(), eq(variables['python.container'], variables['PythonMain']))
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testResultsFiles: 'test-results.xml'
testRunTitle: 'Publish test results for Python $(python.container)'
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: cobertura
summaryFileLocation: coverage.xml
displayName: 'publish coverage artifact'
condition: and(succeeded(), eq(variables['python.container'], variables['PythonMain']))
- stage: 'FullCheck'
dependsOn:

View File

@@ -43,7 +43,7 @@ stages:
release="$(Build.SourceBranchName)"
created_by="$(curl -s https://api.github.com/repos/home-assistant/home-assistant/releases/tags/${release} | jq --raw-output '.author.login')"
if [[ "${created_by}" =~ ^(balloob|pvizeli|fabaff|robbiet480)$ ]]; then
if [[ "${created_by}" =~ ^(balloob|pvizeli|fabaff|robbiet480|bramkragten)$ ]]; then
exit 0
fi

View File

@@ -0,0 +1,66 @@
# https://dev.azure.com/home-assistant
trigger:
batch: true
branches:
include:
- dev
pr: none
schedules:
- cron: "30 0 * * *"
displayName: "translation update"
branches:
include:
- dev
always: true
variables:
- group: translation
resources:
repositories:
- repository: azure
type: github
name: 'home-assistant/ci-azure'
endpoint: 'home-assistant'
jobs:
- job: 'Upload'
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UsePythonVersion@0
displayName: 'Use Python 3.7'
inputs:
versionSpec: '3.7'
- script: |
export LOKALISE_TOKEN="$(lokaliseToken)"
export AZURE_BRANCH="$(Build.SourceBranchName)"
./script/translations_upload
displayName: 'Upload Translation'
- job: 'Download'
dependsOn:
- 'Upload'
condition: or(eq(variables['Build.Reason'], 'Schedule'), eq(variables['Build.Reason'], 'Manual'))
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UsePythonVersion@0
displayName: 'Use Python 3.7'
inputs:
versionSpec: '3.7'
- template: templates/azp-step-git-init.yaml@azure
- script: |
export LOKALISE_TOKEN="$(lokaliseToken)"
export AZURE_BRANCH="$(Build.SourceBranchName)"
./script/translations_download
displayName: 'Download Translation'
- script: |
git checkout dev
git add homeassistant
git commit -am "[ci skip] Translation update"
git push
displayName: 'Update translation'

View File

@@ -10,7 +10,7 @@ trigger:
- requirements_all.txt
pr: none
schedules:
- cron: '0 */8 * * *'
- cron: '0 */4 * * *'
displayName: 'daily builds'
branches:
include:
@@ -18,7 +18,7 @@ schedules:
always: true
variables:
- name: versionWheels
value: '1.1-3.7-alpine3.10'
value: '1.3-3.7-alpine3.10'
resources:
repositories:
- repository: azure
@@ -30,7 +30,8 @@ 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'
preBuild:
@@ -65,5 +66,6 @@ jobs:
sed -i "s|# PySwitchbot|PySwitchbot|g" ${requirement_file}
sed -i "s|# pySwitchmate|pySwitchmate|g" ${requirement_file}
sed -i "s|# face_recognition|face_recognition|g" ${requirement_file}
sed -i "s|# py_noaa|py_noaa|g" ${requirement_file}
done
displayName: 'Prepare requirements files for Hass.io'

View File

@@ -7,7 +7,7 @@ import platform
import subprocess
import sys
import threading
from typing import List, Dict, Any, TYPE_CHECKING # noqa pylint: disable=unused-import
from typing import List, Dict, Any, TYPE_CHECKING
from homeassistant import monkey_patch
from homeassistant.const import __version__, REQUIRED_PYTHON_VER, RESTART_EXIT_CODE
@@ -168,7 +168,7 @@ def get_arguments() -> argparse.Namespace:
parser.add_argument(
"--runner",
action="store_true",
help="On restart exit with code {}".format(RESTART_EXIT_CODE),
help=f"On restart exit with code {RESTART_EXIT_CODE}",
)
parser.add_argument(
"--script", nargs=argparse.REMAINDER, help="Run one of the embedded scripts"
@@ -216,7 +216,7 @@ def check_pid(pid_file: str) -> None:
try:
with open(pid_file, "r") as file:
pid = int(file.readline())
except IOError:
except OSError:
# PID File does not exist
return
@@ -239,8 +239,8 @@ def write_pid(pid_file: str) -> None:
try:
with open(pid_file, "w") as file:
file.write(str(pid))
except IOError:
print("Fatal Error: Unable to write pid file {}".format(pid_file))
except OSError:
print(f"Fatal Error: Unable to write pid file {pid_file}")
sys.exit(1)
@@ -258,7 +258,7 @@ def closefds_osx(min_fd: int, max_fd: int) -> None:
val = fcntl(_fd, F_GETFD)
if not val & FD_CLOEXEC:
fcntl(_fd, F_SETFD, val | FD_CLOEXEC)
except IOError:
except OSError:
pass
@@ -280,7 +280,7 @@ async def setup_and_run_hass(config_dir: str, args: argparse.Namespace) -> int:
hass = core.HomeAssistant()
if args.demo_mode:
config = {"frontend": {}, "demo": {}} # type: Dict[str, Any]
config: Dict[str, Any] = {"frontend": {}, "demo": {}}
bootstrap.async_from_config_dict(
config,
hass,
@@ -326,7 +326,7 @@ def try_to_restart() -> None:
thread.is_alive() and not thread.daemon for thread in threading.enumerate()
)
if nthreads > 1:
sys.stderr.write("Found {} non-daemonic threads.\n".format(nthreads))
sys.stderr.write(f"Found {nthreads} non-daemonic threads.\n")
# Somehow we sometimes seem to trigger an assertion in the python threading
# module. It seems we find threads that have no associated OS level thread

View File

@@ -47,7 +47,7 @@ async def auth_manager_from_config(
else:
providers = ()
# So returned auth providers are in same order as config
provider_hash = OrderedDict() # type: _ProviderDict
provider_hash: _ProviderDict = OrderedDict()
for provider in providers:
key = (provider.type, provider.id)
provider_hash[key] = provider
@@ -59,7 +59,7 @@ async def auth_manager_from_config(
else:
modules = ()
# So returned auth modules are in same order as config
module_hash = OrderedDict() # type: _MfaModuleDict
module_hash: _MfaModuleDict = OrderedDict()
for module in modules:
module_hash[module.id] = module
@@ -168,11 +168,11 @@ class AuthManager:
async def async_create_user(self, name: str) -> models.User:
"""Create a user."""
kwargs = {
kwargs: Dict[str, Any] = {
"name": name,
"is_active": True,
"group_ids": [GROUP_ID_ADMIN],
} # type: Dict[str, Any]
}
if await self._user_should_be_owner():
kwargs["is_owner"] = True
@@ -238,7 +238,7 @@ class AuthManager:
group_ids: Optional[List[str]] = None,
) -> None:
"""Update a user."""
kwargs = {} # type: Dict[str,Any]
kwargs: Dict[str, Any] = {}
if name is not None:
kwargs["name"] = name
if group_ids is not None:
@@ -278,9 +278,7 @@ class AuthManager:
module = self.get_auth_mfa_module(mfa_module_id)
if module is None:
raise ValueError(
"Unable find multi-factor auth module: {}".format(mfa_module_id)
)
raise ValueError(f"Unable find multi-factor auth module: {mfa_module_id}")
await module.async_setup_user(user.id, data)
@@ -295,15 +293,13 @@ class AuthManager:
module = self.get_auth_mfa_module(mfa_module_id)
if module is None:
raise ValueError(
"Unable find multi-factor auth module: {}".format(mfa_module_id)
)
raise ValueError(f"Unable find multi-factor auth module: {mfa_module_id}")
await module.async_depose_user(user.id)
async def async_get_enabled_mfa(self, user: models.User) -> Dict[str, str]:
"""List enabled mfa modules for user."""
modules = OrderedDict() # type: Dict[str, str]
modules: Dict[str, str] = OrderedDict()
for module_id, module in self._mfa_modules.items():
if await module.async_is_user_setup(user.id):
modules[module_id] = module.name
@@ -356,7 +352,7 @@ class AuthManager:
):
# Each client_name can only have one
# long_lived_access_token type of refresh token
raise ValueError("{} already exists".format(client_name))
raise ValueError(f"{client_name} already exists")
return await self._store.async_create_refresh_token(
user,

View File

@@ -4,7 +4,7 @@ from collections import OrderedDict
from datetime import timedelta
import hmac
from logging import getLogger
from typing import Any, Dict, List, Optional # noqa: F401
from typing import Any, Dict, List, Optional
from homeassistant.auth.const import ACCESS_TOKEN_EXPIRATION
from homeassistant.core import HomeAssistant, callback
@@ -13,7 +13,7 @@ from homeassistant.util import dt as dt_util
from . import models
from .const import GROUP_ID_ADMIN, GROUP_ID_USER, GROUP_ID_READ_ONLY
from .permissions import PermissionLookup, system_policies
from .permissions.types import PolicyType # noqa: F401
from .permissions.types import PolicyType
STORAGE_VERSION = 1
STORAGE_KEY = "auth"
@@ -34,9 +34,9 @@ class AuthStore:
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize the auth store."""
self.hass = hass
self._users = None # type: Optional[Dict[str, models.User]]
self._groups = None # type: Optional[Dict[str, models.Group]]
self._perm_lookup = None # type: Optional[PermissionLookup]
self._users: Optional[Dict[str, models.User]] = None
self._groups: Optional[Dict[str, models.Group]] = None
self._perm_lookup: Optional[PermissionLookup] = None
self._store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, private=True
)
@@ -94,16 +94,16 @@ class AuthStore:
for group_id in group_ids or []:
group = self._groups.get(group_id)
if group is None:
raise ValueError("Invalid group specified {}".format(group_id))
raise ValueError(f"Invalid group specified {group_id}")
groups.append(group)
kwargs = {
kwargs: Dict[str, Any] = {
"name": name,
# Until we get group management, we just put everyone in the
# same group.
"groups": groups,
"perm_lookup": self._perm_lookup,
} # type: Dict[str, Any]
}
if is_owner is not None:
kwargs["is_owner"] = is_owner
@@ -210,12 +210,12 @@ class AuthStore:
access_token_expiration: timedelta = ACCESS_TOKEN_EXPIRATION,
) -> models.RefreshToken:
"""Create a new token for a user."""
kwargs = {
kwargs: Dict[str, Any] = {
"user": user,
"client_id": client_id,
"token_type": token_type,
"access_token_expiration": access_token_expiration,
} # type: Dict[str, Any]
}
if client_name:
kwargs["client_name"] = client_name
if client_icon:
@@ -307,8 +307,8 @@ class AuthStore:
self._set_defaults()
return
users = OrderedDict() # type: Dict[str, models.User]
groups = OrderedDict() # type: Dict[str, models.Group]
users: Dict[str, models.User] = OrderedDict()
groups: Dict[str, models.Group] = OrderedDict()
# Soft-migrating data as we load. We are going to make sure we have a
# read only group and an admin group. There are two states that we can
@@ -325,7 +325,7 @@ class AuthStore:
# was added.
for group_dict in data.get("groups", []):
policy = None # type: Optional[PolicyType]
policy: Optional[PolicyType] = None
if group_dict["id"] == GROUP_ID_ADMIN:
has_admin_group = True
@@ -503,11 +503,11 @@ class AuthStore:
groups = []
for group in self._groups.values():
g_dict = {
g_dict: Dict[str, Any] = {
"id": group.id,
# Name not read for sys groups. Kept here for backwards compat
"name": group.name,
} # type: Dict[str, Any]
}
if not group.system_generated:
g_dict["policy"] = group.policy
@@ -558,7 +558,7 @@ class AuthStore:
"""Set default values for auth store."""
self._users = OrderedDict()
groups = OrderedDict() # type: Dict[str, models.Group]
groups: Dict[str, models.Group] = OrderedDict()
admin_group = _system_admin_group()
groups[admin_group.id] = admin_group
user_group = _system_user_group()

View File

@@ -109,7 +109,7 @@ class SetupFlow(data_entry_flow.FlowHandler):
Return self.async_show_form(step_id='init') if user_input is None.
Return self.async_create_entry(data={'result': result}) if finish.
"""
errors = {} # type: Dict[str, str]
errors: Dict[str, str] = {}
if user_input:
result = await self._auth_module.async_setup_user(self._user_id, user_input)
@@ -144,15 +144,13 @@ async def auth_mfa_module_from_config(
async def _load_mfa_module(hass: HomeAssistant, module_name: str) -> types.ModuleType:
"""Load an mfa auth module."""
module_path = "homeassistant.auth.mfa_modules.{}".format(module_name)
module_path = f"homeassistant.auth.mfa_modules.{module_name}"
try:
module = importlib.import_module(module_path)
except ImportError as err:
_LOGGER.error("Unable to load mfa module %s: %s", module_name, err)
raise HomeAssistantError(
"Unable to load mfa module {}: {}".format(module_name, err)
)
raise HomeAssistantError(f"Unable to load mfa module {module_name}: {err}")
if hass.config.skip_pip or not hasattr(module, "REQUIREMENTS"):
return module

View File

@@ -95,7 +95,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
def __init__(self, hass: HomeAssistant, config: Dict[str, Any]) -> None:
"""Initialize the user data store."""
super().__init__(hass, config)
self._user_settings = None # type: Optional[_UsersDict]
self._user_settings: Optional[_UsersDict] = None
self._user_store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, private=True
)
@@ -279,18 +279,18 @@ class NotifySetupFlow(SetupFlow):
"""Initialize the setup flow."""
super().__init__(auth_module, setup_schema, user_id)
# to fix typing complaint
self._auth_module = auth_module # type: NotifyAuthModule
self._auth_module: NotifyAuthModule = auth_module
self._available_notify_services = available_notify_services
self._secret = None # type: Optional[str]
self._count = None # type: Optional[int]
self._notify_service = None # type: Optional[str]
self._target = None # type: Optional[str]
self._secret: Optional[str] = None
self._count: Optional[int] = None
self._notify_service: Optional[str] = None
self._target: Optional[str] = None
async def async_step_init(
self, user_input: Optional[Dict[str, str]] = None
) -> Dict[str, Any]:
"""Let user select available notify services."""
errors = {} # type: Dict[str, str]
errors: Dict[str, str] = {}
hass = self._auth_module.hass
if user_input:
@@ -304,7 +304,7 @@ class NotifySetupFlow(SetupFlow):
if not self._available_notify_services:
return self.async_abort(reason="no_available_service")
schema = OrderedDict() # type: Dict[str, Any]
schema: Dict[str, Any] = OrderedDict()
schema["notify_service"] = vol.In(self._available_notify_services)
schema["target"] = vol.Optional(str)
@@ -316,7 +316,7 @@ class NotifySetupFlow(SetupFlow):
self, user_input: Optional[Dict[str, str]] = None
) -> Dict[str, Any]:
"""Verify user can recevie one-time password."""
errors = {} # type: Dict[str, str]
errors: Dict[str, str] = {}
hass = self._auth_module.hass
if user_input:

View File

@@ -2,7 +2,7 @@
import asyncio
import logging
from io import BytesIO
from typing import Any, Dict, Optional, Tuple # noqa: F401
from typing import Any, Dict, Optional, Tuple
import voluptuous as vol
@@ -75,7 +75,7 @@ class TotpAuthModule(MultiFactorAuthModule):
def __init__(self, hass: HomeAssistant, config: Dict[str, Any]) -> None:
"""Initialize the user data store."""
super().__init__(hass, config)
self._users = None # type: Optional[Dict[str, str]]
self._users: Optional[Dict[str, str]] = None
self._user_store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, private=True
)
@@ -107,7 +107,7 @@ class TotpAuthModule(MultiFactorAuthModule):
"""Create a ota_secret for user."""
import pyotp
ota_secret = secret or pyotp.random_base32() # type: str
ota_secret: str = secret or pyotp.random_base32()
self._users[user_id] = ota_secret # type: ignore
return ota_secret
@@ -181,9 +181,9 @@ class TotpSetupFlow(SetupFlow):
"""Initialize the setup flow."""
super().__init__(auth_module, setup_schema, user.id)
# to fix typing complaint
self._auth_module = auth_module # type: TotpAuthModule
self._auth_module: TotpAuthModule = auth_module
self._user = user
self._ota_secret = None # type: Optional[str]
self._ota_secret: Optional[str] = None
self._url = None # type Optional[str]
self._image = None # type Optional[str]
@@ -197,7 +197,7 @@ class TotpSetupFlow(SetupFlow):
"""
import pyotp
errors = {} # type: Dict[str, str]
errors: Dict[str, str] = {}
if user_input:
verified = await self.hass.async_add_executor_job( # type: ignore

View File

@@ -1,6 +1,6 @@
"""Auth models."""
from datetime import datetime, timedelta
from typing import Dict, List, NamedTuple, Optional # noqa: F401
from typing import Dict, List, NamedTuple, Optional
import uuid
import attr
@@ -20,7 +20,7 @@ TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN = "long_lived_access_token"
class Group:
"""A group."""
name = attr.ib(type=str) # type: Optional[str]
name = attr.ib(type=Optional[str])
policy = attr.ib(type=perm_mdl.PolicyType)
id = attr.ib(type=str, factory=lambda: uuid.uuid4().hex)
system_generated = attr.ib(type=bool, default=False)
@@ -30,24 +30,20 @@ class Group:
class User:
"""A user."""
name = attr.ib(type=str) # type: Optional[str]
perm_lookup = attr.ib(
type=perm_mdl.PermissionLookup, cmp=False
) # type: perm_mdl.PermissionLookup
name = attr.ib(type=Optional[str])
perm_lookup = attr.ib(type=perm_mdl.PermissionLookup, cmp=False)
id = attr.ib(type=str, factory=lambda: uuid.uuid4().hex)
is_owner = attr.ib(type=bool, default=False)
is_active = attr.ib(type=bool, default=False)
system_generated = attr.ib(type=bool, default=False)
groups = attr.ib(type=List, factory=list, cmp=False) # type: List[Group]
groups = attr.ib(type=List[Group], factory=list, cmp=False)
# List of credentials of a user.
credentials = attr.ib(type=list, factory=list, cmp=False) # type: List[Credentials]
credentials = attr.ib(type=List["Credentials"], factory=list, cmp=False)
# Tokens associated with a user.
refresh_tokens = attr.ib(
type=dict, factory=dict, cmp=False
) # type: Dict[str, RefreshToken]
refresh_tokens = attr.ib(type=Dict[str, "RefreshToken"], factory=dict, cmp=False)
_permissions = attr.ib(
type=Optional[perm_mdl.PolicyPermissions], init=False, cmp=False, default=None

View File

@@ -1,6 +1,6 @@
"""Entity permissions."""
from collections import OrderedDict
from typing import Callable, Optional # noqa: F401
from typing import Callable, Optional
import voluptuous as vol
@@ -8,8 +8,7 @@ from .const import SUBCAT_ALL, POLICY_READ, POLICY_CONTROL, POLICY_EDIT
from .models import PermissionLookup
from .types import CategoryType, SubCategoryDict, ValueType
# pylint: disable=unused-import
from .util import SubCatLookupType, lookup_all, compile_policy # noqa
from .util import SubCatLookupType, lookup_all, compile_policy
SINGLE_ENTITY_SCHEMA = vol.Any(
True,
@@ -90,7 +89,7 @@ def compile_entities(
policy: CategoryType, perm_lookup: PermissionLookup
) -> Callable[[str, str], bool]:
"""Compile policy into a function that tests policy."""
subcategories = OrderedDict() # type: SubCatLookupType
subcategories: SubCatLookupType = OrderedDict()
subcategories[ENTITY_ENTITY_IDS] = _lookup_entity_id
subcategories[ENTITY_DEVICE_IDS] = _lookup_device
subcategories[ENTITY_AREAS] = _lookup_area

View File

@@ -1,13 +1,13 @@
"""Merging of policies."""
from typing import cast, Dict, List, Set # noqa: F401
from typing import cast, Dict, List, Set
from .types import PolicyType, CategoryType
def merge_policies(policies: List[PolicyType]) -> PolicyType:
"""Merge policies."""
new_policy = {} # type: Dict[str, CategoryType]
seen = set() # type: Set[str]
new_policy: Dict[str, CategoryType] = {}
seen: Set[str] = set()
for policy in policies:
for category in policy:
if category in seen:
@@ -33,8 +33,8 @@ def _merge_policies(sources: List[CategoryType]) -> CategoryType:
# If there are multiple sources with a dict as policy, we recursively
# merge each key in the source.
policy = None # type: CategoryType
seen = set() # type: Set[str]
policy: CategoryType = None
seen: Set[str] = set()
for source in sources:
if source is None:
continue

View File

@@ -1,7 +1,7 @@
"""Helpers to deal with permissions."""
from functools import wraps
from typing import Callable, Dict, List, Optional, cast # noqa: F401
from typing import Callable, Dict, List, Optional, cast
from .const import SUBCAT_ALL
from .models import PermissionLookup
@@ -45,7 +45,7 @@ def compile_policy(
assert isinstance(policy, dict)
funcs = [] # type: List[Callable[[str, str], Optional[bool]]]
funcs: List[Callable[[str, str], Optional[bool]]] = []
for key, lookup_func in subcategories.items():
lookup_value = policy.get(key)
@@ -85,7 +85,7 @@ def _gen_dict_test_func(
def test_value(object_id: str, key: str) -> Optional[bool]:
"""Test if permission is allowed based on the keys."""
schema = lookup_func(perm_lookup, lookup_dict, object_id) # type: ValueType
schema: ValueType = lookup_func(perm_lookup, lookup_dict, object_id)
if schema is None or isinstance(schema, bool):
return schema

View File

@@ -16,7 +16,7 @@ from homeassistant.util.decorator import Registry
from ..auth_store import AuthStore
from ..const import MFA_SESSION_EXPIRATION
from ..models import Credentials, User, UserMeta # noqa: F401
from ..models import Credentials, User, UserMeta
_LOGGER = logging.getLogger(__name__)
DATA_REQS = "auth_prov_reqs_processed"
@@ -144,14 +144,10 @@ async def load_auth_provider_module(
) -> types.ModuleType:
"""Load an auth provider."""
try:
module = importlib.import_module(
"homeassistant.auth.providers.{}".format(provider)
)
module = importlib.import_module(f"homeassistant.auth.providers.{provider}")
except ImportError as err:
_LOGGER.error("Unable to load auth provider %s: %s", provider, err)
raise HomeAssistantError(
"Unable to load auth provider {}: {}".format(provider, err)
)
raise HomeAssistantError(f"Unable to load auth provider {provider}: {err}")
if hass.config.skip_pip or not hasattr(module, "REQUIREMENTS"):
return module
@@ -166,7 +162,7 @@ async def load_auth_provider_module(
# https://github.com/python/mypy/issues/1424
reqs = module.REQUIREMENTS # type: ignore
await requirements.async_process_requirements(
hass, "auth provider {}".format(provider), reqs
hass, f"auth provider {provider}", reqs
)
processed.add(provider)
@@ -179,12 +175,12 @@ class LoginFlow(data_entry_flow.FlowHandler):
def __init__(self, auth_provider: AuthProvider) -> None:
"""Initialize the login flow."""
self._auth_provider = auth_provider
self._auth_module_id = None # type: Optional[str]
self._auth_module_id: Optional[str] = None
self._auth_manager = auth_provider.hass.auth # type: ignore
self.available_mfa_modules = {} # type: Dict[str, str]
self.available_mfa_modules: Dict[str, str] = {}
self.created_at = dt_util.utcnow()
self.invalid_mfa_times = 0
self.user = None # type: Optional[User]
self.user: Optional[User] = None
async def async_step_init(
self, user_input: Optional[Dict[str, str]] = None
@@ -259,10 +255,10 @@ class LoginFlow(data_entry_flow.FlowHandler):
if not errors:
return await self.async_finish(self.user)
description_placeholders = {
description_placeholders: Dict[str, Optional[str]] = {
"mfa_module_name": auth_module.name,
"mfa_module_id": auth_module.id,
} # type: Dict[str, Optional[str]]
}
return self.async_show_form(
step_id="mfa",

View File

@@ -53,7 +53,7 @@ class CommandLineAuthProvider(AuthProvider):
attributes provided by external programs.
"""
super().__init__(*args, **kwargs)
self._user_meta = {} # type: Dict[str, Dict[str, Any]]
self._user_meta: Dict[str, Dict[str, Any]] = {}
async def async_login_flow(self, context: Optional[dict]) -> LoginFlow:
"""Return a flow to login."""
@@ -85,7 +85,7 @@ class CommandLineAuthProvider(AuthProvider):
raise InvalidAuthError
if self.config[CONF_META]:
meta = {} # type: Dict[str, str]
meta: Dict[str, str] = {}
for _line in stdout.splitlines():
try:
line = _line.decode().lstrip()
@@ -146,7 +146,7 @@ class CommandLineLoginFlow(LoginFlow):
user_input.pop("password")
return await self.async_finish(user_input)
schema = collections.OrderedDict() # type: Dict[str, type]
schema: Dict[str, type] = collections.OrderedDict()
schema["username"] = str
schema["password"] = str

View File

@@ -4,7 +4,7 @@ import base64
from collections import OrderedDict
import logging
from typing import Any, Dict, List, Optional, Set, cast # noqa: F401
from typing import Any, Dict, List, Optional, Set, cast
import bcrypt
import voluptuous as vol
@@ -53,7 +53,7 @@ class Data:
self._store = hass.helpers.storage.Store(
STORAGE_VERSION, STORAGE_KEY, private=True
)
self._data = None # type: Optional[Dict[str, Any]]
self._data: Optional[Dict[str, Any]] = None
# Legacy mode will allow usernames to start/end with whitespace
# and will compare usernames case-insensitive.
# Remove in 2020 or when we launch 1.0.
@@ -74,7 +74,7 @@ class Data:
if data is None:
data = {"users": []}
seen = set() # type: Set[str]
seen: Set[str] = set()
for user in data["users"]:
username = user["username"]
@@ -210,7 +210,7 @@ class HassAuthProvider(AuthProvider):
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""Initialize an Home Assistant auth provider."""
super().__init__(*args, **kwargs)
self.data = None # type: Optional[Data]
self.data: Optional[Data] = None
self._init_lock = asyncio.Lock()
async def async_initialize(self) -> None:
@@ -296,7 +296,7 @@ class HassLoginFlow(LoginFlow):
user_input.pop("password")
return await self.async_finish(user_input)
schema = OrderedDict() # type: Dict[str, type]
schema: Dict[str, type] = OrderedDict()
schema["username"] = str
schema["password"] = str

View File

@@ -112,7 +112,7 @@ class ExampleLoginFlow(LoginFlow):
user_input.pop("password")
return await self.async_finish(user_input)
schema = OrderedDict() # type: Dict[str, type]
schema: Dict[str, type] = OrderedDict()
schema["username"] = str
schema["password"] = str

View File

@@ -97,6 +97,17 @@ async def async_from_config_dict(
stop = time()
_LOGGER.info("Home Assistant initialized in %.2fs", stop - start)
if sys.version_info[:3] < (3, 6, 1):
msg = (
"Python 3.6.0 support is deprecated and will "
"be removed in the first release after October 2. Please "
"upgrade Python to 3.6.1 or higher."
)
_LOGGER.warning(msg)
hass.components.persistent_notification.async_create(
msg, "Python version", "python_version"
)
return hass
@@ -163,7 +174,7 @@ def async_enable_logging(
# ensure that the handlers it sets up wraps the correct streams.
logging.basicConfig(level=logging.INFO)
colorfmt = "%(log_color)s{}%(reset)s".format(fmt)
colorfmt = f"%(log_color)s{fmt}%(reset)s"
logging.getLogger().handlers[0].setFormatter(
ColoredFormatter(
colorfmt,
@@ -206,9 +217,9 @@ def async_enable_logging(
):
if log_rotate_days:
err_handler = logging.handlers.TimedRotatingFileHandler(
err_handler: logging.FileHandler = logging.handlers.TimedRotatingFileHandler(
err_log_path, when="midnight", backupCount=log_rotate_days
) # type: logging.FileHandler
)
else:
err_handler = logging.FileHandler(err_log_path, mode="w", delay=True)
@@ -335,7 +346,7 @@ async def _async_set_up_integrations(
)
# Load all integrations
after_dependencies = {} # type: Dict[str, Set[str]]
after_dependencies: Dict[str, Set[str]] = {}
for int_or_exc in await asyncio.gather(
*(loader.async_get_integration(hass, domain) for domain in stage_2_domains),

View File

@@ -1,7 +1,30 @@
{
"config": {
"abort": {
"existing_instance_updated": "Se ha actualizado la configuraci\u00f3n existente."
}
"existing_instance_updated": "Se ha actualizado la configuraci\u00f3n existente.",
"single_instance_allowed": "S\u00f3lo se permite una \u00fanica configuraci\u00f3n de AdGuard Home."
},
"error": {
"connection_error": "No se conect\u00f3."
},
"step": {
"hassio_confirm": {
"description": "\u00bfDesea configurar Home Assistant para conectarse al AdGuard Home proporcionado por el complemento Hass.io: {addon} ?",
"title": "AdGuard Home a trav\u00e9s del complemento Hass.io"
},
"user": {
"data": {
"host": "Host",
"password": "Contrase\u00f1a",
"port": "Puerto",
"ssl": "AdGuard Home utiliza un certificado SSL",
"username": "Nombre de usuario",
"verify_ssl": "AdGuard Home utiliza un certificado apropiado"
},
"description": "Configure su instancia de AdGuard Home para permitir la supervisi\u00f3n y el control.",
"title": "Enlace su AdGuard Home."
}
},
"title": "AdGuard Home"
}
}

View File

@@ -1,21 +1,30 @@
{
"config": {
"abort": {
"existing_instance_updated": "Configurazione esistente aggiornata.",
"single_instance_allowed": "\u00c8 consentita solo una singola configurazione di AdGuard Home."
},
"error": {
"connection_error": "Impossibile connettersi."
},
"step": {
"hassio_confirm": {
"description": "Vuoi configurare Home Assistant per connettersi alla AdGuard Home fornita dal componente aggiuntivo di Hass.io: {addon} ?",
"title": "AdGuard Home tramite il componente aggiuntivo di Hass.io"
},
"user": {
"data": {
"host": "Host",
"password": "Password",
"port": "Porta",
"ssl": "AdGuard Home utilizza un certificato SSL",
"username": "Nome utente"
}
"username": "Nome utente",
"verify_ssl": "AdGuard Home utilizza un certificato appropriato"
},
"description": "Configura l'istanza di AdGuard Home per consentire il monitoraggio e il controllo.",
"title": "Collega la tua AdGuard Home."
}
}
},
"title": "AdGuard Home"
}
}

View File

@@ -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"
}
},

View File

@@ -132,7 +132,7 @@ class AdGuardHomePercentageBlockedSensor(AdGuardHomeSensor):
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 @@ class AdGuardHomeAverageProcessingTimeSensor(AdGuardHomeSensor):
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):

View File

@@ -194,7 +194,7 @@ class AirVisualSensor(Entity):
@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 @@ class AirVisualSensor(Entity):
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 @@ class AirVisualSensor(Entity):
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(
{

View File

@@ -85,7 +85,7 @@ class AladdinDevice(CoverDevice):
@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):

View File

@@ -13,13 +13,17 @@ from homeassistant.const import (
)
import homeassistant.helpers.config_validation as cv
from . import DATA_AD, SIGNAL_PANEL_MESSAGE
from . import DATA_AD, DOMAIN as DOMAIN_ALARMDECODER, SIGNAL_PANEL_MESSAGE
_LOGGER = logging.getLogger(__name__)
SERVICE_ALARM_TOGGLE_CHIME = "alarmdecoder_alarm_toggle_chime"
ALARM_TOGGLE_CHIME_SCHEMA = vol.Schema({vol.Required(ATTR_CODE): cv.string})
SERVICE_ALARM_KEYPRESS = "alarm_keypress"
ATTR_KEYPRESS = "keypress"
ALARM_KEYPRESS_SCHEMA = vol.Schema({vol.Required(ATTR_KEYPRESS): cv.string})
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up for AlarmDecoder alarm panels."""
@@ -38,6 +42,18 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
schema=ALARM_TOGGLE_CHIME_SCHEMA,
)
def alarm_keypress_handler(service):
"""Register keypress handler."""
keypress = service.data[ATTR_KEYPRESS]
device.alarm_keypress(keypress)
hass.services.register(
DOMAIN_ALARMDECODER,
SERVICE_ALARM_KEYPRESS,
alarm_keypress_handler,
schema=ALARM_KEYPRESS_SCHEMA,
)
class AlarmDecoderAlarmPanel(alarm.AlarmControlPanel):
"""Representation of an AlarmDecoder-based alarm panel."""
@@ -124,24 +140,29 @@ class AlarmDecoderAlarmPanel(alarm.AlarmControlPanel):
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."""
if keypress:
self.hass.data[DATA_AD].send(keypress)

View File

@@ -0,0 +1,9 @@
alarm_keypress:
description: Send custom keypresses to the alarm.
fields:
entity_id:
description: Name of the alarm control panel to trigger.
example: 'alarm_control_panel.downstairs'
keypress:
description: 'String to send to the alarm panel.'
example: '*71'

View File

@@ -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 @@ class AlexaTempRangeError(AlexaError):
"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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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()
@@ -97,12 +97,15 @@ async def async_send_changereport_message(
_LOGGER.debug("Sent: %s", json.dumps(message_serialized))
_LOGGER.debug("Received (%s): %s", response.status, response_text)
if response.status == 202 and not invalidate_access_token:
if response.status == 202:
return
response_json = json.loads(response_text)
if response_json["payload"]["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION":
if (
response_json["payload"]["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION"
and not invalidate_access_token
):
config.async_invalidate_access_token()
return await async_send_changereport_message(
hass, config, alexa_entity, invalidate_access_token=False
@@ -122,7 +125,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 +155,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 = []

View File

@@ -168,7 +168,7 @@ class AlphaVantageForeignExchange(Entity):
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

View File

@@ -1,7 +1,22 @@
{
"config": {
"abort": {
"already_setup": "L'account Ambiclimate \u00e8 configurato."
"access_token": "Errore sconosciuto durante la generazione di un token di accesso.",
"already_setup": "L'account Ambiclimate \u00e8 configurato.",
"no_config": "\u00c8 necessario configurare Ambiclimate prima di poter eseguire l'autenticazione con esso. [Leggere le istruzioni] (https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "Autenticato con successo con Ambiclimate"
},
"error": {
"follow_link": "Si prega di seguire il link e di autenticarsi prima di premere Invia",
"no_token": "Non autenticato con Ambiclimate"
},
"step": {
"auth": {
"description": "Segui questo [link]({authorization_url}) e <b>Consenti</b> accesso al tuo account Ambiclimate, quindi torna indietro e premi <b>Invia</b> qui sotto. \n (Assicurati che l'URL di richiamata specificato sia {cb_url})",
"title": "Autenticare Ambiclimate"
}
},
"title": "Ambiclimate"
}

View File

@@ -3,18 +3,18 @@
"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": {
"description": "Kliknij poni\u017cszy [link]({authorization_url}) i <b>Zezw\u00f3l</b> na dost\u0119p do swojego konta Ambiclimate, a nast\u0119pnie wr\u00f3\u0107 i naci\u015bnij <b>Prze\u015blij</b> poni\u017cej. \n(Upewnij si\u0119, \u017ce podany adres URL to {cb_url})",
"description": "Kliknij poni\u017cszy [link]({authorization_url}) i <b>Zezw\u00f3l</b> na dost\u0119p do konta Ambiclimate, a nast\u0119pnie wr\u00f3\u0107 i naci\u015bnij <b>Prze\u015blij</b> poni\u017cej. \n(Upewnij si\u0119, \u017ce podany adres URL to {cb_url})",
"title": "Uwierzytelnienie Ambiclimate"
}
},

View File

@@ -3,7 +3,7 @@
"abort": {
"access_token": "\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430.",
"already_setup": "\u0423\u0447\u0435\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Ambi Climate \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430.",
"no_config": "\u0412\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Ambi Climate \u043f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. [\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/ambiclimate/)."
"no_config": "\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 Ambi Climate \u043f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u044c\u0442\u0435\u0441\u044c \u0441 [\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438](https://www.home-assistant.io/components/ambiclimate/)."
},
"create_entry": {
"default": "\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e."

View File

@@ -130,7 +130,7 @@ class AmbiclimateFlowHandler(config_entries.ConfigFlow):
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()

View File

@@ -4,7 +4,7 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/components/ambiclimate",
"requirements": [
"ambiclimate==0.2.0"
"ambiclimate==0.2.1"
],
"dependencies": [],
"codeowners": [

View File

@@ -13,6 +13,7 @@
},
"title": "Inserisci i tuoi dati"
}
}
},
"title": "PWS ambientale"
}
}

View File

@@ -11,7 +11,7 @@
"api_key": "Klucz API",
"app_key": "Klucz aplikacji"
},
"title": "Wprowad\u017a swoje dane"
"title": "Wprowad\u017a dane"
}
},
"title": "Ambient PWS"

View File

@@ -492,7 +492,7 @@ class AmbientWeatherEntity(Entity):
@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 @@ class AmbientWeatherEntity(Entity):
@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."""

View File

@@ -490,7 +490,7 @@ class AmcrestCam(Camera):
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 @@ class AmcrestCam(Camera):
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

View File

@@ -4,7 +4,7 @@ from .const import DOMAIN
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

View File

@@ -57,7 +57,7 @@ class AmpioSmogQuality(AirQualityEntity):
@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):

View File

@@ -25,7 +25,7 @@ class IPWebcamBinarySensor(AndroidIPCamEntity, BinarySensorDevice):
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

View File

@@ -39,7 +39,7 @@ class IPWebcamSensor(AndroidIPCamEntity):
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

View File

@@ -39,7 +39,7 @@ class IPWebcamSettingsSwitch(AndroidIPCamEntity, SwitchDevice):
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

View File

@@ -3,7 +3,7 @@
"name": "Androidtv",
"documentation": "https://www.home-assistant.io/components/androidtv",
"requirements": [
"androidtv==0.0.24"
"androidtv==0.0.27"
],
"dependencies": [],
"codeowners": ["@JeffLIrion"]

View File

@@ -392,7 +392,7 @@ class ADBDevice(MediaPlayerDevice):
"""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
@@ -431,8 +431,10 @@ class AndroidTVDevice(ADBDevice):
# Try to connect
self._available = self.aftv.connect(always_log_errors=False)
# To be safe, wait until the next update to run ADB commands.
return
# To be safe, wait until the next update to run ADB commands if
# using the Python ADB implementation.
if not self.aftv.adb_server_ip:
return
# If the ADB connection is not intact, don't update.
if not self._available:
@@ -443,7 +445,9 @@ class AndroidTVDevice(ADBDevice):
self.aftv.update()
)
self._state = ANDROIDTV_STATES[state]
self._state = ANDROIDTV_STATES.get(state)
if self._state is None:
self._available = False
@property
def is_volume_muted(self):
@@ -506,8 +510,10 @@ class FireTVDevice(ADBDevice):
# Try to connect
self._available = self.aftv.connect(always_log_errors=False)
# To be safe, wait until the next update to run ADB commands.
return
# To be safe, wait until the next update to run ADB commands if
# using the Python ADB implementation.
if not self.aftv.adb_server_ip:
return
# If the ADB connection is not intact, don't update.
if not self._available:
@@ -518,7 +524,9 @@ class FireTVDevice(ADBDevice):
self._get_sources
)
self._state = ANDROIDTV_STATES[state]
self._state = ANDROIDTV_STATES.get(state)
if self._state is None:
self._available = False
@property
def source(self):

View File

@@ -81,7 +81,7 @@ class KafkaManager:
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

View File

@@ -138,7 +138,7 @@ class APIEventStream(HomeAssistantView):
if payload is stop_obj:
break
msg = "data: {}\n\n".format(payload)
msg = f"data: {payload}\n\n"
_LOGGER.debug("STREAM %s WRITING %s", id(stop_obj), msg.strip())
await response.write(msg.encode("UTF-8"))
except asyncio.TimeoutError:
@@ -316,7 +316,7 @@ class APIEventView(HomeAssistantView):
event_type, event_data, ha.EventOrigin.remote, self.context(request)
)
return self.json_message("Event {} fired.".format(event_type))
return self.json_message(f"Event {event_type} fired.")
class APIServicesView(HomeAssistantView):
@@ -388,7 +388,7 @@ class APITemplateView(HomeAssistantView):
return tpl.async_render(data.get("variables"))
except (ValueError, TemplateError) as ex:
return self.json_message(
"Error rendering template: {}".format(ex), HTTP_BAD_REQUEST
f"Error rendering template: {ex}", HTTP_BAD_REQUEST
)

View File

@@ -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 @@ class ApnsDevice:
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")

View File

@@ -3,7 +3,7 @@
"name": "Apple tv",
"documentation": "https://www.home-assistant.io/components/apple_tv",
"requirements": [
"pyatv==0.3.12"
"pyatv==0.3.13"
],
"dependencies": ["configurator"],
"codeowners": []

View File

@@ -127,6 +127,7 @@ class AppleTvDevice(MediaPlayerDevice):
const.PLAY_STATE_PAUSED,
const.PLAY_STATE_FAST_FORWARD,
const.PLAY_STATE_FAST_BACKWARD,
const.PLAY_STATE_STOPPED,
):
# Catch fast forward/backward here so "play" is default action
return STATE_PAUSED
@@ -212,7 +213,7 @@ class AppleTvDevice(MediaPlayerDevice):
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):

View File

@@ -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 @@ class AprsListenerThread(threading.Thread):
)
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:

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -0,0 +1,5 @@
{
"config": {
"title": "Arcam FMJ"
}
}

View File

@@ -9,5 +9,5 @@ DEFAULT_PORT = 50000
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"

View File

@@ -319,7 +319,7 @@ class ArcamFmj(MediaPlayerDevice):
channel = self.media_channel
if channel:
value = "{} - {}".format(source.name, channel)
value = f"{source.name} - {channel}"
else:
value = source.name
return value

View File

@@ -73,9 +73,7 @@ class ArestBinarySensor(BinarySensorDevice):
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 @@ class ArestData:
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)

View File

@@ -148,9 +148,7 @@ class ArestSensor(Entity):
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 @@ class ArestData:
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

View File

@@ -114,7 +114,7 @@ class ArestSwitchFunction(ArestSwitchBase):
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 @@ class ArestSwitchFunction(ArestSwitchBase):
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 @@ class ArestSwitchFunction(ArestSwitchBase):
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 @@ class ArestSwitchFunction(ArestSwitchBase):
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 @@ class ArestSwitchPin(ArestSwitchBase):
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 @@ class ArestSwitchPin(ArestSwitchBase):
"""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 @@ class ArestSwitchPin(ArestSwitchBase):
"""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 @@ class ArestSwitchPin(ArestSwitchBase):
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

View File

@@ -0,0 +1 @@
"""Support for Atome devices connected to a Linky Energy Meter."""

View File

@@ -0,0 +1,8 @@
{
"domain": "atome",
"name": "Atome",
"documentation": "https://www.home-assistant.io/components/atome",
"dependencies": [],
"codeowners": ["@baqs"],
"requirements": ["pyatome==0.1.1"]
}

View File

@@ -0,0 +1,279 @@
"""Linky Atome."""
import logging
from datetime import timedelta
import voluptuous as vol
from pyatome.client import AtomeClient
from pyatome.client import PyAtomeError
from homeassistant.const import (
CONF_PASSWORD,
CONF_USERNAME,
CONF_NAME,
DEVICE_CLASS_POWER,
POWER_WATT,
ENERGY_KILO_WATT_HOUR,
)
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "atome"
LIVE_SCAN_INTERVAL = timedelta(seconds=30)
DAILY_SCAN_INTERVAL = timedelta(seconds=150)
WEEKLY_SCAN_INTERVAL = timedelta(hours=1)
MONTHLY_SCAN_INTERVAL = timedelta(hours=1)
YEARLY_SCAN_INTERVAL = timedelta(days=1)
LIVE_NAME = "Atome Live Power"
DAILY_NAME = "Atome Daily"
WEEKLY_NAME = "Atome Weekly"
MONTHLY_NAME = "Atome Monthly"
YEARLY_NAME = "Atome Yearly"
LIVE_TYPE = "live"
DAILY_TYPE = "day"
WEEKLY_TYPE = "week"
MONTHLY_TYPE = "month"
YEARLY_TYPE = "year"
ICON = "mdi:flash"
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
)
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Atome sensor."""
username = config[CONF_USERNAME]
password = config[CONF_PASSWORD]
try:
atome_client = AtomeClient(username, password)
atome_client.login()
except PyAtomeError as exp:
_LOGGER.error(exp)
return
data = AtomeData(atome_client)
sensors = []
sensors.append(AtomeSensor(data, LIVE_NAME, LIVE_TYPE))
sensors.append(AtomeSensor(data, DAILY_NAME, DAILY_TYPE))
sensors.append(AtomeSensor(data, WEEKLY_NAME, WEEKLY_TYPE))
sensors.append(AtomeSensor(data, MONTHLY_NAME, MONTHLY_TYPE))
sensors.append(AtomeSensor(data, YEARLY_NAME, YEARLY_TYPE))
add_entities(sensors, True)
class AtomeData:
"""Stores data retrieved from Neurio sensor."""
def __init__(self, client: AtomeClient):
"""Initialize the data."""
self.atome_client = client
self._live_power = None
self._subscribed_power = None
self._is_connected = None
self._day_usage = None
self._day_price = None
self._week_usage = None
self._week_price = None
self._month_usage = None
self._month_price = None
self._year_usage = None
self._year_price = None
@property
def live_power(self):
"""Return latest active power value."""
return self._live_power
@property
def subscribed_power(self):
"""Return latest active power value."""
return self._subscribed_power
@property
def is_connected(self):
"""Return latest active power value."""
return self._is_connected
@Throttle(LIVE_SCAN_INTERVAL)
def update_live_usage(self):
"""Return current power value."""
try:
values = self.atome_client.get_live()
self._live_power = values["last"]
self._subscribed_power = values["subscribed"]
self._is_connected = values["isConnected"]
_LOGGER.debug(
"Updating Atome live data. Got: %d, isConnected: %s, subscribed: %d",
self._live_power,
self._is_connected,
self._subscribed_power,
)
except KeyError as error:
_LOGGER.error("Missing last value in values: %s: %s", values, error)
@property
def day_usage(self):
"""Return latest daily usage value."""
return self._day_usage
@property
def day_price(self):
"""Return latest daily usage value."""
return self._day_price
@Throttle(DAILY_SCAN_INTERVAL)
def update_day_usage(self):
"""Return current daily power usage."""
try:
values = self.atome_client.get_consumption(DAILY_TYPE)
self._day_usage = values["total"] / 1000
self._day_price = values["price"]
_LOGGER.debug("Updating Atome daily data. Got: %d.", self._day_usage)
except KeyError as error:
_LOGGER.error("Missing last value in values: %s: %s", values, error)
@property
def week_usage(self):
"""Return latest weekly usage value."""
return self._week_usage
@property
def week_price(self):
"""Return latest weekly usage value."""
return self._week_price
@Throttle(WEEKLY_SCAN_INTERVAL)
def update_week_usage(self):
"""Return current weekly power usage."""
try:
values = self.atome_client.get_consumption(WEEKLY_TYPE)
self._week_usage = values["total"] / 1000
self._week_price = values["price"]
_LOGGER.debug("Updating Atome weekly data. Got: %d.", self._week_usage)
except KeyError as error:
_LOGGER.error("Missing last value in values: %s: %s", values, error)
@property
def month_usage(self):
"""Return latest monthly usage value."""
return self._month_usage
@property
def month_price(self):
"""Return latest monthly usage value."""
return self._month_price
@Throttle(MONTHLY_SCAN_INTERVAL)
def update_month_usage(self):
"""Return current monthly power usage."""
try:
values = self.atome_client.get_consumption(MONTHLY_TYPE)
self._month_usage = values["total"] / 1000
self._month_price = values["price"]
_LOGGER.debug("Updating Atome monthly data. Got: %d.", self._month_usage)
except KeyError as error:
_LOGGER.error("Missing last value in values: %s: %s", values, error)
@property
def year_usage(self):
"""Return latest yearly usage value."""
return self._year_usage
@property
def year_price(self):
"""Return latest yearly usage value."""
return self._year_price
@Throttle(YEARLY_SCAN_INTERVAL)
def update_year_usage(self):
"""Return current yearly power usage."""
try:
values = self.atome_client.get_consumption(YEARLY_TYPE)
self._year_usage = values["total"] / 1000
self._year_price = values["price"]
_LOGGER.debug("Updating Atome yearly data. Got: %d.", self._year_usage)
except KeyError as error:
_LOGGER.error("Missing last value in values: %s: %s", values, error)
class AtomeSensor(Entity):
"""Representation of a sensor entity for Atome."""
def __init__(self, data, name, sensor_type):
"""Initialize the sensor."""
self._name = name
self._data = data
self._state = None
self._attributes = {}
self._sensor_type = sensor_type
if sensor_type == LIVE_TYPE:
self._unit_of_measurement = POWER_WATT
else:
self._unit_of_measurement = ENERGY_KILO_WATT_HOUR
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self._attributes
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit_of_measurement
@property
def icon(self):
"""Icon to use in the frontend, if any."""
return ICON
@property
def device_class(self):
"""Return the device class."""
return DEVICE_CLASS_POWER
def update(self):
"""Update device state."""
update_function = getattr(self._data, f"update_{self._sensor_type}_usage")
update_function()
if self._sensor_type == LIVE_TYPE:
self._state = self._data.live_power
self._attributes["subscribed_power"] = self._data.subscribed_power
self._attributes["is_connected"] = self._data.is_connected
else:
self._state = getattr(self._data, f"{self._sensor_type}_usage")
self._attributes["price"] = getattr(
self._data, f"{self._sensor_type}_price"
)

View File

@@ -73,4 +73,4 @@ class AugustCamera(Camera):
@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"

View File

@@ -93,4 +93,4 @@ class AugustLock(LockDevice):
@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"

View File

@@ -64,7 +64,7 @@ class AuroraSensor(BinarySensorDevice):
@property
def name(self):
"""Return the name of the sensor."""
return "{}".format(self._name)
return f"{self._name}"
@property
def is_on(self):

View File

@@ -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

View File

@@ -10,7 +10,7 @@
"step": {
"init": {
"description": "Selezionare uno dei servizi di notifica:",
"title": "Imposta la password one-time fornita dal componente di notifica"
"title": "Imposta la password monouso fornita dal componente di notifica"
},
"setup": {
"description": "\u00c8 stata inviata una password monouso tramite **notify.{notify_service}**. Per favore, inseriscila qui sotto:",
@@ -25,7 +25,7 @@
},
"step": {
"init": {
"description": "Per attivare l'autenticazione a due fattori utilizzando password monouso basate sul tempo, eseguire la scansione del codice QR con l'app di autenticazione. Se non ne hai uno, ti consigliamo [Google Authenticator] (https://support.google.com/accounts/answer/1066447) o [Authy] (https://authy.com/). \n\n {qr_code} \n \n Dopo aver scansionato il codice, inserisci il codice a sei cifre dalla tua app per verificare la configurazione. Se riscontri problemi con la scansione del codice QR, esegui una configurazione manuale con codice ** ` {code} ` **.",
"description": "Per attivare l'autenticazione a due fattori utilizzando le password monouso basate sul tempo, eseguire la scansione del codice QR con l'app di autenticazione. Se non ne hai uno, ti consigliamo [Google Authenticator] (https://support.google.com/accounts/answer/1066447) o [Authy] (https://authy.com/). \n\n {qr_code} \n \nDopo la scansione, inserisci il codice a sei cifre dalla tua app per verificare la configurazione. Se riscontri problemi con la scansione del codice QR, esegui una configurazione manuale con il codice ** ` {code} ` **.",
"title": "Imposta l'autenticazione a due fattori usando TOTP"
}
},

View File

@@ -25,7 +25,7 @@
},
"step": {
"init": {
"description": "\uc2dc\uac04 \uae30\ubc18\uc758 \uc77c\ud68c\uc6a9 \ube44\ubc00\ubc88\ud638\ub97c \uc0ac\uc6a9\ud558\ub294 2\ub2e8\uacc4 \uc778\uc99d\uc744 \ud558\ub824\uba74 \uc778\uc99d\uc6a9 \uc571\uc744 \uc774\uc6a9\ud574\uc11c QR \ucf54\ub4dc\ub97c \uc2a4\uce94\ud574\uc8fc\uc138\uc694. \uc778\uc99d\uc6a9 \uc571\uc740 [Google OTP](https://support.google.com/accounts/answer/1066447) \ub610\ub294 [Authy](https://authy.com/) \ub97c \ucd94\ucc9c\ub4dc\ub9bd\ub2c8\ub2e4.\n\n{qr_code}\n\n\uc2a4\uce94 \ud6c4\uc5d0 \uc0dd\uc131\ub41c 6\uc790\ub9ac \ucf54\ub4dc\ub97c \uc785\ub825\ud574\uc11c \uc124\uc815\uc744 \ud655\uc778\ud558\uc138\uc694. QR \ucf54\ub4dc \uc2a4\uce94\uc5d0 \ubb38\uc81c\uac00 \uc788\ub2e4\uba74, **`{code}`** \ucf54\ub4dc\ub85c \uc9c1\uc811 \uc124\uc815\ud574\ubcf4\uc138\uc694.",
"description": "\uc2dc\uac04 \uae30\ubc18\uc758 \uc77c\ud68c\uc6a9 \ube44\ubc00\ubc88\ud638\ub97c \uc0ac\uc6a9\ud558\ub294 2\ub2e8\uacc4 \uc778\uc99d\uc744 \ud558\ub824\uba74 \uc778\uc99d\uc6a9 \uc571\uc744 \uc774\uc6a9\ud574\uc11c QR \ucf54\ub4dc\ub97c \uc2a4\uce94\ud574\uc8fc\uc138\uc694. \uc778\uc99d\uc6a9 \uc571\uc740 [\uad6c\uae00 OTP](https://support.google.com/accounts/answer/1066447) \ub610\ub294 [Authy](https://authy.com/) \ub97c \ucd94\ucc9c\ub4dc\ub9bd\ub2c8\ub2e4.\n\n{qr_code}\n\n\uc2a4\uce94 \ud6c4\uc5d0 \uc0dd\uc131\ub41c 6\uc790\ub9ac \ucf54\ub4dc\ub97c \uc785\ub825\ud574\uc11c \uc124\uc815\uc744 \ud655\uc778\ud558\uc138\uc694. QR \ucf54\ub4dc \uc2a4\uce94\uc5d0 \ubb38\uc81c\uac00 \uc788\ub2e4\uba74, **`{code}`** \ucf54\ub4dc\ub85c \uc9c1\uc811 \uc124\uc815\ud574\ubcf4\uc138\uc694.",
"title": "TOTP 2\ub2e8\uacc4 \uc778\uc99d \uad6c\uc131"
}
},

View File

@@ -13,7 +13,7 @@
"title": "Skonfiguruj has\u0142o jednorazowe dostarczone przez komponent powiadomie\u0144"
},
"setup": {
"description": "Has\u0142o jednorazowe zosta\u0142o wys\u0142ane przez **notify.{notify_service}**. Wpisz je poni\u017cej:",
"description": "Has\u0142o jednorazowe zosta\u0142o wys\u0142ane przez **notify.{notify_service}**. Wprowad\u017a je poni\u017cej:",
"title": "Sprawd\u017a konfiguracj\u0119"
}
},

View File

@@ -34,7 +34,7 @@ async def async_setup(hass):
"""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 @@ def websocket_setup_mfa(
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 @@ def websocket_depose_mfa(
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

View File

@@ -6,6 +6,9 @@ import logging
import voluptuous as vol
from homeassistant.components.device_automation.exceptions import (
InvalidDeviceAutomationConfig,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_NAME,
@@ -143,7 +146,7 @@ async def async_setup(hass, config):
async def turn_onoff_service_handler(service_call):
"""Handle automation turn on/off service calls."""
tasks = []
method = "async_{}".format(service_call.service)
method = f"async_{service_call.service}"
for entity in await component.async_extract_from_service(service_call):
tasks.append(getattr(entity, method)())
@@ -378,7 +381,7 @@ async def _async_process_config(hass, config, component):
for list_no, config_block in enumerate(conf):
automation_id = config_block.get(CONF_ID)
name = config_block.get(CONF_ALIAS) or "{} {}".format(config_key, list_no)
name = config_block.get(CONF_ALIAS) or f"{config_key} {list_no}"
hidden = config_block[CONF_HIDE_ENTITY]
initial_state = config_block.get(CONF_INITIAL_STATE)
@@ -386,7 +389,7 @@ async def _async_process_config(hass, config, component):
action = _async_get_action(hass, config_block.get(CONF_ACTION, {}), name)
if CONF_CONDITION in config_block:
cond_func = _async_process_if(hass, config, config_block)
cond_func = await _async_process_if(hass, config, config_block)
if cond_func is None:
continue
@@ -431,20 +434,20 @@ def _async_get_action(hass, config, name):
await script_obj.async_run(variables, context)
except Exception as err: # pylint: disable=broad-except
script_obj.async_log_exception(
_LOGGER, "Error while executing automation {}".format(entity_id), err
_LOGGER, f"Error while executing automation {entity_id}", err
)
return action
def _async_process_if(hass, config, p_config):
async def _async_process_if(hass, config, p_config):
"""Process if checks."""
if_configs = p_config.get(CONF_CONDITION)
checks = []
for if_config in if_configs:
try:
checks.append(condition.async_from_config(if_config, False))
checks.append(await condition.async_from_config(hass, if_config, False))
except HomeAssistantError as ex:
_LOGGER.warning("Invalid condition: %s", ex)
return None
@@ -467,7 +470,10 @@ async def _async_process_trigger(hass, config, trigger_configs, name, action):
for conf in trigger_configs:
platform = importlib.import_module(".{}".format(conf[CONF_PLATFORM]), __name__)
remove = await platform.async_trigger(hass, conf, action, info)
try:
remove = await platform.async_trigger(hass, conf, action, info)
except InvalidDeviceAutomationConfig:
remove = False
if not remove:
_LOGGER.error("Error setting up trigger %s", name)

View File

@@ -4,6 +4,7 @@
"documentation": "https://www.home-assistant.io/components/automation",
"requirements": [],
"dependencies": [
"device_automation",
"group",
"webhook"
],

View File

@@ -150,7 +150,7 @@ class AwairSensor(Entity):
"""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 @@ class AwairSensor(Entity):
@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):

View File

@@ -8,6 +8,7 @@
},
"error": {
"already_configured": "El dispositivo ya est\u00e1 configurado",
"already_in_progress": "El flujo de configuraci\u00f3n del dispositivo ya est\u00e1 en curso.",
"device_unavailable": "El dispositivo no est\u00e1 disponible",
"faulty_credentials": "Credenciales de usuario incorrectas"
},

View File

@@ -3,6 +3,7 @@
"abort": {
"already_configured": "Il dispositivo \u00e8 gi\u00e0 configurato",
"bad_config_file": "Dati errati dal file di configurazione",
"link_local_address": "Gli indirizzi locali di collegamento non sono supportati",
"not_axis_device": "Il dispositivo rilevato non \u00e8 un dispositivo Axis"
},
"error": {

View File

@@ -72,7 +72,7 @@ class AxisEventBase(AxisEntityBase):
@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 @@ class AxisEventBase(AxisEntityBase):
@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}"

View File

@@ -92,4 +92,4 @@ class AxisCamera(AxisEntityBase, MjpegCamera):
@property
def unique_id(self):
"""Return a unique identifier for this device."""
return "{}-camera".format(self.device.serial)
return f"{self.device.serial}-camera"

View File

@@ -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
@@ -138,9 +137,9 @@ class AxisFlowHandler(config_entries.ConfigFlow):
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
@@ -151,7 +150,7 @@ class AxisFlowHandler(config_entries.ConfigFlow):
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):

View File

@@ -65,7 +65,7 @@ class AxisNetworkDevice:
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 @@ class AxisNetworkDevice:
@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 @@ class AxisNetworkDevice:
@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 @@ class AxisNetworkDevice:
@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):

Some files were not shown because too many files have changed in this diff Show More