Compare commits

...

932 Commits

Author SHA1 Message Date
Paulus Schoutsen 21aa635ad8 Bumped version to 2021.10.0b1 2021-09-30 14:11:43 -07:00
Erik Montnemery a70daabcea Correct database migration to schema version 22 (#56848) 2021-09-30 14:11:35 -07:00
Milan Meulemans baad8100f9 Upgrade aionanoleaf to 0.0.2 (#56845) 2021-09-30 14:11:35 -07:00
Raman Gupta 6ed46bf549 Add strings for new zwave_js config flow keys (#56844) 2021-09-30 14:11:34 -07:00
Franck Nijhof 0c765a40ae Bumped version to 2021.10.0b0 2021-09-30 18:48:14 +02:00
Daniel Hjelseth Høyer 4a2ed97e0d Add locking state to surepetcare locks (#56830) 2021-09-30 08:16:35 -07:00
Erik Montnemery 6af1a835e6 Optimize statistics generation (#56821)
* Optimize statistics generation

* pylint
2021-09-30 17:14:36 +02:00
Daniel Hjelseth Høyer d5bda3ac14 Surepetcare reauthorize (#56402)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-30 10:11:45 -05:00
Daniel Hjelseth Høyer 08719af794 Bump Mill library (#56833) 2021-09-30 16:59:00 +02:00
Erik Montnemery 6954614e62 Warn if total_increasing sensor has negative states (#56564) 2021-09-30 07:49:16 -07:00
Niels Mündler 3a56e3a823 Correctly handle offline and unsupported printers during setup (#55894) 2021-09-30 16:29:51 +02:00
Bram Kragten 8196a84538 Update frontend to 20210930.0 (#56827) 2021-09-30 16:22:36 +02:00
Robert Svensson d61a9e8b72 Service to remove clients from UniFi Controller (#56717) 2021-09-30 14:38:29 +02:00
Daniel Hjelseth Høyer e729339538 Bump surepy to 0.7.2 (#56828) 2021-09-30 14:33:21 +02:00
Daniel Hjelseth Høyer 53e130d9a8 Deprecated open garage yaml config (#56829) 2021-09-30 14:19:46 +02:00
Erik Montnemery 55328d2c6f Adjust state class of growatt_server lifetime energy sensors (#56826) 2021-09-30 13:48:01 +02:00
Erik Montnemery 942db3fcbc Adjust state class of solaredge lifetime energy sensor (#56825) 2021-09-30 13:38:33 +02:00
Sean Vig f18e4bab60 Add resolution to Amcrest camera unique id (#56207)
Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-09-30 13:38:18 +02:00
Kevin Stillhammer dd52ec78c7 Add Kraken delay after first update to avoid limit (#55736)
* Add delay after first update to avoid limit

* Apply suggestions
2021-09-30 13:23:46 +02:00
Fabrizio Tarizzo ef4b6d7bdf Update viaggiatreno component due to API changes (#56463) 2021-09-30 13:22:43 +02:00
Marko Korhonen c9e1a03fe2 Remove webostv service description github link (#53502)
Co-authored-by: Shay Levy <levyshay1@gmail.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
2021-09-30 13:03:38 +02:00
deosrc d4ed0f9637 Fix OVO Energy reporting consumption as cost (#55856) 2021-09-30 12:31:06 +02:00
logan893 cf6398a949 Fix hue turning on eWeLink switch (#56318) 2021-09-30 12:22:42 +02:00
Simone Chemelli ee28dd57c1 Rename var to compliant name in August integration (#56812) 2021-09-30 12:15:17 +02:00
Oxan van Leeuwen c6f48056fd Remove dead code from ESPHome light entity (#55519) 2021-09-30 12:12:37 +02:00
Oliver Ou d3b1ccb668 Tuya v2 Integration Release (#56820)
Co-authored-by: 乾启 <18442047+tsutsuku@users.noreply.github.com>
Co-authored-by: dengweijun <dengweijunben@gmail.com>
Co-authored-by: dengweijun <mengzi.deng@tuya.com>
Co-authored-by: erchuan <jie.zheng@tuya.com>
Co-authored-by: erchuan <erchuan365@outlook.com>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-30 12:02:56 +02:00
Julian Löhr 26042bdad7 Add Fritz!DECT 440 humidity sensor (#54597)
Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com>
2021-09-30 11:56:38 +02:00
acshef 4ae887ad34 Correct unit of measurement for qbittorrent data rate sensors (#55758) 2021-09-30 11:52:21 +02:00
Mas2112 1f5720199c Add DC voltage and current to Kostal inverter (#54878) 2021-09-30 11:41:55 +02:00
Tim Niemueller 0c1c1f7845 Fix Onvif PTZ for Imou cameras (#56592) 2021-09-30 11:36:49 +02:00
Greg 6a266ae3c0 Change state_class so older Envoys can use Energy Dashboard (#55383) 2021-09-30 11:34:41 +02:00
Ville Skyttä 4c854a06d9 Add some huawei_lte sensor state classifications (#55601) 2021-09-30 11:27:52 +02:00
Chris Talkington a035615016 Use entity descriptions for sonarr (#55818) 2021-09-30 11:25:42 +02:00
Aaron Bach 4b68700763 Add long-term statistics for Ambient PWS sensors (#55412) 2021-09-30 11:20:14 +02:00
Simone Chemelli 8993ff0377 Fritz new binary sensor for link and firmware status + code cleanup (#55446) 2021-09-30 11:18:04 +02:00
ehendrix23 a6a3745413 Handle UpnpError exceptions when getting WAN status and external IP address (#56744) 2021-09-30 10:41:28 +02:00
Ian Foster 2e02945833 Add keyboard event type to keyboard_remote (#56668)
* added keyboard event type to keyboard_remote

* fix emulated hold event

* Update homeassistant/components/keyboard_remote/__init__.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* removed event value

* set key_hold to use string constant

* don't use dict.get() for keyboard event type

Co-authored-by: Erik Montnemery <erik@montnemery.com>
2021-09-30 09:17:57 +02:00
Marc Mueller 54abd80462 Use EntityDescription - smappee (#56747) 2021-09-30 09:15:09 +02:00
Rami Mosleh 51addfc164 Add device_info to Speedtestdotnet and some code cleanup (#56612)
* Apply code cleanup suggestions from previous PRs

* Update homeassistant/components/speedtestdotnet/const.py

Co-authored-by: Franck Nijhof <git@frenck.dev>

* fix native_value, and ping value in test

* use self._state instead of _attr_native_value

* update identifiers and add more tests

Co-authored-by: Franck Nijhof <git@frenck.dev>
2021-09-30 08:28:04 +02:00
J. Nick Koston 2ed35debdc Fix dhcp discovery matching due to deferred imports (#56814) 2021-09-29 23:50:21 -05:00
David F. Mulcahey a7f554e6da Bump ZHA quirks module to 0.0.62 (#56809) 2021-09-29 22:47:15 -04:00
Raman Gupta e9d25974b8 Switch to using constants wherever possible in zwave_js (#56518) 2021-09-30 02:21:53 +02:00
jjlawren 2ff1fc83bc Add latest added media as Plex library sensor attribute (#56235) 2021-09-29 17:11:53 -07:00
João Pedro Hickmann a967a1d1df Get the currency from the api (#56806) 2021-09-29 16:25:07 -07:00
Martin Hjelmare 12b2076351 Fix zwave_js config flow import step (#56808) 2021-09-30 01:15:05 +02:00
Simone Chemelli b9d81c3a7e Handle Fritz portmapping with same name (#56398) 2021-09-29 15:11:22 -07:00
Martin Hjelmare fa716d92ad Manage s2 keys in zwave_js (#56783) 2021-09-29 15:04:24 -07:00
Erik Montnemery 8c3fc95fb8 Fallback to state machine in statistics (#56785) 2021-09-29 14:57:16 -07:00
Martin Hjelmare 7dfcccd43e Bump holidays to 0.11.3.1 (#56804) 2021-09-29 23:57:07 +02:00
RDFurman f8903e11e0 Fix honeywell connection error (#56757)
* Catch ConnectionError and retry

* Add unload and reload functionality

* Update listener on retry

* Call reload directly and await

Co-authored-by: J. Nick Koston <nick@koston.org>

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-29 16:10:22 -05:00
Raman Gupta 18340b2fd9 Bump zwave-js-server-python to 0.31.1 (#56517) 2021-09-29 22:33:35 +02:00
Robert Svensson f224ab6d67 Use isinstance to verify class in deCONZ integration (#56794)
* Don't enable any variants of the daylight sensor entities by default

* Use isinstance rather than doing ZHATYPE compare

* Accidentally removed an import
2021-09-29 21:19:21 +02:00
Maciej Bieniek 0463007050 Add switch platform to Tractive integration (#55517) 2021-09-29 21:06:11 +02:00
J. Nick Koston 23cbd9075a Wait for yeelight internal state to change before update after on/off (#56795) 2021-09-29 13:49:33 -05:00
Franck Nijhof 25ce7f951a Merge branch 'master' into dev 2021-09-29 20:47:34 +02:00
Erik Montnemery a966714032 Minor cleanup of recorder statistics code (#55339) 2021-09-29 11:42:39 -07:00
jjlawren 8f4ba564d4 Plex media browser improvements (#56312) 2021-09-29 11:17:55 -07:00
Erik Montnemery ef13e473cf Warn if template functions fail and no default is specified (#56453)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-29 20:16:02 +02:00
Aaron Bach ae00c221e0 Add long-term statistics for Guardian sensors (#55413)
* Add long-term statistics for Guardian sensors

* Code review
2021-09-29 12:06:48 -06:00
J. Nick Koston f7ef973c68 Bump aiodiscover to 1.4.4 to fix mac matching with leading 0s (#56791) 2021-09-29 13:18:13 -04:00
Alexei Chetroi dbba2c4afe Add "Summation Delivered" Sensor for SmartEnergy metering ZHA channel (#56666) 2021-09-29 09:35:20 -07:00
Daniel Hjelseth Høyer 60eb426451 Add Surepetcare locks (#56396)
* Surepetcare, add lock

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Fix tests

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Surepetcare, lock name

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* surepetcare_id

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* typing

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Fix review comment

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Fix review comment

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Fix review comment

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* add more tests

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Fix review comment

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-29 09:17:12 -07:00
Martin Hjelmare 50fffe48f8 Add zwave to zwave_js migration (#56159)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-29 08:55:27 -07:00
Daniel Hjelseth Høyer d5c3d234ec Open garage, add config flow (#55290) 2021-09-29 09:43:51 -06:00
Erik Montnemery 40ecf22bac Remove automatic splitting of net meters from statistics (#56772) 2021-09-29 17:20:17 +02:00
Andre Richter d13c3e3917 Migrate Vallox to new fan entity model (#56663)
* Migrate Vallox to new fan entity model

* Review comments 1

* Minor corrections

* Review comments 2
2021-09-29 17:14:41 +02:00
Erik Montnemery 00651a4055 Optimize _get_states_with_session (#56734)
* Optimize _get_states_with_session

* Move custom filters to derived table

* Remove useless derived table

* Filter old states after grouping

* Split query

* Add comments

* Simplify state update period criteria

* Only apply custom filters if we didn't get an include list of entities

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-29 17:08:27 +02:00
avee87 daebc34f4d Add code_format to template alarm (#56700)
* Added code_format to template alarm

* review comment

* review comment

* use constant

* back to enum

* none -> no_code
2021-09-29 16:59:46 +02:00
Marc Mueller 77ee72cbb9 Import Callable from collections.abc (1) (#56775) 2021-09-29 16:32:11 +02:00
Marc Mueller d51487f82a Import Callable from collections.abc (3) (#56777) 2021-09-29 16:19:06 +02:00
Marc Mueller 364767ff22 Import Callable from collections.abc (4) (#56778) 2021-09-29 16:15:36 +02:00
jan iversen 19685ecff0 Set strict typing for modbus. (#56779) 2021-09-29 16:15:55 +03:00
Marc Mueller 565a9fea6b Import Callable from collections.abc (2) (#56776) 2021-09-29 14:06:51 +02:00
Franck Nijhof 41e5f05d99 Fix energy validation when not tracking costs (#56768) 2021-09-29 13:24:34 +02:00
Maciej Bieniek d3df6f26f9 Add missing voltage sensor in Shelly integration (#56773)
* Disable voltage sensor by default

* Add voltage sensor for Shelly 2/2.5

* Enable emeter voltage by default
2021-09-29 14:22:42 +03:00
Erik Montnemery 52e9f76f94 Tweak DB migration to schema version 21 (#56767) 2021-09-29 11:25:50 +02:00
Fabian Affolter be34a2ddea Upgrade beautifulsoup4 to 4.10.0 (#56764) 2021-09-29 11:25:29 +02:00
Fabian Affolter deb0cc4116 Upgrade holidays to 0.11.3 (#56762) 2021-09-29 11:25:06 +02:00
Joakim Sørensen 6a9b484f2d Remove timeout for backup services (#56763) 2021-09-29 09:46:05 +02:00
Regev Brody 115bb39c10 Fix cover group to handle unknown state properly (#56739)
* fix cover group unknown state

* fix cover grup state

* fix cover group issue
2021-09-29 08:37:16 +02:00
Simone Chemelli 34ef47db55 Fritz honor sys option pref_disable_new_entities (#56740) 2021-09-28 20:59:03 -07:00
João Pedro Hickmann 4513a46248 Add zeroconf support for yeelight (#56758) 2021-09-28 20:53:43 -05:00
Myles Eftos 8e91e6e97e Adding price spike binary sensor to the Amber electric integration (#56736) 2021-09-28 18:01:35 -07:00
J. Nick Koston cf36d0966d Add coverage to verify tplink unique ids (#56746) 2021-09-28 17:57:22 -07:00
Michael Chisholm f7d95588f8 Provide most media metadata in DlnaDmrEntity (#56728)
Co-authored-by: Steven Looman <steven.looman@gmail.com>
2021-09-28 19:37:23 -05:00
Marc Mueller 718f8d8bf7 Use NamedTuple for xbox media type details (#56753) 2021-09-28 17:00:19 -07:00
Marc Mueller 15aafc8db6 Use NamedTuple for discovery service details (#56751) 2021-09-28 16:59:40 -07:00
Marc Mueller a91fbec198 Use NamedTuple for esphome service metadata (#56754) 2021-09-28 16:58:36 -07:00
Marc Mueller 160571888c Use NamedTuple for intesishome swing settings (#56752) 2021-09-28 16:56:58 -07:00
Raman Gupta e76ddb4b27 Add proper S2 support for adding zwave_js nodes (#56516)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-28 15:37:45 -07:00
Milan Meulemans db30c27455 Clean up Nanoleaf (#56732) 2021-09-28 15:39:54 -05:00
J. Nick Koston bc59387437 Explictly close the TPLink SmartDevice protocol on unload (#56743)
* Explictly close the TPLink SmartDevice protocol on unload

- There is a destructor that will eventually do this when
  the object gets gc. Its better to explictly do it at
  unload.

* fix coro mock
2021-09-28 18:36:45 +02:00
J. Nick Koston c95f7a5ba6 Add network support to tplink for discovery across subnets (#56721) 2021-09-28 09:58:25 -05:00
Maciej Bieniek 0044fa9fb9 Add support for pedestal MIOT fans to Xiaomi Miio integration (#56555)
* Add initial support for Xiaomi Fan ZA5

* Add sensor, number and switch platform

* Addionizer switch

* Improve ionizer icon

* Fix parent of XiaomiFanMiot class

* Add another MIOT models

* Fix consts

* Add powersupply attached binary sensor

* Simplify async_create_miio_device_and_coordinator

* Simplify XiaomiGenericFan

* Fix XiaomiFanZA5 parent

* Remove pass

* Remove unused _available variable

* 1C doesn't support direction

* Suggested change

* Use elif

* Clean up oscillation angle

* Fix typo
2021-09-28 10:21:14 +02:00
Joakim Sørensen b179301152 Adjust lock configuration (#56731) 2021-09-28 10:15:45 +02:00
Adrian Huber b64b926e13 Add raid monitoring to glances (#56623) 2021-09-28 10:04:08 +02:00
gjong 495e5cb1c0 Update YouLess library for support for PVOutput firmware (#55784) 2021-09-28 09:59:40 +02:00
Maciej Bieniek 2581a3a735 Add binary sensor platform to Tractive integration (#56635)
* Add binary sensor platform

* Update .coveragerc file

* Create battery charging sensor only if tracker supports it

* Improve async_setup_entry

* Add TRAXL1 model
2021-09-28 09:56:06 +02:00
jjlawren 0d6aa89fd4 Refactor Sonos alarms and favorites updating (#55529) 2021-09-28 09:49:32 +02:00
Diogo Gomes 922d4c42a3 Inherit Filter sensor state_class from source sensor (#56407) 2021-09-28 09:30:21 +02:00
Regev Brody 9d89e1ae00 Bump WazeRouteCalculator to 0.13 (#56718) 2021-09-28 09:25:34 +02:00
dependabot[bot] 8dc4824aac Bump dessant/lock-threads from 2.1.2 to 3 (#56727)
Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 2.1.2 to 3.
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/master/CHANGELOG.md)
- [Commits](https://github.com/dessant/lock-threads/compare/v2.1.2...v3)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-28 10:19:57 +03:00
Raman Gupta e690d4b006 Add support for zwave_js device actions (#53038)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-28 09:06:02 +02:00
Erik Montnemery 552485bb05 Tweak list_statistic_ids (#55845)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-28 00:05:26 -07:00
Oscar Calvo c48527858d Activate fault handler (#56550) 2021-09-28 00:05:06 -07:00
Myles Eftos 412ecacca3 Amberelectric (#56448)
* Add Amber Electric integration

* Linting

* Fixing some type hinting

* Adding docstrings

* Removing files that shouldn't have been changed

* Splitting out test helpers

* Testing the price sensor

* Testing Controlled load and feed in channels

* Refactoring mocks

* switching state for native_value and unit_of_measurement for native_unit_of_measurement

* Fixing docstrings

* Fixing requiremennts_all.txt

* isort fixes

* Fixing pylint errors

* Omitting __init__.py from test coverage

* Add missing config_flow tests

* Adding more sensor tests

* Applying suggested changes to __init.py__

* Refactor coordinator to return the data object with all of the relevent data already setup

* Another coordinator refactor - Better use the dictionary for when we build the sensors

* Removing first function

* Refactoring sensor files to use entity descriptions, remove factory

* Rounding renewable percentage, return icons correctly

* Cleaning up translation strings

* Fixing relative path, removing TODO

* Coordintator tests now accept new (more accurate) fixtures

* Using a description placeholder

* Putting missing translations strings back in

* tighten up the no site error logic - self._site_id should never be None at the point of loading async_step_site

* Removing DEVICE_CLASS, replacing the units with AUD/kWh

* Settings _attr_unique_id

* Removing icon function (it's already the default)

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Adding strings.json

* Tighter wrapping for try/except

* Generating translations

* Removing update_method - not needed as it's being overriden

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Fixing tests

* Add missing description placeholder

* Fix warning

* changing name from update to update_data to match async_update_data

* renaming [async_]update_data => [async_]update_price_data to avoid confusion

* Creating too man renewable sensors

* Override update method

* Coordinator tests use _async_update_data

* Using $/kWh as the units

* Using isinstance instead of __class__ test. Removing a zero len check

* Asserting self._sites in second step

* Linting

* Remove useless tests

Co-authored-by: jan iversen <jancasacondor@gmail.com>
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-09-28 00:03:51 -07:00
J. Nick Koston f93539ef4c Add api to the network integration to get ipv4 broadcast addresses (#56722) 2021-09-27 21:43:39 -07:00
J. Nick Koston aea754df5d Add dhcp support for TPLink KL60 and EP40 (#56726) 2021-09-27 22:45:53 -05:00
Erik Montnemery 8ef123259e Add WS API for updating unit_of_measurement in statistics metadata (#56184)
* Add WS API for updating statistics metadata

* Update homeassistant/components/recorder/websocket_api.py

Co-authored-by: Bram Kragten <mail@bramkragten.nl>

* Update homeassistant/components/recorder/websocket_api.py

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Fix typo

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-28 00:43:29 +02:00
Diogo Gomes ec9fc0052d Define unit_of_measurement of all utility_meter sensors on HA start (#56112)
* define unit_of_measurement on hass start

* delay utility_meter state

* check state

* store siblings

* don't check unit_of_measurement
2021-09-28 00:42:27 +02:00
Erik Montnemery 5976f898da Add WS API for removing statistics for a list of statistic_ids (#55078)
* Add WS API for removing statistics for a list of statistic_ids

* Refactor according to code review, enable foreign keys support for sqlite

* Adjust tests

* Move clear_statistics WS API to recorder

* Adjust tests after rebase

* Update docstring

* Update homeassistant/components/recorder/websocket_api.py

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Adjust tests after rebase

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-09-27 23:30:13 +02:00
tube0013 0653693dff Add usb discovery for tubeszb ch340B serial devices (#56719) 2021-09-27 16:19:42 -05:00
Michael Chisholm a28fd7d61b Config-flow for DLNA-DMR integration (#55267)
* Modernize dlna_dmr component: configflow, test, types

* Support config-flow with ssdp discovery
* Add unit tests
* Enforce strict typing
* Gracefully handle network devices (dis)appearing

* Fix Aiohttp mock response headers type to match actual response class

* Fixes from code review

* Fixes from code review

* Import device config in flow if unavailable at hass start

* Support SSDP advertisements

* Ignore bad BOOTID, fix ssdp:byebye handling

* Only listen for events on interface connected to device

* Release all listeners when entities are removed

* Warn about deprecated dlna_dmr configuration

* Use sublogger for dlna_dmr.config_flow for easier filtering

* Tests for dlna_dmr.data module

* Rewrite DMR tests for HA style

* Fix DMR strings: "Digital Media *Renderer*"

* Update DMR entity state and device info when changed

* Replace deprecated async_upnp_client State with TransportState

* supported_features are dynamic, based on current device state

* Cleanup fully when subscription fails

* Log warnings when device connection fails unexpectedly

* Set PARALLEL_UPDATES to unlimited

* Fix spelling

* Fixes from code review

* Simplify has & can checks to just can, which includes has

* Treat transitioning state as playing (not idle) to reduce UI jerking

* Test if device is usable

* Handle ssdp:update messages properly

* Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances

* Fix tests for transitioning state

* Mock DmrDevice.is_profile_device (added to support embedded devices)

* Use ST & NT SSDP headers to find DMR devices, not deviceType

The deviceType is extracted from the device's description XML, and will not
be what we want when dealing with embedded devices.

* Use UDN from SSDP headers, not device description, as unique_id

The SSDP headers have the UDN of the embedded device that we're interested
in, whereas the device description (`ATTR_UPNP_UDN`) field will always be
for the root device.

* Fix DMR string English localization

* Test config flow with UDN from SSDP headers

* Bump async-upnp-client==0.22.1, fix flake8 error

* fix test for remapping

* DMR HA Device connections based on root and embedded UDN

* DmrDevice's UpnpDevice is now named profile_device

* Use device type from SSDP headers, not device description

* Mark dlna_dmr constants as Final

* Use embedded device UDN and type for unique ID when connected via URL

* More informative connection error messages

* Also match SSDP messages on NT headers

The NT header is to ssdp:alive messages what ST is to M-SEARCH responses.

* Bump async-upnp-client==0.22.2

* fix merge

* Bump async-upnp-client==0.22.3

Co-authored-by: Steven Looman <steven.looman@gmail.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 15:47:01 -05:00
RenierM26 b15f11f46a Discover Switchbot MAC in config flow (#56616)
* Update config_flow.py

* Switchbot Config_flow discover mac instead of needing to type it.

* Do not show already configured devices in config flow, abort if no unconfigured devices.

* Apply suggestions from code review

Co-authored-by: J. Nick Koston <nick@koston.org>

* Move MAC to top of config flow form dict.

* Update homeassistant/components/switchbot/config_flow.py

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 15:12:40 -05:00
Teemu R b40d229369 Rework TPLink integration to use python-kasa (#56701)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Teemu R. <tpr@iki.fi>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-27 14:11:55 -05:00
Hung Nguyen 7a2bc130b7 Bump elkm1-lib to 1.0.0 (#56703) 2021-09-27 14:10:09 -05:00
Bastien Gautier 806fdc0095 Patch coinbase (#56426)
* Add Clover Finance coin to coinbase

* Add Fetch.ai coin to coinbase

* Fix typo
2021-09-27 20:39:43 +02:00
Marc Mueller 2f4e992662 Use EntityDescription - daikin (#55929) 2021-09-27 20:26:10 +02:00
Raman Gupta f0e0b41f77 Use entity attributes for vizio integration (#56093) 2021-09-27 20:20:15 +02:00
Marc Mueller 0dcd8b32ab Use EntityDescription - meteo_france (#55677) 2021-09-27 19:40:55 +02:00
Marc Mueller 71ce858378 Use EntityDescription - toon (#55035) 2021-09-27 19:37:12 +02:00
Erik Montnemery fe66d6295c Improve migration to recorder schema version 21 (#56204) 2021-09-27 19:31:40 +02:00
Steffen Zimmermann e5642a8648 Add state_class measurements in wiffi integration (#54279)
* add support for state_class measurements in wiffi integration

* use new STATE_CLASS_TOTAL_INCREASING for metered entities

like
- amount of rainfall per hour/day
- rainfall hours per day
- sunshine hours per day

* Update homeassistant/components/wiffi/sensor.py

Co-authored-by: Greg <greg.diehl.gtd@gmail.com>

Co-authored-by: Greg <greg.diehl.gtd@gmail.com>
2021-09-27 18:28:20 +02:00
Erik Montnemery 4d7e3cde5a Minor cleanup and test coverage improvement for MQTT (#55265) 2021-09-27 17:45:52 +02:00
Franck Nijhof eae828a15a Upgrade lupupy to 0.0.21 (#56636) 2021-09-27 17:42:13 +02:00
Michael Chisholm 805e73f78c Add UPNP device connection for Sonos (#56702) 2021-09-27 17:36:47 +02:00
Marc Mueller 70cc6295b5 Use EntityDescription - hydrawise (#55924) 2021-09-27 17:35:09 +02:00
Fredrik Oterholt 4d433e18ac Add more sensor types for airthings devices (#56706)
* add additional sensor types for airthings devices

* remove "out of ten" unit

* change unit on rssi

* remove device class for light

* disable by default
2021-09-27 13:27:02 +02:00
Marius 4ce7166afd Add node sensor status icons (#56137)
Co-authored-by: kpine <keith.pine@gmail.com>
Co-authored-by: Raman Gupta <7243222+raman325@users.noreply.github.com>
2021-09-27 12:50:14 +02:00
Marc Mueller 83b1b3e92c Use EntityDescription - tellduslive (#55928) 2021-09-27 12:28:58 +02:00
Michael f2debf5c01 Remove unnecessary extra attribute from Pi-hole sensors (#56076) 2021-09-27 12:27:03 +02:00
jan iversen 6da548b56a Strictly type modbus cover.py (#56381) 2021-09-27 12:26:25 +02:00
jan iversen 50f97b26eb Strictly type modbus climate.py (#56380) 2021-09-27 12:25:05 +02:00
Simone Chemelli b612e16120 Add current and latest firmware info to Synology_dsm (#56460) 2021-09-27 12:23:26 +02:00
Erik Montnemery 58f465f271 Don't reset meter when last_reset is set to None (#56609) 2021-09-27 12:17:09 +02:00
jjlawren 931cf4eaab Improve Sonos handling of TuneIn stations (#56479) 2021-09-27 12:07:14 +02:00
Robert Svensson ca6b53c16d Remove UniFi config entry reference from device when removing last entity of said device (#56501) 2021-09-27 12:04:29 +02:00
Erik Montnemery efe467217a Don't round in energy cost sensor (#56258) 2021-09-27 12:01:17 +02:00
Aaron Bach 56b94d6809 Simplify native value property for WattTime (#56664) 2021-09-27 11:58:51 +02:00
Franck Nijhof 4f5d6b8ba1 Upgrade sentry-sdk to 1.4.1 (#56707) 2021-09-27 11:20:43 +02:00
Erik Montnemery 14a1bb423c Add is_number template filter and function (#56705) 2021-09-27 10:47:57 +02:00
Fabian Affolter e4dc646237 Upgrade praw to 7.4.0 (#56682) 2021-09-27 08:48:21 +02:00
Michael Chisholm 6c2674734a SSDP starts config flow only for alive devices (#56551)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 08:39:22 +02:00
dependabot[bot] 0f313ec73c Bump home-assistant/builder from 2021.07.0 to 2021.09.0 (#56704)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-27 08:37:54 +02:00
J. Nick Koston 0fce9f39b3 Avoid checking if a package is installed if it already failed (#56698) 2021-09-26 22:32:25 -07:00
Fabian Affolter 01bd3ff138 Upgrade sendgrid to 6.8.2 (#56688) 2021-09-27 07:03:29 +02:00
Fabian Affolter 8884e9691e Upgrade TwitterAPI to 2.7.5 (#56687) 2021-09-27 07:03:09 +02:00
Fabian Affolter 55c9abc58d Upgrade discord.py to 1.7.3 (#56686) 2021-09-27 07:02:46 +02:00
Fabian Affolter 44a4507b51 Upgrade requests to 2.26.0 (#56683)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-26 21:44:28 -05:00
Fabian Affolter 115d34f55a Set certifi to >=2021.5.30 (#56679)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-26 21:19:30 -05:00
J. Nick Koston 7ab6c82ad2 Drop defusedxml dep from ssdp manifest (#56699) 2021-09-26 19:49:43 -05:00
J. Nick Koston 26e031984b Ensure sonos always gets ssdp callbacks from searches (#56591) 2021-09-26 17:16:03 -05:00
J. Nick Koston 6399730d2f Optimize SSDP matching (#56622)
* Optimize SSDP matching

* tweak

* remove

* remove dupe
2021-09-26 16:30:39 -05:00
J. Nick Koston f268227d64 Implement retry and backoff strategy for requirements install (#56580)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-09-26 14:47:03 -05:00
Raman Gupta 8716aa011a Add support for multilevel switch CC select entities (#56656)
* Add support for multilevel switch CC select entities

* Use state names from docs and include more device identifiers from device DB

* black

* pylint

* type fix

* Add failure scenario test

* Update homeassistant/components/zwave_js/select.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-26 14:22:41 -04:00
Fabian Affolter 2326e3ed94 Upgrade voluptuous to 0.12.2 (#56680) 2021-09-26 18:59:00 +02:00
J. Nick Koston 52410ff0d7 Ensure yeelight can be unloaded when device is offline (#56464) 2021-09-26 09:54:43 -07:00
J. Nick Koston 26f73779cc Avoid enabling ipv6 dual stack for zeroconf on unsupported platforms (#56584) 2021-09-26 09:51:34 -07:00
J. Nick Koston f74291ccb6 Expose the ability to move an entity/device between config entries (#56661) 2021-09-26 09:50:57 -07:00
Marc Mueller e35e584b60 Use EntityDescription - sht31 (#56435)
* Use EntityDescription - sht31

* Add device_class for humidity

* Fix monitored conditions

* Add pylint disable
2021-09-26 18:19:36 +02:00
Fabian Affolter 65bce33a63 Upgrade emoji to 1.5.0 (#56684) 2021-09-26 15:09:13 +02:00
Franck Nijhof bfefe82605 Upgrade pre-commit to 2.15.0 (#56677) 2021-09-26 14:47:47 +02:00
Fabian Affolter a0a359e2ef Upgrade ciso8601 to 2.2.0 (#56678) 2021-09-26 14:47:29 +02:00
Daniel Hjelseth Høyer d8387744ec Correct the device name for Airthings (#56655) 2021-09-26 12:48:27 +02:00
Aaron Bach 01e03a223b Simplify native value and attributes properties for Flu Near You (#56665) 2021-09-26 11:12:54 +02:00
Aaron Bach aeba3a703f Revert "Simplify state update for Flu Near You (#56650)" (#56662)
This reverts commit d4ebcf2ba5.
2021-09-25 17:19:17 -06:00
Robert Svensson 8db0bd3c0e Fix state_class for deCONZ power sensors (#56586)
* Fix state_class for power sensors
Rewrite entity descriptions for binary sensor and sensor platforms

* Remove icon if device_class is specified
2021-09-25 20:54:55 +02:00
Aaron Bach d4ebcf2ba5 Simplify state update for Flu Near You (#56650) 2021-09-25 20:22:51 +02:00
Franck Nijhof fabf5204be Ignore config directory symlink in development (#56639) 2021-09-25 12:53:41 +02:00
Franck Nijhof 83f1116432 Upgrade numpy to 1.21.2 (#56640) 2021-09-25 12:39:21 +02:00
Franck Nijhof 23e1c663d4 Upgrade pytest-xdist to 2.4.0 (#56606) 2021-09-25 12:07:29 +02:00
Matt Zimmerman 754ff7e3cb Update python-smarttub to 0.0.27 (#56626) 2021-09-25 12:06:41 +02:00
MatthewFlamm 8bc8081e81 Add state_class_measurement to nws (#56629) 2021-09-25 11:58:07 +02:00
Franck Nijhof 917254e956 Upgrade pyupgrade to v2.27.0 (#56638) 2021-09-25 11:48:47 +02:00
Franck Nijhof 57aaf55678 Upgrade pipdeptree to 2.1.0 (#56637) 2021-09-25 11:48:31 +02:00
Daniel Hjelseth Høyer f0de6dc21a Use SurePetcareEntity for surepetcare binary sensor (#56601)
* Use SurePetcareEntity for surepetcare binary sensor

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* tests

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-25 11:17:55 +02:00
Joakim Plate 5c1f55ffa4 Bump fjäråskupan to 1.0.1 (#56628) 2021-09-25 11:17:26 +02:00
Raman Gupta b1f4ccfd6b Reuse zwave_js device when replacing removed node with same node (#56599)
* Reuse zwave_js device when a removed node is replaced with the same node

* Ensure change is backwards compatible with servers that don't include replaced

* Remove lambda

* Add assertions to remove type ignores

* fix tests by always copying state and setting manufacturer/label attributes
2021-09-25 10:43:37 +02:00
Michaël Arnauts 5d3d6fa1cd Add state_class and use SensorEntityDescription for comfoconnect (#54066)
* Add state_class=measurement and use SensorEntityDescriptions

* Use attributes from entity_description

* Improvements

* Adress remarks

* Revert changes to fan

* move method

* Fix tests

* Revert fan/__init__.py

* Revert key change

* Set default percentage in turn_on
2021-09-24 22:26:56 +02:00
Aaron Bach 0ea5f25594 Add ability to re-auth Notion (#55616) 2021-09-24 11:23:19 -07:00
Robert Hillis a7d56d1c3f Bump goalzero to 0.2.0 (#56613)
* Bump goalzero to 0.1.8

* bump

* recheck

* bump
2021-09-24 12:18:14 -06:00
Eduard van Valkenburg ac576a2bc6 update SIA package (#56615) 2021-09-24 12:15:21 -06:00
RenierM26 3c80e05100 Set Switchbot _attr_is_closed on init (#56611)
* self._attr_is_closed needs to be set initially.

* Set _attr_is_closed on init.
2021-09-24 12:13:45 -06:00
Maikel Punie 8aff51042b Bump velbus-aio to 2021.9.4 (#56478)
* Bump version, move the cache-dir to the home-assistant config

* Moved the cahce into the storage dir

* Bump version, 2021.9.3 will use pathlib

* Bump version to 2021.9.4

* Clean config path

* Remove leading slash

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-24 20:09:44 +02:00
Robert Hillis e078f4ce14 Move efergy api to pyefergy (#56594)
* Move efergy api to pyefergy

* fix permissions

* tweak

* tweak
2021-09-24 12:54:15 +02:00
Franck Nijhof d7e121f3e8 Upgrade pytest to 6.2.5 (#56603) 2021-09-24 10:11:36 +02:00
Daniel Hjelseth Høyer aca00667df Add device info to Surepetcare (#56600) 2021-09-24 09:21:47 +02:00
Erik Montnemery 64393b462d Add migration for 5-minute statistics (#56585)
* Add migration for 5-minute statistics

* Tweaks
2021-09-24 09:19:22 +02:00
Erik Montnemery 7452998081 Convert last_reset timestamps to UTC (#56561)
* Convert last_reset timestamps to UTC

* Add test

* Apply suggestion from code review
2021-09-24 09:16:50 +02:00
Maciej Bieniek e62c9d338e Rework Tractive integration init (#55741)
* Rework integration init

* Suggested chancge

* Use Trackables class

* Use try..except for trackable_objects

* Check that the pet has tracker linked
2021-09-24 08:45:03 +02:00
Jan Bouwhuis e73ca9bd18 Alexa fix Fan support and cleanup (#56053)
* del PowerLevelController, ena fan PowerController

* Use AlexaRangeContoller for speed or default

* Update tests

* no-else-return

* Avoid cases with only one preset_mode

* Only report ghost_mode to Alexa - fix bug

* Add some tests for patched code

* pylint

* pylint and tests with one preset_mode

* correct ghost preset mode check in test

* add tests for RangeController

* ghost preset_mode locale agnostic

* isort

* Update homeassistant/components/alexa/capabilities.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* Update homeassistant/components/alexa/entities.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* Update homeassistant/components/alexa/entities.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* Update homeassistant/components/alexa/entities.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* Update homeassistant/components/alexa/entities.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* Update entities.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>
2021-09-24 08:14:45 +02:00
J. Nick Koston 0363c22dd8 Fix Sonos going offline with 13.3 firmware (#56590) 2021-09-23 20:39:20 -07:00
RenierM26 915afedcfc Add binary_sensor to switchbot (#56415)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-23 17:10:34 -05:00
Milan Meulemans 0b53f73fe2 Convert Nanoleaf integration to use Async library aionanoleaf (#56548) 2021-09-23 15:37:37 -05:00
Michael 7ece35cd6f Assume Fritz!Smarthome device as unavailable (#56542) 2021-09-23 13:29:12 -07:00
RenierM26 972db29c88 Add sensor to switchbot platform (#56416)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-23 15:27:34 -05:00
Daniel Hjelseth Høyer 6e7bc65e2e Airthings (#56578) 2021-09-23 13:20:30 -07:00
Daniel Hjelseth Høyer a94514b00d Add Surepetcare entity class (#56430) 2021-09-23 13:19:46 -07:00
Rami Mosleh 4c40d1767a Remove config for Speedtest.net (#55642) 2021-09-23 20:44:59 +02:00
Franck Nijhof 7fc0717ab1 Upgrade debugpy to 1.4.3 (#56576) 2021-09-23 11:12:19 -07:00
Franck Nijhof 750a1b84ad Add date device_class to Twente Milieu sensors (#56579) 2021-09-23 11:09:00 -07:00
Marc Mueller fed5f5e3b9 Use EntityDescription - fitbit (#55925) 2021-09-23 20:08:47 +02:00
Franck Nijhof 60bb3121b6 Upgrade apprise to 0.9.5.1 (#56577) 2021-09-23 11:00:45 -07:00
Kevin Worrel b43d377b53 Create but disable-by-default RPM and GPM sensors (#56549) 2021-09-23 11:00:33 -07:00
Andre Richter a5c6a65161 Activate mypy for Vallox (#55874) 2021-09-23 10:59:28 -07:00
Franck Nijhof 2fe8c78811 Fix Toon push updates (#56583) 2021-09-23 19:50:30 +02:00
jan iversen 1cc850877f strictly type: fan.py, light.py, switch.py. (#56379) 2021-09-23 18:35:50 +01:00
Brian O'Connor cce906f968 Fix OpenWeatherMap dewpoint conversion (#56303) 2021-09-23 10:14:15 -07:00
Marc Mueller 70f10338cc Use EntityDescription - solaredge_local (#56434) 2021-09-23 18:29:58 +02:00
Joakim Sørensen 98d0c84468 Enable strict typing for the tautulli integration (#55448) 2021-09-23 16:56:21 +02:00
Aaron Bach 1a47fcc4e3 Add long-term statistics for OpenUV sensors (#55417) 2021-09-23 16:54:06 +02:00
Marc Mueller b634bd26d0 Use EntityDescription - kraken (#56436) 2021-09-23 16:42:55 +02:00
Franck Nijhof c1df49e9fc Upgrade black to 21.9b0 (#56575) 2021-09-23 16:33:24 +02:00
Jc2k 442d850fc9 Bump aiohomekit to 0.6.3 (#56574) 2021-09-23 16:30:15 +02:00
Franck Nijhof 237efcf6b1 Upgrade colorlog to 6.4.1 (#56573) 2021-09-23 16:12:13 +02:00
Franck Nijhof bdef131294 Upgrade watchdog to 2.1.5 (#56572) 2021-09-23 16:11:47 +02:00
Franck Nijhof 71ab24f350 Upgrade pre-commit to 2.14.1 (#56569) 2021-09-23 16:11:29 +02:00
Franck Nijhof 655dc890e4 Upgrade PyTurboJPEG to 1.6.1 (#56571) 2021-09-23 15:34:34 +02:00
J. Nick Koston a6ccb1821e Update zeroconf to 0.36.7 (#56553) 2021-09-23 08:00:17 -05:00
Erik Montnemery f0a4a89d21 Add comments to recorder statistics code (#56545)
* Add comments to recorder statistics code

* Revert accidental change of list_statistic_ids
2021-09-23 13:14:45 +02:00
Ricardo Steijn 63610eadc9 Address Crownstone review comments (#56485) 2021-09-23 09:23:45 +02:00
Oscar Calvo ea8f624f28 Fix an issue where core process crashes when an SMS is received (#56552) 2021-09-22 21:49:08 -07:00
Erik Montnemery 83156fb9ec Energy validation: Require last_reset attribute to be set for state_class measurement energy and cost sensors (#56254)
* Require last_reset attribute to be set for measurement state_class

* Tweak

* Improve tests

* Lint

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-22 21:48:37 -07:00
Paulus Schoutsen 974376a8de Bump frontend to 20210922.0 (#56546) 2021-09-22 16:20:58 -07:00
Paulus Schoutsen 677abcd484 Allow confirming local push notifications (#54947)
* Allow confirming local push notifications

* Fix from Zac

* Add tests
2021-09-22 23:17:04 +02:00
Erik Montnemery f77e93ceeb Fix validation of cost entities for energy dashboard (#56219) 2021-09-22 13:57:58 -07:00
Sian 351ef0ab44 Register Google assistant energy storage trait (#56520) 2021-09-22 13:36:03 -07:00
Erik Montnemery 92253f5192 Minor refactoring of periodic statistics (#56492) 2021-09-22 13:31:33 -07:00
Ville Skyttä d8d34fdd3b Prefer HTTPStatus over int in HA view JSON functions (#56504)
* Prefer HTTPStatus over int in HA view JSON functions

* Update zwave tests to not expect a fixed typo
2021-09-22 21:59:52 +03:00
Paulus Schoutsen 39aaa383b3 Fix flaky srp energy test (#56536) 2021-09-22 17:41:10 +02:00
Alexei Chetroi a5d405700c ZHA channel ZCL attributes initialization (#56476)
* Add dict of attributes to initialize

* Refactor get_attributes() method

Read 5 attributes at the time.

* Add ZCL_INIT_ATTRS attribute to base Zigbee channel

* Update tests and general clusters

* Update channels to use ZCL_INIT_ATTRS

* Update channels to use ZCL_INIT_ATTRS

* Fix tests

* Refactor async_initialize() to be a retryable request

* Maky pylint happy again
2021-09-22 11:34:30 -04:00
Tobias Sauerwein 2478ec887a Allow camera usage with HA cloud (#56533) 2021-09-22 16:54:12 +02:00
Paulus Schoutsen e34c985534 Simplify cloud request connection handling (#56243)
Co-authored-by: Pascal Vizeli <pascal.vizeli@syshack.ch>
2021-09-22 07:51:31 -07:00
Erik Montnemery ac053388b4 Convert image_processing tests to pytest (#56451)
* Convert image_processing tests to pytest

* Use existing fixtures and test helpers

* Remove useless code
2021-09-22 15:00:28 +02:00
Tobias Sauerwein 26d310fc8a Split Netatmo camera persons by home (#55598)
* Split persons by home
* Bump pyatmo to 6.0.0
* Check is person exists
* Extract method for fetching person ids
2021-09-22 14:32:30 +02:00
Roel van der Ark aab4b5ec06 Add extra power meter for YouLess (#56528)
* #55535 added extra power meter

* Update sensor.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>
2021-09-22 14:08:23 +02:00
Niklas Åström 783cc1eacd Optimise requests to the tado servers (#56261)
This avoids calling the tado servers unnecessarily many times, especially for bigger homes. This is done by calling aggregating endpoints instead of iterating over the zones and devices and calling endpoints over and over.
2021-09-22 14:01:30 +02:00
Robert Hillis a653da137c Use EntityDescription - efergy (#54210) 2021-09-21 16:53:35 -05:00
Bas Nijholt b7a758bd0c raise PlatformNotReady when speakers unreachable (#56508)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-09-21 14:35:51 -07:00
J. Nick Koston 9831ff0487 Avoid deadlock on shutdown when a task is shielded from cancelation (#56499) 2021-09-21 14:35:14 -07:00
Erik Montnemery d494b3539d Prevent 3rd party lib from opening sockets in google_assistant tests (#56346) 2021-09-21 11:27:10 -07:00
Ville Skyttä 1aa7c87151 Remove redundant aiohttp response status=200 kwargs (#56417)
* Remove redundant aiohttp response status=200 kwargs

* Remove some more in h.c.auth

* Restore explicit status=HTTP_OK for auth and webhook per review request
2021-09-21 10:51:12 -07:00
RenierM26 26e9590927 Add cover platform to switchbot (#56414)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-21 12:35:47 -05:00
jan iversen 34de74d869 Strictly type tradfri config_flow.py (#56391)
* Strictly type config_flow.py.

* Review comments.
2021-09-21 16:23:10 +02:00
Justin Goette 56b66d5124 typo (#56477) 2021-09-21 15:09:21 +01:00
jan iversen c7c789f618 Strictly type modbus __init__.py, validator.py (#56378)
* strictly type: __init__.py, validator.py
2021-09-21 13:43:41 +02:00
jan iversen 518c99c8b7 Strictly type tradfri cover.py (#56390)
* Strictly type cover.py.

* Review comments from other PR.

* Update homeassistant/components/tradfri/cover.py

Co-authored-by: Ruslan Sayfutdinov <ruslan@sayfutdinov.com>

* Update homeassistant/components/tradfri/cover.py

Co-authored-by: Ruslan Sayfutdinov <ruslan@sayfutdinov.com>

* Update homeassistant/components/tradfri/cover.py

Co-authored-by: Ruslan Sayfutdinov <ruslan@sayfutdinov.com>

* Update homeassistant/components/tradfri/cover.py

Co-authored-by: Ruslan Sayfutdinov <ruslan@sayfutdinov.com>
2021-09-21 12:15:45 +01:00
Pascal Vizeli 7698c179ac Upgrade cryptography to 3.4.8 (#56481)
* Upgrade cryptography to 3.4.8

* Fix file
2021-09-21 11:06:52 +02:00
Oscar Calvo f9fde7f7a1 Support unicode in SMS messages (#56468) 2021-09-21 10:07:14 +02:00
Elliot Morales Solé 097fae0348 Correct Alexa scene activation (#56469)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-20 22:51:17 -07:00
Paulus Schoutsen d4864f5750 Deprecate passing template to notify (#56069) 2021-09-20 21:49:02 -07:00
Aaron Bach aabc8cd2d5 Add WattTime integration (#56149) 2021-09-20 21:10:24 -07:00
Paulus Schoutsen 9059ee6604 Merge pull request #56472 from home-assistant/shelly-gen2 2021-09-20 20:19:19 -07:00
Marcin Ciupak b9ffd74db5 Fix recorder Oracle DB models (#55564)
* Fix recorder models for Oracle DB

* Fix StatisticsRuns

* Update migration for Oracle Identity columns.

* Update migration logic

Migration to schema version 22 done only for engine dialect oracle

* Add missing table check in schema 22 migration
2021-09-21 00:38:42 +02:00
Marc Mueller 20ddd092f6 Remove xiaomi_aqara entity_description property (#56456) 2021-09-21 00:14:33 +02:00
Shay Levy 47340802b3 Add Shelly RPC device trigger and logbook platforms (#56428)
* Add RPC device trigger and logbook platforms

* Single input event for Block and RPC

* Add device generation to shelly.click
2021-09-21 00:09:44 +03:00
jan iversen df56953c98 Strictly type tradfri light.py (#56389)
* Strictly type light.py.
2021-09-20 21:54:50 +02:00
Shay Levy 542f637ac4 Improve Shelly light application/consumption type handling (#56461) 2021-09-20 11:12:18 -07:00
J. Nick Koston 9e2a29dc37 Improve yeelight stability by moving timeout handling to upstream library (#56432) 2021-09-20 12:32:01 -05:00
jan iversen f3ad4ca0cc Strictly type modbus.py. (#56375) 2021-09-20 18:47:05 +02:00
Marc Mueller 4c4bd740f3 Use EntityDescription - flume (#56433) 2021-09-20 11:13:09 -05:00
Erik Montnemery 6f36419c6f Improve statistics validation (#56457) 2021-09-20 17:54:25 +02:00
Erik Montnemery fc4bb40a63 Prevent opening sockets in panasonic_viera tests (#56441) 2021-09-20 15:01:49 +02:00
jan iversen a84e86ff13 Strictly type modbus base_platform.py (#56343) 2021-09-20 14:59:30 +02:00
Maciej Bieniek bb6f97c4d3 Rework Xiaomi Miio fan platform (#55846) 2021-09-20 14:49:39 +02:00
jan iversen 93e9a67d7d Make tradfri base_class.py strictly typed (#56341)
* Make base_class.py strictly typed.
2021-09-20 14:33:50 +02:00
Erik Montnemery 5c717cbb1d Prevent opening of sockets in onboarding tests (#56443) 2021-09-20 13:56:50 +02:00
Otto Winter a54854d129 ESPHome Noise Transport Encryption support (#56216) 2021-09-20 09:02:17 +02:00
mbo18 be19c676fa Add missing generic-x86-64 image (#56424) 2021-09-20 08:55:07 +02:00
jan iversen ddd31951bc Strictly type sensor.py. (#56377) 2021-09-20 07:35:11 +02:00
Diogo Gomes b05c1b516e restore float and not string (#56406) 2021-09-20 07:31:58 +02:00
J. Nick Koston b060c025ce Bump zeroconf to 0.36.6 (#56438)
- Performance improvements (faster HomeKit startup)

Changelog: https://github.com/jstasiak/python-zeroconf/compare/0.36.5...0.36.6
2021-09-20 07:00:46 +02:00
Daniel Hjelseth Høyer 00f7548fa0 Surepetcare, strict typing (#56425)
* Surepetcare, strict typing

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Surepetcare, strict typing

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-19 20:57:28 +02:00
Milan Meulemans d76163e5be Add tests for Rituals Perfume Genie number, select and binary_sensor platforms (#55224) 2021-09-19 08:51:57 -10:00
Maciej Bieniek ea189f930a Use attrs in Xiaomi Miio humidifier platform (#56371)
* Use attrs in humidifier platform

* Cleanup min/max humidity attrs
2021-09-19 17:04:33 +02:00
Joakim Sørensen 713d294627 Use _attr_* for the GitHub integration (#56419) 2021-09-19 15:10:51 +02:00
J. Nick Koston 88e42a540e Remove leftover debug prints in tests (#56409) 2021-09-19 12:43:02 +02:00
Erik Montnemery ec52763706 Prevent 3rd party lib from opening sockets in samsungtv tests (#56334) 2021-09-18 22:24:27 -10:00
Erik Montnemery 80a57f5118 Prevent 3rd party lib from opening sockets in smhi tests (#56335) 2021-09-19 10:18:45 +02:00
J. Nick Koston 75c029c56b Bump zeroconf to 0.36.5 (#56413) 2021-09-18 21:52:09 -10:00
Daniel Hjelseth Høyer a57d7717a8 Improve Surepetcare set_pet_location service (#56401)
* Surepetcare, improve set_pet_location

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Surepetcare, improve set_pet_location

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Surepetcare, improve set_pet_location

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Surepetcare, improve set_pet_location

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Surepetcare, improve set_pet_location

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-19 08:38:43 +02:00
Aidan Timson 53d4c0ce2d Increase Lyric update interval to 300 seconds (#56393) 2021-09-18 13:34:28 -10:00
Marc Mueller 7af67d34cf Use assignment expressions 01 (#56394) 2021-09-18 13:31:35 -10:00
Marc Mueller a4f6c3336f Use EntityDescription - august (#56395) 2021-09-18 13:10:15 -10:00
jan iversen 9b710cad5d Add strict typing to tradfri __init__ and switch (#56002)
* Add strict typing to __init__ and switch.

* Review comments.

* Review comments.

* Corrected switch.
2021-09-18 23:24:35 +02:00
Erik Montnemery f6526de7b6 Use hass_client_no_auth test fixture in nest tests (#56326) 2021-09-18 23:17:09 +02:00
Daniel Hjelseth Høyer 8b64cd7e7d Bump pyTibber to 0.19.1 (#56405)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-18 23:15:39 +02:00
Erik Montnemery 43b5dcff76 Use hass_client_no_auth test fixture in withings tests (#56337) 2021-09-18 23:12:02 +02:00
Robert Svensson bf7c2753d5 deCONZ use siren platform (#56397)
* Add siren.py

* Working siren platform with 100% test coverage

* Also add test file...

* Add test to verify that switch platform cleans up legacy entities now that sirens are their own platform

* Update homeassistant/components/deconz/siren.py

Co-authored-by: jjlawren <jjlawren@users.noreply.github.com>
2021-09-18 21:59:04 +02:00
jan iversen 6b6e26c96d Strictly type binary_sensor.py. (#56376) 2021-09-18 20:54:11 +01:00
jan iversen 5c19368ce3 Strictly type sensor.py (#56388) 2021-09-18 20:49:47 +01:00
RenierM26 3ce8109e5e Add config flow to Switchbot (#50653)
Co-authored-by: Daniel Hjelseth Høyer <mail@dahoiv.net>
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-18 09:25:05 -10:00
jjlawren f31b9eae61 Fix creating cert_expiry configs during runtime (#56298)
* Fix creating cert_expiry configs during runtime

* Address review feedback on tests

* Improve delayed startup test
2021-09-18 19:54:54 +02:00
Ashley 'DrToxic' Devine 312a9e5df2 Add Shiba Inu coin to coinbase (#56304)
Added SHIB coin
2021-09-18 18:49:29 +02:00
Daniel Hjelseth Høyer f97cce6f57 Surepetcare, service to set pet location (#56198)
* Surepetcare, add handle_set_pet_location

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Surepetcare, add handle_set_pet_location

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Surepetcare, add handle_set_pet_location

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-18 17:48:58 +02:00
Paulus Schoutsen 9ffdc2594f Merge pull request #56366 from home-assistant/rc 2021-09-18 08:29:25 -07:00
Maciej Bieniek 0a5948dc8b Fetch the data a second time when -9999 error occurs in Xiaomi Miio integration (#56288) 2021-09-18 07:39:28 -07:00
Marc Mueller 811feb69ba Fix dangerous brackets (#56384) 2021-09-18 16:08:22 +02:00
Simone Chemelli 0a5fdb2e68 Address late review of samsungtv (#56382) 2021-09-18 15:42:36 +02:00
Marc Mueller 48bada5a18 Update pylint to 2.11.1 (#56364) 2021-09-18 13:52:59 +02:00
jan iversen 476d04e2fb Activate mypy. (#55965) 2021-09-18 10:02:24 +01:00
Erik Montnemery 39bc127dd6 Prevent 3rd party lib from opening sockets in glances tests (#56345) 2021-09-17 22:22:44 -10:00
Erik Montnemery be0819b456 Mock out network.util.async_get_source_ip in tests (#56339) 2021-09-17 21:40:58 -10:00
J. Nick Koston 0830100df1 Do not reload the isy994 on ip change since there is already a reload listener (#54602) 2021-09-17 21:22:14 -10:00
Robert Svensson 539ef31046 Reflect changes to pydeconz v84 (#56361)
Mostly snake case conversions and typing
But also a change in retry mechanism
Added a more complete set_* call to most types to remove the direct relation to rest API of deCONZ
2021-09-18 09:05:08 +02:00
jan iversen 6947912fa9 Modbus entity update does not occur until after scan_interval (#56221)
* Secure update is called when integration is started.

* Review comments.

* Update homeassistant/components/modbus/base_platform.py

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Update homeassistant/components/modbus/base_platform.py

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-09-18 08:57:27 +02:00
Sean Vig 02ba3c6089 Update amcrest version to 1.9.3 (#56348)
This version fixes a bug that affects the current non-async Home Assistant integration
2021-09-18 08:34:51 +02:00
Paulus Schoutsen f8d62866e5 Bumped version to 2021.9.7 2021-09-17 22:48:16 -07:00
J. Nick Koston 3046adf3b2 Fix yeelight nightlight mode (#56363) 2021-09-17 22:48:09 -07:00
Shay Levy 22307066bb Bump aioswitcher to 2.0.6 (#56358) 2021-09-17 22:48:08 -07:00
Joakim Plate 8c936b320e Avoid sending Standby when already off (#56306) 2021-09-17 22:48:07 -07:00
Erik Montnemery 9c4d6afb3c Bump pychromecast to 9.2.1 (#56296) 2021-09-17 22:48:06 -07:00
Aaron Bach 0442ed54e8 Bump pyopenuv to 2.2.1 (#56270) 2021-09-17 22:48:06 -07:00
J. Nick Koston 3224fc8710 Fix HomeKit requests with hvac mode and temperature in the same call (#56239) 2021-09-17 22:48:05 -07:00
Joakim Sørensen 6f40759ed0 Update docker base image to 2021.09.0 (#56191) 2021-09-17 22:48:04 -07:00
jjlawren 07ba24ac5a Bump plexapi to 4.7.1 (#56163) 2021-09-17 22:48:03 -07:00
Martin Ilievski c0c85a6641 Bump pykodi to 0.2.6 (#56148) 2021-09-17 22:48:03 -07:00
J. Nick Koston 162fab91b2 Ensure rainmachine device name is a string (#56121) 2021-09-17 22:48:02 -07:00
muppet3000 6e80d27770 Bump growattServer to 1.1.0 (#56084) 2021-09-17 22:48:01 -07:00
Brian Egge 2b58a266cc Fix generic thermostat switch state initialization (#56073) 2021-09-17 22:48:00 -07:00
Oscar Calvo bd17da0524 Support incoming SMS messages via polling (#54237)
* Add support to incomming SMS via polling

* Update dependencies

* Only send notification for unread messages

* Only inform if callback is not getting used

* Update gateway.py

* Apply PR feedback

* Update homeassistant/components/sms/gateway.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Apply PR comments

* Make black happy

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-17 22:47:59 -07:00
J. Nick Koston 7524daad86 Fix HomeKit requests with hvac mode and temperature in the same call (#56239) 2021-09-17 22:47:06 -07:00
Shay Levy aaadd42539 Bump aioswitcher to 2.0.6 (#56358) 2021-09-17 22:42:58 -07:00
J. Nick Koston b6763c7245 Fix yeelight nightlight mode (#56363) 2021-09-17 22:26:25 -07:00
J. Nick Koston eb98ac9415 Allow IntegrationNotFound when checking config in safe mode (#56283)
Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-09-17 22:25:50 -07:00
J. Nick Koston bad6b2f7f5 Standardize yeelight exception handling (#56362) 2021-09-17 22:25:19 -07:00
Simone Chemelli 4160a5ee3b Strict typing for SamsungTV (#53585)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-17 18:51:07 -10:00
Alexei Chetroi f5dd71d1e0 Bump up ZHA dependencies (#56359) 2021-09-17 19:52:49 -04:00
jan iversen c4195c547c Update template/test_init.py to use pytest (#56336) 2021-09-17 15:13:17 -07:00
Milan Meulemans f64aa0f8df Fix netgear strings (#56351) 2021-09-17 22:43:23 +02:00
J. Nick Koston e880f1c8f9 Index config entries by domain (#56316) 2021-09-17 10:39:00 -10:00
Alexei Chetroi 5b0e00a74b Refactor ZHA HVAC thermostat channel (#56238)
* Refactor HVAC channel to use zigpy cached attributes

* Allow named attributes in ZHA test attribute reports

* Let attribute write to update cache

* WIP Update tests

* Cleanup
2021-09-17 15:17:34 -04:00
Daniel Hjelseth Høyer 16832bc35b AutomationTriggerInfo as type in rfxtrx (#56353)
* AutomationTriggerInfo as type in rfxtrx

* style

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-17 20:01:00 +02:00
Erik Montnemery 45046941c6 Avoid creating sockets in homekit port available tests (#56342) 2021-09-17 04:16:57 -10:00
Joakim Plate 9b00e0cb7a Rfxtrx device triggers and actions (#47909)
* Add helper

* Add device actions

* Add trigger

* Just make use of standard command

* Generalize code a bit

* Switch tests to currently existing features

* Add tests for capabilities

* Don't check schema asserted value

* Adjust strings somewhat

* Directly expose action subtypes

* Add a status event test

* Switch to modern typing

* Drop chime that is now part of command

* Adjust strings a bit

* Drop ability to set custom value

* Adjust changed base schema

* Validate triggers

* Try fix typing for 3.8
2021-09-17 15:28:43 +02:00
Erik Montnemery ecf4a7813a Prevent 3rd party lib from opening sockets in wilight tests (#56310) 2021-09-17 15:27:26 +02:00
Shay Levy 5249c89c3f Add Shelly RPC sensor and binary sensor platforms (#56253) 2021-09-17 15:53:39 +03:00
Erik Montnemery 797b68b42d Prevent 3rd party lib from opening sockets in rfxtrx tests (#56331) 2021-09-17 12:51:40 +02:00
Erik Montnemery 55a77b2ba2 Prevent 3rd party lib from opening sockets in ps4 tests (#56330) 2021-09-17 12:51:25 +02:00
Erik Montnemery 327bf24940 Prevent 3rd party lib from opening sockets in cloud tests (#56328) 2021-09-17 12:50:59 +02:00
Erik Montnemery e0a232aa36 Prevent 3rd party lib from opening sockets in wallbox tests (#56308) 2021-09-17 12:50:11 +02:00
Erik Montnemery a793fd4134 Prevent 3rd party lib from opening sockets in ping tests (#56329) 2021-09-16 23:41:19 -10:00
Erik Montnemery bce4c5eb11 Prevent 3rd party lib from opening sockets in zeroconf tests (#56324) 2021-09-16 23:19:32 -10:00
Erik Montnemery fce7f0873e Prevent 3rd party lib from opening sockets in sia tests (#56325) 2021-09-16 23:19:19 -10:00
J. Nick Koston 8814c53504 Bump zeroconf to 0.36.4 (#56314) 2021-09-16 21:04:54 -10:00
Sean Vig 6d99a7a730 Add unique id to amcrest sensors (#55243)
* Add unique id to amcrest sensors

* Change 'unique_id' to 'serial_number' on api wrapper

* Update unique id's with channel value that can be used in future changes and remove unrelated camera changes
2021-09-17 07:48:17 +02:00
Joakim Plate 175f207d28 Avoid sending Standby when already off (#56306) 2021-09-17 06:50:46 +02:00
Erik Montnemery 8341ae12d3 Mock out zeroconf in homekit_controller tests (#56307) 2021-09-16 11:29:41 -10:00
jan iversen 70eb519f76 Update template/test_light.py to use pytest (#56300) 2021-09-16 11:05:00 -07:00
jan iversen 94f06f86cf Activate mypy for gpmdp. (#55967) 2021-09-16 20:05:08 +03:00
Erik Montnemery 15a7fe219d Bump pychromecast to 9.2.1 (#56296) 2021-09-16 20:01:02 +03:00
Maciej Bieniek 41bf1eb610 Fetch the data a second time when -9999 error occurs in Xiaomi Miio integration (#56288) 2021-09-16 09:19:41 -07:00
Shay Levy 8418d4ade2 Address Switcher late review comments (#56264)
* Address Switcher late review comments

* Rename wrapper to coordinator
2021-09-16 17:06:58 +02:00
Chris Browet 1609d069bb Fix Meteoalarm expired alerts (#56255) 2021-09-16 16:07:53 +02:00
Paul Owen 28b4b5407b Fix return value of preset_mode in hive climate (#56247) 2021-09-16 13:57:42 +02:00
jjlawren 0438c9308c Delay startup for cert_expiry to allow for self checks (#56266)
* Delay startup of cert_expiry

* Update tests
2021-09-16 13:31:36 +02:00
Erik Montnemery c668dcb1ac Allow smaller step size for input number (#56211)
* Allow smaller step size for input number

* Tweak

* Tweak
2021-09-16 11:07:14 +02:00
Erik Montnemery 8c5efafdd8 Add 5-minute statistics for sensors (#56006)
* Add 5-minute statistics for sensors

* Address pylint issues

* Black

* Apply suggestion from code review

* Apply suggestions from code review

* Improve tests
2021-09-16 10:57:15 +02:00
Malachi Soord 0656407561 Upgrade pylast from 4.2.0 to 4.2.1 (#56015)
* Upgrade pylast from 4.2.0 to 4.2.1

* Fix test

* Use MockNetwork

* Tidy

* Fix lint
2021-09-16 07:00:25 +02:00
Sean Vig 69ff7a968a Bump amcrest version to 1.9.2 (#56281) 2021-09-16 06:53:40 +02:00
Daniel Hjelseth Høyer 4eb656d5d9 Fix Surepetcare string reference (#56262)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-15 22:18:35 +02:00
Aaron Bach ecd827722b Bump pyopenuv to 2.2.1 (#56270) 2021-09-15 21:05:12 +02:00
Daniel Hjelseth Høyer c5544550b4 Deprecate Surepetcare yaml config (#56209) 2021-09-15 10:43:39 +02:00
muppet3000 19054e1ffe Bump growattServer to 1.1.0 (#56084) 2021-09-15 10:08:15 +02:00
jjlawren 0619069ae6 Avoid a zeroconf race condition (#56240) 2021-09-14 22:07:31 -10:00
jan iversen 53d5a59257 Activate mypy for directv (#55963)
* Activate mypy for directv.

* Activate mypy for directv.
2021-09-15 07:58:04 +02:00
Shulyaka ddfe94187e generic_hygrostat: enable tests (#56193) 2021-09-15 07:55:43 +02:00
epenet 0d842a8f01 Adjust charging_power unit (#56167) 2021-09-15 07:54:56 +02:00
Steven Looman 30c25d4448 Clean up upnp YAML config (#56200)
* Put back local_ip option to config schema + deprecate config schema

* More cleanup

* Remove log

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-15 06:57:02 +02:00
Paulus Schoutsen 0a426b5686 Bump aiohue to 2.6.2 (#56234) 2021-09-15 06:23:19 +02:00
J. Nick Koston 98cf34c7c3 Bump zeroconf to 0.36.3 (#56233) 2021-09-14 13:02:37 -10:00
jan iversen 692f611109 Update template/test_fan.py to use pytest (#56215) 2021-09-14 13:51:46 -07:00
Aaron Bach bbc75b5c00 Add long-term statistics for Flu Near You sensors (#55416) 2021-09-14 22:09:45 +02:00
Aaron Bach 441e99b439 Add long-term statistics for AirVisual sensors (#55415) 2021-09-14 22:08:54 +02:00
jan iversen 96a9af8cc4 Update template/test_weather.py to use pytest (#56223) 2021-09-14 13:06:55 -07:00
Aaron Bach 2c348dd2d7 Add long-term statistics for RainMachine sensors (#55418)
* Add long-term statistics for RainMachine sensors

* Code review
2021-09-14 22:06:40 +02:00
jan iversen 4b2ff0a0ba Update template/alarm_control_panel.py to use pytest (#56229) 2021-09-14 13:06:29 -07:00
Marc Mueller 2b51896d7a Use EntityDescription - vicare (#55932)
* Use EntityDescription - vicare binary_sensor

* Use EntityDescription - vicare sensor

* Fix typing

* Remove default values

* Fix pylint
2021-09-14 22:06:06 +02:00
Aaron Bach 0364922d80 Add long-term statistics for AirNow sensors (#56230) 2021-09-14 22:04:55 +02:00
Ricardo Steijn 2a51bb5bba Add Crownstone integration (#50677) 2021-09-14 09:46:52 -10:00
Erik Montnemery bac55b78fe Enforce device class for gas and energy sensors used by energy dashboard (#56218)
* Enforce device class for gas and energy sensors used by energy dashboard

* Adjust tests
2021-09-14 16:56:36 +02:00
jan iversen aaa62dadec Add service to stop/restart modbus (#55599)
* Add service to stop/restart modbus.

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-14 09:42:50 +02:00
dependabot[bot] 31623368c8 Bump codecov/codecov-action from 2.0.3 to 2.1.0 (#56210)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 2.0.3 to 2.1.0.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v2.0.3...v2.1.0)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-14 08:50:29 +02:00
Daniel Hjelseth Høyer dba2998e8c Clean up Surepetcare binary sensor (#56070) 2021-09-14 08:44:20 +02:00
Alexei Chetroi fe1311ba34 Bump up zha dependencies (#56206) 2021-09-13 21:27:29 -04:00
Robert Hillis 14aa9c91eb Add Config Flow to Modem Caller ID integration (#46677)
* Add phone_modem integration

* Use original domain

* Add init tests for Modem Caller ID

* Clean up tests

* Clean up tests

* apply suggestions

* Fix tests

* Make only one instance possible

* Allow more than 1 device and remove hangup service

* simplify already configured

* Update sensor.py

* Update config_flow.py

* Fix manifest

* More cleanup

* Fix tests

* Ue target

* Clean up sensor.py

* Minor tweaks

* Close modem on restart and unload

* Update requirements

* fix tests

* Bump phone_modem

* rework

* add typing

* use async_setup_platform

* typing

* tweak

* cleanup

* fix init

* preserve original name

* remove callback line

* use list of serial devices on host

* tweak

* rework

* Rework for usb dicsovery

* Update requirements_test_all.txt

* Update config_flow.py

* tweaks

* tweak

* move api out of try statement

* suggested tweaks

* clean up

* typing

* tweak

* tweak

* async name the service
2021-09-13 14:22:54 -10:00
tube0013 9bb9f0e070 Add description to match TubesZB Coordinators for USB Discovery (#56201) 2021-09-13 11:22:55 -10:00
Brian Egge 8d87f4148b Fix generic thermostat switch state initialization (#56073) 2021-09-13 22:27:06 +02:00
Abílio Costa c869b78ac1 Add Whirlpool integration (#48346)
* Add Whirlpool integration

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Apply suggestions from code review

* Fix lint

* Fix lint and tests

* Apply suggestions from code review

Co-authored-by: J. Nick Koston <nick@koston.org>

* Use dict lookups

* Lint

* Apply code changes from PR review

* Do real integration setup in tests

* Apply suggestions from review & fix test

* Replace get with array operator

* Add suggestions from code review

* Rename test var

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-13 10:02:34 -10:00
Martin Ilievski f023ec24d7 Bump pykodi to 0.2.6 (#56148) 2021-09-13 10:00:10 -10:00
Daniel Hjelseth Høyer f9de8fb49a Surepetcare config flow (#56127)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-13 09:57:06 -10:00
Michael d661a76462 Use entity description and set state class to all System Monitor sensors (#56140) 2021-09-13 09:55:33 -10:00
Joakim Sørensen 20d96ef4ef Update docker base image to 2021.09.0 (#56191) 2021-09-13 21:11:10 +02:00
Erik Montnemery 17efafb2ea Do not set assumed state for binary sensor groups (#56190) 2021-09-13 10:40:24 -07:00
Bram Kragten 86d24bec75 Update icons for MDI 6 (#56170) 2021-09-13 19:29:38 +02:00
starkillerOG 5f86388f1c Netgear config flow (#54479)
* Original work from Quentame

* Small adjustments

* Add properties and method_version

* fix unknown name

* add consider_home functionality

* fix typo

* fix key

* swao setup order

* use formatted mac

* add tracked_list option

* add options flow

* add config flow

* add config flow

* clean up registries

* only remove if no other integration has that device

* tracked_list formatting

* convert tracked list

* add import

* move imports

* use new tracked list on update

* use update_device instead of remove

* add strings

* initialize already known devices

* Update router.py

* Update router.py

* Update router.py

* small fixes

* styling

* fix typing

* fix spelling

* Update router.py

* get model of router

* add router device info

* fix api

* add listeners

* update router device info

* remove method version option

* Update __init__.py

* fix styling

* ignore typing

* remove typing

* fix mypy config

* Update mypy.ini

* add options flow tests

* Update .coveragerc

* fix styling

* Update homeassistant/components/netgear/__init__.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* Update homeassistant/components/netgear/__init__.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* Update homeassistant/components/netgear/__init__.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* Update homeassistant/components/netgear/config_flow.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* Update homeassistant/components/netgear/router.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* add ConfigEntryNotReady

* Update router.py

* use entry.async_on_unload

* Update homeassistant/components/netgear/device_tracker.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* use cv.ensure_list_csv

* add hostname property

* Update device_tracker.py

* fix typo

* fix isort

* add myself to codeowners

* clean config flow

* further clean config flow

* deprecate old netgear discovery

* split out _async_remove_untracked_registries

* Update homeassistant/components/netgear/config_flow.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* Update homeassistant/components/netgear/config_flow.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* cleanup

* fix rename

* fix typo

* remove URL option

* fixes

* add sensor platform

* fixes

* fix removing multiple entities

* remove extra attributes

* initialize sensors correctly

* extra sensors disabled by default

* fix styling and unused imports

* fix tests

* Update .coveragerc

* fix requirements

* remove tracked list

* remove tracked registry editing

* fix styling

* fix discovery test

* simplify unload

* Update homeassistant/components/netgear/router.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* add typing

Co-authored-by: J. Nick Koston <nick@koston.org>

* add typing

Co-authored-by: J. Nick Koston <nick@koston.org>

* add typing

Co-authored-by: J. Nick Koston <nick@koston.org>

* condense NetgearSensorEntities

Co-authored-by: J. Nick Koston <nick@koston.org>

* Update homeassistant/components/netgear/router.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* Update homeassistant/components/netgear/router.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* Update homeassistant/components/netgear/router.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* Update homeassistant/components/netgear/router.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* add typing

* styling

* add typing

* use ForwardRefrence for typing

* Update homeassistant/components/netgear/device_tracker.py

Co-authored-by: J. Nick Koston <nick@koston.org>

* add typing

* Apply suggestions from code review

Thanks!

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* process review comments

* fix styling

* fix devicename not available on all models

* ensure DeviceName is not needed

* Update homeassistant/components/netgear/config_flow.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update homeassistant/components/netgear/config_flow.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update __init__.py

* fix styling

Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-13 18:18:21 +02:00
jjlawren 37f263e2ac Bump plexapi to 4.7.1 (#56163) 2021-09-13 15:46:54 +02:00
Brian Egge e638e5bb42 Add component for binary sensor groups (#55365)
* Add component for binary sensor groups
https://github.com/home-assistant/home-assistant.io/pull/19239

* Accidental push over prior commit

* Add test for any case

* Add unavailable attribute and tests for unique_id

* Added tests for attributes

link to documentation: https://github.com/home-assistant/home-assistant.io/pull/19297
2021-09-13 15:28:37 +02:00
Vilppu Vuorinen ee616ed992 Support hvac mode in melcloud climate.set_temperature service (#56082)
Setting the HVAC_MODE via the set_temperature service has not been
possible before this change.
2021-09-13 14:14:47 +02:00
epenet 5ccc3c17d9 Use list comprehension in onewire entity descriptions (#56168)
* Use list comprehension in onewire binary sensors

* Use list comprehension in onewire switches
2021-09-13 13:46:21 +02:00
Erik Montnemery d899d15a1e Add statistics validation (#56020)
* Add statistics validation

* Remove redundant None-check

* Move validate_statistics WS API to recorder

* Apply suggestion from code review
2021-09-13 13:44:22 +02:00
Erik Montnemery d2a9f7904a Include end time of statistics data points in API response (#56063)
* Include end time of statistics data points in API response

* Correct typing

* Update tests
2021-09-13 10:02:24 +02:00
Shay Levy e9eb76c7db Add switch support for RPC device (#56153)
* Add switch support for RPC device

* Apply review comments

* Apply review comments
2021-09-13 09:31:35 +03:00
Maikel Punie 7472fb2049 Switch velbus from python-velbus to velbusaio (#54032)
* initial commit

* use new release

* Update for sensors

* big update

* pylint fixes, bump dependancy to 2021.8.2

* New version to try to fix the tests

* Fix a lot of errors, bump version

* more work

* Bump version

* Adde dimmer support

* Make sure the counters are useable in the energy dashboard

* bump version

* Fix testcases

* Update after review

* Bump version to be able to have some decent exception catches, add the temperature device class

* Readd the import of the platform from config file, but add a deprecation warning

* More comments updated

* Fix lefover index

* Fix unique id to be backwards compatible

* Fix small bug in covers

* Fix testcases

* Changes for theenery dashboard

* Fixed services

* Fix memo text

* Make the interface for a service the port string instead of the device selector

* Fix set_memo_text

* added an async scan task, more comments

* Accidently disabled some paltforms

* More comments, bump version

* Bump version, add extra attributes, enable mypy

* Removed new features

* More comments

* Bump version

* Update homeassistant/components/velbus/__init__.py

Co-authored-by: brefra <frank_van_breugel@hotmail.com>

* Readd the import step

Co-authored-by: brefra <frank_van_breugel@hotmail.com>
2021-09-13 08:22:46 +02:00
jan iversen 1f997fcd58 Update pymodbus fixtures to use autospec (#55686) 2021-09-12 21:16:48 -07:00
Sean Vig a180c3f813 Fix polling on online Amcrest binary sensor (#56106) 2021-09-12 20:45:52 -07:00
Paulus Schoutsen 32212651fe Add zeroconf discovery to Hue (#55358)
* Add zeroconf discovery to Hue

* Add coverage for already exists case

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-12 20:00:51 -07:00
joshs85 41b25a765c Changed wording of bond state belief feature from belief to tracked state (#56147)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-12 15:46:43 -10:00
jan iversen 990d474d02 use fixtures. (#56130) 2021-09-12 15:08:46 -07:00
J. Nick Koston 673519f6bf Prefer more targeted matchers in USB discovery (#56142)
- If there is a more targeted match it should win discovery
2021-09-12 15:07:40 -07:00
J. Nick Koston 0fc89780e9 Fix listener leak in HomeKit on reload (#56143)
* Fix listener leak in HomeKit on reload

* Fix mocking
2021-09-12 15:06:03 -07:00
Aaron Bach 4e8db7173a Use EntityDescription - iqvia (#55218) 2021-09-12 09:34:44 -06:00
Greg Thornton f1556ead6d Don't cache HomeKit camera stream source from entity (#56136) 2021-09-12 08:09:09 -07:00
Marc Mueller 2b019b0911 Use EntityDescription - xiaomi_aqara (#55931)
* Use EntityDescription - xiaomi_aqara

* Remove default values

* Add missing SENSOR_TYPES
2021-09-12 12:48:02 +02:00
cdheiser ec28f7eef2 Don't return a unique_id if Lutron doesn't have a UUID for the device. (#56113)
This is a workaround for https://github.com/thecynic/pylutron/issues/70

Co-authored-by: cdheiser <cdheiser@users.noreply.github.com>
2021-09-12 09:24:02 +02:00
Daniel Hjelseth Høyer 4a449902a5 Surepetcare, upgrade library (#56067)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-12 08:12:32 +02:00
J. Nick Koston 2b7cdb70a8 Ensure rainmachine device name is a string (#56121) 2021-09-11 21:38:34 -06:00
Greg Thornton 371aa03bca Add audio support option to HomeKit camera UI config flow (#56107) 2021-09-11 16:41:30 -10:00
J. Nick Koston eff59e8b00 Use the same server name for all HomeKit bridges (#55860) 2021-09-11 19:00:26 -07:00
J. Nick Koston 459bc55e32 Bump HAP-python to 4.2.1 (#55804) 2021-09-11 18:58:19 -07:00
Steven Looman 73260c5b88 Move parts of ssdp to async_upnp_client (#55540)
* Move parts of ssdp to async_upnp_client

* Fix test for environments with multiple sources

* Fix sonos tests

* More fixes/changes

* More fixes

* Use async_upnp_client==0.21.0

* Pylint/test fixes

* More changes after review

* Fix tests

* Improve testing

* Fix mypy

* Fix yamaha_musiccast tests?

* Changes after review

* Pylint

* Reduce calls to combined_headers

* Update to async_upnp_client==0.21.1

* Update to async_upnp_client==0.21.2

* use as_dict

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-11 13:38:16 -10:00
Shay Levy f1a88f0563 Add config flow support for RPC device (#56118) 2021-09-11 23:28:33 +03:00
Paulus Schoutsen ddb0a6092f Merge pull request #56116 from home-assistant/rc 2021-09-11 13:02:14 -07:00
Jaroslav Hanslík a4a6bf8a85 New icon names based on MDI 6.1.95 (#56085) 2021-09-11 12:34:31 -07:00
Joakim Sørensen bcb3c426f4 Blank out discovery info (#56097) 2021-09-11 12:34:19 -07:00
Paulus Schoutsen 64fd496932 Bump frontend to 20210911.0 (#56115) 2021-09-11 12:34:01 -07:00
Paulus Schoutsen 292c05ab9f Bumped version to 2021.9.6 2021-09-11 12:02:44 -07:00
ehendrix23 a900c02c10 Bump pymyq to 3.1.4 (#56089) 2021-09-11 12:02:39 -07:00
Paulus Schoutsen 0cfbff3ff9 Fix singleton not working with falsey values (#56072) 2021-09-11 12:02:38 -07:00
Sean Vig ee892beceb Bump amcrest version to 1.8.1 (#56058)
The current version of the `amcrest` package has a bug in exposing if
the video stream is enabled, which leads to the substream status being
used to set if the camera is on or off.  The updated version of
`amcrest` fixes this bug.

Fixes #55661
2021-09-11 12:02:37 -07:00
micha91 fe713b943f Fix UDP message handling by upgrading aiomusiccast to 0.9.2 (#56041) 2021-09-11 12:02:36 -07:00
Erik Montnemery 2079956350 Suppress last_reset deprecation warning for energy cost sensor (#56037) 2021-09-11 12:02:36 -07:00
Erik Montnemery c424f99aab Correct confusing log message in sensor statistics (#56016) 2021-09-11 12:02:35 -07:00
Paulus Schoutsen 8a611eb640 Fix singleton not working with falsey values (#56072) 2021-09-11 12:02:01 -07:00
Oxan van Leeuwen 6e7ce89c64 Fix attribute access on None on startup in ESPHome (#56105) 2021-09-11 20:53:29 +02:00
jan iversen cb8c0cb123 Update template/test_lock.py to use pytest (#56102) 2021-09-11 11:48:25 -07:00
Ruslan Sayfutdinov a9ed4fa405 Bump awesomeversion to 21.8.1 (#55817) 2021-09-11 11:40:46 -07:00
Aaron Bach ed9b271fd0 Enforce strict typing for IQVIA (#53408)
* Enforce strict typing for IQVIA

* Cleanup

* Code review

* Ignore untyped numpy function
2021-09-11 12:27:13 -06:00
Joakim Sørensen 1b46190a0c Add view to get installation type during onboarding (#56095) 2021-09-11 15:38:38 +02:00
Vilppu Vuorinen ec21c5f4a9 Update pymelcloud to 2.5.4 (#56096) 2021-09-11 12:51:04 +02:00
Brent Petit 97f28878bb Add state_class to Ecobee sensors (#55996) 2021-09-10 22:00:24 -07:00
Michael b11db0b1d7 Remove unnecessary extra attribute from NUT sensors (#56078) 2021-09-10 19:17:46 -07:00
ehendrix23 bd18bc9f3a Bump pymyq to 3.1.4 (#56089) 2021-09-10 19:09:54 -07:00
Raman Gupta c785983cce Handle entity creation on new added zwave_js value (#55987)
* Handle new entity creation when a new value is added

* spacing

* Update homeassistant/components/zwave_js/__init__.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* change variable name and use asyncio.gather

* Centralized where discovered value IDs gets managed

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-10 23:49:31 +02:00
Shay Levy 8c3c2ad8e3 Updated changes for aioshelly 1.0.0 (#56083) 2021-09-11 00:48:55 +03:00
jan iversen ac1251c52b Update template/test_trigger.py to use pytest (#55950) 2021-09-10 09:55:51 -07:00
Paulus Schoutsen dec7877671 Handle logout prefs update for Google/Alexa (#56045) 2021-09-10 09:08:43 -07:00
Erik Montnemery 443147e132 Wait for entities when updating energy preferences (#56057) 2021-09-10 09:07:52 -07:00
Joakim Sørensen c59540cfc7 Revert "Bump pillow to 8.3.2 (#55970)" (#56048)
This reverts commit ee7202d10a.
2021-09-10 17:01:51 +02:00
Daniel Hjelseth Høyer aa39e582c3 Surepetcare, fix late review (#56065)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-10 16:49:42 +02:00
Sean Vig 03df48af9c Bump amcrest version to 1.8.1 (#56058)
The current version of the `amcrest` package has a bug in exposing if
the video stream is enabled, which leads to the substream status being
used to set if the camera is on or off.  The updated version of
`amcrest` fixes this bug.

Fixes #55661
2021-09-10 15:38:01 +02:00
micha91 948a942a0d Fix UDP message handling by upgrading aiomusiccast to 0.9.2 (#56041) 2021-09-10 15:03:34 +02:00
Erik Montnemery d5a8f1af1d Revert "Suppress last_reset deprecation warning for energy cost sensor (#56037)" (#56042)
This reverts commit e990ef249d.
2021-09-10 11:27:47 +02:00
J. Nick Koston ff1b39cda6 Fix circular import of scapy in dhcp (#56040)
* Fix circular import of scapy in dhcp

* Tweak import, add comment

* Tweak import, add comment

* pylint
2021-09-10 10:04:54 +02:00
Oxan van Leeuwen 970a7f9662 Fix compounds in sensor device class comments (#55900) 2021-09-10 09:46:21 +02:00
Erik Montnemery 78909b5227 Add support for state class total to energy cost sensor (#55955)
* Add support for all state classes to energy cost sensor

* Fix bug, adjust tests

* Fix rebase mistake
2021-09-10 09:05:32 +02:00
Erik Montnemery e990ef249d Suppress last_reset deprecation warning for energy cost sensor (#56037) 2021-09-10 08:59:23 +02:00
Daniel Hjelseth Høyer c27ad3078a Surepetcare, use DataUpdateCoordinator (#55982)
* Surepetcare, use dataupdater

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Review comment

Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>

* Apply suggestions from code review

Co-authored-by: J. Nick Koston <nick@koston.org>

* style

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-10 08:37:00 +02:00
Erik Montnemery 89281a273c Correct confusing log message in sensor statistics (#56016) 2021-09-09 23:26:29 -07:00
wranglatang e3a7a253ea Add nut Watts datapoint (#55491)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-10 06:02:06 +02:00
J. Nick Koston 5709640453 Report integrations that block startup wrap up (#56003) 2021-09-09 20:39:22 -07:00
Erik Montnemery 2a8121bdcd Really change character set of statistics_meta table to utf8 (#56029) 2021-09-09 22:55:51 +02:00
Raman Gupta 1fd3faf766 Fix state class for zwave_js energy entities (#56026) 2021-09-09 16:19:28 -04:00
Erik Montnemery 3af4b2639b Exclude @overload from coverage (#56021) 2021-09-09 21:24:23 +02:00
popoviciri f79de2a5bc Bump pysma to 0.6.6 & Fix Unit Checks (#56018) 2021-09-09 20:19:49 +02:00
Raman Gupta 113288cb1f Fix zwave_js/node_state WS API command (#55979)
* Fix zwave_js/node_state WS API command

* Add negative assertion check to avoid regression

* Update tests/components/zwave_js/test_api.py

Co-authored-by: jan iversen <jancasacondor@gmail.com>

* use constant

Co-authored-by: jan iversen <jancasacondor@gmail.com>
2021-09-09 14:04:27 -04:00
Erik Montnemery 88dbc6373f Make sure character set of events, states tables is utf8 (#56012)
* Make sure character set of events, states tables is utf8

* Pylint

* Apply suggestions from code review
2021-09-09 19:26:28 +02:00
Oscar Calvo 1b0e014783 Support incoming SMS messages via polling (#54237)
* Add support to incomming SMS via polling

* Update dependencies

* Only send notification for unread messages

* Only inform if callback is not getting used

* Update gateway.py

* Apply PR feedback

* Update homeassistant/components/sms/gateway.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Apply PR comments

* Make black happy

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-09-09 18:29:11 +02:00
Erik Montnemery a47532c69b Change character set of statistics_meta table to utf8 (#56011) 2021-09-09 17:24:20 +02:00
uvjustin dd9bfe7aa0 Add package constraint anyio>=3.3.1 (#55997) 2021-09-09 15:33:09 +02:00
Jean-Yves Avenard 556dcf6abb Add iotawatt high-accuracy energy readout sensors (#55512) 2021-09-09 15:32:43 +02:00
joshs85 011817b122 Add state belief services to bond integration (#54735)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-09 15:32:32 +02:00
Adam Feldman cbbbc3c4f0 Add state class to Smart Meter Texas sensor (#55665) 2021-09-09 15:32:03 +02:00
jan iversen 9d2861afe3 Add mypy to elkm1. (#55964) 2021-09-09 13:14:28 +02:00
cnico 065e858a03 Address post merge review of flipr binary sensor (#55983) 2021-09-09 09:45:58 +02:00
Erik Montnemery 80fd330479 Add sum_decrease and sum_increase statistics (#55850) 2021-09-08 23:35:53 -07:00
Joakim Plate a8cbb949fa Rfxtrx drop yaml configuration (#54173) 2021-09-08 22:17:02 -07:00
Alan Tse 98ecf2888c Remove tesla integration (#55988)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-08 22:12:03 -07:00
GitHub Action 675426dc25 [ci skip] Translation update 2021-09-09 00:11:32 +00:00
Erik Montnemery a1aca20818 Address review comment from #55833 (#55985) 2021-09-08 13:48:31 -07:00
Paulus Schoutsen 5cc54618c5 Merge pull request #55969 from home-assistant/rc 2021-09-08 13:42:09 -07:00
Philip Allgaier 4d2432cffb Consistent lower-case spelling of "optional" (#55976) 2021-09-08 22:16:12 +02:00
Erik Montnemery 8f344252c4 Add significant change support to AQI type sensors (#55833) 2021-09-08 12:47:59 -07:00
Erik Montnemery 232943c93d Add significant change support to AQI type sensors (#55833) 2021-09-08 12:47:48 -07:00
Erik Montnemery cbe4b2dc1d Add support for state class measurement to energy cost sensor (#55962) 2021-09-08 12:46:43 -07:00
Erik Montnemery bb6c2093a2 Add support for state class measurement to energy cost sensor (#55962) 2021-09-08 12:46:28 -07:00
Paulus Schoutsen a17d2d7c71 Fix gas validation (#55886) 2021-09-08 12:45:41 -07:00
Paulus Schoutsen ee7202d10a Bump pillow to 8.3.2 (#55970) 2021-09-08 12:06:30 -07:00
Ruslan Sayfutdinov e3815c6c2e Pin setuptools<58 2021-09-08 12:04:32 -07:00
Paulus Schoutsen 5cba7932f3 Bumped version to 2021.9.5 2021-09-08 08:22:38 -07:00
Erik Montnemery 413430bdba Fix handling of imperial units in long term statistics (#55959) 2021-09-08 08:22:34 -07:00
Erik Montnemery 81462d8655 Do not allow inf or nan sensor states in statistics (#55943) 2021-09-08 08:22:33 -07:00
Erik Montnemery 8ee4b49aa9 Do not let one bad statistic spoil the bunch (#55942) 2021-09-08 08:22:32 -07:00
Shay Levy 19d7cb4439 Bump aioswitcher to 2.0.5 (#55934) 2021-09-08 08:22:31 -07:00
Raman Gupta 21ebf4f3e6 Allow multiple template.select platform entries (#55908) 2021-09-08 08:22:31 -07:00
Maciej Bieniek 980fcef36f Fix available property for Xiaomi Miio fan platform (#55889)
* Fix available

* Suggested change
2021-09-08 08:22:30 -07:00
Diogo Gomes e7fd24eade Integration Sensor Initial State (#55875)
* initial state is UNAVAILABLE

* update tests
2021-09-08 08:22:08 -07:00
Pascal Winters 9ecb75dc70 Edit unit of measurement for gas/electricity supplier prices (#55771)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-08 08:20:49 -07:00
RDFurman 7f3adce675 Try to avoid rate limiting in honeywell (#55304)
* Limit parallel update and sleep loop

* Use asyncio sleep instead

* Extract sleep to const for testing

* Make loop sleep 0 in test
2021-09-08 08:20:48 -07:00
Erik Montnemery 27764e9985 Fix handling of imperial units in long term statistics (#55959) 2021-09-08 08:08:48 -07:00
Erik Montnemery 9f1e503784 Do not allow inf or nan sensor states in statistics (#55943) 2021-09-08 08:05:16 -07:00
Erik Montnemery 22e6ddf8df Do not let one bad statistic spoil the bunch (#55942) 2021-09-08 07:55:40 -07:00
Shay Levy c514f72c70 Bump aioswitcher to 2.0.5 (#55934) 2021-09-08 07:54:44 -07:00
Diogo Gomes 84140a547b deprecated unit_of_measurement (#55876) 2021-09-08 16:33:53 +02:00
Marc Mueller 0b23ce658e Use EntityDescription - konnected (#55923) 2021-09-08 15:14:03 +02:00
Marc Mueller 32b8be5a6e Use EntityDescription - repetier (#55926) 2021-09-08 14:28:04 +02:00
Marc Mueller 69d6d5ffce Use EntityDescription - incomfort (#55930) 2021-09-08 08:51:17 +02:00
Marc Mueller 5429a67877 Use EntityDescription - zoneminder (#55922) 2021-09-08 08:48:55 +02:00
Ruslan Sayfutdinov 7195b8222b Bump PyJWT to 2.1.0 (#55911) 2021-09-07 20:59:02 -07:00
Pascal Winters a764c79b6f Edit unit of measurement for gas/electricity supplier prices (#55771)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-09-07 20:54:40 -07:00
Paulus Schoutsen ec337101dd Fix gas validation (#55886) 2021-09-07 20:53:43 -07:00
Fuzzy efafe82799 Remove Trackr integration (API removed) (#55917)
* Delete Trackr component directory

* Update .coverage.rc to remove Trackr

* Update requirements_all.txt
2021-09-08 05:01:58 +02:00
GitHub Action f9e6e616f4 [ci skip] Translation update 2021-09-08 00:10:52 +00:00
Raman Gupta 37d75e8a03 Allow multiple template.select platform entries (#55908) 2021-09-07 14:50:07 -07:00
Marc Mueller 42f586c585 Fix upnp add_entities (#55904)
* Fix upnp add_entities

* Remove nesting level
2021-09-07 22:27:03 +02:00
Diogo Gomes d705b35ea1 Address comment in integration Riemann sum PR #55875 (#55895)
* https://github.com/home-assistant/core/pull/55875\#discussion_r703334504

* missing test update
2021-09-07 19:40:20 +02:00
Ville Skyttä 0684f8bddf Add date device class (#55887)
* Add date device class

https://github.com/home-assistant/architecture/discussions/610

* Add date device class to sensors device classes list
2021-09-07 16:46:12 +02:00
RDFurman 3aed58f825 Try to avoid rate limiting in honeywell (#55304)
* Limit parallel update and sleep loop

* Use asyncio sleep instead

* Extract sleep to const for testing

* Make loop sleep 0 in test
2021-09-07 16:32:26 +02:00
Maciej Bieniek 86247c93fc Fix available property for Xiaomi Miio fan platform (#55889)
* Fix available

* Suggested change
2021-09-07 11:34:41 +02:00
cnico 53ea24ec15 Add Flipr binary sensor (#53525) 2021-09-07 09:52:42 +02:00
Michael 2f3a11f930 Rewrite re-auth mechanism in Synology DSM integration (#54298) 2021-09-07 09:10:50 +02:00
Erik Montnemery 0d1412ea17 Set state class to total for net utility_meter sensors (#55877)
* Set state class to total for net utility_meter sensors

* Update tests
2021-09-07 08:13:14 +02:00
Diogo Gomes 1ca9deb520 Integration Sensor Initial State (#55875)
* initial state is UNAVAILABLE

* update tests
2021-09-07 08:12:54 +02:00
Sean Vig 789f21c427 Fix assignment of amcrest camera model (#55266) 2021-09-07 04:52:45 +02:00
GitHub Action 9da3fa5d75 [ci skip] Translation update 2021-09-07 00:11:29 +00:00
Paulus Schoutsen 93083513b4 Bump hass-nabucasa 49 (#55823) 2021-09-06 16:05:33 -07:00
Paulus Schoutsen f0649855f9 Merge pull request #55870 from home-assistant/rc 2021-09-06 16:05:08 -07:00
Alexei Chetroi c6888e4faf Refactor ZHA tests (#55844)
* Replace ZHA tests FakeDevice

* Refactor ZHA tests to use zigpy devices and endpoints

* Use common consts for zigpy device mocks

Use the same dict key names for device signature mocks as zha quirks.

* Use const for test device list

* Update tests/components/zha/common.py
2021-09-06 19:00:06 -04:00
Erik Montnemery b1dbdec2ea Set state class to total for Integration sensors (#55872) 2021-09-07 00:27:31 +02:00
puddly 6895081595 Use async_update_entry in config unit test instead of modifying data (#55855) 2021-09-06 16:57:59 -04:00
Paulus Schoutsen 823c3735ce Bumped version to 2021.9.4 2021-09-06 13:41:39 -07:00
Diogo Gomes 68131a5c00 Integration Sensor unit of measurement overwrite (#55869) 2021-09-06 13:41:33 -07:00
J. Nick Koston be0f767c34 Fix exception during rediscovery of ignored zha config entries (#55859)
Fixes #55709
2021-09-06 13:41:33 -07:00
Maciej Bieniek 450652a501 Fix target humidity step for Xiaomi MJJSQ humidifiers (#55858) 2021-09-06 13:41:32 -07:00
Daniel Hjelseth Høyer 8523f569c0 Surepetcare, bug fix (#55842) 2021-09-06 13:41:31 -07:00
mrwhite31 5f289434d3 Fix typo in in rfxtrx Barometer sensor (#55839)
Fix typo in sensor.py to fix barometer unavailability
2021-09-06 13:41:31 -07:00
Maciej Bieniek 3df6dfecab Fix a lazy preset mode update for Xiaomi Miio fans (#55837) 2021-09-06 13:41:30 -07:00
Martin Hjelmare d6eda65302 Bump zwave-js-server-python to 0.30.0 (#55831) 2021-09-06 13:41:29 -07:00
Brandon Rothweiler 7a5bc2784a Upgrade pymazda to 0.2.1 (#55820) 2021-09-06 13:41:28 -07:00
David Bonnes 00878467cc Fix incomfort min/max temperatures (#55806) 2021-09-06 13:41:28 -07:00
Maciej Bieniek 899d8164b0 Fix xiaomi miio Air Quality Monitor initialization (#55773) 2021-09-06 13:41:27 -07:00
jan iversen 823fd60991 Allow same address different register types in modbus (#55767) 2021-09-06 13:41:26 -07:00
jan iversen a6bb0eadca Allow same IP if ports are different on modbus (#55766) 2021-09-06 13:41:25 -07:00
Tatham Oddie eb70354ee7 Fix logbook entity_matches_only query mode (#55761)
The string matching template needs to match the same compact JSON format
as the data is now written in.
2021-09-06 13:41:25 -07:00
Joshi bd53185bed Fix switch name attribute for thinkingcleaner (#55730) 2021-09-06 13:41:24 -07:00
Diogo Gomes 34d54511e8 Integration Sensor unit of measurement overwrite (#55869) 2021-09-06 13:41:01 -07:00
jan iversen 8d4aac618d Allow same IP if ports are different on modbus (#55766) 2021-09-06 13:40:15 -07:00
Tatham Oddie 4fa9871080 Fix logbook entity_matches_only query mode (#55761)
The string matching template needs to match the same compact JSON format
as the data is now written in.
2021-09-06 13:39:39 -07:00
Martin Hjelmare b088ce601c Bump zwave-js-server-python to 0.30.0 (#55831) 2021-09-06 13:37:12 -07:00
Daniel Hjelseth Høyer bcfedeb797 Surepetcare, bug fix (#55842) 2021-09-06 13:36:45 -07:00
Maciej Bieniek 9093819671 Fix target humidity step for Xiaomi MJJSQ humidifiers (#55858) 2021-09-06 13:36:18 -07:00
jan iversen cac3e1acfa Allow same address different register types in modbus (#55767) 2021-09-06 13:35:40 -07:00
J. Nick Koston eba9b61011 Fix exception during rediscovery of ignored zha config entries (#55859)
Fixes #55709
2021-09-06 13:35:24 -07:00
Joshi 0533a9c714 Fix switch name attribute for thinkingcleaner (#55730) 2021-09-06 14:03:46 -05:00
Brandon Rothweiler 12b1f87b35 Upgrade pymazda to 0.2.1 (#55820) 2021-09-06 13:53:03 -05:00
Simone Chemelli 8b6d0ca13f Replace util.get_local_ip in favor of components.network.async_get_source_ip() - part 2 (#53368)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-06 08:44:38 -10:00
Erik Montnemery dd7dea9a3f Make scapy imports in DHCP local (#55647) 2021-09-06 10:10:27 -07:00
Erik Montnemery b99a22cd4d Re-add state_class total to sensor (#55103)
* Re-add state_class total to sensor

* Make energy cost sensor enforce state_class total_increasing

* Bump deprecation of last_reset for state_class measurement

* Correct rebase mistakes
2021-09-06 18:28:58 +02:00
starkillerOG 2634949999 Add motion_blinds VerticalBlind and cleanup (#55774) 2021-09-06 16:19:02 +02:00
puddly e671ad41ec Replace zigpy-cc with zigpy-znp (#55828)
* Replace zigpy-cc with zigpy-znp in a ZHA config migration

* Fix failing unit tests
2021-09-06 09:50:54 -04:00
Maciej Bieniek 9ee0d8fefe Fix xiaomi miio Air Quality Monitor initialization (#55773) 2021-09-06 15:30:03 +02:00
mrwhite31 e6a29b6a2a Fix typo in in rfxtrx Barometer sensor (#55839)
Fix typo in sensor.py to fix barometer unavailability
2021-09-06 15:11:12 +02:00
Stefan Agner df928c80b8 Shutdown the container on abnormal signals (#55660)
So far the finish script exits whenever the service terminated by a
signal (indicated by 256 as first argument). This is the intended
behavior when SIGTERM is being sent: SIGTERM is used on regular shutdown
through the supervisor. We don't want the finish script to shutdown
itself while being taken down by the supervisor already.

However, every other signal which lead to a process exit likely means
trouble: SIGSEGV, SIGILL, etc. In those cases we want the container to
exit. The Supervisor (or restart policy of Docker in the container case)
will take care of restarting if appropriate.
2021-09-06 14:37:33 +02:00
Erik Montnemery 05abf1405d Migrate emulated_hue tests from unittest to pytest (#55794)
* Migrate emulated_hue tests from unittest to pytest

* Remove unused variables
2021-09-06 13:24:00 +02:00
Maciej Bieniek 753285eae7 Fix a lazy preset mode update for Xiaomi Miio fans (#55837) 2021-09-06 12:33:34 +02:00
David Bonnes 67b7144703 Fix incomfort min/max temperatures (#55806) 2021-09-06 12:26:20 +02:00
Andre Richter d50b700dc7 Refactor exception handling in Vallox (#55461) 2021-09-06 12:03:45 +02:00
Marc Mueller 4475cf24c8 Use EntityDescription - aqualogic (#55791) 2021-09-06 11:59:03 +02:00
Marc Mueller 3001df99cb Use EntityDescription - poolsense (#55743) 2021-09-06 11:58:47 +02:00
Philip Allgaier 364edbfd8a Add service descriptions for supervisor backup restore services (#52766)
* Add service descriptions for supervisor backup restore

* Add fields to restore services

* Update homeassistant/components/hassio/services.yaml

Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>

Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-09-06 10:27:11 +02:00
Jan Bouwhuis 755835ee2e Alexa - Remove legacy speed support for fan platform (#55174)
* Remove legacy fan speed support

* remove fan range controller tests

* retrigger tests
2021-09-06 10:19:57 +02:00
Marc Mueller a4e4ffef0a Use EntityDescription - apcupsd (#55790) 2021-09-06 10:19:31 +02:00
Marc Mueller 655399eb7b Use EntityDescription - aemet (#55744) 2021-09-06 10:12:09 +02:00
Marc Mueller 77b60c712e Use EntityDescription - sabnzbd (#55788) 2021-09-06 09:54:07 +02:00
Marc Mueller a4dae0c1e1 Use EntityDescription - meteoclimatic (#55792) 2021-09-06 09:48:12 +02:00
Marc Mueller 96db04213b Use EntityDescription - vultr (#55789) 2021-09-06 09:44:33 +02:00
Marc Mueller cc6a0d2f8d Use EntityDescription - awair (#55747) 2021-09-06 09:40:41 +02:00
Marc Mueller 99ef2ae54d Use EntityDescription - vilfo (#55746) 2021-09-06 09:33:58 +02:00
jan iversen 0dd128af77 Change fix property to _attr for tradfri (#55691) 2021-09-06 08:49:00 +02:00
Greg 1b3530a3f8 Bump envoy_reader API to 0.20.0 (#55822) 2021-09-05 20:32:50 -10:00
Witold Sowa 8565821394 ZHA: Added support for ZigBee Simple Sensor device and Binary Input c… (#55819)
* ZHA: Added support for ZigBee Simple Sensor device and Binary Input cluster

* Apply suggestions from code review

* Apply suggestions from code review

Co-authored-by: Alexei Chetroi <lexoid@gmail.com>
2021-09-06 01:41:57 -04:00
Paulus Schoutsen 523998f8a1 Drop logger service fields because keys are dynamic (#55750) 2021-09-05 20:53:12 -07:00
GitHub Action c2b89725be [ci skip] Translation update 2021-09-06 00:12:56 +00:00
Oliver 22961b30d2 Update to denonavr version 0.10.9 (#55805) 2021-09-05 13:28:48 -10:00
Alexei Chetroi aa6cb84b27 Optimize ZHA ZCL attribute reporting configuration (#55796)
* Refactor ZCL attribute reporting configuration

Configure up to 3 attributes in a single request.

* Use constant for attribute reporting configuration

* Update tests

* Cleanup

* Remove irrelevant for this PR section
2021-09-05 17:45:08 -04:00
Ville Skyttä 4e1e7a4a71 Protect Huawei LTE against None ltedl/ulfreq (#54411)
Refs https://github.com/home-assistant/core/issues/54400
2021-09-05 21:42:22 +03:00
Chris Browet 5a2bcd2763 ADD: generalize regex_findall (#54584) 2021-09-05 12:41:39 +02:00
GitHub Action f8ebc31576 [ci skip] Translation update 2021-09-05 00:11:36 +00:00
Paulus Schoutsen cce0ca5688 Tag Hue errors as format strings (#55751) 2021-09-04 15:38:14 -07:00
Paulus Schoutsen df9a899bbd Merge pull request #55753 from home-assistant/rc 2021-09-04 14:51:15 -07:00
Paulus Schoutsen 37cf295e20 Bumped version to 2021.9.3 2021-09-04 14:13:37 -07:00
Simone Chemelli 04816fe26d Fix SamsungTV sendkey when not connected (#55723) 2021-09-04 14:13:34 -07:00
Anders Melchiorsen eb48e75fc5 Fix LIFX firmware version information (#55713) 2021-09-04 14:13:33 -07:00
Simone Chemelli 9d5431fba1 Handle Fritz InternalError (#55711) 2021-09-04 14:13:32 -07:00
Erik Montnemery a4f2c5583d Handle negative numbers in sensor long term statistics (#55708)
* Handle negative numbers in sensor long term statistics

* Use negative states in tests
2021-09-04 14:13:32 -07:00
Paulus Schoutsen a37c3af2b4 better detect legacy eagly devices (#55706) 2021-09-04 14:13:31 -07:00
Simone Chemelli d39b861110 Fix SamsungTV sendkey when not connected (#55723) 2021-09-04 13:58:34 -07:00
Simone Chemelli 715ce3185b Handle Fritz InternalError (#55711) 2021-09-04 13:56:59 -07:00
Brian Egge c81a319346 Handle unknown preset mode in generic thermostat (#55588)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-09-04 13:17:57 -07:00
Marc Mueller f5a543b220 Remove deprecated device_state_attributes (#55734) 2021-09-04 13:16:01 -07:00
starkillerOG 58da58c008 Bump motion_blinds to 0.5.5 (#55710) 2021-09-04 22:06:50 +02:00
jan iversen 6348bf70ac Add caplog setup fixture. (#55714) 2021-09-04 07:09:55 -07:00
Marc Mueller 0700108278 Use NamedTuple for device_automation details (#55697) 2021-09-04 13:42:36 +02:00
Anders Melchiorsen d8b85b2067 Fix LIFX firmware version information (#55713) 2021-09-04 13:18:23 +02:00
Simone Chemelli b7e8348c30 Add bluez to the devcontainer (#55469)
* Fix fjaraskupan dependency for tests

* update package list

* Typo

* hadolint fixes

* hadolint fixes #2

* Cleanup

* Rewording
2021-09-04 12:16:06 +02:00
Erik Montnemery 38d42de2c0 Handle negative numbers in sensor long term statistics (#55708)
* Handle negative numbers in sensor long term statistics

* Use negative states in tests
2021-09-04 10:47:42 +02:00
Marc Mueller b3181a0ab2 Use NamedTuple for RGBColor (#55698) 2021-09-04 09:25:25 +02:00
Paulus Schoutsen 10317fba17 better detect legacy eagly devices (#55706) 2021-09-04 09:23:35 +02:00
jan iversen 7aa454231f Update template/test_sensor.py to use pytest (#55288) 2021-09-03 22:56:12 -07:00
Paulus Schoutsen 19c54b8cbf Drop unused ruamel (#55672) 2021-09-03 22:17:10 -07:00
J. Nick Koston 195ee2a188 Avoid creating sockets in homekit port available tests (#55668)
* Avoid creating sockets in homekit port available tests

* prevent new bridge from being setup -- its too fast now that the executor job is gone and it revealed an unpatched setup
2021-09-03 17:15:28 -10:00
Michael 0dc8fb497b Delay state update after switch is toggled for TP-Link HS210 device (#55671)
* delay state update for HS210

* Update workaround comment
2021-09-04 03:01:48 +02:00
Ville Skyttä b10fc89a6b Automation trigger info type hint improvements (#55402)
* Make automation trigger info a TypedDict

* zwave_js trigger type hint fixes

* Remove redundant automation trigger info field presence checks

* Use async_initialize_triggers in mqtt and tasmota device_trigger tests
2021-09-04 02:25:51 +02:00
epenet 0749e045bb Add reauth to Renault config flow (#55547)
* Add reauth flow to async_setup_entry

* Add reauth flow to config_flow

* Add reauth tests

* Split reauth/reauth_confirm

* unindent code

* Add entry_id and unique_id to reauth flow testing

* Use description_placeholders for username

* fix typo
2021-09-04 02:17:24 +02:00
GitHub Action 19dcb19d07 [ci skip] Translation update 2021-09-04 00:13:17 +00:00
Tomasz Wieczorek 501e7c84be Type scaffold PLATFORMS (#55699)
* Added template base type

Proposition to add typing, as pre-commit test on newly created integrations fails on it automatically:

```
homeassistant/components/<my_integration>/__init__.py:11: error: Need type annotation for "PLATFORMS" (hint: "PLATFORMS: List[<type>] = ...")  [var-annotated]
Found 1 error in 1 file (checked 4 source files)
```

I believe there shouldn't be other type than text, hence the proposition.

* Apply suggestions from code review

Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>

Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-09-04 01:21:18 +02:00
Marc Mueller a54b9502ef Use NamedTuple for light color mode mapping (#55696) 2021-09-04 00:48:14 +02:00
Marc Mueller 617e8544c0 Use NamedTuple for touchline preset mode settings (#55695) 2021-09-04 00:44:16 +02:00
Marc Mueller edddeaf5ab Use NamedTuple for api endpoint settings (#55694) 2021-09-04 00:44:01 +02:00
jan iversen a756308e79 Update template/test_binary_sensor.py to use pytest (#55220) 2021-09-03 15:43:07 -07:00
Aidan Timson cd51d994b1 System Bridge - Set device class for binary sensor (#55688) 2021-09-03 23:48:11 +02:00
Marc Mueller 4eba2ccebc Use EntityDescription - synology_dsm (#55407) 2021-09-03 23:35:28 +02:00
Marc Mueller f5cd321185 Use EntityDescription - airnow (#55684) 2021-09-03 22:36:24 +02:00
Marc Mueller bbd9c6eb5b Use EntityDescription - discogs (#55683) 2021-09-03 22:36:17 +02:00
Marc Mueller ce6921d73c Use EntityDescription - picnic (#55682)
* Use EntityDescription - picnic

* Change _attr_extra_state_attributes to be static

* Fix tests
2021-09-03 22:35:59 +02:00
Brian Rogers 9db13a3e74 Fix Rachio service missing with 1st generation controllers (#55679) 2021-09-03 22:35:33 +02:00
Marc Mueller 1e4233fe20 Use EntityDescription - iperf3 (#55681) 2021-09-03 22:35:12 +02:00
Marc Mueller 76ce0f6ea7 Use EntityDescription - econet (#55680)
* Use EntityDescription - econet

* Resolve name constants
2021-09-03 22:34:51 +02:00
Marc Mueller 798f487ea4 Use EntityDescription - faa_delays (#55678)
* Use EntityDescription - faa_delays

* Update binary_sensor.py
2021-09-03 22:34:29 +02:00
Marc Mueller 3c0a34dd01 Use EntityDescription - luftdaten (#55676)
* Use EntityDescription - luftdaten

* Fix name attribute

* Remove default values

* Move SensorTypes back to __init__
2021-09-03 22:34:01 +02:00
Marc Mueller fbf812a845 Use EntityDescription - freebox (#55675)
* Use EntityDescription - freebox

* Remove default values
2021-09-03 22:33:26 +02:00
Paulus Schoutsen 33047d7260 Merge pull request #55673 from home-assistant/rc 2021-09-03 10:53:16 -07:00
Paulus Schoutsen e3405d226a Bumped version to 2021.9.2 2021-09-03 10:16:36 -07:00
Paulus Schoutsen 3008ff03b2 Guard for doRollover failing (#55669) 2021-09-03 10:16:31 -07:00
Joakim Sørensen 8592d94a3c Fix hdmi_cec switches (#55666) 2021-09-03 10:16:30 -07:00
Nikolay Vasilchuk b36e86d95c Fix Starline sensor state AttributeError (#55654)
* Fix starline sensors state

* Black
2021-09-03 10:16:29 -07:00
Paulus Schoutsen f61a1ecae7 Guard for unexpected exceptions in device automation (#55639)
* Guard for unexpected exceptions in device automation

* merge

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-03 10:16:28 -07:00
Paulus Schoutsen 80c074ca82 Better handle invalid trigger config (#55637) 2021-09-03 10:16:28 -07:00
Paulus Schoutsen ff91ff4cd2 Fix template sensor availability (#55635) 2021-09-03 10:16:27 -07:00
J. Nick Koston 93c2a7dd70 Narrow zwave_js USB discovery (#55613)
- Avoid triggering discovery when we can know in advance the
  device is not a Z-Wave stick
2021-09-03 10:16:26 -07:00
Michael da3ee9ed4b Fix CONFIG_SCHEMA validation in Speedtest.net (#55612) 2021-09-03 10:16:25 -07:00
Pascal Vizeli 2ef607651d Disable observer for USB on containers (#55570)
* Disable observer for USB on containers

* remove operating system test

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-03 10:16:24 -07:00
J. Nick Koston 88ca83a30b Ignore missing devices when in ssdp unsee (#55553) 2021-09-03 10:16:24 -07:00
Paulus Schoutsen 7111fc47c4 Better handle invalid trigger config (#55637) 2021-09-03 10:15:57 -07:00
Paulus Schoutsen e0f640c0f8 Guard for doRollover failing (#55669) 2021-09-03 09:53:47 -07:00
Joakim Sørensen 7caa985a59 Fix hdmi_cec switches (#55666) 2021-09-03 09:17:41 -07:00
J. Nick Koston 25b39b36e7 Ignore missing devices when in ssdp unsee (#55553) 2021-09-03 09:06:07 -07:00
Paulus Schoutsen 418d6a6a41 Guard for unexpected exceptions in device automation (#55639)
* Guard for unexpected exceptions in device automation

* merge

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-03 09:04:50 -07:00
Marc Mueller a234f2ab31 Remove dead fritzbox code (#55617)
* EntityInfo has been replaced by EntityDescription (#55104)
* Extra switch attributes have been replaced by dedicated sensors (#52562)
2021-09-03 17:48:48 +02:00
Marc Mueller 7461af68b9 Use NamedTuple for color temperature range (#55626) 2021-09-03 17:41:32 +02:00
Joakim Sørensen 2171922265 Always show state for the updater binary_sensor (#55584) 2021-09-03 17:40:07 +02:00
ehendrix23 4310a7d814 Add upnp sensor for IP, Status, and Uptime (#54780)
Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-09-03 17:15:28 +02:00
Michael ae9e3c237a Fix CONFIG_SCHEMA validation in Speedtest.net (#55612) 2021-09-03 14:11:19 +02:00
Nikolay Vasilchuk b4d4fe4ef8 Fix Starline sensor state AttributeError (#55654)
* Fix starline sensors state

* Black
2021-09-03 14:04:56 +02:00
Pascal Vizeli 70338da50e Remove wheels for alpine 3.13 (#55650) 2021-09-03 11:22:41 +02:00
Yuval Aboulafia 173b87e675 Clean holiday attributes code in Jewish calendar (#55080)
* Clean repetitive code in jewish calendar

* do not return none

* fix holiday
2021-09-03 12:07:53 +03:00
Yuval Aboulafia 91cd6951f3 Minor cleanup in Waze travel times (#55422)
* reduce imports and clean the attriburts

* add icons

* use entity class attributes

* fix icon

* add misc types

* fix update

* do not change icon yet

* address review
2021-09-03 11:54:32 +03:00
Erik Montnemery 4684ea2d14 Prevent 3rd party lib from opening sockets in broadlink tests (#55636) 2021-09-03 10:13:35 +02:00
Paulus Schoutsen 0c2772e0be Fix template sensor availability (#55635) 2021-09-03 09:02:45 +02:00
Pascal Vizeli 8319f232b8 Disable observer for USB on containers (#55570)
* Disable observer for USB on containers

* remove operating system test

Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-03 08:05:37 +02:00
J. Nick Koston d8a81a54d8 Narrow zwave_js USB discovery (#55613)
- Avoid triggering discovery when we can know in advance the
  device is not a Z-Wave stick
2021-09-03 05:11:03 +02:00
GitHub Action 8af0cb9e65 [ci skip] Translation update 2021-09-03 00:16:18 +00:00
Paulus Schoutsen f883fa9eef Merge pull request #55608 from home-assistant/rc 2021-09-02 13:35:47 -07:00
Paulus Schoutsen 5b705dba36 Bumped version to 2021.9.1 2021-09-02 12:50:56 -07:00
Pascal Vizeli 1592408a4b Downgrade sqlite-libs on docker image (#55591) 2021-09-02 12:50:48 -07:00
jan iversen 89b7be52af Correct duplicate address. (#55578) 2021-09-02 12:50:47 -07:00
Alexei Chetroi 8f85472df3 Pick right coordinator (#55555) 2021-09-02 12:50:45 -07:00
Teemu R 6aa771e5e8 xiaomi_miio: bump python-miio dependency (#55549) 2021-09-02 12:50:44 -07:00
Joakim Sørensen 7193e82963 Bump pyuptimerobot to 21.9.0 (#55546) 2021-09-02 12:50:43 -07:00
bsmappee 02db4dbe5e Bump pysmappee to 0.2.27 (#55257)
* bump

* bump
2021-09-02 21:01:16 +02:00
Erik Montnemery 7dbe8070f7 Mock out network.util.async_get_source_ip in tests (#55592) 2021-09-02 20:44:50 +02:00
J. Nick Koston 363320eedb Mock sockets in the network integration tests (#55594) 2021-09-02 20:44:42 +02:00
Erik Montnemery 2e5c1236f9 Prevent 3rd party lib from opening sockets in freedompro tests (#55596) 2021-09-02 19:32:19 +02:00
Erik Montnemery 348bdca647 Prevent 3rd party lib from opening sockets in epson tests (#55595) 2021-09-02 19:30:53 +02:00
Joakim Sørensen 4f33679255 Fix url lookup in telegram_bot webhook (#55587) 2021-09-02 19:17:33 +02:00
Erik Montnemery cabb9c0ea4 Prevent 3rd party lib from opening sockets in broadlink tests (#55593) 2021-09-02 19:03:24 +02:00
Pascal Vizeli d4a2b36638 Downgrade sqlite-libs on docker image (#55591) 2021-09-02 18:09:30 +02:00
Erik Montnemery bfd799dc04 Use hass_client_no_auth test fixture in integrations s-x (#55585) 2021-09-02 14:50:10 +02:00
Erik Montnemery acdddabe1f Use hass_client_no_auth test fixture in integrations h-p (#55583) 2021-09-02 14:49:40 +02:00
Erik Montnemery d5b6dc4f26 Use hass_client_no_auth test fixture in integrations a-g (#55581) 2021-09-02 14:49:20 +02:00
jan iversen 69aba2a6a1 Correct duplicate address. (#55578) 2021-09-02 13:53:38 +02:00
Erik Montnemery cdaba62d2c Add test fixture for unauthenticated HTTP client (#55561)
* Add test fixture for unauthenticated HTTP client

* Remove things from the future
2021-09-02 13:09:16 +02:00
Joakim Sørensen b3b9fb0a7c Bump pyuptimerobot to 21.9.0 (#55546) 2021-09-02 11:40:32 +02:00
Alexei Chetroi cb1e0666c8 Pick right coordinator (#55555) 2021-09-01 22:54:35 -04:00
GitHub Action 6b4f2e6f8f [ci skip] Translation update 2021-09-02 00:20:52 +00:00
Teemu R aef4a69cd0 xiaomi_miio: bump python-miio dependency (#55549) 2021-09-02 00:18:12 +02:00
Raman Gupta 02eba22068 Add additional test coverage for zwave_js meter sensors (#55465) 2021-09-01 17:22:17 -04:00
Erik Montnemery 7dbd0e5274 Fix zeroconf mock and use it in CI group 1's tests (#55526)
* Fix zeroconf mock and use it in CI group 1's tests

* Mock HaAsyncServiceBrowser
2021-09-01 22:38:00 +02:00
Erik Montnemery e631671832 Use respx.mock in generic camera tests (#55521) 2021-09-01 20:45:29 +02:00
Paulus Schoutsen 245eec7041 Merge pull request #55532 from home-assistant/rc 2021-09-01 11:28:21 -07:00
Bram Kragten 493309daa7 Bumped version to 2021.9.0 2021-09-01 19:40:48 +02:00
Paulus Schoutsen af68802c17 Tweaks for the iotawatt integration (#55510) 2021-09-01 19:37:43 +02:00
Brian Egge 576cece7a9 Fix None support_color_modes TypeError (#55497)
* Fix None support_color_modes TypeError 

https://github.com/home-assistant/core/issues/55451

* Update __init__.py
2021-09-01 19:37:43 +02:00
Otto Winter 3b9859940f ESPHome light color mode use capabilities (#55206)
Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
2021-09-01 19:37:41 +02:00
Paulus Schoutsen 27e29b714c Bump cloud to 0.47.1 (#55312)
* Bump cloud to 0.47.0

* Bump reqs

* Bump to 0.47.1

* Do not load hass_nabucasa during http startup

* fix some tests

* Fix test

Co-authored-by: Ludeeus <ludeeus@ludeeus.dev>
2021-09-01 09:54:54 -07:00
Daniel Hjelseth Høyer c68e87c40e OpenGarage, change to attributes (#55528)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2021-09-01 18:33:56 +02:00
Daniel Hjelseth Høyer 80af2f4279 Open garage, add closing and opening to state (#55372) 2021-09-01 08:16:10 -05:00
epenet f8ec85686a Add select platform to Renault integration (#55494)
* Add select platform to Renault integration

* Fix pylint
2021-09-01 14:44:10 +02:00
Joakim Sørensen 33fb080c1e Add remote server to cloud system health (#55506)
* Add sintun server to cloud system health

* Update name

* Adjust test
2021-09-01 13:23:50 +02:00
Paulus Schoutsen 9284f7b147 Tweaks for the iotawatt integration (#55510) 2021-09-01 13:18:50 +02:00
epenet bcf97cb308 Add device tracker platform to Renault integration (#54745) 2021-09-01 13:10:48 +02:00
Stefan 04a052a37d Fix moon phases (#55518) 2021-09-01 12:26:56 +02:00
Joakim Sørensen befcafbc49 Mock setup in spotify tests (#55515) 2021-09-01 11:27:21 +02:00
epenet 02b7356596 Add services to Renault integration (#54820)
* Add services

* Add tests

* Cleanup async

* Fix pylint

* Update services.yaml

* Add extra schema validation

* Rename constants

* Simplify code

* Move constants

* Fix pylint

* Cleanup constants

* Drop charge_set_mode as moved to select platform

* Only register the services if no config entry has registered them yet

* Replace VIN with device selector to select vehicle

* Update logging

* Adjust type checking

* Use a shared base SERVICE_VEHICLE_SCHEMA

* Add selectors for ac_start (temperature/when)

* Add object selector for charge_set_schedules service
2021-09-01 11:23:54 +02:00
Otto Winter 46159c3f18 ESPHome light color mode use capabilities (#55206)
Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
2021-09-01 10:03:41 +02:00
mbo18 a28593f133 Add vacation mode to manual alarm_control_panel (#55340)
* Add vacation mode

* Add vacation to demo

* Deduplicate code in tests
2021-09-01 09:34:21 +02:00
Brian Egge 889aced3b6 Fix None support_color_modes TypeError (#55497)
* Fix None support_color_modes TypeError 

https://github.com/home-assistant/core/issues/55451

* Update __init__.py
2021-09-01 08:26:09 +02:00
Paulus Schoutsen a315fd059a Bumped version to 2021.9.0b7 2021-08-31 22:57:33 -07:00
Brett Adams ba9ef004c8 Add missing device class for temperature sensor in Advantage Air (#55508) 2021-08-31 22:57:13 -07:00
Felipe Martins Diel 22f745b17c Fix BroadlinkSwitch._attr_assumed_state (#55505) 2021-08-31 22:57:12 -07:00
muppet3000 05cf223146 Added trailing slash to US growatt URL (#55504) 2021-08-31 22:57:12 -07:00
Erik Montnemery d4aadd8af0 Improve log for sum statistics (#55502) 2021-08-31 22:56:28 -07:00
Erik Montnemery 4045eee2e5 Correct sum statistics when only last_reset has changed (#55498)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-08-31 22:53:58 -07:00
Joakim Sørensen 83a51f7f30 Add cache-control headers to supervisor entrypoint (#55493) 2021-08-31 22:52:05 -07:00
gjong 29110fe157 Remove Youless native unit of measurement (#55492) 2021-08-31 22:52:05 -07:00
gjong e87b7e24b4 Increase YouLess polling interval (#55490) 2021-08-31 22:52:04 -07:00
uvjustin d9056c01a6 Fix ArestSwitchBase missing is on attribute (#55483) 2021-08-31 22:52:03 -07:00
Matthew Garrett a724bc21b6 Assistant sensors (#55480) 2021-08-31 22:52:03 -07:00
Paulus Schoutsen ef00178339 Add Eagle 200 name back (#55477)
* Add Eagle 200 name back

* add comment

* update tests
2021-08-31 22:52:02 -07:00
Erik Montnemery b8770c3958 Make new cycles for sensor sum statistics start with 0 as zero-point (#55473) 2021-08-31 22:52:01 -07:00
Eric Severance f0c0cfcac0 Wemo Insight devices need polling when off (#55348) 2021-08-31 22:52:00 -07:00
Brett Adams 36b37b6db3 Add missing device class for temperature sensor in Advantage Air (#55508) 2021-08-31 22:50:32 -07:00
Felipe Martins Diel 3bc58f9750 Fix BroadlinkSwitch._attr_assumed_state (#55505) 2021-08-31 22:49:56 -07:00
muppet3000 343054494c Added trailing slash to US growatt URL (#55504) 2021-09-01 07:18:20 +02:00
Erik Montnemery 93c086d830 Correct sum statistics when only last_reset has changed (#55498)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-08-31 21:30:52 -07:00
GitHub Action 9e41a37284 [ci skip] Translation update 2021-09-01 00:19:48 +00:00
gjong ff229dd599 Increase YouLess polling interval (#55490) 2021-08-31 12:24:09 -07:00
gjong cc4b2fbcfa Remove Youless native unit of measurement (#55492) 2021-08-31 19:22:00 +02:00
Erik Montnemery 5d1a193eca Improve log for sum statistics (#55502) 2021-08-31 19:15:22 +02:00
uvjustin 71c6f99d31 Fix ArestSwitchBase missing is on attribute (#55483) 2021-08-31 17:30:05 +02:00
Ernst Klamer bd60a58765 Improvements to the solarlog integration (#55405) 2021-08-31 16:46:19 +02:00
Maciej Bieniek 08a0377dcb Add support for Xiaomi Miio Air Purifier 3C (#55484) 2021-08-31 16:44:13 +02:00
Raman Gupta 4d98a7e156 Allow device_id template function to use device name as input (#55474) 2021-08-31 14:56:47 +02:00
Joakim Sørensen 3e38dc0fd9 Add cache-control headers to supervisor entrypoint (#55493) 2021-08-31 14:45:28 +02:00
JasperPlant afc0a1f376 Add TLX daily power meter. for Growatt (#55445) 2021-08-31 11:55:23 +02:00
epenet 1849eae0ff Renault code quality improvements (#55454) 2021-08-31 11:06:54 +02:00
Erik Montnemery f9225bad5f Make new cycles for sensor sum statistics start with 0 as zero-point (#55473) 2021-08-31 10:45:17 +02:00
Eric Severance 88a08fdf57 Wemo Insight devices need polling when off (#55348) 2021-08-31 09:32:26 +02:00
Paulus Schoutsen d277e0fb03 Add Eagle 200 name back (#55477)
* Add Eagle 200 name back

* add comment

* update tests
2021-08-31 08:45:35 +02:00
Feliksas The Lion 13b001cd9b Fix Zone 2 and Zone 3 detection in onkyo (#55471) 2021-08-30 20:33:52 -07:00
Matthew Garrett dd21bf73fc Assistant sensors (#55480) 2021-08-30 20:33:06 -07:00
GitHub Action 368cac7e5d [ci skip] Translation update 2021-08-31 00:17:01 +00:00
Bram Kragten 4c48ad9108 Bumped version to Bumped version to 2021.9.0b6 2021-08-30 23:35:50 +02:00
Bram Kragten 92b0453749 Update frontend to 20210830.0 (#55472) 2021-08-30 23:33:47 +02:00
Raman Gupta 8ab801a7b4 Fix area_id and area_name template functions (#55470) 2021-08-30 23:33:46 +02:00
Aaron Bach f92c7b1aea Bump aioambient to 1.3.0 (#55468) 2021-08-30 23:33:45 +02:00
Aaron Bach 0d9fbf864f Bump pyiqvia to 1.1.0 (#55466) 2021-08-30 23:33:44 +02:00
Aaron Bach 275f9c8a28 Bump pyopenuv to 2.2.0 (#55464) 2021-08-30 23:33:43 +02:00
Erik Montnemery 84f3b1514f Fix race in MQTT sensor when last_reset_topic is configured (#55463) 2021-08-30 23:33:43 +02:00
Greg 802f5613c4 Add IoTaWatt integration (#55364)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-08-30 23:33:42 +02:00
Erik Montnemery 18c03e2f8d Fix race in MQTT sensor when last_reset_topic is configured (#55463) 2021-08-30 23:32:35 +02:00
Bram Kragten 9b3346bc80 Update frontend to 20210830.0 (#55472) 2021-08-30 23:32:19 +02:00
Aaron Bach 76f21452ee Bump aioambient to 1.3.0 (#55468) 2021-08-30 23:05:28 +02:00
ha0y 433775cf4b Add input_select and select domain support for HomeKit (#54760)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-08-30 15:28:26 -05:00
Aaron Bach 46f05ca279 Bump pyopenuv to 2.2.0 (#55464) 2021-08-30 13:12:27 -07:00
Aaron Bach 3d9d104482 Bump pyiqvia to 1.1.0 (#55466) 2021-08-30 13:12:09 -07:00
Raman Gupta 1d1b5ab345 Fix area_id and area_name template functions (#55470) 2021-08-30 13:09:41 -07:00
Marc Mueller 1c01ff401f Use EntityDescription - qnap (#55410)
* Use EntityDescription - qnap

* Remove default values
2021-08-30 21:59:50 +02:00
Greg 3bd9be2f6d Add IoTaWatt integration (#55364)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2021-08-30 12:52:29 -07:00
Aaron Bach daa9c8d856 Add -term statistics for Notion sensors (#55414) 2021-08-30 19:07:05 +02:00
Aaron Bach 1aa30ea87b Add long-term statistics for SimpliSafe sensors (#55419) 2021-08-30 19:04:21 +02:00
Paulus Schoutsen 8be40cbb00 Bumped version to 2021.9.0b5 2021-08-30 09:41:51 -07:00
Raman Gupta 46ce4e92f6 Bump zwave-js-server-python to 0.29.1 (#55460) 2021-08-30 09:41:42 -07:00
J. Nick Koston 39f11bb46d Bump zeroconf to 0.36.2 (#55459)
- Now sends NSEC records when requesting non-existent address types
  Implements RFC6762 sec 6.2 (http://datatracker.ietf.org/doc/html/rfc6762#section-6.2)

- This solves a case where a HomeKit bridge can take a while to update
  because it is waiting to see if an AAAA (IPv6) address is available
2021-08-30 09:41:42 -07:00
Erik Montnemery 3b0fe9adde Revert "Deprecate last_reset options in MQTT sensor" (#55457)
This reverts commit f9fa5fa804.
2021-08-30 09:41:41 -07:00
Simone Chemelli 707778229b Fix noise/attenuation units to UI display for Fritz (#55447) 2021-08-30 09:41:40 -07:00
Erik Montnemery a474534c08 Fix exception when shutting down DSMR (#55441)
* Fix exception when shutting down DSMR

* Update homeassistant/components/dsmr/sensor.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-08-30 09:41:39 -07:00
Erik Montnemery 65ad99d51c Fix crash in buienradar sensor due to self.hass not set (#55438) 2021-08-30 09:41:39 -07:00
Erik Montnemery 4052a0db89 Improve statistics error messages when sensor's unit is changing (#55436)
* Improve error messages when sensor's unit is changing

* Improve test coverage
2021-08-30 09:41:38 -07:00
Raman Gupta b546fc5067 Don't set zwave_js sensor device class to energy when unit is wrong (#55434) 2021-08-30 09:41:37 -07:00
Christopher Kochan 5dcc760755 Add Sense energy sensors (#54833)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-08-30 09:41:36 -07:00
Raman Gupta 331726ec2f Bump zwave-js-server-python to 0.29.1 (#55460) 2021-08-30 09:40:56 -07:00
J. Nick Koston 27ecd43da3 Bump zeroconf to 0.36.2 (#55459)
- Now sends NSEC records when requesting non-existent address types
  Implements RFC6762 sec 6.2 (http://datatracker.ietf.org/doc/html/rfc6762#section-6.2)

- This solves a case where a HomeKit bridge can take a while to update
  because it is waiting to see if an AAAA (IPv6) address is available
2021-08-30 08:59:41 -07:00
Raman Gupta d62a78ae61 Don't set zwave_js sensor device class to energy when unit is wrong (#55434) 2021-08-30 08:48:36 -07:00
Simone Chemelli fa7873dc6d Fix noise/attenuation units to UI display for Fritz (#55447) 2021-08-30 08:43:11 -07:00
Ian de5a22953d Whole-string match reqs in comment_requirement (#55192)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-08-30 08:20:02 -07:00
Andre Richter cbc68e45cd Refactor vallox constants (#55456) 2021-08-30 17:01:45 +02:00
Christopher Kochan c4235edc41 Add Sense energy sensors (#54833)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-08-30 08:01:26 -07:00
Erik Montnemery ed53bb1d91 Revert "Deprecate last_reset options in MQTT sensor" (#55457)
This reverts commit f9fa5fa804.
2021-08-30 16:58:48 +02:00
Joakim Sørensen a668300c2e Use AwesomeVersion for account link service check (#55449) 2021-08-30 14:11:07 +02:00
Erik Montnemery 722aa0895e Improve statistics error messages when sensor's unit is changing (#55436)
* Improve error messages when sensor's unit is changing

* Improve test coverage
2021-08-30 12:51:46 +02:00
Erik Montnemery 7e9f8de7e0 Fix exception when shutting down DSMR (#55441)
* Fix exception when shutting down DSMR

* Update homeassistant/components/dsmr/sensor.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-08-30 12:08:21 +02:00
Erik Montnemery 8faec3da8d Correct setup of system_bridge sensors (#55442) 2021-08-30 12:06:24 +02:00
Erik Montnemery 1060630bbd Fix crash in buienradar sensor due to self.hass not set (#55438) 2021-08-30 10:29:39 +02:00
Aidan Timson 25273c694a System Bridge 2.5.0 - Additional Sensors (#53892)
* Update package to 2.1.0

* Add version sensor

* Add graphics memory sensors

* Change graphics memory data from MB

* Add GPU usage sensor

* Add gpu clock speed sensors

* GPU sensors

* GPU power usage

* enumerate instead of range len

* Updates from rebase

* Add graphics

* Add Per CPU load sensor

* Cleanup

* Use super class attributes

* Suggested changes and fix

* User, System, Idle sensors

* Average, User, System and idle sensors instead of attrs

* Remove unused attrs

* Remove null/none sensor

* Sensor entity descriptions

* Fix index out of range error

* Set state class

* Use entity_registry_enabled_default

* Use built in entity_registry_enabled_default

* Use built in icon

* Fix

* Use binary sensor entity description

* Fix pylint

* Fix uom

* Add to coveragerc

* is_on

* Move entity descriptions to platforms

* Clearout default values

* Fix docstring

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Cleanup and catch

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-08-30 10:26:48 +02:00
uvjustin 071fcee9a9 Remove byte-range addressed parts in stream (#55396)
Add individually addressed parts
2021-08-30 13:20:19 +08:00
Paulus Schoutsen fb06acf39d Bumped version to 2021.9.0b4 2021-08-29 20:45:45 -07:00
Raman Gupta 948f191f16 Make zwave_js discovery log message more descriptive (#55432) 2021-08-29 20:45:33 -07:00
Klaas Schoute 2c0d9105ac Update entity names for P1 Monitor integration (#55430) 2021-08-29 20:45:32 -07:00
J. Nick Koston 10df9f3542 Bump zeroconf to 0.36.1 (#55425)
- Fixes duplicate records in the cache

- Changelog: https://github.com/jstasiak/python-zeroconf/compare/0.36.0...0.36.1
2021-08-29 20:45:32 -07:00
Aaron Bach 6cf799459b Ensure ReCollect Waste shows pickups for midnight on the actual day (#55424) 2021-08-29 20:44:57 -07:00
Marc Mueller 47e2d1caa5 Fix device_class - qnap drive_temp sensor (#55409) 2021-08-29 20:41:25 -07:00
J. Nick Koston 69d8f94e3b Show device_id in HomeKit when the device registry entry is missing a name (#55391)
- Reported at: https://community.home-assistant.io/t/homekit-unknown-error-occurred/333385
2021-08-29 20:41:24 -07:00
Aaron Bach 4b7803ed03 Bump simplisafe-python to 11.0.6 (#55385) 2021-08-29 20:41:24 -07:00
J. Nick Koston ff6015ff89 Implement import of consider_home in nmap_tracker to avoid breaking change (#55379) 2021-08-29 20:41:23 -07:00
Matt Krasowski fbd144de46 Handle incorrect values reported by some Shelly devices (#55042) 2021-08-29 20:41:22 -07:00
J. Nick Koston 5549a925b8 Implement import of consider_home in nmap_tracker to avoid breaking change (#55379) 2021-08-29 20:38:41 -07:00
Marc Mueller be04d7b92e Fix device_class - qnap drive_temp sensor (#55409) 2021-08-29 20:30:54 -07:00
J. Nick Koston f37c541a50 Bump zeroconf to 0.36.1 (#55425)
- Fixes duplicate records in the cache

- Changelog: https://github.com/jstasiak/python-zeroconf/compare/0.36.0...0.36.1
2021-08-29 20:29:46 -07:00
Klaas Schoute 6823b14d4c Update entity names for P1 Monitor integration (#55430) 2021-08-29 20:29:37 -07:00
Aaron Bach 94e0db8ec4 Ensure ReCollect Waste shows pickups for midnight on the actual day (#55424) 2021-08-29 20:27:34 -07:00
Raman Gupta ebc2a0103e Make zwave_js discovery log message more descriptive (#55432) 2021-08-29 20:25:47 -07:00
GitHub Action ea7f3c8bb3 [ci skip] Translation update 2021-08-30 00:11:40 +00:00
Aaron Bach 32df2f7d8b Deprecate YAML config for ReCollect Waste (#55426) 2021-08-29 14:03:44 -06:00
Aaron Bach b43c80ca21 Give ReCollect Waste sensor a friendlier label (#55427) 2021-08-29 14:03:09 -06:00
Andre Richter fa201b6c2b Add myself to Vallox codeowners (#55428) 2021-08-29 14:02:52 -06:00
Robert Svensson 76ce33dc24 Only return not return None (#55423) 2021-08-29 13:10:18 -06:00
Erik Montnemery 8b436c43f7 Enable basic type checking for cert_expiry (#55335) 2021-08-29 10:57:18 -06:00
Matt Krasowski fd66120d6d Handle incorrect values reported by some Shelly devices (#55042) 2021-08-29 14:52:12 +02:00
J. Nick Koston 43b8353566 Show device_id in HomeKit when the device registry entry is missing a name (#55391)
- Reported at: https://community.home-assistant.io/t/homekit-unknown-error-occurred/333385
2021-08-29 09:01:04 +02:00
Aaron Bach 4aed0b6ccf Use EntityDescription - ambient_station (#55366) 2021-08-28 21:31:18 -06:00
Aidan Timson 3647ada143 OVO Energy - Post #54952 Cleanup (#55393) 2021-08-28 22:31:07 -05:00
Aaron Bach 2dddd31d97 Simplify calcuation of Notion binary sensor state (#55387) 2021-08-28 21:30:44 -06:00
uvjustin 923158cfba Add ll hls to stream (#49608) 2021-08-29 09:53:41 +08:00
GitHub Action 291a2d6258 [ci skip] Translation update 2021-08-29 00:11:57 +00:00
J. Nick Koston 43288d3e1f Prevent storage loads from monopolizing the executor pool (#55389)
* Prevent storage loads from monopolizing the executor pool

- At startup there is an increasing demand to load data
  from storage. Similar to #49451 and #43085, we now prevent
  the thread pool from being monopolized by storage loads and
  allow other consumers that are doing network I/O to proceed
  without having to wait for a free executor thread.

* Only create Semaphore instance when one is not already there
2021-08-28 18:30:20 -05:00
J. Nick Koston d41fa66bca Remove legacy discovery after_dependencies from apple_tv (#55390)
- apple_tv devices are now discovered by zeroconf, and legacy discovery
  is no longer needed
2021-08-28 18:30:07 -05:00
Michael f1ba98927c Address late fritzbox comments (#55388)
* correct imports

* move platform specifics into platforms

* move descriptions into platforms
2021-08-28 23:07:06 +02:00
jan iversen f91cc21bbd Solve modbus shutdown racing condition (#55373) 2021-08-28 23:04:33 +02:00
Michael 13cc671844 Re-configuration possibilities for Synology DSM (#53285)
* add automated host/ip reconfig via SSDP

* add reconfig of existing entry

* adjust tests

* adjust tests again

* use self._async_current_entries()

* _async_get_existing_entry()

* apply suggestions
2021-08-28 14:11:51 -05:00
Matthieu 979797136a Add select entity to Logitech Harmony (#53943)
Co-authored-by: J. Nick Koston <nick@koston.org>
2021-08-28 14:10:19 -05:00
Aaron Bach 778fa2e3fe Bump simplisafe-python to 11.0.6 (#55385) 2021-08-28 12:57:02 -06:00
Paulus Schoutsen adaebdeea8 Bumped version to 2021.9.0b3 2021-08-28 08:59:25 -07:00
Maciej Bieniek 910cb5865a Address late review for Tractive integration (#55371) 2021-08-28 08:58:38 -07:00
Joakim Sørensen baf0d9b2d9 Pin regex to 2021.8.28 (#55368) 2021-08-28 08:58:37 -07:00
Jason Hunter c1bce68549 close connection on connection retry, bump onvif lib (#55363) 2021-08-28 08:58:36 -07:00
Nathan Spencer bde4c0e46f Bump pylitterbot to 2021.8.1 (#55360) 2021-08-28 08:58:35 -07:00
Paulus Schoutsen a275e7aa67 Fix wolflink super call (#55359) 2021-08-28 08:58:35 -07:00
Aaron Bach d96e416d26 Ensure ReCollect Waste starts up even if no future pickup is found (#55349) 2021-08-28 08:58:34 -07:00
Paulus Schoutsen efc3894303 Convert solarlog to coordinator (#55345) 2021-08-28 08:58:33 -07:00
Daniel Hjelseth Høyer 06b47ee2f5 Tractive name (#55342) 2021-08-28 08:58:33 -07:00
Raman Gupta 08ca43221f Listen to node events in the zwave_js node status sensor (#55341) 2021-08-28 08:58:32 -07:00
J. Nick Koston 8641740ed8 Ensure yeelights resync state if they are busy on first connect (#55333) 2021-08-28 08:58:31 -07:00
Daniel Hjelseth Høyer 6a93f5b7ad Tractive name (#55342) 2021-08-28 08:57:57 -07:00
Maciej Bieniek 19873e6547 Address late review for Tractive integration (#55371) 2021-08-28 17:49:34 +02:00
Joakim Sørensen 2fcd77098d Pin regex to 2021.8.28 (#55368) 2021-08-28 15:00:14 +02:00
jan iversen d1965eef8b Activate mypy for sonar (#55327)
* Please mypy.
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-08-28 12:05:48 +02:00
jan iversen 16351ef3c2 Add shutdown test. (#55357) 2021-08-28 08:11:58 +02:00
Nathan Spencer e2f257cb63 Bump pylitterbot to 2021.8.1 (#55360) 2021-08-27 20:58:21 -07:00
Maciej Bieniek ea8702b0df Address late review for Xiaomi Miio number platform (#55275) 2021-08-27 21:41:15 -05:00
Joakim Sørensen 470aa7e871 Add data update coordinator to the Tautulli integration (#54706)
* Add data update coordinator to the Tautulli integration

* update .coveragerc

* Add guard for UpdateFailed

* Apply suggestions from code review

Co-authored-by: Chris Talkington <chris@talkingtontech.com>

* ignore issues

Co-authored-by: Chris Talkington <chris@talkingtontech.com>
2021-08-27 20:39:12 -05:00
Jason Hunter 61a7ce173c close connection on connection retry, bump onvif lib (#55363) 2021-08-27 17:34:32 -07:00
GitHub Action b0c52220bc [ci skip] Translation update 2021-08-28 00:11:00 +00:00
Raman Gupta 714564eaa6 Listen to node events in the zwave_js node status sensor (#55341) 2021-08-27 15:01:20 -07:00
Aaron Bach 1f37c215f6 Ensure ReCollect Waste starts up even if no future pickup is found (#55349) 2021-08-27 15:00:17 -07:00
Paulus Schoutsen 46d0523f98 Convert solarlog to coordinator (#55345) 2021-08-27 14:59:55 -07:00
Paulus Schoutsen eb458fb1d5 Fix wolflink super call (#55359) 2021-08-27 14:59:28 -07:00
J. Nick Koston 10fa63775d Ensure yeelights resync state if they are busy on first connect (#55333) 2021-08-27 12:43:53 -05:00
Paulus Schoutsen d0ada6c6e2 Bumped version to 2021.9.0b2 2021-08-27 10:00:20 -07:00
Anders Melchiorsen 76bb036968 Upgrade aiolifx to 0.6.10 (#55344) 2021-08-27 10:00:00 -07:00
J. Nick Koston d8b64be41c Retrigger config flow when the ssdp location changes for a UDN (#55343)
Fixes #55229
2021-08-27 09:59:59 -07:00
jan iversen b3e0b7b86e Add modbus name to log_error (#55336) 2021-08-27 09:59:59 -07:00
Chris Talkington e097e4c1c2 Fix reauth for sonarr (#55329)
* fix reauth for sonarr

* Update config_flow.py

* Update config_flow.py

* Update config_flow.py

* Update test_config_flow.py

* Update config_flow.py

* Update test_config_flow.py

* Update config_flow.py
2021-08-27 09:59:58 -07:00
Robert Hillis 34f0fecef8 Fix sonos alarm schema (#55318) 2021-08-27 09:59:57 -07:00
Erik Montnemery f53a10d39a Handle statistics for sensor with changing state class (#55316) 2021-08-27 09:59:56 -07:00
J. Nick Koston 5b993129d6 Fix lifx model to be a string (#55309)
Fixes #55307
2021-08-27 09:59:56 -07:00
J. Nick Koston 865656d436 Always send powerview move command in case shade is out of sync (#55308) 2021-08-27 09:59:55 -07:00
Aaron Bach fb25c6c115 Bump simplisafe-python to 11.0.5 (#55306) 2021-08-27 09:59:54 -07:00
Aaron Bach c963cf8743 Bump aiorecollect to 1.0.8 (#55300) 2021-08-27 09:59:54 -07:00
rikroe ddb28db21a Bump bimmer_connected to 0.7.20 (#55299) 2021-08-27 09:59:53 -07:00
J. Nick Koston bfc98b444f Fix creation of new nmap tracker entities (#55297) 2021-08-27 09:59:52 -07:00
realPy f9a0f44137 Correct flash light livarno when use hue (#55294)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-08-27 09:59:51 -07:00
J. Nick Koston 93750d71ce Gracefully handle pyudev failing to filter on WSL (#55286)
* Gracefully handle pyudev failing to filter on WSL

* add debug message

* add mocks so we reach the new check
2021-08-27 09:59:51 -07:00
Paulus Schoutsen 06e4003640 Bump ring to 0.7.1 (#55282) 2021-08-27 09:59:50 -07:00
J. Nick Koston 97ff5e2085 Set yeelight capabilities from external discovery (#55280) 2021-08-27 09:59:49 -07:00
J. Nick Koston 8a2c07ce19 Ensure yeelight model is set in the config entry (#55281)
* Ensure yeelight model is set in the config entry

- If the model was not set in the config entry the light could
  be sent commands it could not handle

* update tests

* fix test
2021-08-27 09:59:21 -07:00
J. Nick Koston 9f7398e0df Fix yeelight brightness when nightlight switch is disabled (#55278) 2021-08-27 09:57:07 -07:00
J. Nick Koston 7df84dadad Fix some yeelights showing wrong state after on/off (#55279) 2021-08-27 09:56:22 -07:00
Chris 2a1e943b18 Fix unique_id conflict in smarttthings (#55235) 2021-08-27 09:54:26 -07:00
prwood80 e6e72bfa82 Improve performance of ring camera still images (#53803)
Co-authored-by: Pat Wood <prwood80@users.noreply.github.com>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-08-27 09:54:25 -07:00
Anders Melchiorsen ed19fdd462 Upgrade aiolifx to 0.6.10 (#55344) 2021-08-27 09:53:42 -07:00
J. Nick Koston 2cc87cb7ab Retrigger config flow when the ssdp location changes for a UDN (#55343)
Fixes #55229
2021-08-27 09:53:29 -07:00
jan iversen 7ac72ebf38 Add modbus name to log_error (#55336) 2021-08-27 09:26:57 -07:00
Robert Hillis 98c8782c2b Fix sonos alarm schema (#55318) 2021-08-27 09:25:40 -07:00
realPy 7bd7d644a0 Correct flash light livarno when use hue (#55294)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-08-27 09:25:27 -07:00
prwood80 3f2fad1a27 Improve performance of ring camera still images (#53803)
Co-authored-by: Pat Wood <prwood80@users.noreply.github.com>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2021-08-27 09:22:49 -07:00
Chris Talkington 819fd811af Fix reauth for sonarr (#55329)
* fix reauth for sonarr

* Update config_flow.py

* Update config_flow.py

* Update config_flow.py

* Update test_config_flow.py

* Update config_flow.py

* Update test_config_flow.py

* Update config_flow.py
2021-08-27 11:04:07 -05:00
Michael e2dac31471 Use EntityDescription - fritzbox (#55104)
* Use sensor entity description

* check if not none instead if callable

* List comprehension in switch and climate

* change state to native_value in description

* merge FritzBoxSensorEntity into FritzBoxEntity

* rename SENSOR_DESCRIPTIONS to SENSOR_TYPES

* use mixins for descriptions

* use comprehension in async_setup_entry()

* improve extra_state_attributes
2021-08-27 17:09:34 +02:00
Erik Montnemery 7e70252de5 Handle statistics for sensor with changing state class (#55316) 2021-08-27 16:18:49 +02:00
J. Nick Koston cc857abfd2 Adjust zha comment to be readable (#55330) 2021-08-27 16:01:26 +02:00
epenet adab367f0e Renault code quality improvements (#55313)
* Use constants

* Drop entity_class for binary_sensor

* Move data property from RenaultDataEntity to RenaultSensor

* Update function description
2021-08-27 12:12:09 +02:00
rikroe 259eeb3169 Bump bimmer_connected to 0.7.20 (#55299) 2021-08-27 12:03:25 +02:00
J. Nick Koston efb1fb9978 Always send powerview move command in case shade is out of sync (#55308) 2021-08-27 08:49:50 +02:00
Aaron Bach 5693f9ff9b Bump simplisafe-python to 11.0.5 (#55306) 2021-08-27 08:48:20 +02:00
epenet 9ba504cd78 Address late review for Renault integration (#55230)
* Add type hints

* Fix isort

* tweaks to state attributes

* Move lambdas to regular functions

* Split CHECK_ATTRIBUTES into DYNAMIC_ATTRIBUTES and FIXED_ATTRIBUTES

* Clarify tests

* Fix typo
2021-08-27 07:22:23 +02:00
J. Nick Koston 176fd39e0b Fix lifx model to be a string (#55309)
Fixes #55307
2021-08-27 06:37:28 +02:00
Matthias Alphart cd0ae66d58 Add CONF_STATE_CLASS to sensor/__init__.py (#54106)
* add CONF_STATE_CLASS to const.py

* move to `sensor/__init__.py`

* move to sensor/const.py

* Revert "move to sensor/const.py"

This reverts commit 604d0d066bfcb93f1a11e3d7732d430ab6de8d59.

* move it to `sensor/const.py` but import it from `sensor/__init__.py`

* add Modbus
2021-08-27 05:54:50 +02:00
GitHub Action 65d14909ee [ci skip] Translation update 2021-08-27 00:14:42 +00:00
J. Nick Koston 5393a16c44 Set yeelight capabilities from external discovery (#55280) 2021-08-26 19:04:12 -05:00
Aaron Bach cbd65efe52 Bump aiorecollect to 1.0.8 (#55300) 2021-08-26 16:59:27 -06:00
J. Nick Koston ef10773202 Fix creation of new nmap tracker entities (#55297) 2021-08-26 15:02:49 -07:00
J. Nick Koston dfc2556669 Gracefully handle pyudev failing to filter on WSL (#55286)
* Gracefully handle pyudev failing to filter on WSL

* add debug message

* add mocks so we reach the new check
2021-08-26 15:47:10 -05:00
Chris 14aa19b814 Fix unique_id conflict in smarttthings (#55235) 2021-08-26 13:43:26 -07:00
J. Nick Koston c3972b22fd Fix yeelight brightness when nightlight switch is disabled (#55278) 2021-08-26 15:18:36 -05:00
J. Nick Koston ae1d2926cf Fix some yeelights showing wrong state after on/off (#55279) 2021-08-26 13:25:26 -05:00
J. Nick Koston 089dfad78a Ensure yeelight model is set in the config entry (#55281)
* Ensure yeelight model is set in the config entry

- If the model was not set in the config entry the light could
  be sent commands it could not handle

* update tests

* fix test
2021-08-26 13:02:59 -05:00
Paulus Schoutsen f6bb5c77a0 Bump ring to 0.7.1 (#55282) 2021-08-26 10:37:53 -07:00
Maciej Bieniek eb9d242ade Move AirlySensorEntityDescription to sensor platform (#55277) 2021-08-26 18:40:42 +02:00
Paulus Schoutsen 219868b308 Bumped version to 2021.9.0b1 2021-08-26 09:37:25 -07:00
Maciej Bieniek 67dd861d8c Fix AttributeError for non-MIOT Xiaomi Miio purifiers (#55271) 2021-08-26 09:37:20 -07:00
Florian Gareis f2765ba320 Don't create DSL sensor for devices that don't support DSL (#55269) 2021-08-26 09:37:19 -07:00
Erik Montnemery aefd3df914 Warn if a sensor with state_class_total has a decreasing value twice (#55251) 2021-08-26 09:37:18 -07:00
Franck Nijhof 3658eeb8d1 Fix MQTT add-on discovery to be ignorable (#55250) 2021-08-26 09:37:07 -07:00
Erik Montnemery 080cb6b6e9 Fix double precision float for postgresql (#55249) 2021-08-26 09:37:06 -07:00
Joakim Sørensen 20796303da Only postfix image name for container (#55248) 2021-08-26 09:37:06 -07:00
J. Nick Koston dff6151ff4 Abort zha usb discovery if deconz is setup (#55245)
* Abort zha usb discovery if deconz is setup

* Update tests/components/zha/test_config_flow.py

* add deconz domain const

* Update homeassistant/components/zha/config_flow.py

Co-authored-by: Robert Svensson <Kane610@users.noreply.github.com>

Co-authored-by: Robert Svensson <Kane610@users.noreply.github.com>
2021-08-26 09:37:05 -07:00
Alexei Chetroi 6f24f4e302 Bump up ZHA dependencies (#55242)
* Bump up ZHA dependencies

* Bump up zha-device-handlers
2021-08-26 09:37:04 -07:00
J. Nick Koston 175febe635 Defer zha auto configure probe until after clicking configure (#55239) 2021-08-26 09:37:03 -07:00
J. Nick Koston aa907f4d10 Only warn once per entity when the async_camera_image signature needs to be updated (#55238) 2021-08-26 09:37:02 -07:00
J. Nick Koston 3d09478aea Limit USB discovery to specific manufacturer/description/serial_number matches (#55236)
* Limit USB discovery to specific manufacturer/description/serial_number matches

* test for None case
2021-08-26 09:37:01 -07:00
Marc Mueller 05df9b4b8b Remove temperature conversion - tado (#55231) 2021-08-26 09:37:01 -07:00
jjlawren 1865a28083 Set up polling task with subscriptions in Sonos (#54355) 2021-08-26 09:37:00 -07:00
J. Nick Koston fbcf21412d Only warn once per entity when the async_camera_image signature needs to be updated (#55238) 2021-08-26 09:36:25 -07:00
jjlawren b3e84c6ee8 Set up polling task with subscriptions in Sonos (#54355) 2021-08-26 09:35:35 -07:00
Florian Gareis c3316df31d Don't create DSL sensor for devices that don't support DSL (#55269) 2021-08-26 09:33:41 -07:00
Maciej Bieniek f942cb03a4 Fix AttributeError for non-MIOT Xiaomi Miio purifiers (#55271) 2021-08-26 09:29:25 -07:00
Alexei Chetroi d3ac72d013 Bump up ZHA dependencies (#55242)
* Bump up ZHA dependencies

* Bump up zha-device-handlers
2021-08-26 11:38:35 -04:00
J. Nick Koston d59ea5329e Abort zha usb discovery if deconz is setup (#55245)
* Abort zha usb discovery if deconz is setup

* Update tests/components/zha/test_config_flow.py

* add deconz domain const

* Update homeassistant/components/zha/config_flow.py

Co-authored-by: Robert Svensson <Kane610@users.noreply.github.com>

Co-authored-by: Robert Svensson <Kane610@users.noreply.github.com>
2021-08-26 10:00:32 -04:00
J. Nick Koston d4fa625a7f Defer zha auto configure probe until after clicking configure (#55239) 2021-08-26 09:59:41 -04:00
J. Nick Koston a89057ece5 Limit USB discovery to specific manufacturer/description/serial_number matches (#55236)
* Limit USB discovery to specific manufacturer/description/serial_number matches

* test for None case
2021-08-26 09:59:02 -04:00
jan iversen 2d5176eee9 Change entity_timers to be a local variable. (#55258)
Ensure outstanding pymodbus calls are handled before closing.
2021-08-26 15:23:00 +02:00
Erik Montnemery 0a07ff4d23 Warn if a sensor with state_class_total has a decreasing value twice (#55251) 2021-08-26 14:27:14 +02:00
Franck Nijhof 96303a1d80 Fix MQTT add-on discovery to be ignorable (#55250) 2021-08-26 11:14:42 +02:00
Joakim Sørensen 03d3bbfba1 Only postfix image name for container (#55248) 2021-08-26 10:54:42 +02:00
Eric Severance 56246056ce Be tolerant of Wemo insight_param keys that might not exist (#55232) 2021-08-26 10:27:06 +02:00
Erik Montnemery 6d4a47a53d Fix double precision float for postgresql (#55249) 2021-08-26 10:06:53 +02:00
Milan Meulemans e6d710c203 Remove option and range checks in Rituals integration (#55222)
* Fix number

* Fix select
2021-08-26 08:37:27 +02:00
Sean Vig b45c985d58 Remove un-needed asserts on hass in Amecrest (#55244) 2021-08-26 08:34:58 +02:00
GitHub Action 3d7bfa8357 [ci skip] Translation update 2021-08-26 00:13:27 +00:00
Marc Mueller b81c2806bb Remove temperature conversion - tado (#55231) 2021-08-26 00:37:18 +02:00
Franck Nijhof 06a30c882f Bump version to 2021.10.0dev0 (#55227) 2021-08-25 23:19:14 +02:00
epenet 9315f3bdd9 Use EntityDescription - renault (#55061)
* Cleanup sensor.py

* Add EntityDescription

* Add checks for state attributes

* Fix pylint

* Simplify checks

* Add icon checks

* Update data type

* Use mixin for required keys, and review class initialisation

* Add constraint to TypeVar("T")

* Enable lambda for icon handling

* Enable lambda for value handling

* Enable lambda for value handling
2021-08-25 23:15:49 +02:00
1989 changed files with 70020 additions and 38104 deletions
+31 -20
View File
@@ -36,6 +36,8 @@ omit =
homeassistant/components/agent_dvr/helpers.py
homeassistant/components/airnow/__init__.py
homeassistant/components/airnow/sensor.py
homeassistant/components/airthings/__init__.py
homeassistant/components/airthings/sensor.py
homeassistant/components/airtouch4/__init__.py
homeassistant/components/airtouch4/climate.py
homeassistant/components/airtouch4/const.py
@@ -49,6 +51,7 @@ omit =
homeassistant/components/alarmdecoder/sensor.py
homeassistant/components/alpha_vantage/sensor.py
homeassistant/components/amazon_polly/*
homeassistant/components/amberelectric/__init__.py
homeassistant/components/ambiclimate/climate.py
homeassistant/components/ambient_station/*
homeassistant/components/amcrest/*
@@ -171,6 +174,13 @@ omit =
homeassistant/components/coolmaster/const.py
homeassistant/components/cppm_tracker/device_tracker.py
homeassistant/components/cpuspeed/sensor.py
homeassistant/components/crownstone/__init__.py
homeassistant/components/crownstone/const.py
homeassistant/components/crownstone/listeners.py
homeassistant/components/crownstone/helpers.py
homeassistant/components/crownstone/devices.py
homeassistant/components/crownstone/entry_manager.py
homeassistant/components/crownstone/light.py
homeassistant/components/cups/sensor.py
homeassistant/components/currencylayer/sensor.py
homeassistant/components/daikin/*
@@ -203,7 +213,6 @@ omit =
homeassistant/components/dlib_face_detect/image_processing.py
homeassistant/components/dlib_face_identify/image_processing.py
homeassistant/components/dlink/switch.py
homeassistant/components/dlna_dmr/media_player.py
homeassistant/components/dnsip/sensor.py
homeassistant/components/dominos/*
homeassistant/components/doods/*
@@ -368,7 +377,6 @@ omit =
homeassistant/components/garages_amsterdam/sensor.py
homeassistant/components/gc100/*
homeassistant/components/geniushub/*
homeassistant/components/generic_hygrostat/*
homeassistant/components/github/sensor.py
homeassistant/components/gitlab_ci/sensor.py
homeassistant/components/gitter/sensor.py
@@ -687,7 +695,6 @@ omit =
homeassistant/components/nad/media_player.py
homeassistant/components/nanoleaf/__init__.py
homeassistant/components/nanoleaf/light.py
homeassistant/components/nanoleaf/util.py
homeassistant/components/neato/__init__.py
homeassistant/components/neato/api.py
homeassistant/components/neato/camera.py
@@ -699,7 +706,10 @@ omit =
homeassistant/components/nello/lock.py
homeassistant/components/nest/legacy/*
homeassistant/components/netdata/sensor.py
homeassistant/components/netgear/__init__.py
homeassistant/components/netgear/device_tracker.py
homeassistant/components/netgear/router.py
homeassistant/components/netgear/sensor.py
homeassistant/components/netgear_lte/*
homeassistant/components/netio/switch.py
homeassistant/components/neurio_energy/sensor.py
@@ -754,6 +764,7 @@ omit =
homeassistant/components/opencv/*
homeassistant/components/openevse/sensor.py
homeassistant/components/openexchangerates/sensor.py
homeassistant/components/opengarage/__init__.py
homeassistant/components/opengarage/cover.py
homeassistant/components/openhome/__init__.py
homeassistant/components/openhome/media_player.py
@@ -864,9 +875,6 @@ omit =
homeassistant/components/rest/switch.py
homeassistant/components/ring/camera.py
homeassistant/components/ripple/sensor.py
homeassistant/components/rituals_perfume_genie/binary_sensor.py
homeassistant/components/rituals_perfume_genie/number.py
homeassistant/components/rituals_perfume_genie/select.py
homeassistant/components/rocketchat/notify.py
homeassistant/components/roomba/__init__.py
homeassistant/components/roomba/binary_sensor.py
@@ -990,7 +998,6 @@ omit =
homeassistant/components/squeezebox/__init__.py
homeassistant/components/squeezebox/browse_media.py
homeassistant/components/squeezebox/media_player.py
homeassistant/components/ssdp/util.py
homeassistant/components/starline/*
homeassistant/components/starlingbank/sensor.py
homeassistant/components/steam_online/sensor.py
@@ -1001,12 +1008,20 @@ omit =
homeassistant/components/suez_water/*
homeassistant/components/supervisord/sensor.py
homeassistant/components/surepetcare/__init__.py
homeassistant/components/surepetcare/entity.py
homeassistant/components/surepetcare/binary_sensor.py
homeassistant/components/surepetcare/sensor.py
homeassistant/components/swiss_hydrological_data/sensor.py
homeassistant/components/swiss_public_transport/sensor.py
homeassistant/components/swisscom/device_tracker.py
homeassistant/components/switchbot/switch.py
homeassistant/components/switchbot/binary_sensor.py
homeassistant/components/switchbot/__init__.py
homeassistant/components/switchbot/const.py
homeassistant/components/switchbot/entity.py
homeassistant/components/switchbot/cover.py
homeassistant/components/switchbot/sensor.py
homeassistant/components/switchbot/coordinator.py
homeassistant/components/switchmate/switch.py
homeassistant/components/syncthing/__init__.py
homeassistant/components/syncthing/sensor.py
@@ -1032,6 +1047,8 @@ omit =
homeassistant/components/tank_utility/sensor.py
homeassistant/components/tankerkoenig/*
homeassistant/components/tapsaff/binary_sensor.py
homeassistant/components/tautulli/const.py
homeassistant/components/tautulli/coordinator.py
homeassistant/components/tautulli/sensor.py
homeassistant/components/ted5000/sensor.py
homeassistant/components/telegram/notify.py
@@ -1047,14 +1064,6 @@ omit =
homeassistant/components/telnet/switch.py
homeassistant/components/temper/sensor.py
homeassistant/components/tensorflow/image_processing.py
homeassistant/components/tesla/__init__.py
homeassistant/components/tesla/binary_sensor.py
homeassistant/components/tesla/climate.py
homeassistant/components/tesla/const.py
homeassistant/components/tesla/device_tracker.py
homeassistant/components/tesla/lock.py
homeassistant/components/tesla/sensor.py
homeassistant/components/tesla/switch.py
homeassistant/components/tfiac/climate.py
homeassistant/components/thermoworks_smoke/sensor.py
homeassistant/components/thethingsnetwork/*
@@ -1088,16 +1097,15 @@ omit =
homeassistant/components/totalconnect/binary_sensor.py
homeassistant/components/totalconnect/const.py
homeassistant/components/touchline/climate.py
homeassistant/components/tplink/common.py
homeassistant/components/tplink/switch.py
homeassistant/components/tplink_lte/*
homeassistant/components/traccar/device_tracker.py
homeassistant/components/traccar/const.py
homeassistant/components/trackr/device_tracker.py
homeassistant/components/tractive/__init__.py
homeassistant/components/tractive/binary_sensor.py
homeassistant/components/tractive/device_tracker.py
homeassistant/components/tractive/entity.py
homeassistant/components/tractive/sensor.py
homeassistant/components/tractive/switch.py
homeassistant/components/tradfri/*
homeassistant/components/trafikverket_train/sensor.py
homeassistant/components/trafikverket_weatherstation/sensor.py
@@ -1107,9 +1115,9 @@ omit =
homeassistant/components/transmission/errors.py
homeassistant/components/travisci/sensor.py
homeassistant/components/tuya/__init__.py
homeassistant/components/tuya/base.py
homeassistant/components/tuya/climate.py
homeassistant/components/tuya/const.py
homeassistant/components/tuya/cover.py
homeassistant/components/tuya/fan.py
homeassistant/components/tuya/light.py
homeassistant/components/tuya/scene.py
@@ -1177,6 +1185,8 @@ omit =
homeassistant/components/waterfurnace/*
homeassistant/components/watson_iot/*
homeassistant/components/watson_tts/tts.py
homeassistant/components/watttime/__init__.py
homeassistant/components/watttime/sensor.py
homeassistant/components/waze_travel_time/__init__.py
homeassistant/components/waze_travel_time/helpers.py
homeassistant/components/waze_travel_time/sensor.py
@@ -1283,5 +1293,6 @@ exclude_lines =
raise AssertionError
raise NotImplementedError
# TYPE_CHECKING block is never executed during pytest run
# TYPE_CHECKING and @overload blocks are never executed during pytest run
if TYPE_CHECKING:
@overload
+2 -2
View File
@@ -133,7 +133,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build base image
uses: home-assistant/builder@2021.07.0
uses: home-assistant/builder@2021.09.0
with:
args: |
$BUILD_ARGS \
@@ -186,7 +186,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build base image
uses: home-assistant/builder@2021.07.0
uses: home-assistant/builder@2021.09.0
with:
args: |
$BUILD_ARGS \
+2 -2
View File
@@ -10,7 +10,7 @@ on:
pull_request: ~
env:
CACHE_VERSION: 2
CACHE_VERSION: 3
DEFAULT_PYTHON: 3.8
PRE_COMMIT_CACHE: ~/.cache/pre-commit
SQLALCHEMY_WARN_20: 1
@@ -740,4 +740,4 @@ jobs:
coverage report --fail-under=94
coverage xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2.0.3
uses: codecov/codecov-action@v2.1.0
+5 -5
View File
@@ -9,12 +9,12 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2.1.2
- uses: dessant/lock-threads@v3
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: "30"
issue-exclude-created-before: "2020-10-01T00:00:00Z"
issue-inactive-days: "30"
exclude-issue-created-before: "2020-10-01T00:00:00Z"
issue-lock-reason: ""
pr-lock-inactive-days: "1"
pr-exclude-created-before: "2020-11-01T00:00:00Z"
pr-inactive-days: "1"
exclude-pr-created-before: "2020-11-01T00:00:00Z"
pr-lock-reason: ""
+2 -4
View File
@@ -65,7 +65,6 @@ jobs:
matrix:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
tag:
- "3.9-alpine3.13"
- "3.9-alpine3.14"
steps:
- name: Checkout the repository
@@ -90,7 +89,7 @@ jobs:
wheels-key: ${{ secrets.WHEELS_KEY }}
wheels-user: wheels
env-file: true
apk: "build-base;cmake;git;linux-headers;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev"
apk: "build-base;cmake;git;linux-headers;bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;cargo"
pip: "Cython;numpy"
skip-binary: aiohttp
constraints: "homeassistant/package_constraints.txt"
@@ -106,7 +105,6 @@ jobs:
matrix:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
tag:
- "3.9-alpine3.13"
- "3.9-alpine3.14"
steps:
- name: Checkout the repository
@@ -160,7 +158,7 @@ jobs:
wheels-key: ${{ secrets.WHEELS_KEY }}
wheels-user: wheels
env-file: true
apk: "build-base;cmake;git;linux-headers;libexecinfo-dev;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;gammu-dev"
apk: "build-base;cmake;git;linux-headers;libexecinfo-dev;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;gammu-dev;cargo"
pip: "Cython;numpy;scikit-build"
skip-binary: aiohttp
constraints: "homeassistant/package_constraints.txt"
+1 -1
View File
@@ -1,4 +1,4 @@
config/*
/config
config2/*
tests/testing_config/deps
+2 -2
View File
@@ -1,11 +1,11 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v2.23.3
rev: v2.27.0
hooks:
- id: pyupgrade
args: [--py38-plus]
- repo: https://github.com/psf/black
rev: 21.7b0
rev: 21.9b0
hooks:
- id: black
args:
+10
View File
@@ -27,9 +27,11 @@ homeassistant.components.calendar.*
homeassistant.components.camera.*
homeassistant.components.canary.*
homeassistant.components.cover.*
homeassistant.components.crownstone.*
homeassistant.components.device_automation.*
homeassistant.components.device_tracker.*
homeassistant.components.devolo_home_control.*
homeassistant.components.dlna_dmr.*
homeassistant.components.dnsip.*
homeassistant.components.dsmr.*
homeassistant.components.dunehd.*
@@ -54,6 +56,7 @@ homeassistant.components.huawei_lte.*
homeassistant.components.hyperion.*
homeassistant.components.image_processing.*
homeassistant.components.integration.*
homeassistant.components.iqvia.*
homeassistant.components.knx.*
homeassistant.components.kraken.*
homeassistant.components.lcn.*
@@ -62,6 +65,7 @@ homeassistant.components.local_ip.*
homeassistant.components.lock.*
homeassistant.components.mailbox.*
homeassistant.components.media_player.*
homeassistant.components.modbus.*
homeassistant.components.mysensors.*
homeassistant.components.nam.*
homeassistant.components.neato.*
@@ -85,6 +89,7 @@ homeassistant.components.recorder.statistics
homeassistant.components.remote.*
homeassistant.components.renault.*
homeassistant.components.rituals_perfume_genie.*
homeassistant.components.samsungtv.*
homeassistant.components.scene.*
homeassistant.components.select.*
homeassistant.components.sensor.*
@@ -95,18 +100,23 @@ homeassistant.components.sonos.media_player
homeassistant.components.ssdp.*
homeassistant.components.stream.*
homeassistant.components.sun.*
homeassistant.components.surepetcare.*
homeassistant.components.switch.*
homeassistant.components.switcher_kis.*
homeassistant.components.synology_dsm.*
homeassistant.components.systemmonitor.*
homeassistant.components.tag.*
homeassistant.components.tautulli.*
homeassistant.components.tcp.*
homeassistant.components.tile.*
homeassistant.components.tplink.*
homeassistant.components.tradfri.*
homeassistant.components.tts.*
homeassistant.components.upcloud.*
homeassistant.components.uptime.*
homeassistant.components.uptimerobot.*
homeassistant.components.vacuum.*
homeassistant.components.vallox.*
homeassistant.components.water_heater.*
homeassistant.components.weather.*
homeassistant.components.websocket_api.*
+16 -6
View File
@@ -29,6 +29,7 @@ homeassistant/components/aemet/* @noltari
homeassistant/components/agent_dvr/* @ispysoftware
homeassistant/components/airly/* @bieniu
homeassistant/components/airnow/* @asymworks
homeassistant/components/airthings/* @danielhiversen
homeassistant/components/airtouch4/* @LonePurpleWolf
homeassistant/components/airvisual/* @bachya
homeassistant/components/alarmdecoder/* @ajschmidt8
@@ -36,6 +37,7 @@ homeassistant/components/alexa/* @home-assistant/cloud @ochlocracy
homeassistant/components/almond/* @gcampax @balloob
homeassistant/components/alpha_vantage/* @fabaff
homeassistant/components/ambee/* @frenck
homeassistant/components/amberelectric/* @madpilot
homeassistant/components/ambiclimate/* @danielhiversen
homeassistant/components/ambient_station/* @bachya
homeassistant/components/amcrest/* @flacjacket
@@ -73,7 +75,7 @@ homeassistant/components/blink/* @fronzbot
homeassistant/components/blueprint/* @home-assistant/core
homeassistant/components/bmp280/* @belidzs
homeassistant/components/bmw_connected_drive/* @gerard33 @rikroe
homeassistant/components/bond/* @prystupa
homeassistant/components/bond/* @prystupa @joshs85
homeassistant/components/bosch_shc/* @tschamm
homeassistant/components/braviatv/* @bieniu @Drafteed
homeassistant/components/broadlink/* @danielhiversen @felipediel
@@ -104,6 +106,7 @@ homeassistant/components/coronavirus/* @home-assistant/core
homeassistant/components/counter/* @fabaff
homeassistant/components/cover/* @home-assistant/core
homeassistant/components/cpuspeed/* @fabaff
homeassistant/components/crownstone/* @Crownstone @RicArch97
homeassistant/components/cups/* @fabaff
homeassistant/components/daikin/* @fredrike
homeassistant/components/darksky/* @fabaff
@@ -120,6 +123,7 @@ homeassistant/components/dhcp/* @bdraco
homeassistant/components/dht/* @thegardenmonkey
homeassistant/components/digital_ocean/* @fabaff
homeassistant/components/discogs/* @thibmaek
homeassistant/components/dlna_dmr/* @StevenLooman @chishm
homeassistant/components/doorbird/* @oblogic7 @bdraco
homeassistant/components/dsmr/* @Robbie1221 @frenck
homeassistant/components/dsmr_reader/* @depl0y
@@ -132,6 +136,7 @@ homeassistant/components/ecobee/* @marthoc
homeassistant/components/econet/* @vangorra @w1ll1am23
homeassistant/components/ecovacs/* @OverloadUT
homeassistant/components/edl21/* @mtdcr
homeassistant/components/efergy/* @tkdrob
homeassistant/components/egardia/* @jeroenterheerdt
homeassistant/components/eight_sleep/* @mezz64
homeassistant/components/elgato/* @frenck
@@ -202,7 +207,7 @@ homeassistant/components/group/* @home-assistant/core
homeassistant/components/growatt_server/* @indykoning @muppet3000 @JasperPlant
homeassistant/components/guardian/* @bachya
homeassistant/components/habitica/* @ASMfreaK @leikoilja
homeassistant/components/harmony/* @ehendrix23 @bramkragten @bdraco @mkeesey
homeassistant/components/harmony/* @ehendrix23 @bramkragten @bdraco @mkeesey @Aohzan
homeassistant/components/hassio/* @home-assistant/supervisor
homeassistant/components/heatmiser/* @andylockran
homeassistant/components/heos/* @andrewsayre
@@ -248,6 +253,7 @@ homeassistant/components/integration/* @dgomes
homeassistant/components/intent/* @home-assistant/core
homeassistant/components/intesishome/* @jnimmo
homeassistant/components/ios/* @robbiet480
homeassistant/components/iotawatt/* @gtdiehl @jyavenard
homeassistant/components/iperf3/* @rohankapoorcom
homeassistant/components/ipma/* @dgomes @abmantis
homeassistant/components/ipp/* @ctalkington
@@ -262,7 +268,7 @@ homeassistant/components/kaiterra/* @Michsior14
homeassistant/components/keba/* @dannerph
homeassistant/components/keenetic_ndms2/* @foxel
homeassistant/components/kef/* @basnijholt
homeassistant/components/keyboard_remote/* @bendavid
homeassistant/components/keyboard_remote/* @bendavid @lanrat
homeassistant/components/kmtronic/* @dgomes
homeassistant/components/knx/* @Julius2342 @farmio @marvin-w
homeassistant/components/kodi/* @OnFreund @cgtobi
@@ -311,6 +317,7 @@ homeassistant/components/minecraft_server/* @elmurato
homeassistant/components/minio/* @tkislan
homeassistant/components/mobile_app/* @robbiet480
homeassistant/components/modbus/* @adamchengtkc @janiversen @vzahradnik
homeassistant/components/modem_callerid/* @tkdrob
homeassistant/components/modern_forms/* @wonderslug
homeassistant/components/monoprice/* @etsinko @OnFreund
homeassistant/components/moon/* @fabaff
@@ -334,6 +341,7 @@ homeassistant/components/ness_alarm/* @nickw444
homeassistant/components/nest/* @allenporter
homeassistant/components/netatmo/* @cgtobi
homeassistant/components/netdata/* @fabaff
homeassistant/components/netgear/* @hacf-fr @Quentame @starkillerOG
homeassistant/components/nexia/* @bdraco
homeassistant/components/nextbus/* @vividboarder
homeassistant/components/nextcloud/* @meichthys
@@ -499,7 +507,7 @@ homeassistant/components/supla/* @mwegrzynek
homeassistant/components/surepetcare/* @benleb @danielhiversen
homeassistant/components/swiss_hydrological_data/* @fabaff
homeassistant/components/swiss_public_transport/* @fabaff
homeassistant/components/switchbot/* @danielhiversen
homeassistant/components/switchbot/* @danielhiversen @RenierM26
homeassistant/components/switcher_kis/* @tomerfi @thecode
homeassistant/components/switchmate/* @danielhiversen
homeassistant/components/syncthing/* @zhulik
@@ -517,7 +525,6 @@ homeassistant/components/tasmota/* @emontnemery
homeassistant/components/tautulli/* @ludeeus
homeassistant/components/tellduslive/* @fredrike
homeassistant/components/template/* @PhracturedBlue @tetienne @home-assistant/core
homeassistant/components/tesla/* @zabuldon @alandtse
homeassistant/components/tfiac/* @fredrike @mellado
homeassistant/components/thethingsnetwork/* @fabaff
homeassistant/components/threshold/* @fabaff
@@ -537,7 +544,7 @@ homeassistant/components/trafikverket_train/* @endor-force
homeassistant/components/trafikverket_weatherstation/* @endor-force
homeassistant/components/transmission/* @engrbm87 @JPHutchins
homeassistant/components/tts/* @pvizeli
homeassistant/components/tuya/* @ollo69
homeassistant/components/tuya/* @Tuya
homeassistant/components/twentemilieu/* @frenck
homeassistant/components/twinkly/* @dr1rrb
homeassistant/components/ubus/* @noltari
@@ -552,6 +559,7 @@ homeassistant/components/uptimerobot/* @ludeeus
homeassistant/components/usb/* @bdraco
homeassistant/components/usgs_earthquakes_feed/* @exxamalte
homeassistant/components/utility_meter/* @dgomes
homeassistant/components/vallox/* @andre-richter
homeassistant/components/velbus/* @Cereal2nd @brefra
homeassistant/components/velux/* @Julius2342
homeassistant/components/vera/* @pavoni
@@ -570,10 +578,12 @@ homeassistant/components/wake_on_lan/* @ntilley905
homeassistant/components/wallbox/* @hesselonline
homeassistant/components/waqi/* @andrey-git
homeassistant/components/watson_tts/* @rutkai
homeassistant/components/watttime/* @bachya
homeassistant/components/weather/* @fabaff
homeassistant/components/webostv/* @bendavid @thecode
homeassistant/components/websocket_api/* @home-assistant/core
homeassistant/components/wemo/* @esev
homeassistant/components/whirlpool/* @abmantis
homeassistant/components/wiffi/* @mampfes
homeassistant/components/wilight/* @leofig-rj
homeassistant/components/wirelesstag/* @sergeymaysak
+15
View File
@@ -16,6 +16,21 @@ RUN \
-e ./homeassistant \
&& python3 -m compileall homeassistant/homeassistant
# Fix Bug with Alpine 3.14 and sqlite 3.35
# https://gitlab.alpinelinux.org/alpine/aports/-/issues/12524
ARG BUILD_ARCH
RUN \
if [ "${BUILD_ARCH}" = "amd64" ]; then \
export APK_ARCH=x86_64; \
elif [ "${BUILD_ARCH}" = "i386" ]; then \
export APK_ARCH=x86; \
else \
export APK_ARCH=${BUILD_ARCH}; \
fi \
&& curl -O http://dl-cdn.alpinelinux.org/alpine/v3.13/main/${APK_ARCH}/sqlite-libs-3.34.1-r0.apk \
&& apk add --no-cache sqlite-libs-3.34.1-r0.apk \
&& rm -f sqlite-libs-3.34.1-r0.apk
# Home Assistant S6-Overlay
COPY rootfs /
+2
View File
@@ -6,6 +6,8 @@ RUN \
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
# Additional library needed by some tests and accordingly by VScode Tests Discovery
bluez \
libudev-dev \
libavformat-dev \
libavcodec-dev \
+6 -6
View File
@@ -2,11 +2,11 @@
"image": "homeassistant/{arch}-homeassistant",
"shadow_repository": "ghcr.io/home-assistant",
"build_from": {
"aarch64": "ghcr.io/home-assistant/aarch64-homeassistant-base:2021.08.0",
"armhf": "ghcr.io/home-assistant/armhf-homeassistant-base:2021.08.0",
"armv7": "ghcr.io/home-assistant/armv7-homeassistant-base:2021.08.0",
"amd64": "ghcr.io/home-assistant/amd64-homeassistant-base:2021.08.0",
"i386": "ghcr.io/home-assistant/i386-homeassistant-base:2021.08.0"
"aarch64": "ghcr.io/home-assistant/aarch64-homeassistant-base:2021.09.0",
"armhf": "ghcr.io/home-assistant/armhf-homeassistant-base:2021.09.0",
"armv7": "ghcr.io/home-assistant/armv7-homeassistant-base:2021.09.0",
"amd64": "ghcr.io/home-assistant/amd64-homeassistant-base:2021.09.0",
"i386": "ghcr.io/home-assistant/i386-homeassistant-base:2021.09.0"
},
"labels": {
"io.hass.type": "core",
@@ -19,4 +19,4 @@
"org.opencontainers.image.licenses": "Apache License 2.0"
},
"version_tag": true
}
}
-8
View File
@@ -118,14 +118,6 @@ homeassistant.util.pressure
:undoc-members:
:show-inheritance:
homeassistant.util.ruamel\_yaml
-------------------------------
.. automodule:: homeassistant.util.ruamel_yaml
:members:
:undoc-members:
:show-inheritance:
homeassistant.util.ssl
----------------------
+14 -5
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import argparse
import faulthandler
import os
import platform
import subprocess
@@ -10,6 +11,8 @@ import threading
from homeassistant.const import REQUIRED_PYTHON_VER, RESTART_EXIT_CODE, __version__
FAULT_LOG_FILENAME = "home-assistant.log.fault"
def validate_python() -> None:
"""Validate that the right Python version is running."""
@@ -132,16 +135,14 @@ def get_arguments() -> argparse.Namespace:
def daemonize() -> None:
"""Move current process to daemon process."""
# Create first fork
pid = os.fork()
if pid > 0:
if os.fork() > 0:
sys.exit(0)
# Decouple fork
os.setsid()
# Create second fork
pid = os.fork()
if pid > 0:
if os.fork() > 0:
sys.exit(0)
# redirect standard file descriptors to devnull
@@ -311,7 +312,15 @@ def main() -> int:
open_ui=args.open_ui,
)
exit_code = runner.run(runtime_conf)
fault_file_name = os.path.join(config_dir, FAULT_LOG_FILENAME)
with open(fault_file_name, mode="a", encoding="utf8") as fault_file:
faulthandler.enable(fault_file)
exit_code = runner.run(runtime_conf)
faulthandler.disable()
if os.path.getsize(fault_file_name) == 0:
os.remove(fault_file_name)
if exit_code == RESTART_EXIT_CODE and not args.runner:
try_to_restart()
+7 -8
View File
@@ -341,8 +341,7 @@ class AuthManager:
"System generated users cannot enable multi-factor auth module."
)
module = self.get_auth_mfa_module(mfa_module_id)
if module is None:
if (module := self.get_auth_mfa_module(mfa_module_id)) is None:
raise ValueError(f"Unable find multi-factor auth module: {mfa_module_id}")
await module.async_setup_user(user.id, data)
@@ -356,8 +355,7 @@ class AuthManager:
"System generated users cannot disable multi-factor auth module."
)
module = self.get_auth_mfa_module(mfa_module_id)
if module is None:
if (module := self.get_auth_mfa_module(mfa_module_id)) is None:
raise ValueError(f"Unable find multi-factor auth module: {mfa_module_id}")
await module.async_depose_user(user.id)
@@ -466,7 +464,7 @@ class AuthManager:
},
refresh_token.jwt_key,
algorithm="HS256",
).decode()
)
@callback
def _async_resolve_provider(
@@ -498,8 +496,7 @@ class AuthManager:
Will raise InvalidAuthError on errors.
"""
provider = self._async_resolve_provider(refresh_token)
if provider:
if provider := self._async_resolve_provider(refresh_token):
provider.async_validate_refresh_token(refresh_token, remote_ip)
async def async_validate_access_token(
@@ -507,7 +504,9 @@ class AuthManager:
) -> models.RefreshToken | None:
"""Return refresh token if an access token is valid."""
try:
unverif_claims = jwt.decode(token, verify=False)
unverif_claims = jwt.decode(
token, algorithms=["HS256"], options={"verify_signature": False}
)
except jwt.InvalidTokenError:
return None
+4 -8
View File
@@ -96,8 +96,7 @@ class AuthStore:
groups = []
for group_id in group_ids or []:
group = self._groups.get(group_id)
if group is None:
if (group := self._groups.get(group_id)) is None:
raise ValueError(f"Invalid group specified {group_id}")
groups.append(group)
@@ -160,8 +159,7 @@ class AuthStore:
if group_ids is not None:
groups = []
for grid in group_ids:
group = self._groups.get(grid)
if group is None:
if (group := self._groups.get(grid)) is None:
raise ValueError("Invalid group specified.")
groups.append(group)
@@ -446,16 +444,14 @@ class AuthStore:
)
continue
token_type = rt_dict.get("token_type")
if token_type is None:
if (token_type := rt_dict.get("token_type")) is None:
if rt_dict["client_id"] is None:
token_type = models.TOKEN_TYPE_SYSTEM
else:
token_type = models.TOKEN_TYPE_NORMAL
# old refresh_token don't have last_used_at (pre-0.78)
last_used_at_str = rt_dict.get("last_used_at")
if last_used_at_str:
if last_used_at_str := rt_dict.get("last_used_at"):
last_used_at = dt_util.parse_datetime(last_used_at_str)
else:
last_used_at = None
+3 -7
View File
@@ -118,9 +118,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
if self._user_settings is not None:
return
data = await self._user_store.async_load()
if data is None:
if (data := await self._user_store.async_load()) is None:
data = {STORAGE_USERS: {}}
self._user_settings = {
@@ -207,8 +205,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
await self._async_load()
assert self._user_settings is not None
notify_setting = self._user_settings.get(user_id)
if notify_setting is None:
if (notify_setting := self._user_settings.get(user_id)) is None:
return False
# user_input has been validate in caller
@@ -225,8 +222,7 @@ class NotifyAuthModule(MultiFactorAuthModule):
await self._async_load()
assert self._user_settings is not None
notify_setting = self._user_settings.get(user_id)
if notify_setting is None:
if (notify_setting := self._user_settings.get(user_id)) is None:
raise ValueError("Cannot find user_id")
def generate_secret_and_one_time_password() -> str:
+2 -5
View File
@@ -92,9 +92,7 @@ class TotpAuthModule(MultiFactorAuthModule):
if self._users is not None:
return
data = await self._user_store.async_load()
if data is None:
if (data := await self._user_store.async_load()) is None:
data = {STORAGE_USERS: {}}
self._users = data.get(STORAGE_USERS, {})
@@ -163,8 +161,7 @@ class TotpAuthModule(MultiFactorAuthModule):
"""Validate two factor authentication code."""
import pyotp # pylint: disable=import-outside-toplevel
ota_secret = self._users.get(user_id) # type: ignore
if ota_secret is None:
if (ota_secret := self._users.get(user_id)) is None: # type: ignore
# even we cannot find user, we still do verify
# to make timing the same as if user was found.
pyotp.TOTP(DUMMY_SECRET).verify(code, valid_window=1)
+3 -4
View File
@@ -1,8 +1,9 @@
"""Permissions for Home Assistant."""
from __future__ import annotations
from collections.abc import Callable
import logging
from typing import Any, Callable
from typing import Any
import voluptuous as vol
@@ -33,9 +34,7 @@ class AbstractPermissions:
def check_entity(self, entity_id: str, key: str) -> bool:
"""Check if we can access entity."""
entity_func = self._cached_entity_func
if entity_func is None:
if (entity_func := self._cached_entity_func) is None:
entity_func = self._cached_entity_func = self._entity_func()
return entity_func(entity_id, key)
+1 -1
View File
@@ -2,7 +2,7 @@
from __future__ import annotations
from collections import OrderedDict
from typing import Callable
from collections.abc import Callable
import voluptuous as vol
+1 -2
View File
@@ -72,8 +72,7 @@ def compile_policy(
def apply_policy_funcs(object_id: str, key: str) -> bool:
"""Apply several policy functions."""
for func in funcs:
result = func(object_id, key)
if result is not None:
if (result := func(object_id, key)) is not None:
return result
return False
+1 -3
View File
@@ -169,9 +169,7 @@ async def load_auth_provider_module(
if hass.config.skip_pip or not hasattr(module, "REQUIREMENTS"):
return module
processed = hass.data.get(DATA_REQS)
if processed is None:
if (processed := hass.data.get(DATA_REQS)) is None:
processed = hass.data[DATA_REQS] = set()
elif provider in processed:
return module
@@ -82,9 +82,7 @@ class Data:
async def async_load(self) -> None:
"""Load stored data."""
data = await self._store.async_load()
if data is None:
if (data := await self._store.async_load()) is None:
data = {"users": []}
seen: set[str] = set()
@@ -93,9 +91,7 @@ class Data:
username = user["username"]
# check if we have duplicates
folded = username.casefold()
if folded in seen:
if (folded := username.casefold()) in seen:
self.is_legacy = True
logging.getLogger(__name__).warning(
+18 -22
View File
@@ -109,9 +109,8 @@ async def async_setup_hass(
config_dict = None
basic_setup_success = False
safe_mode = runtime_config.safe_mode
if not safe_mode:
if not (safe_mode := runtime_config.safe_mode):
await hass.async_add_executor_job(conf_util.process_ha_config_upgrade, hass)
try:
@@ -342,7 +341,11 @@ def async_enable_logging(
err_log_path, backupCount=1
)
err_handler.doRollover()
try:
err_handler.doRollover()
except OSError as err:
_LOGGER.error("Error rolling over log file: %s", err)
err_handler.setLevel(logging.INFO if verbose else logging.WARNING)
err_handler.setFormatter(logging.Formatter(fmt, datefmt=datefmt))
@@ -364,8 +367,7 @@ async def async_mount_local_lib_path(config_dir: str) -> str:
This function is a coroutine.
"""
deps_dir = os.path.join(config_dir, "deps")
lib_dir = await async_get_user_site(deps_dir)
if lib_dir not in sys.path:
if (lib_dir := await async_get_user_site(deps_dir)) not in sys.path:
sys.path.insert(0, lib_dir)
return deps_dir
@@ -490,17 +492,13 @@ async def _async_set_up_integrations(
_LOGGER.info("Domains to be set up: %s", domains_to_setup)
logging_domains = domains_to_setup & LOGGING_INTEGRATIONS
# Load logging as soon as possible
if logging_domains:
if logging_domains := domains_to_setup & LOGGING_INTEGRATIONS:
_LOGGER.info("Setting up logging: %s", logging_domains)
await async_setup_multi_components(hass, logging_domains, config)
# Start up debuggers. Start these first in case they want to wait.
debuggers = domains_to_setup & DEBUGGER_INTEGRATIONS
if debuggers:
if debuggers := domains_to_setup & DEBUGGER_INTEGRATIONS:
_LOGGER.debug("Setting up debuggers: %s", debuggers)
await async_setup_multi_components(hass, debuggers, config)
@@ -520,9 +518,7 @@ async def _async_set_up_integrations(
stage_1_domains.add(domain)
dep_itg = integration_cache.get(domain)
if dep_itg is None:
if (dep_itg := integration_cache.get(domain)) is None:
continue
deps_promotion.update(dep_itg.all_dependencies)
@@ -560,6 +556,14 @@ async def _async_set_up_integrations(
except asyncio.TimeoutError:
_LOGGER.warning("Setup timed out for stage 2 - moving forward")
# Wrap up startup
_LOGGER.debug("Waiting for startup to wrap up")
try:
async with hass.timeout.async_timeout(WRAP_UP_TIMEOUT, cool_down=COOLDOWN_TIME):
await hass.async_block_till_done()
except asyncio.TimeoutError:
_LOGGER.warning("Setup timed out for bootstrap - moving forward")
watch_task.cancel()
async_dispatcher_send(hass, SIGNAL_BOOTSTRAP_INTEGRATONS, {})
@@ -572,11 +576,3 @@ async def _async_set_up_integrations(
)
},
)
# Wrap up startup
_LOGGER.debug("Waiting for startup to wrap up")
try:
async with hass.timeout.async_timeout(WRAP_UP_TIMEOUT, cool_down=COOLDOWN_TIME):
await hass.async_block_till_done()
except asyncio.TimeoutError:
_LOGGER.warning("Setup timed out for bootstrap - moving forward")
@@ -2,7 +2,7 @@
"config": {
"abort": {
"reauth_successful": "La r\u00e9-authentification a r\u00e9ussi",
"single_instance_allowed": "D\u00e9ja configur\u00e9. Une seule configuration possible."
"single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible."
},
"error": {
"cannot_connect": "\u00c9chec de connexion",
@@ -14,7 +14,7 @@
"api_key": "Cl\u00e9 d'API",
"latitude": "Latitude",
"longitude": "Longitude",
"name": "Nom de l'int\u00e9gration"
"name": "Nom"
},
"description": "Si vous avez besoin d'aide pour la configuration, consultez le site suivant : https://www.home-assistant.io/integrations/accuweather/\n\nCertains capteurs ne sont pas activ\u00e9s par d\u00e9faut. Vous pouvez les activer dans le registre des entit\u00e9s apr\u00e8s la configuration de l'int\u00e9gration.\nLes pr\u00e9visions m\u00e9t\u00e9orologiques ne sont pas activ\u00e9es par d\u00e9faut. Vous pouvez l'activer dans les options d'int\u00e9gration.",
"title": "AccuWeather"
@@ -3,7 +3,9 @@
"step": {
"user": {
"data": {
"account_id": "ID de la cuenta"
"account_id": "ID de la cuenta",
"host": "Anfitri\u00f3n",
"password": "Contrase\u00f1a"
}
}
}
@@ -17,9 +17,9 @@
"host": "H\u00f4te",
"password": "Mot de passe",
"port": "Port",
"ssl": "AdGuard Home utilise un certificat SSL",
"ssl": "Utilise un certificat SSL",
"username": "Nom d'utilisateur",
"verify_ssl": "AdGuard Home utilise un certificat appropri\u00e9"
"verify_ssl": "V\u00e9rifier le certificat SSL"
},
"description": "Configurez votre instance AdGuard Home pour permettre la surveillance et le contr\u00f4le."
}
@@ -1,7 +1,11 @@
"""Sensor platform for Advantage Air integration."""
import voluptuous as vol
from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity
from homeassistant.components.sensor import (
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
SensorEntity,
)
from homeassistant.const import PERCENTAGE, TEMP_CELSIUS
from homeassistant.helpers import config_validation as cv, entity_platform
@@ -138,11 +142,11 @@ class AdvantageAirZoneSignal(AdvantageAirEntity, SensorEntity):
class AdvantageAirZoneTemp(AdvantageAirEntity, SensorEntity):
"""Representation of Advantage Air Zone wireless signal sensor."""
"""Representation of Advantage Air Zone temperature sensor."""
_attr_native_unit_of_measurement = TEMP_CELSIUS
_attr_device_class = DEVICE_CLASS_TEMPERATURE
_attr_state_class = STATE_CLASS_MEASUREMENT
_attr_icon = "mdi:thermometer"
_attr_entity_registry_enabled_default = False
def __init__(self, instance, ac_key, zone_key):
+141 -115
View File
@@ -1,5 +1,7 @@
"""Constant values for the AEMET OpenData component."""
from __future__ import annotations
from homeassistant.components.sensor import SensorEntityDescription
from homeassistant.components.weather import (
ATTR_CONDITION_CLEAR_NIGHT,
ATTR_CONDITION_CLOUDY,
@@ -40,9 +42,6 @@ DEFAULT_NAME = "AEMET"
DOMAIN = "aemet"
ENTRY_NAME = "name"
ENTRY_WEATHER_COORDINATOR = "weather_coordinator"
SENSOR_NAME = "sensor_name"
SENSOR_UNIT = "sensor_unit"
SENSOR_DEVICE_CLASS = "sensor_device_class"
ATTR_API_CONDITION = "condition"
ATTR_API_FORECAST_DAILY = "forecast-daily"
@@ -200,118 +199,145 @@ FORECAST_MODE_ATTR_API = {
FORECAST_MODE_HOURLY: ATTR_API_FORECAST_HOURLY,
}
FORECAST_SENSOR_TYPES = {
ATTR_FORECAST_CONDITION: {
SENSOR_NAME: "Condition",
},
ATTR_FORECAST_PRECIPITATION: {
SENSOR_NAME: "Precipitation",
SENSOR_UNIT: PRECIPITATION_MILLIMETERS_PER_HOUR,
},
ATTR_FORECAST_PRECIPITATION_PROBABILITY: {
SENSOR_NAME: "Precipitation probability",
SENSOR_UNIT: PERCENTAGE,
},
ATTR_FORECAST_TEMP: {
SENSOR_NAME: "Temperature",
SENSOR_UNIT: TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
},
ATTR_FORECAST_TEMP_LOW: {
SENSOR_NAME: "Temperature Low",
SENSOR_UNIT: TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
},
ATTR_FORECAST_TIME: {
SENSOR_NAME: "Time",
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP,
},
ATTR_FORECAST_WIND_BEARING: {
SENSOR_NAME: "Wind bearing",
SENSOR_UNIT: DEGREE,
},
ATTR_FORECAST_WIND_SPEED: {
SENSOR_NAME: "Wind speed",
SENSOR_UNIT: SPEED_KILOMETERS_PER_HOUR,
},
}
WEATHER_SENSOR_TYPES = {
ATTR_API_CONDITION: {
SENSOR_NAME: "Condition",
},
ATTR_API_HUMIDITY: {
SENSOR_NAME: "Humidity",
SENSOR_UNIT: PERCENTAGE,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY,
},
ATTR_API_PRESSURE: {
SENSOR_NAME: "Pressure",
SENSOR_UNIT: PRESSURE_HPA,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE,
},
ATTR_API_RAIN: {
SENSOR_NAME: "Rain",
SENSOR_UNIT: PRECIPITATION_MILLIMETERS_PER_HOUR,
},
ATTR_API_RAIN_PROB: {
SENSOR_NAME: "Rain probability",
SENSOR_UNIT: PERCENTAGE,
},
ATTR_API_SNOW: {
SENSOR_NAME: "Snow",
SENSOR_UNIT: PRECIPITATION_MILLIMETERS_PER_HOUR,
},
ATTR_API_SNOW_PROB: {
SENSOR_NAME: "Snow probability",
SENSOR_UNIT: PERCENTAGE,
},
ATTR_API_STATION_ID: {
SENSOR_NAME: "Station ID",
},
ATTR_API_STATION_NAME: {
SENSOR_NAME: "Station name",
},
ATTR_API_STATION_TIMESTAMP: {
SENSOR_NAME: "Station timestamp",
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP,
},
ATTR_API_STORM_PROB: {
SENSOR_NAME: "Storm probability",
SENSOR_UNIT: PERCENTAGE,
},
ATTR_API_TEMPERATURE: {
SENSOR_NAME: "Temperature",
SENSOR_UNIT: TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
},
ATTR_API_TEMPERATURE_FEELING: {
SENSOR_NAME: "Temperature feeling",
SENSOR_UNIT: TEMP_CELSIUS,
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
},
ATTR_API_TOWN_ID: {
SENSOR_NAME: "Town ID",
},
ATTR_API_TOWN_NAME: {
SENSOR_NAME: "Town name",
},
ATTR_API_TOWN_TIMESTAMP: {
SENSOR_NAME: "Town timestamp",
SENSOR_DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP,
},
ATTR_API_WIND_BEARING: {
SENSOR_NAME: "Wind bearing",
SENSOR_UNIT: DEGREE,
},
ATTR_API_WIND_MAX_SPEED: {
SENSOR_NAME: "Wind max speed",
SENSOR_UNIT: SPEED_KILOMETERS_PER_HOUR,
},
ATTR_API_WIND_SPEED: {
SENSOR_NAME: "Wind speed",
SENSOR_UNIT: SPEED_KILOMETERS_PER_HOUR,
},
}
FORECAST_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=ATTR_FORECAST_CONDITION,
name="Condition",
),
SensorEntityDescription(
key=ATTR_FORECAST_PRECIPITATION,
name="Precipitation",
native_unit_of_measurement=PRECIPITATION_MILLIMETERS_PER_HOUR,
),
SensorEntityDescription(
key=ATTR_FORECAST_PRECIPITATION_PROBABILITY,
name="Precipitation probability",
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TEMP,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TEMP_LOW,
name="Temperature Low",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_FORECAST_TIME,
name="Time",
device_class=DEVICE_CLASS_TIMESTAMP,
),
SensorEntityDescription(
key=ATTR_FORECAST_WIND_BEARING,
name="Wind bearing",
native_unit_of_measurement=DEGREE,
),
SensorEntityDescription(
key=ATTR_FORECAST_WIND_SPEED,
name="Wind speed",
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
),
)
WEATHER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=ATTR_API_CONDITION,
name="Condition",
),
SensorEntityDescription(
key=ATTR_API_HUMIDITY,
name="Humidity",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=ATTR_API_PRESSURE,
name="Pressure",
native_unit_of_measurement=PRESSURE_HPA,
device_class=DEVICE_CLASS_PRESSURE,
),
SensorEntityDescription(
key=ATTR_API_RAIN,
name="Rain",
native_unit_of_measurement=PRECIPITATION_MILLIMETERS_PER_HOUR,
),
SensorEntityDescription(
key=ATTR_API_RAIN_PROB,
name="Rain probability",
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=ATTR_API_SNOW,
name="Snow",
native_unit_of_measurement=PRECIPITATION_MILLIMETERS_PER_HOUR,
),
SensorEntityDescription(
key=ATTR_API_SNOW_PROB,
name="Snow probability",
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=ATTR_API_STATION_ID,
name="Station ID",
),
SensorEntityDescription(
key=ATTR_API_STATION_NAME,
name="Station name",
),
SensorEntityDescription(
key=ATTR_API_STATION_TIMESTAMP,
name="Station timestamp",
device_class=DEVICE_CLASS_TIMESTAMP,
),
SensorEntityDescription(
key=ATTR_API_STORM_PROB,
name="Storm probability",
native_unit_of_measurement=PERCENTAGE,
),
SensorEntityDescription(
key=ATTR_API_TEMPERATURE,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_API_TEMPERATURE_FEELING,
name="Temperature feeling",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key=ATTR_API_TOWN_ID,
name="Town ID",
),
SensorEntityDescription(
key=ATTR_API_TOWN_NAME,
name="Town name",
),
SensorEntityDescription(
key=ATTR_API_TOWN_TIMESTAMP,
name="Town timestamp",
device_class=DEVICE_CLASS_TIMESTAMP,
),
SensorEntityDescription(
key=ATTR_API_WIND_BEARING,
name="Wind bearing",
native_unit_of_measurement=DEGREE,
),
SensorEntityDescription(
key=ATTR_API_WIND_MAX_SPEED,
name="Wind max speed",
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
),
SensorEntityDescription(
key=ATTR_API_WIND_SPEED,
name="Wind speed",
native_unit_of_measurement=SPEED_KILOMETERS_PER_HOUR,
),
)
WIND_BEARING_MAP = {
"C": None,
+41 -53
View File
@@ -1,5 +1,7 @@
"""Support for the AEMET OpenData service."""
from homeassistant.components.sensor import SensorEntity
from __future__ import annotations
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@@ -14,9 +16,6 @@ from .const import (
FORECAST_MONITORED_CONDITIONS,
FORECAST_SENSOR_TYPES,
MONITORED_CONDITIONS,
SENSOR_DEVICE_CLASS,
SENSOR_NAME,
SENSOR_UNIT,
WEATHER_SENSOR_TYPES,
)
from .weather_update_coordinator import WeatherUpdateCoordinator
@@ -28,37 +27,30 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
name = domain_data[ENTRY_NAME]
weather_coordinator = domain_data[ENTRY_WEATHER_COORDINATOR]
weather_sensor_types = WEATHER_SENSOR_TYPES
forecast_sensor_types = FORECAST_SENSOR_TYPES
entities = []
for sensor_type in MONITORED_CONDITIONS:
unique_id = f"{config_entry.unique_id}-{sensor_type}"
entities.append(
AemetSensor(
name,
unique_id,
sensor_type,
weather_sensor_types[sensor_type],
unique_id = config_entry.unique_id
entities: list[AbstractAemetSensor] = [
AemetSensor(name, unique_id, weather_coordinator, description)
for description in WEATHER_SENSOR_TYPES
if description.key in MONITORED_CONDITIONS
]
entities.extend(
[
AemetForecastSensor(
name_prefix,
unique_id_prefix,
weather_coordinator,
mode,
description,
)
)
for mode in FORECAST_MODES:
name = f"{domain_data[ENTRY_NAME]} {mode}"
for sensor_type in FORECAST_MONITORED_CONDITIONS:
unique_id = f"{config_entry.unique_id}-forecast-{mode}-{sensor_type}"
entities.append(
AemetForecastSensor(
f"{name} Forecast",
unique_id,
sensor_type,
forecast_sensor_types[sensor_type],
weather_coordinator,
mode,
)
for mode in FORECAST_MODES
if (
(name_prefix := f"{domain_data[ENTRY_NAME]} {mode} Forecast")
and (unique_id_prefix := f"{unique_id}-forecast-{mode}")
)
for description in FORECAST_SENSOR_TYPES
if description.key in FORECAST_MONITORED_CONDITIONS
]
)
async_add_entities(entities)
@@ -72,20 +64,14 @@ class AbstractAemetSensor(CoordinatorEntity, SensorEntity):
self,
name,
unique_id,
sensor_type,
sensor_configuration,
coordinator: WeatherUpdateCoordinator,
description: SensorEntityDescription,
):
"""Initialize the sensor."""
super().__init__(coordinator)
self._name = name
self._unique_id = unique_id
self._sensor_type = sensor_type
self._sensor_name = sensor_configuration[SENSOR_NAME]
self._attr_name = f"{self._name} {self._sensor_name}"
self._attr_unique_id = self._unique_id
self._attr_device_class = sensor_configuration.get(SENSOR_DEVICE_CLASS)
self._attr_native_unit_of_measurement = sensor_configuration.get(SENSOR_UNIT)
self.entity_description = description
self._attr_name = f"{name} {description.name}"
self._attr_unique_id = unique_id
class AemetSensor(AbstractAemetSensor):
@@ -95,20 +81,21 @@ class AemetSensor(AbstractAemetSensor):
self,
name,
unique_id,
sensor_type,
sensor_configuration,
weather_coordinator: WeatherUpdateCoordinator,
description: SensorEntityDescription,
):
"""Initialize the sensor."""
super().__init__(
name, unique_id, sensor_type, sensor_configuration, weather_coordinator
name=name,
unique_id=f"{unique_id}-{description.key}",
coordinator=weather_coordinator,
description=description,
)
self._weather_coordinator = weather_coordinator
@property
def native_value(self):
"""Return the state of the device."""
return self._weather_coordinator.data.get(self._sensor_type)
return self.coordinator.data.get(self.entity_description.key)
class AemetForecastSensor(AbstractAemetSensor):
@@ -118,16 +105,17 @@ class AemetForecastSensor(AbstractAemetSensor):
self,
name,
unique_id,
sensor_type,
sensor_configuration,
weather_coordinator: WeatherUpdateCoordinator,
forecast_mode,
description: SensorEntityDescription,
):
"""Initialize the sensor."""
super().__init__(
name, unique_id, sensor_type, sensor_configuration, weather_coordinator
name=name,
unique_id=f"{unique_id}-{description.key}",
coordinator=weather_coordinator,
description=description,
)
self._weather_coordinator = weather_coordinator
self._forecast_mode = forecast_mode
self._attr_entity_registry_enabled_default = (
self._forecast_mode == FORECAST_MODE_DAILY
@@ -137,9 +125,9 @@ class AemetForecastSensor(AbstractAemetSensor):
def native_value(self):
"""Return the state of the device."""
forecast = None
forecasts = self._weather_coordinator.data.get(
forecasts = self.coordinator.data.get(
FORECAST_MODE_ATTR_API[self._forecast_mode]
)
if forecasts:
forecast = forecasts[0].get(self._sensor_type)
forecast = forecasts[0].get(self.entity_description.key)
return forecast
@@ -4,13 +4,13 @@
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9"
},
"error": {
"already_in_progress": "La configuration de l'appareil est d\u00e9j\u00e0 en cours.",
"already_in_progress": "La configuration est d\u00e9j\u00e0 en cours",
"cannot_connect": "\u00c9chec de connexion"
},
"step": {
"user": {
"data": {
"host": "Nom d'h\u00f4te ou adresse IP",
"host": "H\u00f4te",
"port": "Port"
},
"title": "Configurer l'agent DVR"
-70
View File
@@ -3,23 +3,6 @@ from __future__ import annotations
from typing import Final
from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
DEVICE_CLASS_AQI,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_PM1,
DEVICE_CLASS_PM10,
DEVICE_CLASS_PM25,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
PERCENTAGE,
PRESSURE_HPA,
TEMP_CELSIUS,
)
from .model import AirlySensorEntityDescription
ATTR_API_ADVICE: Final = "ADVICE"
ATTR_API_CAQI: Final = "CAQI"
ATTR_API_CAQI_DESCRIPTION: Final = "DESCRIPTION"
@@ -49,56 +32,3 @@ MANUFACTURER: Final = "Airly sp. z o.o."
MAX_UPDATE_INTERVAL: Final = 90
MIN_UPDATE_INTERVAL: Final = 5
NO_AIRLY_SENSORS: Final = "There are no Airly sensors in this area yet."
SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_CAQI,
device_class=DEVICE_CLASS_AQI,
name=ATTR_API_CAQI,
native_unit_of_measurement="CAQI",
),
AirlySensorEntityDescription(
key=ATTR_API_PM1,
device_class=DEVICE_CLASS_PM1,
name=ATTR_API_PM1,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_PM25,
device_class=DEVICE_CLASS_PM25,
name="PM2.5",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_PM10,
device_class=DEVICE_CLASS_PM10,
name=ATTR_API_PM10,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_HUMIDITY,
device_class=DEVICE_CLASS_HUMIDITY,
name=ATTR_API_HUMIDITY.capitalize(),
native_unit_of_measurement=PERCENTAGE,
state_class=STATE_CLASS_MEASUREMENT,
value=lambda value: round(value, 1),
),
AirlySensorEntityDescription(
key=ATTR_API_PRESSURE,
device_class=DEVICE_CLASS_PRESSURE,
name=ATTR_API_PRESSURE.capitalize(),
native_unit_of_measurement=PRESSURE_HPA,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_TEMPERATURE,
device_class=DEVICE_CLASS_TEMPERATURE,
name=ATTR_API_TEMPERATURE.capitalize(),
native_unit_of_measurement=TEMP_CELSIUS,
state_class=STATE_CLASS_MEASUREMENT,
value=lambda value: round(value, 1),
),
)
-14
View File
@@ -1,14 +0,0 @@
"""Type definitions for Airly integration."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Callable
from homeassistant.components.sensor import SensorEntityDescription
@dataclass
class AirlySensorEntityDescription(SensorEntityDescription):
"""Class describing Airly sensor entities."""
value: Callable = round
+87 -4
View File
@@ -1,11 +1,31 @@
"""Support for the Airly sensor service."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, cast
from homeassistant.components.sensor import SensorEntity
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ATTRIBUTION, CONF_NAME
from homeassistant.const import (
ATTR_ATTRIBUTION,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONF_NAME,
DEVICE_CLASS_AQI,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_PM1,
DEVICE_CLASS_PM10,
DEVICE_CLASS_PM25,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
PERCENTAGE,
PRESSURE_HPA,
TEMP_CELSIUS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
@@ -18,8 +38,12 @@ from .const import (
ATTR_API_CAQI,
ATTR_API_CAQI_DESCRIPTION,
ATTR_API_CAQI_LEVEL,
ATTR_API_HUMIDITY,
ATTR_API_PM1,
ATTR_API_PM10,
ATTR_API_PM25,
ATTR_API_PRESSURE,
ATTR_API_TEMPERATURE,
ATTR_DESCRIPTION,
ATTR_LEVEL,
ATTR_LIMIT,
@@ -28,15 +52,74 @@ from .const import (
DEFAULT_NAME,
DOMAIN,
MANUFACTURER,
SENSOR_TYPES,
SUFFIX_LIMIT,
SUFFIX_PERCENT,
)
from .model import AirlySensorEntityDescription
PARALLEL_UPDATES = 1
@dataclass
class AirlySensorEntityDescription(SensorEntityDescription):
"""Class describing Airly sensor entities."""
value: Callable = round
SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_CAQI,
device_class=DEVICE_CLASS_AQI,
name=ATTR_API_CAQI,
native_unit_of_measurement="CAQI",
),
AirlySensorEntityDescription(
key=ATTR_API_PM1,
device_class=DEVICE_CLASS_PM1,
name=ATTR_API_PM1,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_PM25,
device_class=DEVICE_CLASS_PM25,
name="PM2.5",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_PM10,
device_class=DEVICE_CLASS_PM10,
name=ATTR_API_PM10,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_HUMIDITY,
device_class=DEVICE_CLASS_HUMIDITY,
name=ATTR_API_HUMIDITY.capitalize(),
native_unit_of_measurement=PERCENTAGE,
state_class=STATE_CLASS_MEASUREMENT,
value=lambda value: round(value, 1),
),
AirlySensorEntityDescription(
key=ATTR_API_PRESSURE,
device_class=DEVICE_CLASS_PRESSURE,
name=ATTR_API_PRESSURE.capitalize(),
native_unit_of_measurement=PRESSURE_HPA,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_TEMPERATURE,
device_class=DEVICE_CLASS_TEMPERATURE,
name=ATTR_API_TEMPERATURE.capitalize(),
native_unit_of_measurement=TEMP_CELSIUS,
state_class=STATE_CLASS_MEASUREMENT,
value=lambda value: round(value, 1),
),
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
@@ -1,7 +1,7 @@
{
"config": {
"abort": {
"already_configured": "L'int\u00e9gration des coordonn\u00e9es d'Airly est d\u00e9j\u00e0 configur\u00e9."
"already_configured": "L'emplacement est d\u00e9j\u00e0 configur\u00e9"
},
"error": {
"invalid_api_key": "Cl\u00e9 API invalide",
@@ -13,7 +13,7 @@
"api_key": "Cl\u00e9 d'API",
"latitude": "Latitude",
"longitude": "Longitude",
"name": "Nom de l'int\u00e9gration"
"name": "Nom"
},
"description": "Configurez l'int\u00e9gration de la qualit\u00e9 de l'air Airly. Pour g\u00e9n\u00e9rer une cl\u00e9 API, rendez-vous sur https://developer.airly.eu/register.",
"title": "Airly"
+47 -39
View File
@@ -1,14 +1,19 @@
"""Support for the AirNow sensor service."""
from homeassistant.components.sensor import SensorEntity
from __future__ import annotations
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.const import (
ATTR_ATTRIBUTION,
ATTR_DEVICE_CLASS,
ATTR_ICON,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_MILLION,
)
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import AirNowDataUpdateCoordinator
from .const import (
ATTR_API_AQI,
ATTR_API_AQI_DESCRIPTION,
@@ -22,69 +27,72 @@ from .const import (
ATTRIBUTION = "Data provided by AirNow"
ATTR_LABEL = "label"
ATTR_UNIT = "unit"
PARALLEL_UPDATES = 1
SENSOR_TYPES = {
ATTR_API_AQI: {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:blur",
ATTR_LABEL: ATTR_API_AQI,
ATTR_UNIT: "aqi",
},
ATTR_API_PM25: {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:blur",
ATTR_LABEL: ATTR_API_PM25,
ATTR_UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
},
ATTR_API_O3: {
ATTR_DEVICE_CLASS: None,
ATTR_ICON: "mdi:blur",
ATTR_LABEL: ATTR_API_O3,
ATTR_UNIT: CONCENTRATION_PARTS_PER_MILLION,
},
}
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=ATTR_API_AQI,
icon="mdi:blur",
name=ATTR_API_AQI,
native_unit_of_measurement="aqi",
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=ATTR_API_PM25,
icon="mdi:blur",
name=ATTR_API_PM25,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=ATTR_API_O3,
icon="mdi:blur",
name=ATTR_API_O3,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
state_class=STATE_CLASS_MEASUREMENT,
),
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up AirNow sensor entities based on a config entry."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]
sensors = []
for sensor in SENSOR_TYPES:
sensors.append(AirNowSensor(coordinator, sensor))
entities = [AirNowSensor(coordinator, description) for description in SENSOR_TYPES]
async_add_entities(sensors, False)
async_add_entities(entities, False)
class AirNowSensor(CoordinatorEntity, SensorEntity):
"""Define an AirNow sensor."""
def __init__(self, coordinator, kind):
coordinator: AirNowDataUpdateCoordinator
def __init__(
self,
coordinator: AirNowDataUpdateCoordinator,
description: SensorEntityDescription,
) -> None:
"""Initialize."""
super().__init__(coordinator)
self.kind = kind
self.entity_description = description
self._state = None
self._attrs = {ATTR_ATTRIBUTION: ATTRIBUTION}
self._attr_name = f"AirNow {SENSOR_TYPES[self.kind][ATTR_LABEL]}"
self._attr_icon = SENSOR_TYPES[self.kind][ATTR_ICON]
self._attr_device_class = SENSOR_TYPES[self.kind][ATTR_DEVICE_CLASS]
self._attr_native_unit_of_measurement = SENSOR_TYPES[self.kind][ATTR_UNIT]
self._attr_unique_id = f"{self.coordinator.latitude}-{self.coordinator.longitude}-{self.kind.lower()}"
self._attr_name = f"AirNow {description.name}"
self._attr_unique_id = (
f"{coordinator.latitude}-{coordinator.longitude}-{description.key.lower()}"
)
@property
def native_value(self):
"""Return the state."""
self._state = self.coordinator.data[self.kind]
self._state = self.coordinator.data[self.entity_description.key]
return self._state
@property
def extra_state_attributes(self):
"""Return the state attributes."""
if self.kind == ATTR_API_AQI:
if self.entity_description.key == ATTR_API_AQI:
self._attrs[SENSOR_AQI_ATTR_DESCR] = self.coordinator.data[
ATTR_API_AQI_DESCRIPTION
]
@@ -4,7 +4,7 @@
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9"
},
"error": {
"cannot_connect": "\u00c9chec \u00e0 la connexion",
"cannot_connect": "\u00c9chec de connexion",
"invalid_auth": "Authentification invalide",
"invalid_location": "Aucun r\u00e9sultat trouv\u00e9 pour cet emplacement",
"unknown": "Erreur inattendue"
@@ -12,7 +12,7 @@
"step": {
"user": {
"data": {
"api_key": "Cl\u00e9 API",
"api_key": "Cl\u00e9 d'API",
"latitude": "Latitude",
"longitude": "Longitude",
"radius": "Rayon d'action de la station (en miles, facultatif)"
@@ -0,0 +1,61 @@
"""The Airthings integration."""
from __future__ import annotations
from datetime import timedelta
import logging
from airthings import Airthings, AirthingsError
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import CONF_ID, CONF_SECRET, DOMAIN
_LOGGER = logging.getLogger(__name__)
PLATFORMS: list[str] = ["sensor"]
SCAN_INTERVAL = timedelta(minutes=6)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Airthings from a config entry."""
hass.data.setdefault(DOMAIN, {})
airthings = Airthings(
entry.data[CONF_ID],
entry.data[CONF_SECRET],
async_get_clientsession(hass),
)
async def _update_method():
"""Get the latest data from Airthings."""
try:
return await airthings.update_devices()
except AirthingsError as err:
raise UpdateFailed(f"Unable to fetch data: {err}") from err
coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
name=DOMAIN,
update_method=_update_method,
update_interval=SCAN_INTERVAL,
)
await coordinator.async_config_entry_first_refresh()
hass.data[DOMAIN][entry.entry_id] = coordinator
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
@@ -0,0 +1,67 @@
"""Config flow for Airthings integration."""
from __future__ import annotations
import logging
from typing import Any
import airthings
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import CONF_ID, CONF_SECRET, DOMAIN
_LOGGER = logging.getLogger(__name__)
STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_ID): str,
vol.Required(CONF_SECRET): str,
}
)
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Airthings."""
VERSION = 1
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the initial step."""
if user_input is None:
return self.async_show_form(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA,
description_placeholders={
"url": "https://dashboard.airthings.com/integrations/api-integration",
},
)
errors = {}
try:
await airthings.get_token(
async_get_clientsession(self.hass),
user_input[CONF_ID],
user_input[CONF_SECRET],
)
except airthings.AirthingsConnectionError:
errors["base"] = "cannot_connect"
except airthings.AirthingsAuthError:
errors["base"] = "invalid_auth"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(user_input[CONF_ID])
self._abort_if_unique_id_configured()
return self.async_create_entry(title="Airthings", data=user_input)
return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
)
@@ -0,0 +1,6 @@
"""Constants for the Airthings integration."""
DOMAIN = "airthings"
CONF_ID = "id"
CONF_SECRET = "secret"
@@ -0,0 +1,11 @@
{
"domain": "airthings",
"name": "Airthings",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/airthings",
"requirements": ["airthings_cloud==0.0.1"],
"codeowners": [
"@danielhiversen"
],
"iot_class": "cloud_polling"
}
@@ -0,0 +1,164 @@
"""Support for Airthings sensors."""
from __future__ import annotations
from airthings import AirthingsDevice
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorEntity,
SensorEntityDescription,
StateType,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_CO2,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_PM1,
DEVICE_CLASS_PM25,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_TEMPERATURE,
PERCENTAGE,
PRESSURE_MBAR,
SIGNAL_STRENGTH_DECIBELS,
TEMP_CELSIUS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
from .const import DOMAIN
SENSORS: dict[str, SensorEntityDescription] = {
"radonShortTermAvg": SensorEntityDescription(
key="radonShortTermAvg",
native_unit_of_measurement="Bq/m³",
name="Radon",
),
"temp": SensorEntityDescription(
key="temp",
device_class=DEVICE_CLASS_TEMPERATURE,
native_unit_of_measurement=TEMP_CELSIUS,
name="Temperature",
),
"humidity": SensorEntityDescription(
key="humidity",
device_class=DEVICE_CLASS_HUMIDITY,
native_unit_of_measurement=PERCENTAGE,
name="Humidity",
),
"pressure": SensorEntityDescription(
key="pressure",
device_class=DEVICE_CLASS_PRESSURE,
native_unit_of_measurement=PRESSURE_MBAR,
name="Pressure",
),
"battery": SensorEntityDescription(
key="battery",
device_class=DEVICE_CLASS_BATTERY,
native_unit_of_measurement=PERCENTAGE,
name="Battery",
),
"co2": SensorEntityDescription(
key="co2",
device_class=DEVICE_CLASS_CO2,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
name="CO2",
),
"voc": SensorEntityDescription(
key="voc",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
name="VOC",
),
"light": SensorEntityDescription(
key="light",
native_unit_of_measurement=PERCENTAGE,
name="Light",
),
"virusRisk": SensorEntityDescription(
key="virusRisk",
name="Virus Risk",
),
"mold": SensorEntityDescription(
key="mold",
name="Mold",
),
"rssi": SensorEntityDescription(
key="rssi",
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
name="RSSI",
entity_registry_enabled_default=False,
),
"pm1": SensorEntityDescription(
key="pm1",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=DEVICE_CLASS_PM1,
name="PM1",
),
"pm25": SensorEntityDescription(
key="pm25",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=DEVICE_CLASS_PM25,
name="PM25",
),
}
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Airthings sensor."""
coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
entities = [
AirthingsHeaterEnergySensor(
coordinator,
airthings_device,
SENSORS[sensor_types],
)
for airthings_device in coordinator.data.values()
for sensor_types in airthings_device.sensor_types
if sensor_types in SENSORS
]
async_add_entities(entities)
class AirthingsHeaterEnergySensor(CoordinatorEntity, SensorEntity):
"""Representation of a Airthings Sensor device."""
_attr_state_class = STATE_CLASS_MEASUREMENT
def __init__(
self,
coordinator: DataUpdateCoordinator,
airthings_device: AirthingsDevice,
entity_description: SensorEntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
self.entity_description = entity_description
self._attr_name = f"{airthings_device.name} {entity_description.name}"
self._attr_unique_id = f"{airthings_device.device_id}_{entity_description.key}"
self._id = airthings_device.device_id
self._attr_device_info = {
"identifiers": {(DOMAIN, airthings_device.device_id)},
"name": airthings_device.name,
"manufacturer": "Airthings",
}
@property
def native_value(self) -> StateType:
"""Return the value reported by the sensor."""
return self.coordinator.data[self._id].sensors[self.entity_description.key]
@@ -0,0 +1,21 @@
{
"config": {
"step": {
"user": {
"data": {
"id": "ID",
"secret": "Secret",
"description": "Login at {url} to find your credentials"
}
}
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]"
}
}
}
@@ -0,0 +1,9 @@
{
"config": {
"step": {
"user": {
"title": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03c4\u03b5 \u03c4\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7\u03c2 \u03c4\u03bf\u03c5 {intergration}."
}
}
}
}
@@ -0,0 +1,15 @@
{
"config": {
"error": {
"no_units": "No se pudo encontrar ning\u00fan grupo AirTouch 4."
},
"step": {
"user": {
"data": {
"host": "Anfitri\u00f3n"
},
"title": "Configura los detalles de conexi\u00f3n de tu AirTouch 4."
}
}
}
}
@@ -0,0 +1,17 @@
{
"config": {
"abort": {
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9"
},
"error": {
"cannot_connect": "\u00c9chec de connexion"
},
"step": {
"user": {
"data": {
"host": "H\u00f4te"
}
}
}
}
}
+13 -1
View File
@@ -1,7 +1,11 @@
"""Support for AirVisual air quality sensors."""
from __future__ import annotations
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_LATITUDE,
@@ -76,6 +80,7 @@ GEOGRAPHY_SENSOR_DESCRIPTIONS = (
name="Air Quality Index",
device_class=DEVICE_CLASS_AQI,
native_unit_of_measurement="AQI",
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_POLLUTANT,
@@ -92,6 +97,7 @@ NODE_PRO_SENSOR_DESCRIPTIONS = (
name="Air Quality Index",
device_class=DEVICE_CLASS_AQI,
native_unit_of_measurement="AQI",
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_BATTERY_LEVEL,
@@ -104,6 +110,7 @@ NODE_PRO_SENSOR_DESCRIPTIONS = (
name="C02",
device_class=DEVICE_CLASS_CO2,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_HUMIDITY,
@@ -116,30 +123,35 @@ NODE_PRO_SENSOR_DESCRIPTIONS = (
name="PM 0.1",
device_class=DEVICE_CLASS_PM1,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_PM_1_0,
name="PM 1.0",
device_class=DEVICE_CLASS_PM10,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_PM_2_5,
name="PM 2.5",
device_class=DEVICE_CLASS_PM25,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_TEMPERATURE,
name="Temperature",
device_class=DEVICE_CLASS_TEMPERATURE,
native_unit_of_measurement=TEMP_CELSIUS,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=SENSOR_KIND_VOC,
name="VOC",
device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
state_class=STATE_CLASS_MEASUREMENT,
),
)
@@ -13,7 +13,7 @@
"step": {
"geography_by_coords": {
"data": {
"api_key": "Clef d'API",
"api_key": "Cl\u00e9 d'API",
"latitude": "Latitude",
"longitude": "Longitude"
},
@@ -22,7 +22,7 @@
},
"geography_by_name": {
"data": {
"api_key": "Clef d'API",
"api_key": "Cl\u00e9 d'API",
"city": "Ville",
"country": "Pays",
"state": "Etat"
@@ -9,11 +9,11 @@
"s2": "Di\u00f3xido de azufre"
},
"airvisual__pollutant_level": {
"good": "Bien",
"hazardous": "Peligroso",
"good": "Bueno",
"hazardous": "Da\u00f1ino",
"moderate": "Moderado",
"unhealthy": "Insalubre",
"unhealthy_sensitive": "Incorrecto para grupos sensibles",
"unhealthy_sensitive": "Insalubre para grupos sensibles",
"very_unhealthy": "Muy poco saludable"
}
}
@@ -1,12 +1,12 @@
{
"state": {
"airvisual__pollutant_label": {
"co": "Tlenek w\u0119gla",
"n2": "Dwutlenek azotu",
"o3": "Ozon",
"co": "tlenek w\u0119gla",
"n2": "dwutlenek azotu",
"o3": "ozon",
"p1": "PM10",
"p2": "PM2.5",
"s2": "Dwutlenek siarki"
"s2": "dwutlenek siarki"
},
"airvisual__pollutant_level": {
"good": "dobry",
@@ -11,7 +11,10 @@ from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_NIGHT,
SUPPORT_ALARM_ARM_VACATION,
)
from homeassistant.components.automation import AutomationActionType
from homeassistant.components.automation import (
AutomationActionType,
AutomationTriggerInfo,
)
from homeassistant.components.device_automation import DEVICE_TRIGGER_BASE_SCHEMA
from homeassistant.components.homeassistant.triggers import state as state_trigger
from homeassistant.const import (
@@ -129,7 +132,7 @@ async def async_attach_trigger(
hass: HomeAssistant,
config: ConfigType,
action: AutomationActionType,
automation_info: dict,
automation_info: AutomationTriggerInfo,
) -> CALLBACK_TYPE:
"""Attach a trigger."""
if config[CONF_TYPE] == "triggered":
@@ -4,7 +4,7 @@
"arm_away": "Schakel {entity_name} in voor vertrek",
"arm_home": "Schakel {entity_name} in voor thuis",
"arm_night": "Schakel {entity_name} in voor 's nachts",
"arm_vacation": "Schakel {entity_name} in op vakantie",
"arm_vacation": "Schakel {entity_name} in voor vakantie",
"disarm": "Schakel {entity_name} uit",
"trigger": "Laat {entity_name} afgaan"
},
@@ -12,7 +12,7 @@
"is_armed_away": "{entity_name} ingeschakeld voor vertrek",
"is_armed_home": "{entity_name} ingeschakeld voor thuis",
"is_armed_night": "{entity_name} is ingeschakeld voor 's nachts",
"is_armed_vacation": "{entity_name} is in vakantie geschakeld",
"is_armed_vacation": "{entity_name} is ingeschakeld voor vakantie",
"is_disarmed": "{entity_name} is uitgeschakeld",
"is_triggered": "{entity_name} gaat af"
},
@@ -20,7 +20,7 @@
"armed_away": "{entity_name} ingeschakeld voor vertrek",
"armed_home": "{entity_name} ingeschakeld voor thuis",
"armed_night": "{entity_name} ingeschakeld voor 's nachts",
"armed_vacation": "{entity_name} schakelde vakantie in",
"armed_vacation": "{entity_name} schakelde in voor vakantie",
"disarmed": "{entity_name} uitgeschakeld",
"triggered": "{entity_name} afgegaan"
}
@@ -40,5 +40,5 @@
"triggered": "Gaat af"
}
},
"title": "Alarm bedieningspaneel"
"title": "Alarmbedieningspaneel"
}
+39 -33
View File
@@ -48,6 +48,7 @@ from .const import (
API_THERMOSTAT_MODES,
API_THERMOSTAT_PRESETS,
DATE_FORMAT,
PRESET_MODE_NA,
Inputs,
)
from .errors import UnsupportedProperty
@@ -391,6 +392,8 @@ class AlexaPowerController(AlexaCapability):
if self.entity.domain == climate.DOMAIN:
is_on = self.entity.state != climate.HVAC_MODE_OFF
elif self.entity.domain == fan.DOMAIN:
is_on = self.entity.state == fan.STATE_ON
elif self.entity.domain == vacuum.DOMAIN:
is_on = self.entity.state == vacuum.STATE_CLEANING
elif self.entity.domain == timer.DOMAIN:
@@ -1155,9 +1158,6 @@ class AlexaPowerLevelController(AlexaCapability):
if name != "powerLevel":
raise UnsupportedProperty(name)
if self.entity.domain == fan.DOMAIN:
return self.entity.attributes.get(fan.ATTR_PERCENTAGE) or 0
class AlexaSecurityPanelController(AlexaCapability):
"""Implements Alexa.SecurityPanelController.
@@ -1354,10 +1354,17 @@ class AlexaModeController(AlexaCapability):
self._resource = AlexaModeResource(
[AlexaGlobalCatalog.SETTING_PRESET], False
)
for preset_mode in self.entity.attributes.get(fan.ATTR_PRESET_MODES, []):
preset_modes = self.entity.attributes.get(fan.ATTR_PRESET_MODES, [])
for preset_mode in preset_modes:
self._resource.add_mode(
f"{fan.ATTR_PRESET_MODE}.{preset_mode}", [preset_mode]
)
# Fans with a single preset_mode completely break Alexa discovery, add a
# fake preset (see issue #53832).
if len(preset_modes) == 1:
self._resource.add_mode(
f"{fan.ATTR_PRESET_MODE}.{PRESET_MODE_NA}", [PRESET_MODE_NA]
)
return self._resource.serialize_capability_resources()
# Cover Position Resources
@@ -1483,16 +1490,6 @@ class AlexaRangeController(AlexaCapability):
if self.entity.state in (STATE_UNAVAILABLE, STATE_UNKNOWN, None):
return None
# Fan Speed
if self.instance == f"{fan.DOMAIN}.{fan.ATTR_SPEED}":
speed_list = self.entity.attributes.get(fan.ATTR_SPEED_LIST)
speed = self.entity.attributes.get(fan.ATTR_SPEED)
if speed_list is not None and speed is not None:
speed_index = next(
(i for i, v in enumerate(speed_list) if v == speed), None
)
return speed_index
# Cover Position
if self.instance == f"{cover.DOMAIN}.{cover.ATTR_POSITION}":
return self.entity.attributes.get(cover.ATTR_CURRENT_POSITION)
@@ -1501,6 +1498,13 @@ class AlexaRangeController(AlexaCapability):
if self.instance == f"{cover.DOMAIN}.tilt":
return self.entity.attributes.get(cover.ATTR_CURRENT_TILT_POSITION)
# Fan speed percentage
if self.instance == f"{fan.DOMAIN}.{fan.ATTR_PERCENTAGE}":
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if supported and fan.SUPPORT_SET_SPEED:
return self.entity.attributes.get(fan.ATTR_PERCENTAGE)
return 100 if self.entity.state == fan.STATE_ON else 0
# Input Number Value
if self.instance == f"{input_number.DOMAIN}.{input_number.ATTR_VALUE}":
return float(self.entity.state)
@@ -1527,28 +1531,16 @@ class AlexaRangeController(AlexaCapability):
def capability_resources(self):
"""Return capabilityResources object."""
# Fan Speed Resources
if self.instance == f"{fan.DOMAIN}.{fan.ATTR_SPEED}":
speed_list = self.entity.attributes[fan.ATTR_SPEED_LIST]
max_value = len(speed_list) - 1
# Fan Speed Percentage Resources
if self.instance == f"{fan.DOMAIN}.{fan.ATTR_PERCENTAGE}":
percentage_step = self.entity.attributes.get(fan.ATTR_PERCENTAGE_STEP)
self._resource = AlexaPresetResource(
labels=[AlexaGlobalCatalog.SETTING_FAN_SPEED],
labels=["Percentage", AlexaGlobalCatalog.SETTING_FAN_SPEED],
min_value=0,
max_value=max_value,
precision=1,
max_value=100,
precision=percentage_step if percentage_step else 100,
unit=AlexaGlobalCatalog.UNIT_PERCENT,
)
for index, speed in enumerate(speed_list):
labels = []
if isinstance(speed, str):
labels.append(speed.replace("_", " "))
if index == 1:
labels.append(AlexaGlobalCatalog.VALUE_MINIMUM)
if index == max_value:
labels.append(AlexaGlobalCatalog.VALUE_MAXIMUM)
if len(labels) > 0:
self._resource.add_preset(value=index, labels=labels)
return self._resource.serialize_capability_resources()
# Cover Position Resources
@@ -1661,6 +1653,20 @@ class AlexaRangeController(AlexaCapability):
)
return self._semantics.serialize_semantics()
# Fan Speed Percentage
if self.instance == f"{fan.DOMAIN}.{fan.ATTR_PERCENTAGE}":
lower_labels = [AlexaSemantics.ACTION_LOWER]
raise_labels = [AlexaSemantics.ACTION_RAISE]
self._semantics = AlexaSemantics()
self._semantics.add_action_to_directive(
lower_labels, "SetRangeValue", {"rangeValue": 0}
)
self._semantics.add_action_to_directive(
raise_labels, "SetRangeValue", {"rangeValue": 100}
)
return self._semantics.serialize_semantics()
return None
+3
View File
@@ -78,6 +78,9 @@ API_THERMOSTAT_MODES = OrderedDict(
API_THERMOSTAT_MODES_CUSTOM = {climate.HVAC_MODE_DRY: "DEHUMIDIFY"}
API_THERMOSTAT_PRESETS = {climate.PRESET_ECO: "ECO"}
# AlexaModeController does not like a single mode for the fan preset, we add PRESET_MODE_NA if a fan has only one preset_mode
PRESET_MODE_NA = "-"
class Cause:
"""Possible causes for property changes.
+13 -10
View File
@@ -60,11 +60,9 @@ from .capabilities import (
AlexaLockController,
AlexaModeController,
AlexaMotionSensor,
AlexaPercentageController,
AlexaPlaybackController,
AlexaPlaybackStateReporter,
AlexaPowerController,
AlexaPowerLevelController,
AlexaRangeController,
AlexaSceneController,
AlexaSecurityPanelController,
@@ -530,27 +528,32 @@ class FanCapabilities(AlexaEntity):
def interfaces(self):
"""Yield the supported interfaces."""
yield AlexaPowerController(self.entity)
force_range_controller = True
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if supported & fan.SUPPORT_SET_SPEED:
yield AlexaPercentageController(self.entity)
yield AlexaPowerLevelController(self.entity)
# The use of legacy speeds is deprecated in the schema, support will be removed after a quarter (2021.7)
yield AlexaRangeController(
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_SPEED}"
)
if supported & fan.SUPPORT_OSCILLATE:
yield AlexaToggleController(
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_OSCILLATING}"
)
force_range_controller = False
if supported & fan.SUPPORT_PRESET_MODE:
yield AlexaModeController(
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_PRESET_MODE}"
)
force_range_controller = False
if supported & fan.SUPPORT_DIRECTION:
yield AlexaModeController(
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_DIRECTION}"
)
force_range_controller = False
# AlexaRangeController controls the Fan Speed Percentage.
# For fans which only support on/off, no controller is added. This makes the
# fan impossible to turn on or off through Alexa, most likely due to a bug in Alexa.
# As a workaround, we add a range controller which can only be set to 0% or 100%.
if force_range_controller or supported & fan.SUPPORT_SET_SPEED:
yield AlexaRangeController(
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_PERCENTAGE}"
)
yield AlexaEndpointHealth(self.hass, self.entity)
yield Alexa(self.hass)
+45 -84
View File
@@ -54,6 +54,8 @@ from .const import (
API_THERMOSTAT_MODES,
API_THERMOSTAT_MODES_CUSTOM,
API_THERMOSTAT_PRESETS,
DATE_FORMAT,
PRESET_MODE_NA,
Cause,
Inputs,
)
@@ -122,6 +124,8 @@ async def async_api_turn_on(hass, config, directive, context):
service = SERVICE_TURN_ON
if domain == cover.DOMAIN:
service = cover.SERVICE_OPEN_COVER
elif domain == fan.DOMAIN:
service = fan.SERVICE_TURN_ON
elif domain == vacuum.DOMAIN:
supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if not supported & vacuum.SUPPORT_TURN_ON and supported & vacuum.SUPPORT_START:
@@ -156,6 +160,8 @@ async def async_api_turn_off(hass, config, directive, context):
service = SERVICE_TURN_OFF
if entity.domain == cover.DOMAIN:
service = cover.SERVICE_CLOSE_COVER
elif domain == fan.DOMAIN:
service = fan.SERVICE_TURN_OFF
elif domain == vacuum.DOMAIN:
supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if (
@@ -318,7 +324,7 @@ async def async_api_activate(hass, config, directive, context):
payload = {
"cause": {"type": Cause.VOICE_INTERACTION},
"timestamp": f"{dt_util.utcnow().replace(tzinfo=None).isoformat()}Z",
"timestamp": dt_util.utcnow().strftime(DATE_FORMAT),
}
return directive.response(
@@ -342,7 +348,7 @@ async def async_api_deactivate(hass, config, directive, context):
payload = {
"cause": {"type": Cause.VOICE_INTERACTION},
"timestamp": f"{dt_util.utcnow().replace(tzinfo=None).isoformat()}Z",
"timestamp": dt_util.utcnow().strftime(DATE_FORMAT),
}
return directive.response(
@@ -825,48 +831,6 @@ async def async_api_reportstate(hass, config, directive, context):
return directive.response(name="StateReport")
@HANDLERS.register(("Alexa.PowerLevelController", "SetPowerLevel"))
async def async_api_set_power_level(hass, config, directive, context):
"""Process a SetPowerLevel request."""
entity = directive.entity
service = None
data = {ATTR_ENTITY_ID: entity.entity_id}
if entity.domain == fan.DOMAIN:
service = fan.SERVICE_SET_PERCENTAGE
percentage = int(directive.payload["powerLevel"])
data[fan.ATTR_PERCENTAGE] = percentage
await hass.services.async_call(
entity.domain, service, data, blocking=False, context=context
)
return directive.response()
@HANDLERS.register(("Alexa.PowerLevelController", "AdjustPowerLevel"))
async def async_api_adjust_power_level(hass, config, directive, context):
"""Process an AdjustPowerLevel request."""
entity = directive.entity
percentage_delta = int(directive.payload["powerLevelDelta"])
service = None
data = {ATTR_ENTITY_ID: entity.entity_id}
if entity.domain == fan.DOMAIN:
service = fan.SERVICE_SET_PERCENTAGE
current = entity.attributes.get(fan.ATTR_PERCENTAGE) or 0
# set percentage
percentage = min(100, max(0, percentage_delta + current))
data[fan.ATTR_PERCENTAGE] = percentage
await hass.services.async_call(
entity.domain, service, data, blocking=False, context=context
)
return directive.response()
@HANDLERS.register(("Alexa.SecurityPanelController", "Arm"))
async def async_api_arm(hass, config, directive, context):
"""Process a Security Panel Arm request."""
@@ -961,7 +925,9 @@ async def async_api_set_mode(hass, config, directive, context):
# Fan preset_mode
elif instance == f"{fan.DOMAIN}.{fan.ATTR_PRESET_MODE}":
preset_mode = mode.split(".")[1]
if preset_mode in entity.attributes.get(fan.ATTR_PRESET_MODES):
if preset_mode != PRESET_MODE_NA and preset_mode in entity.attributes.get(
fan.ATTR_PRESET_MODES
):
service = fan.SERVICE_SET_PRESET_MODE
data[fan.ATTR_PRESET_MODE] = preset_mode
else:
@@ -1091,24 +1057,8 @@ async def async_api_set_range(hass, config, directive, context):
data = {ATTR_ENTITY_ID: entity.entity_id}
range_value = directive.payload["rangeValue"]
# Fan Speed
if instance == f"{fan.DOMAIN}.{fan.ATTR_SPEED}":
range_value = int(range_value)
service = fan.SERVICE_SET_SPEED
speed_list = entity.attributes[fan.ATTR_SPEED_LIST]
speed = next((v for i, v in enumerate(speed_list) if i == range_value), None)
if not speed:
msg = "Entity does not support value"
raise AlexaInvalidValueError(msg)
if speed == fan.SPEED_OFF:
service = fan.SERVICE_TURN_OFF
data[fan.ATTR_SPEED] = speed
# Cover Position
elif instance == f"{cover.DOMAIN}.{cover.ATTR_POSITION}":
if instance == f"{cover.DOMAIN}.{cover.ATTR_POSITION}":
range_value = int(range_value)
if range_value == 0:
service = cover.SERVICE_CLOSE_COVER
@@ -1129,6 +1079,19 @@ async def async_api_set_range(hass, config, directive, context):
service = cover.SERVICE_SET_COVER_TILT_POSITION
data[cover.ATTR_TILT_POSITION] = range_value
# Fan Speed
elif instance == f"{fan.DOMAIN}.{fan.ATTR_PERCENTAGE}":
range_value = int(range_value)
if range_value == 0:
service = fan.SERVICE_TURN_OFF
else:
supported = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if supported and fan.SUPPORT_SET_SPEED:
service = fan.SERVICE_SET_PERCENTAGE
data[fan.ATTR_PERCENTAGE] = range_value
else:
service = fan.SERVICE_TURN_ON
# Input Number Value
elif instance == f"{input_number.DOMAIN}.{input_number.ATTR_VALUE}":
range_value = float(range_value)
@@ -1184,29 +1147,8 @@ async def async_api_adjust_range(hass, config, directive, context):
range_delta_default = bool(directive.payload["rangeValueDeltaDefault"])
response_value = 0
# Fan Speed
if instance == f"{fan.DOMAIN}.{fan.ATTR_SPEED}":
range_delta = int(range_delta)
service = fan.SERVICE_SET_SPEED
speed_list = entity.attributes[fan.ATTR_SPEED_LIST]
current_speed = entity.attributes[fan.ATTR_SPEED]
current_speed_index = next(
(i for i, v in enumerate(speed_list) if v == current_speed), 0
)
new_speed_index = min(
len(speed_list) - 1, max(0, current_speed_index + range_delta)
)
speed = next(
(v for i, v in enumerate(speed_list) if i == new_speed_index), None
)
if speed == fan.SPEED_OFF:
service = fan.SERVICE_TURN_OFF
data[fan.ATTR_SPEED] = response_value = speed
# Cover Position
elif instance == f"{cover.DOMAIN}.{cover.ATTR_POSITION}":
if instance == f"{cover.DOMAIN}.{cover.ATTR_POSITION}":
range_delta = int(range_delta * 20) if range_delta_default else int(range_delta)
service = SERVICE_SET_COVER_POSITION
current = entity.attributes.get(cover.ATTR_POSITION)
@@ -1237,6 +1179,25 @@ async def async_api_adjust_range(hass, config, directive, context):
else:
data[cover.ATTR_TILT_POSITION] = tilt_position
# Fan speed percentage
elif instance == f"{fan.DOMAIN}.{fan.ATTR_PERCENTAGE}":
percentage_step = entity.attributes.get(fan.ATTR_PERCENTAGE_STEP) or 20
range_delta = (
int(range_delta * percentage_step)
if range_delta_default
else int(range_delta)
)
service = fan.SERVICE_SET_PERCENTAGE
current = entity.attributes.get(fan.ATTR_PERCENTAGE)
if not current:
msg = f"Unable to determine {entity.entity_id} current fan speed"
raise AlexaInvalidValueError(msg)
percentage = response_value = min(100, max(0, range_delta + current))
if percentage:
data[fan.ATTR_PERCENTAGE] = percentage
else:
service = fan.SERVICE_TURN_OFF
# Input Number Value
elif instance == f"{input_number.DOMAIN}.{input_number.ATTR_VALUE}":
range_delta = float(range_delta)
@@ -13,7 +13,7 @@ from homeassistant.core import HomeAssistant, State, callback
from homeassistant.helpers.significant_change import create_checker
import homeassistant.util.dt as dt_util
from .const import API_CHANGE, DOMAIN, Cause
from .const import API_CHANGE, DATE_FORMAT, DOMAIN, Cause
from .entities import ENTITY_ADAPTERS, AlexaEntity, generate_alexa_id
from .messages import AlexaResponse
@@ -252,7 +252,7 @@ async def async_send_doorbell_event_message(hass, config, alexa_entity):
namespace="Alexa.DoorbellEventSource",
payload={
"cause": {"type": Cause.PHYSICAL_INTERACTION},
"timestamp": f"{dt_util.utcnow().replace(tzinfo=None).isoformat()}Z",
"timestamp": dt_util.utcnow().strftime(DATE_FORMAT),
},
)
@@ -1,8 +1,8 @@
{
"config": {
"abort": {
"cannot_connect": "Impossible de se connecter au serveur Almond",
"missing_configuration": "Veuillez consulter la documentation pour savoir comment configurer Almond.",
"cannot_connect": "\u00c9chec de connexion",
"missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation.",
"no_url_available": "Aucune URL disponible. Pour plus d'informations sur cette erreur, [consultez la section d'aide] ( {docs_url} )",
"single_instance_allowed": "D\u00e9j\u00e0 configur\u00e9. Une seule configuration possible."
},
@@ -1,22 +1,22 @@
{
"config": {
"abort": {
"reauth_successful": "R\u00e9-authentification r\u00e9ussie"
"reauth_successful": "La r\u00e9-authentification a r\u00e9ussi"
},
"error": {
"cannot_connect": "\u00c9chec de connexion",
"invalid_api_key": "Cl\u00e9 API non valide"
"invalid_api_key": "Cl\u00e9 API invalide"
},
"step": {
"reauth_confirm": {
"data": {
"api_key": "cl\u00e9 API",
"api_key": "Cl\u00e9 d'API",
"description": "R\u00e9-authentifiez-vous avec votre compte Ambee."
}
},
"user": {
"data": {
"api_key": "cl\u00e9 API",
"api_key": "Cl\u00e9 d'API",
"latitude": "Latitude",
"longitude": "Longitude",
"name": "Nom"
@@ -1,10 +1,10 @@
{
"state": {
"ambee__risk": {
"high": "Wysoki",
"low": "Niski",
"moderate": "Umiarkowany",
"very high": "Bardzo wysoki"
"high": "wysoki",
"low": "niski",
"moderate": "umiarkowany",
"very high": "bardzo wysoki"
}
}
}
@@ -0,0 +1,32 @@
"""Support for Amber Electric."""
from amberelectric import Configuration
from amberelectric.api import amber_api
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from .const import CONF_API_TOKEN, CONF_SITE_ID, DOMAIN, PLATFORMS
from .coordinator import AmberUpdateCoordinator
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Amber Electric from a config entry."""
configuration = Configuration(access_token=entry.data[CONF_API_TOKEN])
api_instance = amber_api.AmberApi.create(configuration)
site_id = entry.data[CONF_SITE_ID]
coordinator = AmberUpdateCoordinator(hass, api_instance, site_id)
await coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
@@ -0,0 +1,88 @@
"""Amber Electric Binary Sensor definitions."""
from __future__ import annotations
from collections.abc import Mapping
from typing import Any
from homeassistant.components.binary_sensor import (
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import ATTRIBUTION, DOMAIN
from .coordinator import AmberUpdateCoordinator
PRICE_SPIKE_ICONS = {
"none": "mdi:power-plug",
"potential": "mdi:power-plug-outline",
"spike": "mdi:power-plug-off",
}
class AmberPriceGridSensor(CoordinatorEntity, BinarySensorEntity):
"""Sensor to show single grid binary values."""
def __init__(
self,
coordinator: AmberUpdateCoordinator,
description: BinarySensorEntityDescription,
) -> None:
"""Initialize the Sensor."""
super().__init__(coordinator)
self.site_id = coordinator.site_id
self.entity_description = description
self._attr_unique_id = f"{coordinator.site_id}-{description.key}"
self._attr_device_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
@property
def is_on(self) -> bool | None:
"""Return true if the binary sensor is on."""
return self.coordinator.data["grid"][self.entity_description.key]
class AmberPriceSpikeBinarySensor(AmberPriceGridSensor):
"""Sensor to show single grid binary values."""
@property
def icon(self):
"""Return the sensor icon."""
status = self.coordinator.data["grid"]["price_spike"]
return PRICE_SPIKE_ICONS[status]
@property
def is_on(self) -> bool | None:
"""Return true if the binary sensor is on."""
return self.coordinator.data["grid"]["price_spike"] == "spike"
@property
def device_state_attributes(self) -> Mapping[str, Any] | None:
"""Return additional pieces of information about the price spike."""
spike_status = self.coordinator.data["grid"]["price_spike"]
return {
"spike_status": spike_status,
ATTR_ATTRIBUTION: ATTRIBUTION,
}
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up a config entry."""
coordinator: AmberUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
entities: list = []
price_spike_description = BinarySensorEntityDescription(
key="price_spike",
name=f"{entry.title} - Price Spike",
)
entities.append(AmberPriceSpikeBinarySensor(coordinator, price_spike_description))
async_add_entities(entities)
@@ -0,0 +1,120 @@
"""Config flow for the Amber Electric integration."""
from __future__ import annotations
from typing import Any
import amberelectric
from amberelectric.api import amber_api
from amberelectric.model.site import Site
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_API_TOKEN
from .const import CONF_SITE_ID, CONF_SITE_NAME, CONF_SITE_NMI, DOMAIN
API_URL = "https://app.amber.com.au/developers"
class AmberElectricConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow."""
VERSION = 1
def __init__(self) -> None:
"""Initialize the config flow."""
self._errors: dict[str, str] = {}
self._sites: list[Site] | None = None
self._api_token: str | None = None
def _fetch_sites(self, token: str) -> list[Site] | None:
configuration = amberelectric.Configuration(access_token=token)
api = amber_api.AmberApi.create(configuration)
try:
sites = api.get_sites()
if len(sites) == 0:
self._errors[CONF_API_TOKEN] = "no_site"
return None
return sites
except amberelectric.ApiException as api_exception:
if api_exception.status == 403:
self._errors[CONF_API_TOKEN] = "invalid_api_token"
else:
self._errors[CONF_API_TOKEN] = "unknown_error"
return None
async def async_step_user(self, user_input: dict[str, Any] | None = None):
"""Step when user initializes a integration."""
self._errors = {}
self._sites = None
self._api_token = None
if user_input is not None:
token = user_input[CONF_API_TOKEN]
self._sites = await self.hass.async_add_executor_job(
self._fetch_sites, token
)
if self._sites is not None:
self._api_token = token
return await self.async_step_site()
else:
user_input = {CONF_API_TOKEN: ""}
return self.async_show_form(
step_id="user",
description_placeholders={"api_url": API_URL},
data_schema=vol.Schema(
{
vol.Required(
CONF_API_TOKEN, default=user_input[CONF_API_TOKEN]
): str,
}
),
errors=self._errors,
)
async def async_step_site(self, user_input: dict[str, Any] = None):
"""Step to select site."""
self._errors = {}
assert self._sites is not None
api_token = self._api_token
if user_input is not None:
site_nmi = user_input[CONF_SITE_NMI]
sites = [site for site in self._sites if site.nmi == site_nmi]
site = sites[0]
site_id = site.id
name = user_input.get(CONF_SITE_NAME, site_id)
return self.async_create_entry(
title=name,
data={
CONF_SITE_ID: site_id,
CONF_API_TOKEN: api_token,
CONF_SITE_NMI: site.nmi,
},
)
user_input = {
CONF_API_TOKEN: api_token,
CONF_SITE_NMI: "",
CONF_SITE_NAME: "",
}
return self.async_show_form(
step_id="site",
data_schema=vol.Schema(
{
vol.Required(
CONF_SITE_NMI, default=user_input[CONF_SITE_NMI]
): vol.In([site.nmi for site in self._sites]),
vol.Optional(
CONF_SITE_NAME, default=user_input[CONF_SITE_NAME]
): str,
}
),
errors=self._errors,
)
@@ -0,0 +1,13 @@
"""Amber Electric Constants."""
import logging
DOMAIN = "amberelectric"
CONF_API_TOKEN = "api_token"
CONF_SITE_NAME = "site_name"
CONF_SITE_ID = "site_id"
CONF_SITE_NMI = "site_nmi"
ATTRIBUTION = "Data provided by Amber Electric"
LOGGER = logging.getLogger(__package__)
PLATFORMS = ["sensor", "binary_sensor"]
@@ -0,0 +1,111 @@
"""Amber Electric Coordinator."""
from __future__ import annotations
from datetime import timedelta
from typing import Any
from amberelectric import ApiException
from amberelectric.api import amber_api
from amberelectric.model.actual_interval import ActualInterval
from amberelectric.model.channel import ChannelType
from amberelectric.model.current_interval import CurrentInterval
from amberelectric.model.forecast_interval import ForecastInterval
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import LOGGER
def is_current(interval: ActualInterval | CurrentInterval | ForecastInterval) -> bool:
"""Return true if the supplied interval is a CurrentInterval."""
return isinstance(interval, CurrentInterval)
def is_forecast(interval: ActualInterval | CurrentInterval | ForecastInterval) -> bool:
"""Return true if the supplied interval is a ForecastInterval."""
return isinstance(interval, ForecastInterval)
def is_general(interval: ActualInterval | CurrentInterval | ForecastInterval) -> bool:
"""Return true if the supplied interval is on the general channel."""
return interval.channel_type == ChannelType.GENERAL
def is_controlled_load(
interval: ActualInterval | CurrentInterval | ForecastInterval,
) -> bool:
"""Return true if the supplied interval is on the controlled load channel."""
return interval.channel_type == ChannelType.CONTROLLED_LOAD
def is_feed_in(interval: ActualInterval | CurrentInterval | ForecastInterval) -> bool:
"""Return true if the supplied interval is on the feed in channel."""
return interval.channel_type == ChannelType.FEED_IN
class AmberUpdateCoordinator(DataUpdateCoordinator):
"""AmberUpdateCoordinator - In charge of downloading the data for a site, which all the sensors read."""
def __init__(
self, hass: HomeAssistant, api: amber_api.AmberApi, site_id: str
) -> None:
"""Initialise the data service."""
super().__init__(
hass,
LOGGER,
name="amberelectric",
update_interval=timedelta(minutes=1),
)
self._api = api
self.site_id = site_id
def update_price_data(self) -> dict[str, dict[str, Any]]:
"""Update callback."""
result: dict[str, dict[str, Any]] = {
"current": {},
"forecasts": {},
"grid": {},
}
try:
data = self._api.get_current_price(self.site_id, next=48)
except ApiException as api_exception:
raise UpdateFailed("Missing price data, skipping update") from api_exception
current = [interval for interval in data if is_current(interval)]
forecasts = [interval for interval in data if is_forecast(interval)]
general = [interval for interval in current if is_general(interval)]
if len(general) == 0:
raise UpdateFailed("No general channel configured")
result["current"]["general"] = general[0]
result["forecasts"]["general"] = [
interval for interval in forecasts if is_general(interval)
]
result["grid"]["renewables"] = round(general[0].renewables)
result["grid"]["price_spike"] = general[0].spike_status.value
controlled_load = [
interval for interval in current if is_controlled_load(interval)
]
if controlled_load:
result["current"]["controlled_load"] = controlled_load[0]
result["forecasts"]["controlled_load"] = [
interval for interval in forecasts if is_controlled_load(interval)
]
feed_in = [interval for interval in current if is_feed_in(interval)]
if feed_in:
result["current"]["feed_in"] = feed_in[0]
result["forecasts"]["feed_in"] = [
interval for interval in forecasts if is_feed_in(interval)
]
LOGGER.debug("Fetched new Amber data: %s", data)
return result
async def _async_update_data(self) -> dict[str, Any]:
"""Async update wrapper."""
return await self.hass.async_add_executor_job(self.update_price_data)
@@ -0,0 +1,13 @@
{
"domain": "amberelectric",
"name": "Amber Electric",
"documentation": "https://www.home-assistant.io/integrations/amberelectric",
"config_flow": true,
"codeowners": [
"@madpilot"
],
"requirements": [
"amberelectric==1.0.3"
],
"iot_class": "cloud_polling"
}
@@ -0,0 +1,229 @@
"""Amber Electric Sensor definitions."""
# There are three types of sensor: Current, Forecast and Grid
# Current and forecast will create general, controlled load and feed in as required
# At the moment renewables in the only grid sensor.
from __future__ import annotations
from collections.abc import Mapping
from typing import Any
from amberelectric.model.channel import ChannelType
from amberelectric.model.current_interval import CurrentInterval
from amberelectric.model.forecast_interval import ForecastInterval
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ATTRIBUTION, CURRENCY_DOLLAR, ENERGY_KILO_WATT_HOUR
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import ATTRIBUTION, DOMAIN
from .coordinator import AmberUpdateCoordinator
ICONS = {
"general": "mdi:transmission-tower",
"controlled_load": "mdi:clock-outline",
"feed_in": "mdi:solar-power",
}
UNIT = f"{CURRENCY_DOLLAR}/{ENERGY_KILO_WATT_HOUR}"
def friendly_channel_type(channel_type: str) -> str:
"""Return a human readable version of the channel type."""
if channel_type == "controlled_load":
return "Controlled Load"
if channel_type == "feed_in":
return "Feed In"
return "General"
class AmberSensor(CoordinatorEntity, SensorEntity):
"""Amber Base Sensor."""
def __init__(
self,
coordinator: AmberUpdateCoordinator,
description: SensorEntityDescription,
channel_type: ChannelType,
) -> None:
"""Initialize the Sensor."""
super().__init__(coordinator)
self.site_id = coordinator.site_id
self.entity_description = description
self.channel_type = channel_type
self._attr_unique_id = (
f"{self.site_id}-{self.entity_description.key}-{self.channel_type}"
)
class AmberPriceSensor(AmberSensor):
"""Amber Price Sensor."""
@property
def native_value(self) -> str | None:
"""Return the current price in $/kWh."""
interval = self.coordinator.data[self.entity_description.key][self.channel_type]
if interval.channel_type == ChannelType.FEED_IN:
return round(interval.per_kwh, 0) / 100 * -1
return round(interval.per_kwh, 0) / 100
@property
def device_state_attributes(self) -> Mapping[str, Any] | None:
"""Return additional pieces of information about the price."""
interval = self.coordinator.data[self.entity_description.key][self.channel_type]
data: dict[str, Any] = {ATTR_ATTRIBUTION: ATTRIBUTION}
if interval is None:
return data
data["duration"] = interval.duration
data["date"] = interval.date.isoformat()
data["per_kwh"] = round(interval.per_kwh)
if interval.channel_type == ChannelType.FEED_IN:
data["per_kwh"] = data["per_kwh"] * -1
data["nem_date"] = interval.nem_time.isoformat()
data["spot_per_kwh"] = round(interval.spot_per_kwh)
data["start_time"] = interval.start_time.isoformat()
data["end_time"] = interval.end_time.isoformat()
data["renewables"] = round(interval.renewables)
data["estimate"] = interval.estimate
data["spike_status"] = interval.spike_status.value
data["channel_type"] = interval.channel_type.value
if interval.range is not None:
data["range_min"] = interval.range.min
data["range_max"] = interval.range.max
return data
class AmberForecastSensor(AmberSensor):
"""Amber Forecast Sensor."""
@property
def native_value(self) -> str | None:
"""Return the first forecast price in $/kWh."""
intervals = self.coordinator.data[self.entity_description.key].get(
self.channel_type
)
if not intervals:
return None
interval = intervals[0]
if interval.channel_type == ChannelType.FEED_IN:
return round(interval.per_kwh, 0) / 100 * -1
return round(interval.per_kwh, 0) / 100
@property
def device_state_attributes(self) -> Mapping[str, Any] | None:
"""Return additional pieces of information about the price."""
intervals = self.coordinator.data[self.entity_description.key].get(
self.channel_type
)
if not intervals:
return None
data = {
"forecasts": [],
"channel_type": intervals[0].channel_type.value,
ATTR_ATTRIBUTION: ATTRIBUTION,
}
for interval in intervals:
datum = {}
datum["duration"] = interval.duration
datum["date"] = interval.date.isoformat()
datum["nem_date"] = interval.nem_time.isoformat()
datum["per_kwh"] = round(interval.per_kwh)
if interval.channel_type == ChannelType.FEED_IN:
datum["per_kwh"] = datum["per_kwh"] * -1
datum["spot_per_kwh"] = round(interval.spot_per_kwh)
datum["start_time"] = interval.start_time.isoformat()
datum["end_time"] = interval.end_time.isoformat()
datum["renewables"] = round(interval.renewables)
datum["spike_status"] = interval.spike_status.value
if interval.range is not None:
datum["range_min"] = interval.range.min
datum["range_max"] = interval.range.max
data["forecasts"].append(datum)
return data
class AmberGridSensor(CoordinatorEntity, SensorEntity):
"""Sensor to show single grid specific values."""
def __init__(
self,
coordinator: AmberUpdateCoordinator,
description: SensorEntityDescription,
) -> None:
"""Initialize the Sensor."""
super().__init__(coordinator)
self.site_id = coordinator.site_id
self.entity_description = description
self._attr_device_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
self._attr_unique_id = f"{coordinator.site_id}-{description.key}"
@property
def native_value(self) -> str | None:
"""Return the value of the sensor."""
return self.coordinator.data["grid"][self.entity_description.key]
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up a config entry."""
coordinator: AmberUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
current: dict[str, CurrentInterval] = coordinator.data["current"]
forecasts: dict[str, list[ForecastInterval]] = coordinator.data["forecasts"]
entities: list = []
for channel_type in current:
description = SensorEntityDescription(
key="current",
name=f"{entry.title} - {friendly_channel_type(channel_type)} Price",
native_unit_of_measurement=UNIT,
state_class=STATE_CLASS_MEASUREMENT,
icon=ICONS[channel_type],
)
entities.append(AmberPriceSensor(coordinator, description, channel_type))
for channel_type in forecasts:
description = SensorEntityDescription(
key="forecasts",
name=f"{entry.title} - {friendly_channel_type(channel_type)} Forecast",
native_unit_of_measurement=UNIT,
state_class=STATE_CLASS_MEASUREMENT,
icon=ICONS[channel_type],
)
entities.append(AmberForecastSensor(coordinator, description, channel_type))
renewables_description = SensorEntityDescription(
key="renewables",
name=f"{entry.title} - Renewables",
native_unit_of_measurement="%",
state_class=STATE_CLASS_MEASUREMENT,
icon="mdi:solar-power",
)
entities.append(AmberGridSensor(coordinator, renewables_description))
async_add_entities(entities)
@@ -0,0 +1,22 @@
{
"config": {
"step": {
"user": {
"data": {
"api_token": "API Token",
"site_id": "Site ID"
},
"title": "Amber Electric",
"description": "Go to {api_url} to generate an API key"
},
"site": {
"data": {
"site_nmi": "Site NMI",
"site_name": "Site Name"
},
"title": "Amber Electric",
"description": "Select the NMI of the site you would like to add"
}
}
}
}
@@ -0,0 +1,22 @@
{
"config": {
"step": {
"site": {
"data": {
"site_name": "Site Name",
"site_nmi": "Site NMI"
},
"description": "Select the NMI of the site you would like to add",
"title": "Amber Electric"
},
"user": {
"data": {
"api_token": "API Token",
"site_id": "Site ID"
},
"description": "Go to {api_url} to generate an API key",
"title": "Amber Electric"
}
}
}
}
@@ -142,6 +142,7 @@ class AmbiclimateAuthCallbackView(HomeAssistantView):
async def get(self, request: web.Request) -> str:
"""Receive authorization token."""
# pylint: disable=no-self-use
code = request.query.get("code")
if code is None:
return "No code"
@@ -6,7 +6,7 @@
"missing_configuration": "Le composant n'est pas configur\u00e9. Veuillez suivre la documentation."
},
"create_entry": {
"default": "Authentifi\u00e9 avec succ\u00e8s avec Ambiclimate"
"default": "Authentification r\u00e9ussie"
},
"error": {
"follow_link": "Veuillez suivre le lien et vous authentifier avant d'appuyer sur Soumettre.",
@@ -1,38 +1,17 @@
"""Support for Ambient Weather Station Service."""
from __future__ import annotations
from typing import Any
from aioambient import Client
from aioambient.errors import WebsocketError
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_CONNECTIVITY,
DOMAIN as BINARY_SENSOR,
)
from homeassistant.components.sensor import DOMAIN as SENSOR
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_LOCATION,
ATTR_NAME,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_MILLION,
CONF_API_KEY,
DEGREE,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_CO2,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_ILLUMINANCE,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_TIMESTAMP,
EVENT_HOMEASSISTANT_STOP,
IRRADIATION_WATTS_PER_SQUARE_METER,
LIGHT_LUX,
PERCENTAGE,
PRECIPITATION_INCHES,
PRECIPITATION_INCHES_PER_HOUR,
PRESSURE_INHG,
SPEED_MILES_PER_HOUR,
TEMP_FAHRENHEIT,
)
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady
@@ -41,266 +20,43 @@ from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity import Entity, EntityDescription
from homeassistant.helpers.event import async_call_later
from .const import (
ATTR_LAST_DATA,
ATTR_MONITORED_CONDITIONS,
CONF_APP_KEY,
DATA_CLIENT,
DOMAIN,
LOGGER,
TYPE_SOLARRADIATION,
TYPE_SOLARRADIATION_LX,
)
PLATFORMS = [BINARY_SENSOR, SENSOR]
PLATFORMS = ["binary_sensor", "sensor"]
DATA_CONFIG = "config"
DEFAULT_SOCKET_MIN_RETRY = 15
TYPE_24HOURRAININ = "24hourrainin"
TYPE_BAROMABSIN = "baromabsin"
TYPE_BAROMRELIN = "baromrelin"
TYPE_BATT1 = "batt1"
TYPE_BATT10 = "batt10"
TYPE_BATT2 = "batt2"
TYPE_BATT3 = "batt3"
TYPE_BATT4 = "batt4"
TYPE_BATT5 = "batt5"
TYPE_BATT6 = "batt6"
TYPE_BATT7 = "batt7"
TYPE_BATT8 = "batt8"
TYPE_BATT9 = "batt9"
TYPE_BATT_CO2 = "batt_co2"
TYPE_BATTOUT = "battout"
TYPE_CO2 = "co2"
TYPE_DAILYRAININ = "dailyrainin"
TYPE_DEWPOINT = "dewPoint"
TYPE_EVENTRAININ = "eventrainin"
TYPE_FEELSLIKE = "feelsLike"
TYPE_HOURLYRAININ = "hourlyrainin"
TYPE_HUMIDITY = "humidity"
TYPE_HUMIDITY1 = "humidity1"
TYPE_HUMIDITY10 = "humidity10"
TYPE_HUMIDITY2 = "humidity2"
TYPE_HUMIDITY3 = "humidity3"
TYPE_HUMIDITY4 = "humidity4"
TYPE_HUMIDITY5 = "humidity5"
TYPE_HUMIDITY6 = "humidity6"
TYPE_HUMIDITY7 = "humidity7"
TYPE_HUMIDITY8 = "humidity8"
TYPE_HUMIDITY9 = "humidity9"
TYPE_HUMIDITYIN = "humidityin"
TYPE_LASTRAIN = "lastRain"
TYPE_MAXDAILYGUST = "maxdailygust"
TYPE_MONTHLYRAININ = "monthlyrainin"
TYPE_PM25 = "pm25"
TYPE_PM25_24H = "pm25_24h"
TYPE_PM25_BATT = "batt_25"
TYPE_PM25_IN = "pm25_in"
TYPE_PM25_IN_24H = "pm25_in_24h"
TYPE_PM25IN_BATT = "batt_25in"
TYPE_RELAY1 = "relay1"
TYPE_RELAY10 = "relay10"
TYPE_RELAY2 = "relay2"
TYPE_RELAY3 = "relay3"
TYPE_RELAY4 = "relay4"
TYPE_RELAY5 = "relay5"
TYPE_RELAY6 = "relay6"
TYPE_RELAY7 = "relay7"
TYPE_RELAY8 = "relay8"
TYPE_RELAY9 = "relay9"
TYPE_SOILHUM1 = "soilhum1"
TYPE_SOILHUM10 = "soilhum10"
TYPE_SOILHUM2 = "soilhum2"
TYPE_SOILHUM3 = "soilhum3"
TYPE_SOILHUM4 = "soilhum4"
TYPE_SOILHUM5 = "soilhum5"
TYPE_SOILHUM6 = "soilhum6"
TYPE_SOILHUM7 = "soilhum7"
TYPE_SOILHUM8 = "soilhum8"
TYPE_SOILHUM9 = "soilhum9"
TYPE_SOILTEMP1F = "soiltemp1f"
TYPE_SOILTEMP10F = "soiltemp10f"
TYPE_SOILTEMP2F = "soiltemp2f"
TYPE_SOILTEMP3F = "soiltemp3f"
TYPE_SOILTEMP4F = "soiltemp4f"
TYPE_SOILTEMP5F = "soiltemp5f"
TYPE_SOILTEMP6F = "soiltemp6f"
TYPE_SOILTEMP7F = "soiltemp7f"
TYPE_SOILTEMP8F = "soiltemp8f"
TYPE_SOILTEMP9F = "soiltemp9f"
TYPE_SOLARRADIATION = "solarradiation"
TYPE_SOLARRADIATION_LX = "solarradiation_lx"
TYPE_TEMP10F = "temp10f"
TYPE_TEMP1F = "temp1f"
TYPE_TEMP2F = "temp2f"
TYPE_TEMP3F = "temp3f"
TYPE_TEMP4F = "temp4f"
TYPE_TEMP5F = "temp5f"
TYPE_TEMP6F = "temp6f"
TYPE_TEMP7F = "temp7f"
TYPE_TEMP8F = "temp8f"
TYPE_TEMP9F = "temp9f"
TYPE_TEMPF = "tempf"
TYPE_TEMPINF = "tempinf"
TYPE_TOTALRAININ = "totalrainin"
TYPE_UV = "uv"
TYPE_WEEKLYRAININ = "weeklyrainin"
TYPE_WINDDIR = "winddir"
TYPE_WINDDIR_AVG10M = "winddir_avg10m"
TYPE_WINDDIR_AVG2M = "winddir_avg2m"
TYPE_WINDGUSTDIR = "windgustdir"
TYPE_WINDGUSTMPH = "windgustmph"
TYPE_WINDSPDMPH_AVG10M = "windspdmph_avg10m"
TYPE_WINDSPDMPH_AVG2M = "windspdmph_avg2m"
TYPE_WINDSPEEDMPH = "windspeedmph"
TYPE_YEARLYRAININ = "yearlyrainin"
SENSOR_TYPES = {
TYPE_24HOURRAININ: ("24 Hr Rain", PRECIPITATION_INCHES, SENSOR, None),
TYPE_BAROMABSIN: ("Abs Pressure", PRESSURE_INHG, SENSOR, DEVICE_CLASS_PRESSURE),
TYPE_BAROMRELIN: ("Rel Pressure", PRESSURE_INHG, SENSOR, DEVICE_CLASS_PRESSURE),
TYPE_BATT10: ("Battery 10", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT1: ("Battery 1", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT2: ("Battery 2", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT3: ("Battery 3", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT4: ("Battery 4", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT5: ("Battery 5", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT6: ("Battery 6", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT7: ("Battery 7", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT8: ("Battery 8", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT9: ("Battery 9", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATTOUT: ("Battery", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_BATT_CO2: ("CO2 Battery", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_CO2: ("co2", CONCENTRATION_PARTS_PER_MILLION, SENSOR, DEVICE_CLASS_CO2),
TYPE_DAILYRAININ: ("Daily Rain", PRECIPITATION_INCHES, SENSOR, None),
TYPE_DEWPOINT: ("Dew Point", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_EVENTRAININ: ("Event Rain", PRECIPITATION_INCHES, SENSOR, None),
TYPE_FEELSLIKE: ("Feels Like", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_HOURLYRAININ: (
"Hourly Rain Rate",
PRECIPITATION_INCHES_PER_HOUR,
SENSOR,
None,
),
TYPE_HUMIDITY10: ("Humidity 10", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY1: ("Humidity 1", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY2: ("Humidity 2", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY3: ("Humidity 3", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY4: ("Humidity 4", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY5: ("Humidity 5", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY6: ("Humidity 6", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY7: ("Humidity 7", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY8: ("Humidity 8", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY9: ("Humidity 9", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITY: ("Humidity", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_HUMIDITYIN: ("Humidity In", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_LASTRAIN: ("Last Rain", None, SENSOR, DEVICE_CLASS_TIMESTAMP),
TYPE_MAXDAILYGUST: ("Max Gust", SPEED_MILES_PER_HOUR, SENSOR, None),
TYPE_MONTHLYRAININ: ("Monthly Rain", PRECIPITATION_INCHES, SENSOR, None),
TYPE_PM25_24H: (
"PM25 24h Avg",
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
SENSOR,
None,
),
TYPE_PM25_BATT: ("PM25 Battery", None, BINARY_SENSOR, DEVICE_CLASS_BATTERY),
TYPE_PM25_IN: (
"PM25 Indoor",
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
SENSOR,
None,
),
TYPE_PM25_IN_24H: (
"PM25 Indoor 24h Avg",
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
SENSOR,
None,
),
TYPE_PM25: ("PM25", CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, SENSOR, None),
TYPE_PM25IN_BATT: (
"PM25 Indoor Battery",
None,
BINARY_SENSOR,
DEVICE_CLASS_BATTERY,
),
TYPE_RELAY10: ("Relay 10", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_RELAY1: ("Relay 1", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_RELAY2: ("Relay 2", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_RELAY3: ("Relay 3", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_RELAY4: ("Relay 4", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_RELAY5: ("Relay 5", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_RELAY6: ("Relay 6", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_RELAY7: ("Relay 7", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_RELAY8: ("Relay 8", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_RELAY9: ("Relay 9", None, BINARY_SENSOR, DEVICE_CLASS_CONNECTIVITY),
TYPE_SOILHUM10: ("Soil Humidity 10", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILHUM1: ("Soil Humidity 1", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILHUM2: ("Soil Humidity 2", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILHUM3: ("Soil Humidity 3", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILHUM4: ("Soil Humidity 4", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILHUM5: ("Soil Humidity 5", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILHUM6: ("Soil Humidity 6", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILHUM7: ("Soil Humidity 7", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILHUM8: ("Soil Humidity 8", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILHUM9: ("Soil Humidity 9", PERCENTAGE, SENSOR, DEVICE_CLASS_HUMIDITY),
TYPE_SOILTEMP10F: (
"Soil Temp 10",
TEMP_FAHRENHEIT,
SENSOR,
DEVICE_CLASS_TEMPERATURE,
),
TYPE_SOILTEMP1F: ("Soil Temp 1", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_SOILTEMP2F: ("Soil Temp 2", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_SOILTEMP3F: ("Soil Temp 3", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_SOILTEMP4F: ("Soil Temp 4", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_SOILTEMP5F: ("Soil Temp 5", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_SOILTEMP6F: ("Soil Temp 6", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_SOILTEMP7F: ("Soil Temp 7", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_SOILTEMP8F: ("Soil Temp 8", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_SOILTEMP9F: ("Soil Temp 9", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_SOLARRADIATION: (
"Solar Rad",
IRRADIATION_WATTS_PER_SQUARE_METER,
SENSOR,
None,
),
TYPE_SOLARRADIATION_LX: (
"Solar Rad (lx)",
LIGHT_LUX,
SENSOR,
DEVICE_CLASS_ILLUMINANCE,
),
TYPE_TEMP10F: ("Temp 10", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMP1F: ("Temp 1", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMP2F: ("Temp 2", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMP3F: ("Temp 3", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMP4F: ("Temp 4", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMP5F: ("Temp 5", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMP6F: ("Temp 6", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMP7F: ("Temp 7", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMP8F: ("Temp 8", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMP9F: ("Temp 9", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMPF: ("Temp", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TEMPINF: ("Inside Temp", TEMP_FAHRENHEIT, SENSOR, DEVICE_CLASS_TEMPERATURE),
TYPE_TOTALRAININ: ("Lifetime Rain", PRECIPITATION_INCHES, SENSOR, None),
TYPE_UV: ("uv", "Index", SENSOR, None),
TYPE_WEEKLYRAININ: ("Weekly Rain", PRECIPITATION_INCHES, SENSOR, None),
TYPE_WINDDIR: ("Wind Dir", DEGREE, SENSOR, None),
TYPE_WINDDIR_AVG10M: ("Wind Dir Avg 10m", DEGREE, SENSOR, None),
TYPE_WINDDIR_AVG2M: ("Wind Dir Avg 2m", SPEED_MILES_PER_HOUR, SENSOR, None),
TYPE_WINDGUSTDIR: ("Gust Dir", DEGREE, SENSOR, None),
TYPE_WINDGUSTMPH: ("Wind Gust", SPEED_MILES_PER_HOUR, SENSOR, None),
TYPE_WINDSPDMPH_AVG10M: ("Wind Avg 10m", SPEED_MILES_PER_HOUR, SENSOR, None),
TYPE_WINDSPDMPH_AVG2M: ("Wind Avg 2m", SPEED_MILES_PER_HOUR, SENSOR, None),
TYPE_WINDSPEEDMPH: ("Wind Speed", SPEED_MILES_PER_HOUR, SENSOR, None),
TYPE_YEARLYRAININ: ("Yearly Rain", PRECIPITATION_INCHES, SENSOR, None),
}
CONFIG_SCHEMA = cv.deprecated(DOMAIN)
@callback
def async_wm2_to_lx(value: float) -> int:
"""Calculate illuminance (in lux)."""
return round(value / 0.0079)
@callback
def async_hydrate_station_data(data: dict[str, Any]) -> dict[str, Any]:
"""Hydrate station data with addition or normalized data."""
if (irradiation := data.get(TYPE_SOLARRADIATION)) is not None:
data[TYPE_SOLARRADIATION_LX] = async_wm2_to_lx(irradiation)
return data
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Set up the Ambient PWS as config entry."""
hass.data.setdefault(DOMAIN, {DATA_CLIENT: {}})
@@ -319,6 +75,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
config_entry.data[CONF_API_KEY],
config_entry.data[CONF_APP_KEY],
session=session,
logger=LOGGER,
),
)
hass.loop.create_task(ambient.ws_connect())
@@ -405,13 +162,14 @@ class AmbientStation:
def on_data(data: dict) -> None:
"""Define a handler to fire when the data is received."""
mac_address = data["macAddress"]
if data != self.stations[mac_address][ATTR_LAST_DATA]:
LOGGER.debug("New data received: %s", data)
self.stations[mac_address][ATTR_LAST_DATA] = data
async_dispatcher_send(
self._hass, f"ambient_station_data_update_{mac_address}"
)
mac = data["macAddress"]
if data == self.stations[mac][ATTR_LAST_DATA]:
return
LOGGER.debug("New data received: %s", data)
self.stations[mac][ATTR_LAST_DATA] = async_hydrate_station_data(data)
async_dispatcher_send(self._hass, f"ambient_station_data_update_{mac}")
def on_disconnect() -> None:
"""Define a handler to fire when the websocket is disconnected."""
@@ -420,26 +178,17 @@ class AmbientStation:
def on_subscribed(data: dict) -> None:
"""Define a handler to fire when the subscription is set."""
for station in data["devices"]:
if station["macAddress"] in self.stations:
if (mac := station["macAddress"]) in self.stations:
continue
LOGGER.debug("New station subscription: %s", data)
# Only create entities based on the data coming through the socket.
# If the user is monitoring brightness (in W/m^2), make sure we also
# add a calculated sensor for the same data measured in lx:
monitored_conditions = [
k for k in station["lastData"] if k in SENSOR_TYPES
]
if TYPE_SOLARRADIATION in monitored_conditions:
monitored_conditions.append(TYPE_SOLARRADIATION_LX)
self.stations[station["macAddress"]] = {
ATTR_LAST_DATA: station["lastData"],
self.stations[mac] = {
ATTR_LAST_DATA: async_hydrate_station_data(station["lastData"]),
ATTR_LOCATION: station.get("info", {}).get("location"),
ATTR_MONITORED_CONDITIONS: monitored_conditions,
ATTR_NAME: station.get("info", {}).get(
"name", station["macAddress"]
),
ATTR_NAME: station.get("info", {}).get("name", mac),
}
# If the websocket disconnects and reconnects, the on_subscribed
# handler will get called again; in that case, we don't want to
# attempt forward setup of the config entry (because it will have
@@ -466,28 +215,26 @@ class AmbientStation:
class AmbientWeatherEntity(Entity):
"""Define a base Ambient PWS entity."""
_attr_should_poll = False
def __init__(
self,
ambient: AmbientStation,
mac_address: str,
station_name: str,
sensor_type: str,
sensor_name: str,
device_class: str | None,
description: EntityDescription,
) -> None:
"""Initialize the sensor."""
"""Initialize the entity."""
self._ambient = ambient
self._attr_device_class = device_class
self._attr_device_info = {
"identifiers": {(DOMAIN, mac_address)},
"name": station_name,
"manufacturer": "Ambient Weather",
}
self._attr_name = f"{station_name}_{sensor_name}"
self._attr_should_poll = False
self._attr_unique_id = f"{mac_address}_{sensor_type}"
self._attr_name = f"{station_name}_{description.name}"
self._attr_unique_id = f"{mac_address}_{description.key}"
self._mac_address = mac_address
self._sensor_type = sensor_type
self.entity_description = description
async def async_added_to_hass(self) -> None:
"""Register callbacks."""
@@ -495,18 +242,18 @@ class AmbientWeatherEntity(Entity):
@callback
def update() -> None:
"""Update the state."""
if self._sensor_type == TYPE_SOLARRADIATION_LX:
if self.entity_description.key == TYPE_SOLARRADIATION_LX:
self._attr_available = (
self._ambient.stations[self._mac_address][ATTR_LAST_DATA].get(
self._ambient.stations[self._mac_address][ATTR_LAST_DATA][
TYPE_SOLARRADIATION
)
]
is not None
)
else:
self._attr_available = (
self._ambient.stations[self._mac_address][ATTR_LAST_DATA].get(
self._sensor_type
)
self._ambient.stations[self._mac_address][ATTR_LAST_DATA][
self.entity_description.key
]
is not None
)
@@ -1,34 +1,209 @@
"""Support for Ambient Weather Station binary sensors."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Literal
from homeassistant.components.binary_sensor import (
DOMAIN as BINARY_SENSOR,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_CONNECTIVITY,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_NAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import (
SENSOR_TYPES,
TYPE_BATT1,
TYPE_BATT2,
TYPE_BATT3,
TYPE_BATT4,
TYPE_BATT5,
TYPE_BATT6,
TYPE_BATT7,
TYPE_BATT8,
TYPE_BATT9,
TYPE_BATT10,
TYPE_BATT_CO2,
TYPE_BATTOUT,
TYPE_PM25_BATT,
TYPE_PM25IN_BATT,
AmbientWeatherEntity,
from . import AmbientWeatherEntity
from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN
TYPE_BATT1 = "batt1"
TYPE_BATT10 = "batt10"
TYPE_BATT2 = "batt2"
TYPE_BATT3 = "batt3"
TYPE_BATT4 = "batt4"
TYPE_BATT5 = "batt5"
TYPE_BATT6 = "batt6"
TYPE_BATT7 = "batt7"
TYPE_BATT8 = "batt8"
TYPE_BATT9 = "batt9"
TYPE_BATT_CO2 = "batt_co2"
TYPE_BATTOUT = "battout"
TYPE_PM25_BATT = "batt_25"
TYPE_PM25IN_BATT = "batt_25in"
TYPE_RELAY1 = "relay1"
TYPE_RELAY10 = "relay10"
TYPE_RELAY2 = "relay2"
TYPE_RELAY3 = "relay3"
TYPE_RELAY4 = "relay4"
TYPE_RELAY5 = "relay5"
TYPE_RELAY6 = "relay6"
TYPE_RELAY7 = "relay7"
TYPE_RELAY8 = "relay8"
TYPE_RELAY9 = "relay9"
@dataclass
class AmbientBinarySensorDescriptionMixin:
"""Define an entity description mixin for binary sensors."""
on_state: Literal[0, 1]
@dataclass
class AmbientBinarySensorDescription(
BinarySensorEntityDescription, AmbientBinarySensorDescriptionMixin
):
"""Describe an Ambient PWS binary sensor."""
BINARY_SENSOR_DESCRIPTIONS = (
AmbientBinarySensorDescription(
key=TYPE_BATTOUT,
name="Battery",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT1,
name="Battery 1",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT2,
name="Battery 2",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT3,
name="Battery 3",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT4,
name="Battery 4",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT5,
name="Battery 5",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT6,
name="Battery 6",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT7,
name="Battery 7",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT8,
name="Battery 8",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT9,
name="Battery 9",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT10,
name="Battery 10",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_BATT_CO2,
name="CO2 Battery",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_PM25IN_BATT,
name="PM25 Indoor Battery",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_PM25_BATT,
name="PM25 Battery",
device_class=DEVICE_CLASS_BATTERY,
on_state=0,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY1,
name="Relay 1",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY2,
name="Relay 2",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY3,
name="Relay 3",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY4,
name="Relay 4",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY5,
name="Relay 5",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY6,
name="Relay 6",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY7,
name="Relay 7",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY8,
name="Relay 8",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY9,
name="Relay 9",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
AmbientBinarySensorDescription(
key=TYPE_RELAY10,
name="Relay 10",
device_class=DEVICE_CLASS_CONNECTIVITY,
on_state=1,
),
)
from .const import ATTR_LAST_DATA, ATTR_MONITORED_CONDITIONS, DATA_CLIENT, DOMAIN
async def async_setup_entry(
@@ -37,51 +212,29 @@ async def async_setup_entry(
"""Set up Ambient PWS binary sensors based on a config entry."""
ambient = hass.data[DOMAIN][DATA_CLIENT][entry.entry_id]
binary_sensor_list = []
for mac_address, station in ambient.stations.items():
for condition in station[ATTR_MONITORED_CONDITIONS]:
name, _, kind, device_class = SENSOR_TYPES[condition]
if kind == BINARY_SENSOR:
binary_sensor_list.append(
AmbientWeatherBinarySensor(
ambient,
mac_address,
station[ATTR_NAME],
condition,
name,
device_class,
)
)
async_add_entities(binary_sensor_list)
async_add_entities(
[
AmbientWeatherBinarySensor(
ambient, mac_address, station[ATTR_NAME], description
)
for mac_address, station in ambient.stations.items()
for description in BINARY_SENSOR_DESCRIPTIONS
if description.key in station[ATTR_LAST_DATA]
]
)
class AmbientWeatherBinarySensor(AmbientWeatherEntity, BinarySensorEntity):
"""Define an Ambient binary sensor."""
entity_description: AmbientBinarySensorDescription
@callback
def update_from_latest_data(self) -> None:
"""Fetch new state data for the entity."""
state = self._ambient.stations[self._mac_address][ATTR_LAST_DATA].get(
self._sensor_type
self._attr_is_on = (
self._ambient.stations[self._mac_address][ATTR_LAST_DATA][
self.entity_description.key
]
== self.entity_description.on_state
)
if self._sensor_type in (
TYPE_BATT1,
TYPE_BATT10,
TYPE_BATT2,
TYPE_BATT3,
TYPE_BATT4,
TYPE_BATT5,
TYPE_BATT6,
TYPE_BATT7,
TYPE_BATT8,
TYPE_BATT9,
TYPE_BATT_CO2,
TYPE_BATTOUT,
TYPE_PM25_BATT,
TYPE_PM25IN_BATT,
):
self._attr_is_on = state == 0
else:
self._attr_is_on = state == 1
@@ -5,8 +5,10 @@ DOMAIN = "ambient_station"
LOGGER = logging.getLogger(__package__)
ATTR_LAST_DATA = "last_data"
ATTR_MONITORED_CONDITIONS = "monitored_conditions"
CONF_APP_KEY = "app_key"
DATA_CLIENT = "data_client"
TYPE_SOLARRADIATION = "solarradiation"
TYPE_SOLARRADIATION_LX = "solarradiation_lx"
@@ -3,7 +3,7 @@
"name": "Ambient Weather Station",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/ambient_station",
"requirements": ["aioambient==1.2.6"],
"requirements": ["aioambient==1.3.0"],
"codeowners": ["@bachya"],
"iot_class": "cloud_push"
}
@@ -1,20 +1,608 @@
"""Support for Ambient Weather Station sensors."""
from __future__ import annotations
from homeassistant.components.sensor import DOMAIN as SENSOR, SensorEntity
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_NAME
from homeassistant.const import (
ATTR_NAME,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_MILLION,
DEGREE,
DEVICE_CLASS_CO2,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_ILLUMINANCE,
DEVICE_CLASS_PM25,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_TIMESTAMP,
IRRADIATION_WATTS_PER_SQUARE_METER,
LIGHT_LUX,
PERCENTAGE,
PRECIPITATION_INCHES,
PRECIPITATION_INCHES_PER_HOUR,
PRESSURE_INHG,
SPEED_MILES_PER_HOUR,
TEMP_FAHRENHEIT,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import (
SENSOR_TYPES,
TYPE_SOLARRADIATION,
TYPE_SOLARRADIATION_LX,
AmbientStation,
AmbientWeatherEntity,
)
from .const import ATTR_LAST_DATA, ATTR_MONITORED_CONDITIONS, DATA_CLIENT, DOMAIN
from .const import ATTR_LAST_DATA, DATA_CLIENT, DOMAIN
TYPE_24HOURRAININ = "24hourrainin"
TYPE_BAROMABSIN = "baromabsin"
TYPE_BAROMRELIN = "baromrelin"
TYPE_CO2 = "co2"
TYPE_DAILYRAININ = "dailyrainin"
TYPE_DEWPOINT = "dewPoint"
TYPE_EVENTRAININ = "eventrainin"
TYPE_FEELSLIKE = "feelsLike"
TYPE_HOURLYRAININ = "hourlyrainin"
TYPE_HUMIDITY = "humidity"
TYPE_HUMIDITY1 = "humidity1"
TYPE_HUMIDITY10 = "humidity10"
TYPE_HUMIDITY2 = "humidity2"
TYPE_HUMIDITY3 = "humidity3"
TYPE_HUMIDITY4 = "humidity4"
TYPE_HUMIDITY5 = "humidity5"
TYPE_HUMIDITY6 = "humidity6"
TYPE_HUMIDITY7 = "humidity7"
TYPE_HUMIDITY8 = "humidity8"
TYPE_HUMIDITY9 = "humidity9"
TYPE_HUMIDITYIN = "humidityin"
TYPE_LASTRAIN = "lastRain"
TYPE_MAXDAILYGUST = "maxdailygust"
TYPE_MONTHLYRAININ = "monthlyrainin"
TYPE_PM25 = "pm25"
TYPE_PM25_24H = "pm25_24h"
TYPE_PM25_IN = "pm25_in"
TYPE_PM25_IN_24H = "pm25_in_24h"
TYPE_SOILHUM1 = "soilhum1"
TYPE_SOILHUM10 = "soilhum10"
TYPE_SOILHUM2 = "soilhum2"
TYPE_SOILHUM3 = "soilhum3"
TYPE_SOILHUM4 = "soilhum4"
TYPE_SOILHUM5 = "soilhum5"
TYPE_SOILHUM6 = "soilhum6"
TYPE_SOILHUM7 = "soilhum7"
TYPE_SOILHUM8 = "soilhum8"
TYPE_SOILHUM9 = "soilhum9"
TYPE_SOILTEMP1F = "soiltemp1f"
TYPE_SOILTEMP10F = "soiltemp10f"
TYPE_SOILTEMP2F = "soiltemp2f"
TYPE_SOILTEMP3F = "soiltemp3f"
TYPE_SOILTEMP4F = "soiltemp4f"
TYPE_SOILTEMP5F = "soiltemp5f"
TYPE_SOILTEMP6F = "soiltemp6f"
TYPE_SOILTEMP7F = "soiltemp7f"
TYPE_SOILTEMP8F = "soiltemp8f"
TYPE_SOILTEMP9F = "soiltemp9f"
TYPE_TEMP10F = "temp10f"
TYPE_TEMP1F = "temp1f"
TYPE_TEMP2F = "temp2f"
TYPE_TEMP3F = "temp3f"
TYPE_TEMP4F = "temp4f"
TYPE_TEMP5F = "temp5f"
TYPE_TEMP6F = "temp6f"
TYPE_TEMP7F = "temp7f"
TYPE_TEMP8F = "temp8f"
TYPE_TEMP9F = "temp9f"
TYPE_TEMPF = "tempf"
TYPE_TEMPINF = "tempinf"
TYPE_TOTALRAININ = "totalrainin"
TYPE_UV = "uv"
TYPE_WEEKLYRAININ = "weeklyrainin"
TYPE_WINDDIR = "winddir"
TYPE_WINDDIR_AVG10M = "winddir_avg10m"
TYPE_WINDDIR_AVG2M = "winddir_avg2m"
TYPE_WINDGUSTDIR = "windgustdir"
TYPE_WINDGUSTMPH = "windgustmph"
TYPE_WINDSPDMPH_AVG10M = "windspdmph_avg10m"
TYPE_WINDSPDMPH_AVG2M = "windspdmph_avg2m"
TYPE_WINDSPEEDMPH = "windspeedmph"
TYPE_YEARLYRAININ = "yearlyrainin"
SENSOR_DESCRIPTIONS = (
SensorEntityDescription(
key=TYPE_24HOURRAININ,
name="24 Hr Rain",
icon="mdi:water",
native_unit_of_measurement=PRECIPITATION_INCHES,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
SensorEntityDescription(
key=TYPE_BAROMABSIN,
name="Abs Pressure",
native_unit_of_measurement=PRESSURE_INHG,
device_class=DEVICE_CLASS_PRESSURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_BAROMRELIN,
name="Rel Pressure",
native_unit_of_measurement=PRESSURE_INHG,
device_class=DEVICE_CLASS_PRESSURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_CO2,
name="co2",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
device_class=DEVICE_CLASS_CO2,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_DAILYRAININ,
name="Daily Rain",
icon="mdi:water",
native_unit_of_measurement=PRECIPITATION_INCHES,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
SensorEntityDescription(
key=TYPE_DEWPOINT,
name="Dew Point",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_EVENTRAININ,
name="Event Rain",
icon="mdi:water",
native_unit_of_measurement=PRECIPITATION_INCHES,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_FEELSLIKE,
name="Feels Like",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_HOURLYRAININ,
name="Hourly Rain Rate",
icon="mdi:water",
native_unit_of_measurement=PRECIPITATION_INCHES_PER_HOUR,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
SensorEntityDescription(
key=TYPE_HUMIDITY10,
name="Humidity 10",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY1,
name="Humidity 1",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY2,
name="Humidity 2",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY3,
name="Humidity 3",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY4,
name="Humidity 4",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY5,
name="Humidity 5",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY6,
name="Humidity 6",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY7,
name="Humidity 7",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY8,
name="Humidity 8",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY9,
name="Humidity 9",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITY,
name="Humidity",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_HUMIDITYIN,
name="Humidity In",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_LASTRAIN,
name="Last Rain",
icon="mdi:water",
device_class=DEVICE_CLASS_TIMESTAMP,
),
SensorEntityDescription(
key=TYPE_MAXDAILYGUST,
name="Max Gust",
icon="mdi:weather-windy",
native_unit_of_measurement=SPEED_MILES_PER_HOUR,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_MONTHLYRAININ,
name="Monthly Rain",
icon="mdi:water",
native_unit_of_measurement=PRECIPITATION_INCHES,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_PM25_24H,
name="PM25 24h Avg",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=DEVICE_CLASS_PM25,
),
SensorEntityDescription(
key=TYPE_PM25_IN,
name="PM25 Indoor",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=DEVICE_CLASS_PM25,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_PM25_IN_24H,
name="PM25 Indoor 24h Avg",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=DEVICE_CLASS_PM25,
),
SensorEntityDescription(
key=TYPE_PM25,
name="PM25",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=DEVICE_CLASS_PM25,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILHUM10,
name="Soil Humidity 10",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILHUM1,
name="Soil Humidity 1",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILHUM2,
name="Soil Humidity 2",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILHUM3,
name="Soil Humidity 3",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILHUM4,
name="Soil Humidity 4",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILHUM5,
name="Soil Humidity 5",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILHUM6,
name="Soil Humidity 6",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILHUM7,
name="Soil Humidity 7",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILHUM8,
name="Soil Humidity 8",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILHUM9,
name="Soil Humidity 9",
native_unit_of_measurement=PERCENTAGE,
device_class=DEVICE_CLASS_HUMIDITY,
),
SensorEntityDescription(
key=TYPE_SOILTEMP10F,
name="Soil Temp 10",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILTEMP1F,
name="Soil Temp 1",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILTEMP2F,
name="Soil Temp 2",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILTEMP3F,
name="Soil Temp 3",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILTEMP4F,
name="Soil Temp 4",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILTEMP5F,
name="Soil Temp 5",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILTEMP6F,
name="Soil Temp 6",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILTEMP7F,
name="Soil Temp 7",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILTEMP8F,
name="Soil Temp 8",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOILTEMP9F,
name="Soil Temp 9",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOLARRADIATION,
name="Solar Rad",
native_unit_of_measurement=IRRADIATION_WATTS_PER_SQUARE_METER,
device_class=DEVICE_CLASS_ILLUMINANCE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_SOLARRADIATION_LX,
name="Solar Rad",
native_unit_of_measurement=LIGHT_LUX,
device_class=DEVICE_CLASS_ILLUMINANCE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP10F,
name="Temp 10",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP1F,
name="Temp 1",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP2F,
name="Temp 2",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP3F,
name="Temp 3",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP4F,
name="Temp 4",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP5F,
name="Temp 5",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP6F,
name="Temp 6",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP7F,
name="Temp 7",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP8F,
name="Temp 8",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMP9F,
name="Temp 9",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMPF,
name="Temp",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TEMPINF,
name="Inside Temp",
native_unit_of_measurement=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_TOTALRAININ,
name="Lifetime Rain",
icon="mdi:water",
native_unit_of_measurement=PRECIPITATION_INCHES,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_UV,
name="UV Index",
native_unit_of_measurement="Index",
device_class=DEVICE_CLASS_ILLUMINANCE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_WEEKLYRAININ,
name="Weekly Rain",
icon="mdi:water",
native_unit_of_measurement=PRECIPITATION_INCHES,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_WINDDIR,
name="Wind Dir",
icon="mdi:weather-windy",
native_unit_of_measurement=DEGREE,
),
SensorEntityDescription(
key=TYPE_WINDDIR_AVG10M,
name="Wind Dir Avg 10m",
icon="mdi:weather-windy",
native_unit_of_measurement=DEGREE,
),
SensorEntityDescription(
key=TYPE_WINDDIR_AVG2M,
name="Wind Dir Avg 2m",
icon="mdi:weather-windy",
native_unit_of_measurement=DEGREE,
),
SensorEntityDescription(
key=TYPE_WINDGUSTDIR,
name="Gust Dir",
icon="mdi:weather-windy",
native_unit_of_measurement=DEGREE,
),
SensorEntityDescription(
key=TYPE_WINDGUSTMPH,
name="Wind Gust",
icon="mdi:weather-windy",
native_unit_of_measurement=SPEED_MILES_PER_HOUR,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_WINDSPDMPH_AVG10M,
name="Wind Avg 10m",
icon="mdi:weather-windy",
native_unit_of_measurement=SPEED_MILES_PER_HOUR,
),
SensorEntityDescription(
key=TYPE_WINDSPDMPH_AVG2M,
name="Wind Avg 2m",
icon="mdi:weather-windy",
native_unit_of_measurement=SPEED_MILES_PER_HOUR,
),
SensorEntityDescription(
key=TYPE_WINDSPEEDMPH,
name="Wind Speed",
icon="mdi:weather-windy",
native_unit_of_measurement=SPEED_MILES_PER_HOUR,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key=TYPE_YEARLYRAININ,
name="Yearly Rain",
icon="mdi:water",
native_unit_of_measurement=PRECIPITATION_INCHES,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
)
async def async_setup_entry(
@@ -23,24 +611,14 @@ async def async_setup_entry(
"""Set up Ambient PWS sensors based on a config entry."""
ambient = hass.data[DOMAIN][DATA_CLIENT][entry.entry_id]
sensor_list = []
for mac_address, station in ambient.stations.items():
for condition in station[ATTR_MONITORED_CONDITIONS]:
name, unit, kind, device_class = SENSOR_TYPES[condition]
if kind == SENSOR:
sensor_list.append(
AmbientWeatherSensor(
ambient,
mac_address,
station[ATTR_NAME],
condition,
name,
device_class,
unit,
)
)
async_add_entities(sensor_list)
async_add_entities(
[
AmbientWeatherSensor(ambient, mac_address, station[ATTR_NAME], description)
for mac_address, station in ambient.stations.items()
for description in SENSOR_DESCRIPTIONS
if description.key in station[ATTR_LAST_DATA]
]
)
class AmbientWeatherSensor(AmbientWeatherEntity, SensorEntity):
@@ -51,34 +629,20 @@ class AmbientWeatherSensor(AmbientWeatherEntity, SensorEntity):
ambient: AmbientStation,
mac_address: str,
station_name: str,
sensor_type: str,
sensor_name: str,
device_class: str | None,
unit: str | None,
description: EntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(
ambient, mac_address, station_name, sensor_type, sensor_name, device_class
)
super().__init__(ambient, mac_address, station_name, description)
self._attr_native_unit_of_measurement = unit
if description.key == TYPE_SOLARRADIATION_LX:
# Since TYPE_SOLARRADIATION and TYPE_SOLARRADIATION_LX will have the same
# name in the UI, we influence the entity ID of TYPE_SOLARRADIATION_LX here
# to differentiate them:
self.entity_id = f"sensor.{station_name}_solar_rad_lx"
@callback
def update_from_latest_data(self) -> None:
"""Fetch new state data for the sensor."""
if self._sensor_type == TYPE_SOLARRADIATION_LX:
# If the user requests the solarradiation_lx sensor, use the
# value of the solarradiation sensor and apply a very accurate
# approximation of converting sunlight W/m^2 to lx:
w_m2_brightness_val = self._ambient.stations[self._mac_address][
ATTR_LAST_DATA
].get(TYPE_SOLARRADIATION)
if w_m2_brightness_val is None:
self._attr_native_value = None
else:
self._attr_native_value = round(float(w_m2_brightness_val) / 0.0079)
else:
self._attr_native_value = self._ambient.stations[self._mac_address][
ATTR_LAST_DATA
].get(self._sensor_type)
self._attr_native_value = self._ambient.stations[self._mac_address][
ATTR_LAST_DATA
][self.entity_description.key]
@@ -1,10 +1,10 @@
{
"config": {
"abort": {
"already_configured": "Cette cl\u00e9 d'application est d\u00e9j\u00e0 utilis\u00e9e."
"already_configured": "Le service est d\u00e9j\u00e0 configur\u00e9"
},
"error": {
"invalid_key": "Cl\u00e9 d'API et / ou cl\u00e9 d'application non valide",
"invalid_key": "Cl\u00e9 API invalide",
"no_devices": "Aucun appareil trouv\u00e9 dans le compte"
},
"step": {
+3 -1
View File
@@ -1,12 +1,13 @@
"""Support for Amcrest IP cameras."""
from __future__ import annotations
from collections.abc import Callable
from contextlib import suppress
from dataclasses import dataclass
from datetime import datetime, timedelta
import logging
import threading
from typing import Any, Callable
from typing import Any
import aiohttp
from amcrest import AmcrestError, ApiWrapper, LoginError
@@ -379,3 +380,4 @@ class AmcrestDevice:
stream_source: str
resolution: int
control_light: bool
channel: int = 0
@@ -1,11 +1,12 @@
"""Support for Amcrest IP camera binary sensors."""
from __future__ import annotations
from collections.abc import Callable
from contextlib import suppress
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import TYPE_CHECKING, Callable
from typing import TYPE_CHECKING
from amcrest import AmcrestError
import voluptuous as vol
@@ -111,6 +112,7 @@ BINARY_SENSORS: tuple[AmcrestSensorEntityDescription, ...] = (
key=_ONLINE_KEY,
name="Online",
device_class=DEVICE_CLASS_CONNECTIVITY,
should_poll=True,
),
)
BINARY_SENSOR_KEYS = [description.key for description in BINARY_SENSORS]
@@ -168,6 +170,7 @@ class AmcrestBinarySensor(BinarySensorEntity):
"""Initialize entity."""
self._signal_name = name
self._api = device.api
self._channel = device.channel
self.entity_description: AmcrestSensorEntityDescription = entity_description
self._attr_name = f"{name} {entity_description.name}"
@@ -191,12 +194,14 @@ class AmcrestBinarySensor(BinarySensorEntity):
if not (self._api.available or self.is_on):
return
_LOGGER.debug(_UPDATE_MSG, self.name)
if self._api.available:
# Send a command to the camera to test if we can still communicate with it.
# Override of Http.command() in __init__.py will set self._api.available
# accordingly.
with suppress(AmcrestError):
self._api.current_time # pylint: disable=pointless-statement
self._update_unique_id()
self._attr_is_on = self._api.available
def _update_others(self) -> None:
@@ -204,6 +209,12 @@ class AmcrestBinarySensor(BinarySensorEntity):
return
_LOGGER.debug(_UPDATE_MSG, self.name)
try:
self._update_unique_id()
except AmcrestError as error:
log_update_error(_LOGGER, "update", self.name, "binary sensor", error)
return
event_code = self.entity_description.event_code
if event_code is None:
_LOGGER.error("Binary sensor %s event code not set", self.name)
@@ -213,6 +224,16 @@ class AmcrestBinarySensor(BinarySensorEntity):
self._attr_is_on = len(self._api.event_channels_happened(event_code)) > 0
except AmcrestError as error:
log_update_error(_LOGGER, "update", self.name, "binary sensor", error)
return
def _update_unique_id(self) -> None:
"""Set the unique id."""
if self._attr_unique_id is None:
serial_number = self._api.serial_number
if serial_number:
self._attr_unique_id = (
f"{serial_number}-{self.entity_description.key}-{self._channel}"
)
async def async_on_demand_update(self) -> None:
"""Update state."""
@@ -232,8 +253,6 @@ class AmcrestBinarySensor(BinarySensorEntity):
async def async_added_to_hass(self) -> None:
"""Subscribe to signals."""
assert self.hass is not None
self._unsub_dispatcher.append(
async_dispatcher_connect(
self.hass,
+33 -25
View File
@@ -2,10 +2,11 @@
from __future__ import annotations
import asyncio
from collections.abc import Callable
from datetime import timedelta
from functools import partial
import logging
from typing import TYPE_CHECKING, Any, Callable
from typing import TYPE_CHECKING, Any
from aiohttp import web
from amcrest import AmcrestError
@@ -13,9 +14,11 @@ from haffmpeg.camera import CameraMjpeg
import voluptuous as vol
from homeassistant.components.camera import SUPPORT_ON_OFF, SUPPORT_STREAM, Camera
from homeassistant.components.camera.const import DOMAIN as CAMERA_DOMAIN
from homeassistant.components.ffmpeg import DATA_FFMPEG, FFmpegManager
from homeassistant.const import ATTR_ENTITY_ID, CONF_NAME, STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
from homeassistant.helpers.aiohttp_client import (
async_aiohttp_proxy_stream,
async_aiohttp_proxy_web,
@@ -32,6 +35,7 @@ from .const import (
COMM_TIMEOUT,
DATA_AMCREST,
DEVICES,
DOMAIN,
SERVICE_UPDATE,
SNAPSHOT_TIMEOUT,
)
@@ -132,7 +136,21 @@ async def async_setup_platform(
name = discovery_info[CONF_NAME]
device = hass.data[DATA_AMCREST][DEVICES][name]
async_add_entities([AmcrestCam(name, device, hass.data[DATA_FFMPEG])], True)
entity = AmcrestCam(name, device, hass.data[DATA_FFMPEG])
# 2021.9.0 introduced unique id's for the camera entity, but these were not
# unique for different resolution streams. If any cameras were configured
# with this version, update the old entity with the new unique id.
serial_number = await hass.async_add_executor_job(lambda: device.api.serial_number) # type: ignore[no-any-return]
serial_number = serial_number.strip()
registry = entity_registry.async_get(hass)
entity_id = registry.async_get_entity_id(CAMERA_DOMAIN, DOMAIN, serial_number)
if entity_id is not None:
_LOGGER.debug("Updating unique id for camera %s", entity_id)
new_unique_id = f"{serial_number}-{device.resolution}-{device.channel}"
registry.async_update_entity(entity_id, new_unique_id=new_unique_id)
async_add_entities([entity], True)
class CannotSnapshot(Exception):
@@ -155,6 +173,7 @@ class AmcrestCam(Camera):
self._ffmpeg_arguments = device.ffmpeg_arguments
self._stream_source = device.stream_source
self._resolution = device.resolution
self._channel = device.channel
self._token = self._auth = device.authentication
self._control_light = device.control_light
self._is_recording: bool = False
@@ -180,7 +199,6 @@ class AmcrestCam(Camera):
raise CannotSnapshot
async def _async_get_image(self) -> None:
assert self.hass is not None
try:
# Send the request to snap a picture and return raw jpg data
# Snapshot command needs a much longer read timeout than other commands.
@@ -201,7 +219,6 @@ class AmcrestCam(Camera):
self, width: int | None = None, height: int | None = None
) -> bytes | None:
"""Return a still image response from the camera."""
assert self.hass is not None
_LOGGER.debug("Take snapshot from %s", self._name)
try:
# Amcrest cameras only support one snapshot command at a time.
@@ -226,7 +243,6 @@ class AmcrestCam(Camera):
self, request: web.Request
) -> web.StreamResponse | None:
"""Return an MJPEG stream."""
assert self.hass is not None
# The snapshot implementation is handled by the parent class
if self._stream_source == "snapshot":
return await super().handle_async_mjpeg_stream(request)
@@ -344,7 +360,6 @@ class AmcrestCam(Camera):
async def async_added_to_hass(self) -> None:
"""Subscribe to signals and add camera to list."""
assert self.hass is not None
self._unsub_dispatcher.extend(
async_dispatcher_connect(
self.hass,
@@ -364,7 +379,6 @@ class AmcrestCam(Camera):
async def async_will_remove_from_hass(self) -> None:
"""Remove camera from list and disconnect from signals."""
assert self.hass is not None
self.hass.data[DATA_AMCREST][CAMERAS].remove(self.entity_id)
for unsub_dispatcher in self._unsub_dispatcher:
unsub_dispatcher()
@@ -379,20 +393,25 @@ class AmcrestCam(Camera):
try:
if self._brand is None:
resp = self._api.vendor_information.strip()
if resp.startswith("vendor="):
self._brand = resp.split("=")[-1]
_LOGGER.debug("Assigned brand=%s", resp)
if resp:
self._brand = resp
else:
self._brand = "unknown"
if self._model is None:
resp = self._api.device_type.strip()
_LOGGER.debug("Device_type=%s", resp)
if resp.startswith("type="):
self._model = resp.split("=")[-1]
_LOGGER.debug("Assigned model=%s", resp)
if resp:
self._model = resp
else:
self._model = "unknown"
if self._attr_unique_id is None:
self._attr_unique_id = self._api.serial_number.strip()
_LOGGER.debug("Assigned unique_id=%s", self._attr_unique_id)
serial_number = self._api.serial_number.strip()
if serial_number:
self._attr_unique_id = (
f"{serial_number}-{self._resolution}-{self._channel}"
)
_LOGGER.debug("Assigned unique_id=%s", self._attr_unique_id)
self.is_streaming = self._get_video()
self._is_recording = self._get_recording()
self._motion_detection_enabled = self._get_motion_detection()
@@ -428,57 +447,46 @@ class AmcrestCam(Camera):
async def async_enable_recording(self) -> None:
"""Call the job and enable recording."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._enable_recording, True)
async def async_disable_recording(self) -> None:
"""Call the job and disable recording."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._enable_recording, False)
async def async_enable_audio(self) -> None:
"""Call the job and enable audio."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._enable_audio, True)
async def async_disable_audio(self) -> None:
"""Call the job and disable audio."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._enable_audio, False)
async def async_enable_motion_recording(self) -> None:
"""Call the job and enable motion recording."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._enable_motion_recording, True)
async def async_disable_motion_recording(self) -> None:
"""Call the job and disable motion recording."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._enable_motion_recording, False)
async def async_goto_preset(self, preset: int) -> None:
"""Call the job and move camera to preset position."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._goto_preset, preset)
async def async_set_color_bw(self, color_bw: str) -> None:
"""Call the job and set camera color mode."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._set_color_bw, color_bw)
async def async_start_tour(self) -> None:
"""Call the job and start camera tour."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._start_tour, True)
async def async_stop_tour(self) -> None:
"""Call the job and stop camera tour."""
assert self.hass is not None
await self.hass.async_add_executor_job(self._start_tour, False)
async def async_ptz_control(self, movement: str, travel_time: float) -> None:
"""Move or zoom camera in specified direction."""
assert self.hass is not None
code = _ACTION[_MOV.index(movement)]
kwargs = {"code": code, "arg1": 0, "arg2": 0, "arg3": 0}
@@ -2,7 +2,7 @@
"domain": "amcrest",
"name": "Amcrest",
"documentation": "https://www.home-assistant.io/integrations/amcrest",
"requirements": ["amcrest==1.8.0"],
"requirements": ["amcrest==1.9.3"],
"dependencies": ["ffmpeg"],
"codeowners": ["@flacjacket"],
"iot_class": "local_polling"
+15 -2
View File
@@ -1,9 +1,10 @@
"""Support for Amcrest IP camera sensors."""
from __future__ import annotations
from collections.abc import Callable
from datetime import timedelta
import logging
from typing import TYPE_CHECKING, Callable
from typing import TYPE_CHECKING
from amcrest import AmcrestError
@@ -77,6 +78,7 @@ class AmcrestSensor(SensorEntity):
self.entity_description = description
self._signal_name = name
self._api = device.api
self._channel = device.channel
self._unsub_dispatcher: Callable[[], None] | None = None
self._attr_name = f"{name} {description.name}"
@@ -94,7 +96,19 @@ class AmcrestSensor(SensorEntity):
_LOGGER.debug("Updating %s sensor", self.name)
sensor_type = self.entity_description.key
if self._attr_unique_id is None:
serial_number = self._api.serial_number
if serial_number:
self._attr_unique_id = f"{serial_number}-{sensor_type}-{self._channel}"
try:
if self._attr_unique_id is None:
serial_number = self._api.serial_number
if serial_number:
self._attr_unique_id = (
f"{serial_number}-{sensor_type}-{self._channel}"
)
if sensor_type == SENSOR_PTZ_PRESET:
self._attr_native_value = self._api.ptz_presets_count
@@ -129,7 +143,6 @@ class AmcrestSensor(SensorEntity):
async def async_added_to_hass(self) -> None:
"""Subscribe to update signal."""
assert self.hass is not None
self._unsub_dispatcher = async_dispatcher_connect(
self.hass,
service_signal(SERVICE_UPDATE, self._signal_name),
@@ -358,6 +358,7 @@ def adb_decorator(override_available=False):
@functools.wraps(func)
async def _adb_exception_catcher(self, *args, **kwargs):
"""Call an ADB-related method and catch exceptions."""
# pylint: disable=protected-access
if not self.available and not override_available:
return None
+378 -95
View File
@@ -1,10 +1,16 @@
"""Support for APCUPSd sensors."""
from __future__ import annotations
import logging
from apcaccess.status import ALL_UNITS
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.const import (
CONF_RESOURCES,
DEVICE_CLASS_TEMPERATURE,
@@ -25,74 +31,360 @@ from . import DOMAIN
_LOGGER = logging.getLogger(__name__)
SENSOR_PREFIX = "UPS "
SENSOR_TYPES = {
"alarmdel": ["Alarm Delay", None, "mdi:alarm", None],
"ambtemp": ["Ambient Temperature", None, "mdi:thermometer", None],
"apc": ["Status Data", None, "mdi:information-outline", None],
"apcmodel": ["Model", None, "mdi:information-outline", None],
"badbatts": ["Bad Batteries", None, "mdi:information-outline", None],
"battdate": ["Battery Replaced", None, "mdi:calendar-clock", None],
"battstat": ["Battery Status", None, "mdi:information-outline", None],
"battv": ["Battery Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"bcharge": ["Battery", PERCENTAGE, "mdi:battery", None],
"cable": ["Cable Type", None, "mdi:ethernet-cable", None],
"cumonbatt": ["Total Time on Battery", None, "mdi:timer-outline", None],
"date": ["Status Date", None, "mdi:calendar-clock", None],
"dipsw": ["Dip Switch Settings", None, "mdi:information-outline", None],
"dlowbatt": ["Low Battery Signal", None, "mdi:clock-alert", None],
"driver": ["Driver", None, "mdi:information-outline", None],
"dshutd": ["Shutdown Delay", None, "mdi:timer-outline", None],
"dwake": ["Wake Delay", None, "mdi:timer-outline", None],
"endapc": ["Date and Time", None, "mdi:calendar-clock", None],
"extbatts": ["External Batteries", None, "mdi:information-outline", None],
"firmware": ["Firmware Version", None, "mdi:information-outline", None],
"hitrans": ["Transfer High", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"hostname": ["Hostname", None, "mdi:information-outline", None],
"humidity": ["Ambient Humidity", PERCENTAGE, "mdi:water-percent", None],
"itemp": ["Internal Temperature", TEMP_CELSIUS, None, DEVICE_CLASS_TEMPERATURE],
"lastxfer": ["Last Transfer", None, "mdi:transfer", None],
"linefail": ["Input Voltage Status", None, "mdi:information-outline", None],
"linefreq": ["Line Frequency", FREQUENCY_HERTZ, "mdi:information-outline", None],
"linev": ["Input Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"loadpct": ["Load", PERCENTAGE, "mdi:gauge", None],
"loadapnt": ["Load Apparent Power", PERCENTAGE, "mdi:gauge", None],
"lotrans": ["Transfer Low", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"mandate": ["Manufacture Date", None, "mdi:calendar", None],
"masterupd": ["Master Update", None, "mdi:information-outline", None],
"maxlinev": ["Input Voltage High", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"maxtime": ["Battery Timeout", None, "mdi:timer-off-outline", None],
"mbattchg": ["Battery Shutdown", PERCENTAGE, "mdi:battery-alert", None],
"minlinev": ["Input Voltage Low", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"mintimel": ["Shutdown Time", None, "mdi:timer-outline", None],
"model": ["Model", None, "mdi:information-outline", None],
"nombattv": ["Battery Nominal Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"nominv": ["Nominal Input Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"nomoutv": ["Nominal Output Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"nompower": ["Nominal Output Power", POWER_WATT, "mdi:flash", None],
"nomapnt": ["Nominal Apparent Power", POWER_VOLT_AMPERE, "mdi:flash", None],
"numxfers": ["Transfer Count", None, "mdi:counter", None],
"outcurnt": ["Output Current", ELECTRIC_CURRENT_AMPERE, "mdi:flash", None],
"outputv": ["Output Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", None],
"reg1": ["Register 1 Fault", None, "mdi:information-outline", None],
"reg2": ["Register 2 Fault", None, "mdi:information-outline", None],
"reg3": ["Register 3 Fault", None, "mdi:information-outline", None],
"retpct": ["Restore Requirement", PERCENTAGE, "mdi:battery-alert", None],
"selftest": ["Last Self Test", None, "mdi:calendar-clock", None],
"sense": ["Sensitivity", None, "mdi:information-outline", None],
"serialno": ["Serial Number", None, "mdi:information-outline", None],
"starttime": ["Startup Time", None, "mdi:calendar-clock", None],
"statflag": ["Status Flag", None, "mdi:information-outline", None],
"status": ["Status", None, "mdi:information-outline", None],
"stesti": ["Self Test Interval", None, "mdi:information-outline", None],
"timeleft": ["Time Left", None, "mdi:clock-alert", None],
"tonbatt": ["Time on Battery", None, "mdi:timer-outline", None],
"upsmode": ["Mode", None, "mdi:information-outline", None],
"upsname": ["Name", None, "mdi:information-outline", None],
"version": ["Daemon Info", None, "mdi:information-outline", None],
"xoffbat": ["Transfer from Battery", None, "mdi:transfer", None],
"xoffbatt": ["Transfer from Battery", None, "mdi:transfer", None],
"xonbatt": ["Transfer to Battery", None, "mdi:transfer", None],
}
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key="alarmdel",
name="Alarm Delay",
icon="mdi:alarm",
),
SensorEntityDescription(
key="ambtemp",
name="Ambient Temperature",
icon="mdi:thermometer",
),
SensorEntityDescription(
key="apc",
name="Status Data",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="apcmodel",
name="Model",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="badbatts",
name="Bad Batteries",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="battdate",
name="Battery Replaced",
icon="mdi:calendar-clock",
),
SensorEntityDescription(
key="battstat",
name="Battery Status",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="battv",
name="Battery Voltage",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="bcharge",
name="Battery",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:battery",
),
SensorEntityDescription(
key="cable",
name="Cable Type",
icon="mdi:ethernet-cable",
),
SensorEntityDescription(
key="cumonbatt",
name="Total Time on Battery",
icon="mdi:timer-outline",
),
SensorEntityDescription(
key="date",
name="Status Date",
icon="mdi:calendar-clock",
),
SensorEntityDescription(
key="dipsw",
name="Dip Switch Settings",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="dlowbatt",
name="Low Battery Signal",
icon="mdi:clock-alert",
),
SensorEntityDescription(
key="driver",
name="Driver",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="dshutd",
name="Shutdown Delay",
icon="mdi:timer-outline",
),
SensorEntityDescription(
key="dwake",
name="Wake Delay",
icon="mdi:timer-outline",
),
SensorEntityDescription(
key="endapc",
name="Date and Time",
icon="mdi:calendar-clock",
),
SensorEntityDescription(
key="extbatts",
name="External Batteries",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="firmware",
name="Firmware Version",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="hitrans",
name="Transfer High",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="hostname",
name="Hostname",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="humidity",
name="Ambient Humidity",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:water-percent",
),
SensorEntityDescription(
key="itemp",
name="Internal Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
device_class=DEVICE_CLASS_TEMPERATURE,
),
SensorEntityDescription(
key="lastxfer",
name="Last Transfer",
icon="mdi:transfer",
),
SensorEntityDescription(
key="linefail",
name="Input Voltage Status",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="linefreq",
name="Line Frequency",
native_unit_of_measurement=FREQUENCY_HERTZ,
icon="mdi:information-outline",
),
SensorEntityDescription(
key="linev",
name="Input Voltage",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="loadpct",
name="Load",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:gauge",
),
SensorEntityDescription(
key="loadapnt",
name="Load Apparent Power",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:gauge",
),
SensorEntityDescription(
key="lotrans",
name="Transfer Low",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="mandate",
name="Manufacture Date",
icon="mdi:calendar",
),
SensorEntityDescription(
key="masterupd",
name="Master Update",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="maxlinev",
name="Input Voltage High",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="maxtime",
name="Battery Timeout",
icon="mdi:timer-off-outline",
),
SensorEntityDescription(
key="mbattchg",
name="Battery Shutdown",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:battery-alert",
),
SensorEntityDescription(
key="minlinev",
name="Input Voltage Low",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="mintimel",
name="Shutdown Time",
icon="mdi:timer-outline",
),
SensorEntityDescription(
key="model",
name="Model",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="nombattv",
name="Battery Nominal Voltage",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="nominv",
name="Nominal Input Voltage",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="nomoutv",
name="Nominal Output Voltage",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="nompower",
name="Nominal Output Power",
native_unit_of_measurement=POWER_WATT,
icon="mdi:flash",
),
SensorEntityDescription(
key="nomapnt",
name="Nominal Apparent Power",
native_unit_of_measurement=POWER_VOLT_AMPERE,
icon="mdi:flash",
),
SensorEntityDescription(
key="numxfers",
name="Transfer Count",
icon="mdi:counter",
),
SensorEntityDescription(
key="outcurnt",
name="Output Current",
native_unit_of_measurement=ELECTRIC_CURRENT_AMPERE,
icon="mdi:flash",
),
SensorEntityDescription(
key="outputv",
name="Output Voltage",
native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT,
icon="mdi:flash",
),
SensorEntityDescription(
key="reg1",
name="Register 1 Fault",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="reg2",
name="Register 2 Fault",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="reg3",
name="Register 3 Fault",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="retpct",
name="Restore Requirement",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:battery-alert",
),
SensorEntityDescription(
key="selftest",
name="Last Self Test",
icon="mdi:calendar-clock",
),
SensorEntityDescription(
key="sense",
name="Sensitivity",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="serialno",
name="Serial Number",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="starttime",
name="Startup Time",
icon="mdi:calendar-clock",
),
SensorEntityDescription(
key="statflag",
name="Status Flag",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="status",
name="Status",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="stesti",
name="Self Test Interval",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="timeleft",
name="Time Left",
icon="mdi:clock-alert",
),
SensorEntityDescription(
key="tonbatt",
name="Time on Battery",
icon="mdi:timer-outline",
),
SensorEntityDescription(
key="upsmode",
name="Mode",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="upsname",
name="Name",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="version",
name="Daemon Info",
icon="mdi:information-outline",
),
SensorEntityDescription(
key="xoffbat",
name="Transfer from Battery",
icon="mdi:transfer",
),
SensorEntityDescription(
key="xoffbatt",
name="Transfer from Battery",
icon="mdi:transfer",
),
SensorEntityDescription(
key="xonbatt",
name="Transfer to Battery",
icon="mdi:transfer",
),
)
SENSOR_KEYS: list[str] = [desc.key for desc in SENSOR_TYPES]
SPECIFIC_UNITS = {"ITEMP": TEMP_CELSIUS}
INFERRED_UNITS = {
@@ -111,7 +403,7 @@ INFERRED_UNITS = {
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_RESOURCES, default=[]): vol.All(
cv.ensure_list, [vol.In(SENSOR_TYPES)]
cv.ensure_list, [vol.In(SENSOR_KEYS)]
)
}
)
@@ -120,25 +412,20 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the APCUPSd sensors."""
apcups_data = hass.data[DOMAIN]
entities = []
resources = config[CONF_RESOURCES]
for resource in config[CONF_RESOURCES]:
sensor_type = resource.lower()
if sensor_type not in SENSOR_TYPES:
SENSOR_TYPES[sensor_type] = [
sensor_type.title(),
"",
"mdi:information-outline",
]
if sensor_type.upper() not in apcups_data.status:
for resource in resources:
if resource.upper() not in apcups_data.status:
_LOGGER.warning(
"Sensor type: %s does not appear in the APCUPSd status output",
sensor_type,
resource,
)
entities.append(APCUPSdSensor(apcups_data, sensor_type))
entities = [
APCUPSdSensor(apcups_data, description)
for description in SENSOR_TYPES
if description.key in resources
]
add_entities(entities, True)
@@ -159,22 +446,18 @@ def infer_unit(value):
class APCUPSdSensor(SensorEntity):
"""Representation of a sensor entity for APCUPSd status values."""
def __init__(self, data, sensor_type):
def __init__(self, data, description: SensorEntityDescription):
"""Initialize the sensor."""
self.entity_description = description
self._data = data
self.type = sensor_type
self._attr_name = SENSOR_PREFIX + SENSOR_TYPES[sensor_type][0]
self._attr_icon = SENSOR_TYPES[self.type][2]
self._attr_native_unit_of_measurement = SENSOR_TYPES[sensor_type][1]
self._attr_device_class = SENSOR_TYPES[sensor_type][3]
self._attr_name = f"{SENSOR_PREFIX}{description.name}"
def update(self):
"""Get the latest status and use it to update our sensor state."""
if self.type.upper() not in self._data.status:
key = self.entity_description.key.upper()
if key not in self._data.status:
self._attr_native_value = None
else:
self._attr_native_value, inferred_unit = infer_unit(
self._data.status[self.type.upper()]
)
if not self._attr_native_unit_of_measurement:
self._attr_native_value, inferred_unit = infer_unit(self._data.status[key])
if not self.native_unit_of_measurement:
self._attr_native_unit_of_measurement = inferred_unit
+31 -44
View File
@@ -1,6 +1,6 @@
"""Rest API for Home Assistant."""
import asyncio
from contextlib import suppress
from http import HTTPStatus
import json
import logging
@@ -15,10 +15,6 @@ from homeassistant.components.http import HomeAssistantView
from homeassistant.const import (
EVENT_HOMEASSISTANT_STOP,
EVENT_TIME_CHANGED,
HTTP_BAD_REQUEST,
HTTP_CREATED,
HTTP_NOT_FOUND,
HTTP_OK,
MATCH_ALL,
URL_API,
URL_API_COMPONENTS,
@@ -30,15 +26,12 @@ from homeassistant.const import (
URL_API_STATES,
URL_API_STREAM,
URL_API_TEMPLATE,
__version__,
)
import homeassistant.core as ha
from homeassistant.exceptions import ServiceNotFound, TemplateError, Unauthorized
from homeassistant.helpers import template
from homeassistant.helpers.json import JSONEncoder
from homeassistant.helpers.network import NoURLAvailableError, get_url
from homeassistant.helpers.service import async_get_all_descriptions
from homeassistant.helpers.system_info import async_get_system_info
_LOGGER = logging.getLogger(__name__)
@@ -97,6 +90,7 @@ class APIEventStream(HomeAssistantView):
async def get(self, request):
"""Provide a streaming interface for the event bus."""
# pylint: disable=no-self-use
if not request["hass_user"].is_admin:
raise Unauthorized()
hass = request.app["hass"]
@@ -173,7 +167,11 @@ class APIConfigView(HomeAssistantView):
class APIDiscoveryView(HomeAssistantView):
"""View to provide Discovery information."""
"""
View to provide Discovery information.
DEPRECATED: To be removed in 2022.1
"""
requires_auth = False
url = URL_API_DISCOVERY_INFO
@@ -181,32 +179,18 @@ class APIDiscoveryView(HomeAssistantView):
async def get(self, request):
"""Get discovery information."""
hass = request.app["hass"]
uuid = await hass.helpers.instance_id.async_get()
system_info = await async_get_system_info(hass)
data = {
ATTR_UUID: uuid,
ATTR_BASE_URL: None,
ATTR_EXTERNAL_URL: None,
ATTR_INTERNAL_URL: None,
ATTR_LOCATION_NAME: hass.config.location_name,
ATTR_INSTALLATION_TYPE: system_info[ATTR_INSTALLATION_TYPE],
# always needs authentication
ATTR_REQUIRES_API_PASSWORD: True,
ATTR_VERSION: __version__,
}
with suppress(NoURLAvailableError):
data["external_url"] = get_url(hass, allow_internal=False)
with suppress(NoURLAvailableError):
data["internal_url"] = get_url(hass, allow_external=False)
# Set old base URL based on external or internal
data["base_url"] = data["external_url"] or data["internal_url"]
return self.json(data)
return self.json(
{
ATTR_UUID: "",
ATTR_BASE_URL: "",
ATTR_EXTERNAL_URL: "",
ATTR_INTERNAL_URL: "",
ATTR_LOCATION_NAME: "",
ATTR_INSTALLATION_TYPE: "",
ATTR_REQUIRES_API_PASSWORD: True,
ATTR_VERSION: "",
}
)
class APIStatesView(HomeAssistantView):
@@ -244,7 +228,7 @@ class APIEntityStateView(HomeAssistantView):
state = request.app["hass"].states.get(entity_id)
if state:
return self.json(state)
return self.json_message("Entity not found.", HTTP_NOT_FOUND)
return self.json_message("Entity not found.", HTTPStatus.NOT_FOUND)
async def post(self, request, entity_id):
"""Update state of entity."""
@@ -254,12 +238,12 @@ class APIEntityStateView(HomeAssistantView):
try:
data = await request.json()
except ValueError:
return self.json_message("Invalid JSON specified.", HTTP_BAD_REQUEST)
return self.json_message("Invalid JSON specified.", HTTPStatus.BAD_REQUEST)
new_state = data.get("state")
if new_state is None:
return self.json_message("No state specified.", HTTP_BAD_REQUEST)
return self.json_message("No state specified.", HTTPStatus.BAD_REQUEST)
attributes = data.get("attributes")
force_update = data.get("force_update", False)
@@ -272,7 +256,7 @@ class APIEntityStateView(HomeAssistantView):
)
# Read the state back for our response
status_code = HTTP_CREATED if is_new_state else HTTP_OK
status_code = HTTPStatus.CREATED if is_new_state else HTTPStatus.OK
resp = self.json(hass.states.get(entity_id), status_code)
resp.headers.add("Location", f"/api/states/{entity_id}")
@@ -286,7 +270,7 @@ class APIEntityStateView(HomeAssistantView):
raise Unauthorized(entity_id=entity_id)
if request.app["hass"].states.async_remove(entity_id):
return self.json_message("Entity removed.")
return self.json_message("Entity not found.", HTTP_NOT_FOUND)
return self.json_message("Entity not found.", HTTPStatus.NOT_FOUND)
class APIEventListenersView(HomeAssistantView):
@@ -316,12 +300,12 @@ class APIEventView(HomeAssistantView):
event_data = json.loads(body) if body else None
except ValueError:
return self.json_message(
"Event data should be valid JSON.", HTTP_BAD_REQUEST
"Event data should be valid JSON.", HTTPStatus.BAD_REQUEST
)
if event_data is not None and not isinstance(event_data, dict):
return self.json_message(
"Event data should be a JSON object", HTTP_BAD_REQUEST
"Event data should be a JSON object", HTTPStatus.BAD_REQUEST
)
# Special case handling for event STATE_CHANGED
@@ -368,7 +352,9 @@ class APIDomainServicesView(HomeAssistantView):
try:
data = json.loads(body) if body else None
except ValueError:
return self.json_message("Data should be valid JSON.", HTTP_BAD_REQUEST)
return self.json_message(
"Data should be valid JSON.", HTTPStatus.BAD_REQUEST
)
context = self.context(request)
@@ -416,7 +402,7 @@ class APITemplateView(HomeAssistantView):
return tpl.async_render(variables=data.get("variables"), parse_result=False)
except (ValueError, TemplateError) as ex:
return self.json_message(
f"Error rendering template: {ex}", HTTP_BAD_REQUEST
f"Error rendering template: {ex}", HTTPStatus.BAD_REQUEST
)
@@ -428,6 +414,7 @@ class APIErrorLog(HomeAssistantView):
async def get(self, request):
"""Retrieve API error log."""
# pylint: disable=no-self-use
if not request["hass_user"].is_admin:
raise Unauthorized()
return web.FileResponse(request.app["hass"].data[DATA_LOGGING])
@@ -5,7 +5,6 @@
"documentation": "https://www.home-assistant.io/integrations/apple_tv",
"requirements": ["pyatv==0.8.2"],
"zeroconf": ["_mediaremotetv._tcp.local.", "_touch-able._tcp.local."],
"after_dependencies": ["discovery"],
"codeowners": ["@postlund"],
"iot_class": "local_push"
}
@@ -1,7 +1,7 @@
{
"config": {
"abort": {
"already_configured_device": "Le p\u00e9riph\u00e9rique est d\u00e9j\u00e0 configur\u00e9",
"already_configured_device": "L'appareil est d\u00e9j\u00e0 configur\u00e9",
"already_in_progress": "La configuration est d\u00e9j\u00e0 en cours",
"backoff": "L'appareil n'accepte pas les demandes d'appariement pour le moment (vous avez peut-\u00eatre saisi un code PIN non valide trop de fois), r\u00e9essayez plus tard.",
"device_did_not_pair": "Aucune tentative pour terminer l'appairage n'a \u00e9t\u00e9 effectu\u00e9e \u00e0 partir de l'appareil.",
@@ -11,10 +11,10 @@
},
"error": {
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9",
"invalid_auth": "Autentification invalide",
"no_devices_found": "Aucun appareil d\u00e9tect\u00e9 sur le r\u00e9seau",
"invalid_auth": "Authentification invalide",
"no_devices_found": "Aucun appareil trouv\u00e9 sur le r\u00e9seau",
"no_usable_service": "Un dispositif a \u00e9t\u00e9 trouv\u00e9, mais aucun moyen d\u2019\u00e9tablir un lien avec lui. Si vous continuez \u00e0 voir ce message, essayez de sp\u00e9cifier son adresse IP ou de red\u00e9marrer votre Apple TV.",
"unknown": "Erreur innatendue"
"unknown": "Erreur inattendue"
},
"flow_title": "Apple TV: {name}",
"step": {
@@ -2,7 +2,7 @@
"domain": "apprise",
"name": "Apprise",
"documentation": "https://www.home-assistant.io/integrations/apprise",
"requirements": ["apprise==0.9.4"],
"requirements": ["apprise==0.9.5.1"],
"codeowners": ["@caronc"],
"iot_class": "cloud_push"
}
+105 -43
View File
@@ -1,8 +1,15 @@
"""Support for AquaLogic sensors."""
from __future__ import annotations
from dataclasses import dataclass
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.const import (
CONF_MONITORED_CONDITIONS,
DEVICE_CLASS_TEMPERATURE,
@@ -16,40 +23,88 @@ import homeassistant.helpers.config_validation as cv
from . import DOMAIN, UPDATE_TOPIC
TEMP_UNITS = [TEMP_CELSIUS, TEMP_FAHRENHEIT]
PERCENT_UNITS = [PERCENTAGE, PERCENTAGE]
SALT_UNITS = ["g/L", "PPM"]
WATT_UNITS = [POWER_WATT, POWER_WATT]
NO_UNITS = [None, None]
# sensor_type [ description, unit, icon, device_class ]
# sensor_type corresponds to property names in aqualogic.core.AquaLogic
SENSOR_TYPES = {
"air_temp": ["Air Temperature", TEMP_UNITS, None, DEVICE_CLASS_TEMPERATURE],
"pool_temp": [
"Pool Temperature",
TEMP_UNITS,
"mdi:oil-temperature",
DEVICE_CLASS_TEMPERATURE,
],
"spa_temp": [
"Spa Temperature",
TEMP_UNITS,
"mdi:oil-temperature",
DEVICE_CLASS_TEMPERATURE,
],
"pool_chlorinator": ["Pool Chlorinator", PERCENT_UNITS, "mdi:gauge", None],
"spa_chlorinator": ["Spa Chlorinator", PERCENT_UNITS, "mdi:gauge", None],
"salt_level": ["Salt Level", SALT_UNITS, "mdi:gauge", None],
"pump_speed": ["Pump Speed", PERCENT_UNITS, "mdi:speedometer", None],
"pump_power": ["Pump Power", WATT_UNITS, "mdi:gauge", None],
"status": ["Status", NO_UNITS, "mdi:alert", None],
}
@dataclass
class AquaLogicSensorEntityDescription(SensorEntityDescription):
"""Describes AquaLogic sensor entity."""
unit_metric: str | None = None
unit_imperial: str | None = None
# keys correspond to property names in aqualogic.core.AquaLogic
SENSOR_TYPES: tuple[AquaLogicSensorEntityDescription, ...] = (
AquaLogicSensorEntityDescription(
key="air_temp",
name="Air Temperature",
unit_metric=TEMP_CELSIUS,
unit_imperial=TEMP_FAHRENHEIT,
device_class=DEVICE_CLASS_TEMPERATURE,
),
AquaLogicSensorEntityDescription(
key="pool_temp",
name="Pool Temperature",
unit_metric=TEMP_CELSIUS,
unit_imperial=TEMP_FAHRENHEIT,
icon="mdi:oil-temperature",
device_class=DEVICE_CLASS_TEMPERATURE,
),
AquaLogicSensorEntityDescription(
key="spa_temp",
name="Spa Temperature",
unit_metric=TEMP_CELSIUS,
unit_imperial=TEMP_FAHRENHEIT,
icon="mdi:oil-temperature",
device_class=DEVICE_CLASS_TEMPERATURE,
),
AquaLogicSensorEntityDescription(
key="pool_chlorinator",
name="Pool Chlorinator",
unit_metric=PERCENTAGE,
unit_imperial=PERCENTAGE,
icon="mdi:gauge",
),
AquaLogicSensorEntityDescription(
key="spa_chlorinator",
name="Spa Chlorinator",
unit_metric=PERCENTAGE,
unit_imperial=PERCENTAGE,
icon="mdi:gauge",
),
AquaLogicSensorEntityDescription(
key="salt_level",
name="Salt Level",
unit_metric="g/L",
unit_imperial="PPM",
icon="mdi:gauge",
),
AquaLogicSensorEntityDescription(
key="pump_speed",
name="Pump Speed",
unit_metric=PERCENTAGE,
unit_imperial=PERCENTAGE,
icon="mdi:speedometer",
),
AquaLogicSensorEntityDescription(
key="pump_power",
name="Pump Power",
unit_metric=POWER_WATT,
unit_imperial=POWER_WATT,
icon="mdi:gauge",
),
AquaLogicSensorEntityDescription(
key="status",
name="Status",
icon="mdi:alert",
),
)
SENSOR_KEYS: list[str] = [desc.key for desc in SENSOR_TYPES]
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_MONITORED_CONDITIONS, default=list(SENSOR_TYPES)): vol.All(
cv.ensure_list, [vol.In(SENSOR_TYPES)]
vol.Required(CONF_MONITORED_CONDITIONS, default=SENSOR_KEYS): vol.All(
cv.ensure_list, [vol.In(SENSOR_KEYS)]
)
}
)
@@ -57,26 +112,29 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the sensor platform."""
sensors = []
processor = hass.data[DOMAIN]
for sensor_type in config[CONF_MONITORED_CONDITIONS]:
sensors.append(AquaLogicSensor(processor, sensor_type))
monitored_conditions = config[CONF_MONITORED_CONDITIONS]
async_add_entities(sensors)
entities = [
AquaLogicSensor(processor, description)
for description in SENSOR_TYPES
if description.key in monitored_conditions
]
async_add_entities(entities)
class AquaLogicSensor(SensorEntity):
"""Sensor implementation for the AquaLogic component."""
entity_description: AquaLogicSensorEntityDescription
_attr_should_poll = False
def __init__(self, processor, sensor_type):
def __init__(self, processor, description: AquaLogicSensorEntityDescription):
"""Initialize sensor."""
self.entity_description = description
self._processor = processor
self._type = sensor_type
self._attr_name = f"AquaLogic {SENSOR_TYPES[sensor_type][0]}"
self._attr_icon = SENSOR_TYPES[sensor_type][2]
self._attr_name = f"AquaLogic {description.name}"
async def async_added_to_hass(self):
"""Register callbacks."""
@@ -92,11 +150,15 @@ class AquaLogicSensor(SensorEntity):
panel = self._processor.panel
if panel is not None:
if panel.is_metric:
self._attr_native_unit_of_measurement = SENSOR_TYPES[self._type][1][0]
self._attr_native_unit_of_measurement = (
self.entity_description.unit_metric
)
else:
self._attr_native_unit_of_measurement = SENSOR_TYPES[self._type][1][1]
self._attr_native_unit_of_measurement = (
self.entity_description.unit_imperial
)
self._attr_native_value = getattr(panel, self._type)
self._attr_native_value = getattr(panel, self.entity_description.key)
self.async_write_ha_state()
else:
self._attr_native_unit_of_measurement = None
@@ -5,7 +5,10 @@ from typing import Any
import voluptuous as vol
from homeassistant.components.automation import AutomationActionType
from homeassistant.components.automation import (
AutomationActionType,
AutomationTriggerInfo,
)
from homeassistant.components.device_automation import DEVICE_TRIGGER_BASE_SCHEMA
from homeassistant.const import (
ATTR_ENTITY_ID,
@@ -57,10 +60,10 @@ async def async_attach_trigger(
hass: HomeAssistant,
config: ConfigType,
action: AutomationActionType,
automation_info: dict,
automation_info: AutomationTriggerInfo,
) -> CALLBACK_TYPE:
"""Attach a trigger."""
trigger_data = automation_info.get("trigger_data", {}) if automation_info else {}
trigger_data = automation_info["trigger_data"]
job = HassJob(action)
if config[CONF_TYPE] == "turn_on":
@@ -1,8 +1,8 @@
{
"config": {
"abort": {
"already_configured": "L'appareil \u00e9tait d\u00e9j\u00e0 configur\u00e9.",
"already_in_progress": "Le flux de configuration de l'appareil est d\u00e9j\u00e0 en cours.",
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9",
"already_in_progress": "La configuration est d\u00e9j\u00e0 en cours",
"cannot_connect": "\u00c9chec de connexion"
},
"error": {
+1
View File
@@ -88,6 +88,7 @@ class ArestSwitchBase(SwitchEntity):
self._resource = resource
self._attr_name = f"{location.title()} {name.title()}"
self._attr_available = True
self._attr_is_on = False
class ArestSwitchFunction(ArestSwitchBase):
+1 -1
View File
@@ -81,7 +81,7 @@ async def async_setup(hass, config):
options = {}
mode = conf.get(CONF_MODE, MODE_ROUTER)
for name, value in conf.items():
if name in ([CONF_DNSMASQ, CONF_INTERFACE, CONF_REQUIRE_IP]):
if name in [CONF_DNSMASQ, CONF_INTERFACE, CONF_REQUIRE_IP]:
if name == CONF_REQUIRE_IP and mode != MODE_AP:
continue
options[name] = value
+3 -2
View File
@@ -1,9 +1,10 @@
"""Represent the AsusWrt router."""
from __future__ import annotations
from collections.abc import Callable
from datetime import datetime, timedelta
import logging
from typing import Any, Callable
from typing import Any
from aioasuswrt.asuswrt import AsusWrt
@@ -373,7 +374,7 @@ class AsusWrtRouter:
"""Update router options."""
req_reload = False
for name, new_opt in new_options.items():
if name in (CONF_REQ_RELOAD):
if name in CONF_REQ_RELOAD:
old_opt = self._options.get(name)
if not old_opt or old_opt != new_opt:
req_reload = True
@@ -8,6 +8,7 @@
"invalid_host": "\u05e9\u05dd \u05de\u05d0\u05e8\u05d7 \u05d0\u05d5 \u05db\u05ea\u05d5\u05d1\u05ea IP \u05dc\u05d0 \u05d7\u05d5\u05e7\u05d9\u05d9\u05dd",
"pwd_and_ssh": "\u05e1\u05e4\u05e7 \u05e8\u05e7 \u05e1\u05d9\u05e1\u05de\u05d4 \u05d0\u05d5 \u05e7\u05d5\u05d1\u05e5 \u05de\u05e4\u05ea\u05d7 SSH",
"pwd_or_ssh": "\u05d0\u05e0\u05d0 \u05e1\u05e4\u05e7 \u05e1\u05d9\u05e1\u05de\u05d4 \u05d0\u05d5 \u05e7\u05d5\u05d1\u05e5 \u05de\u05e4\u05ea\u05d7 SSH",
"ssh_not_file": "\u05e7\u05d5\u05d1\u05e5 \u05de\u05e4\u05ea\u05d7 SSH \u05dc\u05d0 \u05e0\u05de\u05e6\u05d0",
"unknown": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05d1\u05dc\u05ea\u05d9 \u05e6\u05e4\u05d5\u05d9\u05d4"
},
"step": {
@@ -1,7 +1,7 @@
{
"config": {
"abort": {
"already_configured": "Un seul appareil Atag peut \u00eatre ajout\u00e9 \u00e0 Home Assistant"
"already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9"
},
"error": {
"cannot_connect": "\u00c9chec de connexion",
@@ -10,7 +10,7 @@
"step": {
"user": {
"data": {
"host": "Nom d'h\u00f4te ou adresse IP",
"host": "H\u00f4te",
"port": "Port"
},
"title": "Se connecter \u00e0 l'appareil"
@@ -1,17 +1,30 @@
"""Support for August binary sensors."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime, timedelta
import logging
from typing import cast
from yalexs.activity import ACTION_DOORBELL_CALL_MISSED, SOURCE_PUBNUB, ActivityType
from yalexs.activity import (
ACTION_DOORBELL_CALL_MISSED,
SOURCE_PUBNUB,
Activity,
ActivityType,
)
from yalexs.doorbell import DoorbellDetail
from yalexs.lock import LockDoorStatus
from yalexs.util import update_lock_detail_from_activity
from homeassistant.components.august import AugustData
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_CONNECTIVITY,
DEVICE_CLASS_DOOR,
DEVICE_CLASS_MOTION,
DEVICE_CLASS_OCCUPANCY,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.core import callback
from homeassistant.helpers.event import async_call_later
@@ -27,7 +40,7 @@ TIME_TO_RECHECK_DETECTION = timedelta(
)
def _retrieve_online_state(data, detail):
def _retrieve_online_state(data: AugustData, detail: DoorbellDetail) -> bool:
"""Get the latest state of the sensor."""
# The doorbell will go into standby mode when there is no motion
# for a short while. It will wake by itself when needed so we need
@@ -36,7 +49,7 @@ def _retrieve_online_state(data, detail):
return detail.is_online or detail.is_standby
def _retrieve_motion_state(data, detail):
def _retrieve_motion_state(data: AugustData, detail: DoorbellDetail) -> bool:
latest = data.activity_stream.get_latest_device_activity(
detail.device_id, {ActivityType.DOORBELL_MOTION}
)
@@ -47,7 +60,7 @@ def _retrieve_motion_state(data, detail):
return _activity_time_based_state(latest)
def _retrieve_ding_state(data, detail):
def _retrieve_ding_state(data: AugustData, detail: DoorbellDetail) -> bool:
latest = data.activity_stream.get_latest_device_activity(
detail.device_id, {ActivityType.DOORBELL_DING}
)
@@ -64,34 +77,62 @@ def _retrieve_ding_state(data, detail):
return _activity_time_based_state(latest)
def _activity_time_based_state(latest):
def _activity_time_based_state(latest: Activity) -> bool:
"""Get the latest state of the sensor."""
start = latest.activity_start_time
end = latest.activity_end_time + TIME_TO_DECLARE_DETECTION
return start <= _native_datetime() <= end
def _native_datetime():
def _native_datetime() -> datetime:
"""Return time in the format august uses without timezone."""
return datetime.now()
SENSOR_NAME = 0
SENSOR_DEVICE_CLASS = 1
SENSOR_STATE_PROVIDER = 2
SENSOR_STATE_IS_TIME_BASED = 3
@dataclass
class AugustRequiredKeysMixin:
"""Mixin for required keys."""
# sensor_type: [name, device_class, state_provider, is_time_based]
SENSOR_TYPES_DOORBELL = {
"doorbell_ding": ["Ding", DEVICE_CLASS_OCCUPANCY, _retrieve_ding_state, True],
"doorbell_motion": ["Motion", DEVICE_CLASS_MOTION, _retrieve_motion_state, True],
"doorbell_online": [
"Online",
DEVICE_CLASS_CONNECTIVITY,
_retrieve_online_state,
False,
],
}
value_fn: Callable[[AugustData, DoorbellDetail], bool]
is_time_based: bool
@dataclass
class AugustBinarySensorEntityDescription(
BinarySensorEntityDescription, AugustRequiredKeysMixin
):
"""Describes August binary_sensor entity."""
SENSOR_TYPE_DOOR = BinarySensorEntityDescription(
key="door_open",
name="Open",
)
SENSOR_TYPES_DOORBELL: tuple[AugustBinarySensorEntityDescription, ...] = (
AugustBinarySensorEntityDescription(
key="doorbell_ding",
name="Ding",
device_class=DEVICE_CLASS_OCCUPANCY,
value_fn=_retrieve_ding_state,
is_time_based=True,
),
AugustBinarySensorEntityDescription(
key="doorbell_motion",
name="Motion",
device_class=DEVICE_CLASS_MOTION,
value_fn=_retrieve_motion_state,
is_time_based=True,
),
AugustBinarySensorEntityDescription(
key="doorbell_online",
name="Online",
device_class=DEVICE_CLASS_CONNECTIVITY,
value_fn=_retrieve_online_state,
is_time_based=False,
),
)
async def async_setup_entry(hass, config_entry, async_add_entities):
@@ -109,16 +150,16 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
continue
_LOGGER.debug("Adding sensor class door for %s", door.device_name)
entities.append(AugustDoorBinarySensor(data, "door_open", door))
entities.append(AugustDoorBinarySensor(data, door, SENSOR_TYPE_DOOR))
for doorbell in data.doorbells:
for sensor_type, sensor in SENSOR_TYPES_DOORBELL.items():
for description in SENSOR_TYPES_DOORBELL:
_LOGGER.debug(
"Adding doorbell sensor class %s for %s",
sensor[SENSOR_DEVICE_CLASS],
description.device_class,
doorbell.device_name,
)
entities.append(AugustDoorbellBinarySensor(data, sensor_type, doorbell))
entities.append(AugustDoorbellBinarySensor(data, doorbell, description))
async_add_entities(entities)
@@ -128,14 +169,16 @@ class AugustDoorBinarySensor(AugustEntityMixin, BinarySensorEntity):
_attr_device_class = DEVICE_CLASS_DOOR
def __init__(self, data, sensor_type, device):
def __init__(self, data, device, description: BinarySensorEntityDescription):
"""Initialize the sensor."""
super().__init__(data, device)
self.entity_description = description
self._data = data
self._sensor_type = sensor_type
self._device = device
self._attr_name = f"{device.device_name} Open"
self._attr_unique_id = f"{self._device_id}_open"
self._attr_name = f"{device.device_name} {description.name}"
self._attr_unique_id = (
f"{self._device_id}_{cast(str, description.name).lower()}"
)
self._update_from_data()
@callback
@@ -164,41 +207,27 @@ class AugustDoorBinarySensor(AugustEntityMixin, BinarySensorEntity):
class AugustDoorbellBinarySensor(AugustEntityMixin, BinarySensorEntity):
"""Representation of an August binary sensor."""
def __init__(self, data, sensor_type, device):
entity_description: AugustBinarySensorEntityDescription
def __init__(self, data, device, description: AugustBinarySensorEntityDescription):
"""Initialize the sensor."""
super().__init__(data, device)
self.entity_description = description
self._check_for_off_update_listener = None
self._data = data
self._sensor_type = sensor_type
self._attr_device_class = self._sensor_config[SENSOR_DEVICE_CLASS]
self._attr_name = f"{device.device_name} {self._sensor_config[SENSOR_NAME]}"
self._attr_name = f"{device.device_name} {description.name}"
self._attr_unique_id = (
f"{self._device_id}_{self._sensor_config[SENSOR_NAME].lower()}"
f"{self._device_id}_{cast(str, description.name).lower()}"
)
self._update_from_data()
@property
def _sensor_config(self):
"""Return the config for the sensor."""
return SENSOR_TYPES_DOORBELL[self._sensor_type]
@property
def _state_provider(self):
"""Return the state provider for the binary sensor."""
return self._sensor_config[SENSOR_STATE_PROVIDER]
@property
def _is_time_based(self):
"""Return true of false if the sensor is time based."""
return self._sensor_config[SENSOR_STATE_IS_TIME_BASED]
@callback
def _update_from_data(self):
"""Get the latest state of the sensor."""
self._cancel_any_pending_updates()
self._attr_is_on = self._state_provider(self._data, self._detail)
self._attr_is_on = self.entity_description.value_fn(self._data, self._detail)
if self._is_time_based:
if self.entity_description.is_time_based:
self._attr_available = _retrieve_online_state(self._data, self._detail)
self._schedule_update_to_recheck_turn_off_sensor()
else:
+65 -20
View File
@@ -1,9 +1,21 @@
"""Support for August sensors."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
import logging
from typing import Generic, TypeVar
from yalexs.activity import ActivityType
from yalexs.keypad import KeypadDetail
from yalexs.lock import LockDetail
from homeassistant.components.sensor import DEVICE_CLASS_BATTERY, SensorEntity
from homeassistant.components.august import AugustData
from homeassistant.components.sensor import (
DEVICE_CLASS_BATTERY,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.const import ATTR_ENTITY_PICTURE, PERCENTAGE, STATE_UNAVAILABLE
from homeassistant.core import callback
from homeassistant.helpers.entity_registry import async_get_registry
@@ -26,20 +38,44 @@ from .entity import AugustEntityMixin
_LOGGER = logging.getLogger(__name__)
def _retrieve_device_battery_state(detail):
def _retrieve_device_battery_state(detail: LockDetail) -> int:
"""Get the latest state of the sensor."""
return detail.battery_level
def _retrieve_linked_keypad_battery_state(detail):
def _retrieve_linked_keypad_battery_state(detail: KeypadDetail) -> int | None:
"""Get the latest state of the sensor."""
return detail.battery_percentage
SENSOR_TYPES_BATTERY = {
"device_battery": {"state_provider": _retrieve_device_battery_state},
"linked_keypad_battery": {"state_provider": _retrieve_linked_keypad_battery_state},
}
T = TypeVar("T", LockDetail, KeypadDetail)
@dataclass
class AugustRequiredKeysMixin(Generic[T]):
"""Mixin for required keys."""
value_fn: Callable[[T], int | None]
@dataclass
class AugustSensorEntityDescription(
SensorEntityDescription, AugustRequiredKeysMixin[T]
):
"""Describes August sensor entity."""
SENSOR_TYPE_DEVICE_BATTERY = AugustSensorEntityDescription[LockDetail](
key="device_battery",
name="Battery",
value_fn=_retrieve_device_battery_state,
)
SENSOR_TYPE_KEYPAD_BATTERY = AugustSensorEntityDescription[KeypadDetail](
key="linked_keypad_battery",
name="Battery",
value_fn=_retrieve_linked_keypad_battery_state,
)
async def async_setup_entry(hass, config_entry, async_add_entities):
@@ -60,9 +96,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
operation_sensors.append(device)
for device in batteries["device_battery"]:
state_provider = SENSOR_TYPES_BATTERY["device_battery"]["state_provider"]
detail = data.get_device_detail(device.device_id)
if detail is None or state_provider(detail) is None:
if detail is None or SENSOR_TYPE_DEVICE_BATTERY.value_fn(detail) is None:
_LOGGER.debug(
"Not adding battery sensor for %s because it is not present",
device.device_name,
@@ -72,7 +107,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
"Adding battery sensor for %s",
device.device_name,
)
entities.append(AugustBatterySensor(data, "device_battery", device, device))
entities.append(
AugustBatterySensor[LockDetail](
data, device, device, SENSOR_TYPE_DEVICE_BATTERY
)
)
for device in batteries["linked_keypad_battery"]:
detail = data.get_device_detail(device.device_id)
@@ -87,8 +126,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
"Adding keypad battery sensor for %s",
device.device_name,
)
keypad_battery_sensor = AugustBatterySensor(
data, "linked_keypad_battery", detail.keypad, device
keypad_battery_sensor = AugustBatterySensor[KeypadDetail](
data, detail.keypad, device, SENSOR_TYPE_KEYPAD_BATTERY
)
entities.append(keypad_battery_sensor)
migrate_unique_id_devices.append(keypad_battery_sensor)
@@ -204,29 +243,35 @@ class AugustOperatorSensor(AugustEntityMixin, RestoreEntity, SensorEntity):
return f"{self._device_id}_lock_operator"
class AugustBatterySensor(AugustEntityMixin, SensorEntity):
class AugustBatterySensor(AugustEntityMixin, SensorEntity, Generic[T]):
"""Representation of an August sensor."""
entity_description: AugustSensorEntityDescription[T]
_attr_device_class = DEVICE_CLASS_BATTERY
_attr_native_unit_of_measurement = PERCENTAGE
def __init__(self, data, sensor_type, device, old_device):
def __init__(
self,
data: AugustData,
device,
old_device,
description: AugustSensorEntityDescription[T],
):
"""Initialize the sensor."""
super().__init__(data, device)
self._sensor_type = sensor_type
self.entity_description = description
self._old_device = old_device
self._attr_name = f"{device.device_name} Battery"
self._attr_unique_id = f"{self._device_id}_{sensor_type}"
self._attr_name = f"{device.device_name} {description.name}"
self._attr_unique_id = f"{self._device_id}_{description.key}"
self._update_from_data()
@callback
def _update_from_data(self):
"""Get the latest state of the sensor."""
state_provider = SENSOR_TYPES_BATTERY[self._sensor_type]["state_provider"]
self._attr_native_value = state_provider(self._detail)
self._attr_native_value = self.entity_description.value_fn(self._detail)
self._attr_available = self._attr_native_value is not None
@property
def old_unique_id(self) -> str:
"""Get the old unique id of the device sensor."""
return f"{self._old_device.device_id}_{self._sensor_type}"
return f"{self._old_device.device_id}_{self.entity_description.key}"
@@ -5,8 +5,8 @@
"reauth_successful": "La r\u00e9-authentification a r\u00e9ussi"
},
"error": {
"cannot_connect": "Impossible de se connecter, veuillez r\u00e9essayer",
"invalid_auth": "Authentification non valide",
"cannot_connect": "\u00c9chec de connexion",
"invalid_auth": "Authentification invalide",
"unknown": "Erreur inattendue"
},
"step": {

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