Compare commits

...

207 Commits

Author SHA1 Message Date
Paulus Schoutsen
cdbdf1ba4f 2023.4.6 (#91833) 2023-04-21 20:31:05 -04:00
J. Nick Koston
d58f62cb5e Remove old migration tests that have been replaced (#91842)
These tests were moved to test_migration_from_schema_32.py in `dev`
and have changed. Remove the old tests as they are no longer
correct
2023-04-21 19:12:21 -04:00
Paulus Schoutsen
f1c4605fba Bumped version to 2023.4.6 2023-04-21 14:58:46 -04:00
Paulus Schoutsen
deb55a74da Disallow uploading files to bypass the media dirs (#91817) 2023-04-21 14:58:42 -04:00
Allen Porter
30da629285 Relax the constraint that events must have a consistent timezone for start/end (#91788) 2023-04-21 14:58:41 -04:00
Stephan Uhle
26b28001c5 Bump pysml to 0.0.10 (#91773) 2023-04-21 14:58:40 -04:00
Nathan Spencer
64f8059f00 Bump pylitterbot to 2023.4.0 (#91759) 2023-04-21 14:58:39 -04:00
Jan Bouwhuis
8363183943 Do not wait for mqtt at startup mqtt_statestream (#91721) 2023-04-21 14:58:38 -04:00
Teemu R
e19279fda5 Bump python-songpal dependency (#91708) 2023-04-21 14:58:38 -04:00
J. Nick Koston
591ffe2340 Fallback to generating a new ULID on migraiton if context is missing or invalid (#91704)
* Fallback to generating a new ULID on migraiton if context is missing or invalid

It was discovered that postgresql will do a full scan if
there is a low cardinality on the index because of missing
context ids. We will now generate a ULID for the timestamp
of the row if the context data is missing or invalid

fixes #91514

* tests

* tweak

* tweak

* preen
2023-04-21 14:58:37 -04:00
Shay Levy
fc4e8e5e7b Bump aioshelly to 5.3.2 (#91679) 2023-04-21 14:58:36 -04:00
J. Nick Koston
36d2accb5b Handle long format context UUIDs during migration (#91657)
In https://github.com/home-assistant/core/issues/91514 is was discovered
these exist in older versions
2023-04-21 14:58:07 -04:00
epenet
38de9765df Bump renault-api to 0.1.13 (#91609) 2023-04-21 14:55:51 -04:00
Duco Sebel
6b02892c28 Handle UnsupportedError in HomeWizard (#91608)
* Handle UnsupportedEror

* Make error message more clear

* Remove debug line, whoops
2023-04-21 14:55:50 -04:00
Tom Harris
c544da7426 Fix Insteon thermostat issue (#91568)
* Bump pyinsteon

* Bump pyinsteon

* Bump pyinsteon
2023-04-21 14:55:49 -04:00
Aaron Godfrey
71f0f53ddc Fix tasks with no due date from not triggering on calendar state. (#91196)
Fix tasks with no due date.

Prior to this change we were setting the start date/time to utc rather
than the user's timezone.
2023-04-21 14:55:48 -04:00
J. Nick Koston
03c517b066 Add a guard against selecting all entities in state_changes_during_period (#91585)
Add a guard against selecting all entities in state_changes_during_period

This cannot happen in `dev` because we require entity ids
2023-04-18 09:26:41 -04:00
Paulus Schoutsen
b05fcd7904 2023.4.5 (#91544) 2023-04-17 22:20:19 -04:00
Franck Nijhof
940861e2be Bumped version to 2023.4.5 2023-04-17 15:37:08 +02:00
Christopher Bailey
559ce6a275 Bump unifiprotect to 4.8.1 (#91522) 2023-04-17 15:36:51 +02:00
rappenze
273e1fd2be Fix state mapping in fibaro climate (#91505) 2023-04-17 15:36:48 +02:00
Ben Morton
5ddc18f8ed Resolve issue with switchbot blind tilt devices getting stuck in opening/closing state (#91495) 2023-04-17 15:36:44 +02:00
J. Nick Koston
489a6e766b Fix onvif failing to reload (#91482) 2023-04-17 15:36:40 +02:00
starkillerOG
572f2cc167 Reolink ONVIF move read to primary callback (#91478)
* Move read to primary callback

* fix styling

* Do not raise on ConnectionResetError

* Split request.text() to .read() and decode("utf-8")
2023-04-17 15:36:37 +02:00
J. Nick Koston
5321c60058 Handle a few more transient onvif errors (#91473) 2023-04-17 15:36:33 +02:00
J. Nick Koston
00a86757fa Bump onvif-zeep-async to 1.2.11 (#91472) 2023-04-17 15:36:30 +02:00
J. Nick Koston
b06d624d43 Fix creating onvif pull point subscriptions when InitialTerminationTime is required (#91470)
* Fix creating onvif pull point subscriptions when InitialTerminationTime is required

fixes #85902

* Bump again because I got it wrong the first time.. this is why retest is good
2023-04-17 15:36:26 +02:00
Michael Davie
89b1d5bb68 Bump env_canada to v0.5.33 (#91468) 2023-04-17 15:36:22 +02:00
Erik Montnemery
bf389440dc Save Thread dataset store when changing preferred dataset (#91411) 2023-04-17 15:36:18 +02:00
puddly
2b9cc39d2b Fix attribute reporting config failures in ZHA (#91403) 2023-04-17 15:36:15 +02:00
J. Nick Koston
afe3fd5ec0 Bump onvif-zeep-async to 1.2.5 (#91399) 2023-04-17 15:36:11 +02:00
Aidan Timson
e29d5a1356 Fix listener running in foreground for System Bridge integration (#91391)
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-04-17 15:36:08 +02:00
rich-kettlewell
5f7b447d7a Tado set_water_heater_timer should use water_heater domain (#91364) 2023-04-17 15:36:03 +02:00
epenet
0e3f462bfb Add missing mock in sharkiq tests (#91325) 2023-04-17 15:33:52 +02:00
starkillerOG
8feab57d59 Reolink prevent ONVIF push being lost due to ConnectionResetError (#91070)
* Make "Connection lost" error less likely

* Handle connection loss during ONVIF event reading

* tweak

* fix styling

* catch asyncio.CancelledError from request.text()

* missing ()

* re-raise cancelation for proper cleanup

* Simplify

* Also set webhook_reachable if connection lost

* fix styntax

* Send HTTP_OK directly after data read done

* protect agains garbage collection

* Protect shielded task (inner) not shielded future (outer)

* fix black

* Make sure exceptions are logged

* fix spelling

* fix black

* fix spelling

* Simplify using hass.async_create_task

* clarify comment

* Eleborate comment

* Update homeassistant/components/reolink/host.py

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

* Apply suggestions from bdraco

---------

Co-authored-by: J. Nick Koston <nick@koston.org>
2023-04-17 15:28:25 +02:00
Mark Adkins
2bda40d352 Fix SharkIQ token expiration (#89357) 2023-04-17 15:27:44 +02:00
Meow
47398f03dd Add SetSynchronizationPoint fallback to onvif (#86400)
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-04-17 15:22:17 +02:00
Franck Nijhof
3f0f5dc303 2023.4.4 (#91356) 2023-04-13 15:32:45 +02:00
Franck Nijhof
b5ac3ee288 Bumped version to 2023.4.4 2023-04-13 13:50:25 +02:00
Bram Kragten
51c99d26b4 Update frontend to 20230411.1 (#91344) 2023-04-13 13:50:10 +02:00
J. Nick Koston
f77ce413be Bump aiolifx to 0.8.10 (#91324) 2023-04-13 13:50:06 +02:00
Duco Sebel
7a8159052e Bump python-homewizard-energy to 2.0.1 (#91097) 2023-04-13 13:50:02 +02:00
Paulus Schoutsen
8ec6afb85a 2023.4.3 (#91316) 2023-04-12 21:50:11 -04:00
Franck Nijhof
bbf2d0e6ad Remove codecov from Python test requirements (#91295) 2023-04-12 20:51:59 -04:00
tronikos
c073cee049 Google Assistant SDK: Fix broadcast command for Portuguese (#91293)
Fix broadcast command for pt
2023-04-12 20:51:58 -04:00
Paulus Schoutsen
e9f1148c0a Bumped version to 2023.4.3 2023-04-12 20:35:59 -04:00
J. Nick Koston
a420007e80 Restore use of local timezone for MariaDB/MySQL in SQL integration (#91313)
* Use local timezone for recorder connection

The fix in #90335 had an unexpected side effect of
using UTC for the timezone since all recorder operations
use UTC. Since only sqlite much use the database executor
we can use a seperate connection pool which uses local time

This also ensures that the engines are disposed of
when Home Assistant is shutdown as previously we
did not cleanly disconnect

* coverage

* fix unclean shutdown in config flow

* tweaks
2023-04-12 20:35:50 -04:00
puddly
64a9bfcc22 Bump ZHA dependencies (#91291) 2023-04-12 20:35:49 -04:00
codyhackw
fd53eda5c6 Update Inovelli Blue Series switch support in ZHA (#91254)
Co-authored-by: David F. Mulcahey <david.mulcahey@icloud.com>
2023-04-12 20:35:49 -04:00
Erik Montnemery
d6574b4a2e Fix switch_as_x name (#91232) 2023-04-12 20:35:48 -04:00
Bram Kragten
8eb75beb96 Update frontend to 20230411.0 (#91219) 2023-04-12 20:35:47 -04:00
Erik Montnemery
68920a12aa Flush conversation name cache when an entity is renamed (#91214) 2023-04-12 20:35:46 -04:00
Aaron Bach
a806e070a2 Bump pytile to 2023.04.0 (#91191) 2023-04-12 20:35:45 -04:00
David F. Mulcahey
a87c78ca20 Cleanup ZHA from Zigpy deprecated property removal (#91180) 2023-04-12 20:35:44 -04:00
Aidan Timson
48df638f5d Reduce startup time for System Bridge integration (#91171) 2023-04-12 20:35:43 -04:00
Allen Porter
c601266f9c Fix all day event coercion logic (#91169) 2023-04-12 20:35:42 -04:00
starkillerOG
30d615f206 Reolink config flow fix custom port when USE_HTTPS not selected (#91137)
give USE_HTTPS a default
2023-04-12 20:35:41 -04:00
J. Nick Koston
2db8d70c2f Fix false positive in SQL sensor full table scan check (#91134) 2023-04-12 20:35:40 -04:00
J. Nick Koston
3efffe7688 Bump ulid-transform to 0.6.3 (#91133)
* Bump ulid-transform to 0.6.2

changelog: https://github.com/bdraco/ulid-transform/compare/v0.6.0...v0.6.2

32bit fixes

fixes #91092

* 0.6.3
2023-04-12 20:35:39 -04:00
Allen Porter
dc777f78b8 Relax calendar event validation to allow existing zero duration events (#91129)
Relax event valudation to allow existing zero duration events
2023-04-12 20:35:38 -04:00
Michael Davie
4cd00da319 Bump env_canada to 0.5.32 (#91126) 2023-04-12 20:35:37 -04:00
Robert Hillis
3f6486db3e Bump aiopyarr to 23.4.0 (#91110) 2023-04-12 20:35:36 -04:00
Diogo Gomes
2d41fe837c Track availability of source sensor in utility meter (#91035)
* track availability of source sensor

* address review comments
2023-04-12 20:35:35 -04:00
Pascal Reeb
34394d90c0 Fall back to polling if webhook cannot be registered on Nuki (#91013)
fix(nuki): throw warning if webhook cannot be created
2023-04-12 20:35:34 -04:00
Anthony Mattas
fa29aea68e Fix configuring Flo instances (#90990)
* Update config_flow.py

Used constant string for consistency

* Update config_flow.py

Removed code for location ID and name the integration using the username

* Update manifest.json

Updated codeowners

* Update config_flow.py

* Update config_flow.py

Formatted with black

* Update manifest.json

Updated codeowners

* Update test_config_flow.py

Updated test
2023-04-12 20:35:33 -04:00
Paulus Schoutsen
7928b31087 2023.4.2 (#91111) 2023-04-08 23:41:48 -04:00
J. Nick Koston
e792350be6 Fix fnvhash import in schema 32 test backport (#91112) 2023-04-08 23:41:19 -04:00
Paulus Schoutsen
5f0553dd22 Bumped version to 2023.4.2 2023-04-08 22:58:28 -04:00
J. Nick Koston
8f6b77235e Make the device_tracker more forgiving when passed an empty ip address string (#91101)
This has come up over and over and over again

fixes #87165 fixes #51980
2023-04-08 22:56:49 -04:00
J. Nick Koston
8ababc75d4 Bump flux_led to 0.28.37 (#91099)
changes: https://github.com/Danielhiversen/flux_led/releases/tag/0.28.37
2023-04-08 22:56:48 -04:00
J. Nick Koston
0a8f399655 Fix context_user_id round trip when calling to_native (#91098)
We do not actually use this in the history or logbook
APIs so nothing broke but there was a bug here for anyone
calling this directly

fixes #91090
2023-04-08 22:56:47 -04:00
Michael Davie
19567e7fee Bump env_canada to v0.5.31 (#91094) 2023-04-08 22:56:46 -04:00
Garrett
3a137cb24c Bump subarulink to 0.7.6 (#91064) 2023-04-08 22:56:45 -04:00
Allen Porter
935af6904d Bump gcal_sync to 4.1.4 (#91062) 2023-04-08 22:56:44 -04:00
Allen Porter
4fed5ad21c Make location optional in google calendar create service (#91061) 2023-04-08 22:56:44 -04:00
J. Nick Koston
9dc15687b5 Bump zeroconf to 0.56.0 (#91060) 2023-04-08 22:56:43 -04:00
J. Nick Koston
38a0eca223 Bump zeroconf to 0.55.0 (#90987) 2023-04-08 22:56:42 -04:00
David F. Mulcahey
6836e0b511 Fix Smartthings acceleration sensor in ZHA (#91056) 2023-04-08 22:55:52 -04:00
David F. Mulcahey
cab88b72b8 Bump ZHA quirks lib (#91054) 2023-04-08 22:55:51 -04:00
Steven Looman
07421927ec Make sure upnp-router is also initialized when first seen through an advertisement (#91037) 2023-04-08 22:55:50 -04:00
Diogo Gomes
828a2779a0 Delay utility_meter until HA has started (#91017)
* increase information for end user

* only warn after home assistant has started

* delay utility_meter until HA has startED
2023-04-08 22:55:49 -04:00
Joost Lekkerkerker
7392a5780c Bump roombapy to 1.6.8 (#91012)
* Update roombapy to 1.6.7

* Update roombapy to 1.6.8
2023-04-08 22:55:48 -04:00
Aaron Bach
804270a797 Bump aioambient to 2023.04.0 (#90991) 2023-04-08 22:55:47 -04:00
J. Nick Koston
7f5f286648 Bump vallox-websocket-api to 3.2.1 (#90980)
unblocks https://github.com/home-assistant/core/pull/90901
which will finally fix the races in websockets
2023-04-08 22:55:46 -04:00
J. Nick Koston
0a70a29e92 Resume entity id post migration after a restart (#90973)
* Restart entity id post migration after a restart

If the entity migration finished and Home Assistant was
restarted during the post migration it would never be resumed
which means the old index and space would never be recovered

* add migration resume test
2023-04-08 22:55:46 -04:00
J. Nick Koston
dc2f2e8d3f Raise an issue for legacy SQL queries that will cause full table scans (#90971)
* Raise an issue for SQL queries that will cause full table scans

* Raise an issue for SQL queries that will cause full table scans

* Raise an issue for SQL queries that will cause full table scans

* Raise an issue for SQL queries that will cause full table scans

* Update homeassistant/components/sql/sensor.py

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

* coverage

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-04-08 22:55:45 -04:00
J. Nick Koston
6522a3ad1b Bump websockets constraint to 11.0.1+ (#90901) 2023-04-08 22:55:44 -04:00
PatrickGlesner
be65d4f33e Fix NMBS AttributeError (#90525)
* Fix NMBS AttributeError (Issue #90505)

* Set and use API_FAILURE

* Configure the logger to track API failures

* Remove broad exceptions and rewite logging
2023-04-08 22:55:43 -04:00
Paulus Schoutsen
0c15c75781 2023.4.1 (#90956) 2023-04-06 17:52:14 -04:00
Heikki Partanen
2bf51a033b Fix verisure autolock (#90960)
Fix verisure autolock #90959
2023-04-06 20:54:40 +00:00
Steven Rollason
cfd8695aaa Fix command_template sensor value_template not being used if json_attributes set (#90603)
* Allow value_template to be used if json_attributes set

* Set state to None if no value_template and json_attributes used

* Refactor check for no value_template when json_attributes used

* Updated and additional unit test

* Updated to set _attr_native_value and return if value_template is None

* Update unit test docstring

* Updated test docstring based on feedback
2023-04-06 20:49:32 +00:00
Jan Bouwhuis
e8a6a2e105 Fix error after losing an imap connection (#90966)
Cleanup first after losing an imap connection
2023-04-06 20:46:54 +00:00
Allen Porter
73a960af34 Bump gcal_sync to 4.1.3 (#90968) 2023-04-06 20:44:52 +00:00
Allen Porter
bbb571fdf8 Coerce previously persisted local calendars to have valid durations (#90970) 2023-04-06 20:42:00 +00:00
J. Nick Koston
c944be8215 Fix state being cleared on disconnect with deep sleep esphome devices (#90925)
* Fix state being cleared on disconnect with deep sleep esphome devices

fixes #90923

* fix logic
2023-04-06 20:39:04 +00:00
J. Nick Koston
5e903e04cf Avoid writing state to all esphome entities at shutdown (#90555) 2023-04-06 20:39:00 +00:00
starkillerOG
6884b0a421 Bump reolink-aio to 0.5.10 (#90963)
* use is_doorbell instead of is_doorbell_enabled

* Bump reolink-aio to 0.5.10
2023-04-06 14:35:39 -04:00
Aaron Bach
a1c7159304 Bump aioambient to 2022.10.0 (#90940)
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-04-06 14:34:25 -04:00
epenet
d65791027f Fix flaky test in vesync (#90921)
* Fix flaky test in vesync

* Move sorting to the test
2023-04-06 14:34:24 -04:00
Paulus Schoutsen
5ffa0cba39 Bumped version to 2023.4.1 2023-04-06 13:21:13 -04:00
Bram Kragten
f5be600383 Update frontend to 20230406.1 (#90951) 2023-04-06 13:21:07 -04:00
Pascal Reeb
9b2e26c270 Handle NoURLAvailableError in Nuki component (#90927)
* fix(nuki): handle NoURLAvailableError

* only try internal URLs
2023-04-06 13:21:06 -04:00
stickpin
e25edea815 Return empty available programs list if an appliance is off during initial configuration (#90905) 2023-04-06 13:21:05 -04:00
J. Nick Koston
849000d5ac Bump aiodiscover to 1.4.16 (#90903) 2023-04-06 13:21:04 -04:00
Aaron Bach
cb06541fda Bump simplisafe-python to 2023.04.0 (#90896)
Co-authored-by: J. Nick Koston <nick@koston.org>
2023-04-06 13:21:03 -04:00
J. Nick Koston
70d1e733f6 Fix entity_id migration query failing with MySQL 8.0.30 (#90895) 2023-04-06 13:21:02 -04:00
J. Nick Koston
0b3012071e Guard against invalid ULIDs in contexts while recording events (#90889) 2023-04-06 13:21:01 -04:00
J. Nick Koston
42b7ed115f Bump ulid-transform 0.6.0 (#90888)
* Bump ulid-transform 0.6.0

changelog: https://github.com/bdraco/ulid-transform/compare/v0.5.1...v0.6.0

to find the source of the invalid ulids in https://github.com/home-assistant/core/issues/90887
2023-04-06 13:21:00 -04:00
J. Nick Koston
513a13f369 Fix missing bluetooth client wrapper in bleak_retry_connector (#90885) 2023-04-06 13:20:59 -04:00
Michael
f341d0787e Migrate entity unique ids in PI-Hole (#90883)
* migrate entity unique ids

* Update homeassistant/components/pi_hole/__init__.py

---------

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2023-04-06 13:20:58 -04:00
J. Nick Koston
c8ee45b53c Add MariaDB deadlock retry wrapper to database timestamp column migrations (#90880)
Add deadlock retry wrapper to timestamp column migrations

fixes #90819
2023-04-06 13:20:57 -04:00
J. Nick Koston
b4e2dd4e06 Add constraint for websockets to <11.0 (#90868) 2023-04-06 13:20:56 -04:00
J. Nick Koston
c663d8754b Generate a seperate log message per dumped object for profiler.dump_log_objects (#90867)
Since some objects are very large we can generate overly large log messages
```
Event data for system_log_event exceed maximum size of 32768 bytes. This can cause database performance issues; Event data will not be stored
```

Reported in https://ptb.discord.com/channels/330944238910963714/427516175237382144/1093069996101472306
2023-04-06 13:20:55 -04:00
Tom Harris
968a4e4818 Fix issue with Insteon All-Link Database loading (#90858)
Bump to 1.4.1
2023-04-06 13:20:54 -04:00
saschaabraham
833b95722e Bump fritzconnection to 1.12.0 (#90799) 2023-04-06 13:20:53 -04:00
mkmer
096e814929 Handle Uncaught exceptions in async_update Honeywell (#90746) 2023-04-06 13:20:52 -04:00
Franck Nijhof
cff493fb98 2023.4.0 (#90855) 2023-04-05 19:57:42 +02:00
Franck Nijhof
d67265bb66 Bumped version to 2023.4.0 2023-04-05 17:37:57 +02:00
Erik Montnemery
6e51f0d6f5 Adjust OTBR channel conflict URL (#90847) 2023-04-05 17:37:06 +02:00
Bram Kragten
82977f33ed Bump frontend to 20230405.0 (#90841) 2023-04-05 17:37:03 +02:00
epenet
fb2d432d32 Adjust async_track_time_interval name argument (#90838)
Adjust async_track_time_interval naming
2023-04-05 17:36:59 +02:00
Tom Puttemans
0d019a3c4c Support entity name translation in DSMR Reader component (#90836)
* Use translation_key instead of name for the entity names and enum values

This change allows for the translation of entity names and their values based on a key, instead of having the English text in the code

* Adjusted tariff options order

Not really wrong, but this way it is consistent with all other entities
2023-04-05 17:36:55 +02:00
Paul Bottein
65b877bb77 Add entity name translations to prusalink entities (#90833) 2023-04-05 17:36:52 +02:00
Jan Bouwhuis
2a23583d67 Suppress imap logging on reconnect and presume state (#90826) 2023-04-05 17:36:48 +02:00
Penny Wood
80fe5051b3 Master RAS zone (#90825)
Fixes issue in some systems with different numbering systems
2023-04-05 17:36:44 +02:00
J. Nick Koston
2dfe33d177 Bump aioesphomeapi to 10.6.1 (#90816) 2023-04-05 17:36:41 +02:00
J. Nick Koston
617037a92d Fix BLEDevice not getting updated when details change for remote scanners (#90815) 2023-04-05 17:36:36 +02:00
Paulus Schoutsen
8f60a2bdd4 Bumped version to 2023.4.0b7 2023-04-04 21:09:22 -04:00
Patrick ZAJDA
9f7b2ba6c1 Add entity name translations to Broadlink sensors (#90783)
* Add entity name translations to Broadlink sensors

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>

* Update tests

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>

* Apply suggestions from code review

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

---------

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-04-04 21:09:10 -04:00
Patrick ZAJDA
af34e25c89 Add translations for Nuki entity name and battery critical state attribute (#90772)
* Add translations for Nuki entity name and battery critical state attribute

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>

* Remove door sensor name

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>

---------

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>
2023-04-04 21:09:09 -04:00
Pascal Reeb
c43dc37713 Add Warning in the issue registry if a HTTPS webhook is used for Nuki (#90718)
feat(nuki): create issue when https webhook URL was created
2023-04-04 21:09:08 -04:00
Maciej Bieniek
0d6177dbdb Address late review for NextDNS entity name translations (#90771) 2023-04-04 21:07:21 -04:00
starkillerOG
f03b9036c5 Add async_write_ha_state to Reolink select (#90764)
Add async_write_ha_state to select
2023-04-04 21:07:20 -04:00
Jan Bouwhuis
1848a723cd Fix recovering imap connection triggers re-auth (#90762) 2023-04-04 21:07:19 -04:00
Erik Montnemery
8230a52e0a Update template environment from the event loop (#90758) 2023-04-04 21:07:18 -04:00
Paulus Schoutsen
d0e9470c7c Fix frontend test again (#90754) 2023-04-04 21:07:17 -04:00
J. Nick Koston
b50354f362 Add render count to templates repr (#90753) 2023-04-04 21:07:16 -04:00
J. Nick Koston
e4b3a146be Bump aiohomekit to 2.6.3 (#90752) 2023-04-04 21:07:15 -04:00
TheJulianJES
1861a621b2 Restore state for ZHA OnOff binary sensors (#90749)
* Restore state for ZHA OnOff binary sensors

* Let `Motion` extend `Opening`

`Motion` is just a specified version of `Opening` that only changes the device class for some motion sensors.
Since we have more "special code" in the OnOff/Opening sensor now, we also want to make sure that gets applied to `Motion` binary sensors.

* Improve comment and type

* Add test to verify that binary sensors restore last HA state
2023-04-04 21:07:14 -04:00
J. Nick Koston
0746e09256 Prevent overly large event data from being stored in the database (#90747)
This is the same change as #87105 for events
2023-04-04 21:07:13 -04:00
J. Nick Koston
0166cd082b Bump zeroconf to 0.54.0 (#90744)
* Bump zeroconf to 0.54.0

fixes incorrect addresses when the server name changes

changelog: https://github.com/python-zeroconf/python-zeroconf/compare/0.53.0...0.54.0

* fix
2023-04-04 21:07:12 -04:00
Maciej Bieniek
0a74f946db Add entity name translations to NextDNS (#90743)
Add entity name translations
2023-04-04 21:07:11 -04:00
Mark Adkins
d04b45a821 SharkIQ Hotfix - Handle current installations by using default REGION (#90741)
* Add default region on async_setup_entry

* Move logic to migration function

* Move update logic back to setup function, but updates the config if needed.

* Remove commented out code

* Update Tests & Config setting method

* Update homeassistant/components/sharkiq/__init__.py

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

* Update homeassistant/components/sharkiq/__init__.py

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

* Accept Suggestions & Formatting

---------

Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2023-04-04 21:07:10 -04:00
Maciej Bieniek
a5a6641bb4 Add entity name translations to Tractive (#90738)
Add entity name translations
2023-04-04 21:07:09 -04:00
Michael
1420cda837 Add entity name translations to SMS (#90727) 2023-04-04 21:07:08 -04:00
Fabio De Simone
cba5751ca2 Fix bluetooth_le_tracker reporting devices Home when they leave (#90641)
* fix bluetooth_le_tracker reporting devices Home when they leave

* refactor

* implement tests for BLE service_info.time check

* update bluetooth_le_tracker tests

* tweaks

---------

Co-authored-by: J. Nick Koston <nick@koston.org>
2023-04-04 21:07:07 -04:00
Paulus Schoutsen
a3e66b5dde Bumped version to 2023.4.0b6 2023-04-03 16:51:04 -04:00
Bram Kragten
83dd52ab1f Update frontend to 20230403.0 (#90735) 2023-04-03 16:51:01 -04:00
Michael
da1e5f6a3c Add entity name translations to sun (#90732) 2023-04-03 16:51:00 -04:00
Michael
8f9868024c Add entity name translations to Luftdaten (#90725) 2023-04-03 16:50:59 -04:00
Erik Montnemery
c90396cd57 Bump pychromecast to 13.0.7 (#90724) 2023-04-03 16:50:58 -04:00
Aaron Bach
509c1ca99c Fix missing battery sensors for SimpliSafe locks (#90722) 2023-04-03 16:50:57 -04:00
Michael
431fbee641 Fix translation of status binary sensor in PI-Hole (#90719) 2023-04-03 16:50:56 -04:00
Michael
28983bca85 Add entity name translations to Pi-hole (#90713) 2023-04-03 16:50:55 -04:00
Felix Rotthowe
601498617d Fix Livisi climate min/max temperature (#90712)
* Correctly set livisi climate min/max temp

* fix imports
2023-04-03 16:50:54 -04:00
Michael
6c208f655d Add entity name translations to NUT (#90709) 2023-04-03 16:50:53 -04:00
Michael
eaaf24d326 Add entity name translations to AVM Fritz!SmartHome (#90707)
* add entity name translation

* sort and capitalize

* adjust tests

* sort entities
2023-04-03 16:50:52 -04:00
Michael
0c12d45581 Add entity name translations to Synology DSM (#90706)
* add entity name translation

* sort strings

* sort and capitalize strings
2023-04-03 16:50:51 -04:00
Michael
c2e46db76d Add entity name translations to AVM Fritz!Tools (#90703)
* add entity name translation

* apply suggestions

* sort strings
2023-04-03 16:50:50 -04:00
Maciej Bieniek
47c8b7804d Add entity name translations to BraviaTV (#90702)
Add entity name translations
2023-04-03 16:50:49 -04:00
Maciej Bieniek
8d302aea9e Use the default entity names in GIOS (#90700) 2023-04-03 16:50:48 -04:00
Stephan Uhle
3a73425888 Fix ha version in EDL21 deprecation warning (#90699)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
2023-04-03 16:50:47 -04:00
epenet
f9e4fe016f Use entity name translations in SFR Box (#90698) 2023-04-03 16:50:46 -04:00
epenet
5835ae03bc Use entity name translations in Renault (#90697) 2023-04-03 16:50:45 -04:00
epenet
71608d4795 Use entity name translations in 1-wire (#90696)
* Use entity name translations in onewire

* Adjust binary sensors

* Adjust switches

* Cleanup
2023-04-03 16:50:44 -04:00
Maciej Bieniek
e38590e40a Use the default entity names in Airly (#90693) 2023-04-03 16:50:43 -04:00
Maciej Bieniek
9e3b54f539 Add entity name translations to NAM (#90681) 2023-04-03 16:50:42 -04:00
J. Nick Koston
24ff2ddae5 Ensure system log does not raise while processing logger messages (#90652) 2023-04-03 16:50:41 -04:00
Michael Davie
621de8bb5f Bump env_canada to v0.5.30 (#90644) 2023-04-03 16:50:40 -04:00
Patrick ZAJDA
6cbf9288b5 Add entity name translations to Switchbot (#90600)
* Add entity name translations to Switchbot

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>

* Apply suggestions from code review

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>

* Fix tests

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>

* Update homeassistant/components/switchbot/strings.json

Co-authored-by: Patrick ZAJDA <patrick@zajda.fr>

---------

Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
2023-04-03 16:50:39 -04:00
Franck Nijhof
9f95da7793 Add entity name translations to Plugwise (#90537)
* Add entity name translations to Plugwise

* Re-use extisting translation where possible
2023-04-03 16:50:38 -04:00
Nerdix
cb5326b798 Correct handling if WIFI combine suffix is "None" (#90528)
* Correct handling of "None" WIFI combine suffix

* Update tests/components/unifi/test_config_flow.py

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

* Update tests/components/unifi/test_config_flow.py

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

---------

Co-authored-by: Robert Svensson <Kane610@users.noreply.github.com>
2023-04-03 16:50:37 -04:00
Erik Montnemery
1aa6d3e896 Raise repair issue if OTBR and ZHA are on different channels (#90494)
* Raise repair issue if OTBR and ZHA are on different channels

* Update issues after creating or setting dataset

* Explain impact

* Add link to documentation, adjust language

* Update homeassistant/components/otbr/strings.json

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-04-03 16:50:36 -04:00
Matthias Alphart
1c8d4b8bb8 Use entity name translations in Fronius (#90463) 2023-04-03 16:50:35 -04:00
G Johansson
8669ee3685 Remove Darksky integration (#90322) 2023-04-03 16:50:34 -04:00
Paulus Schoutsen
20d8bbbd0c Bumped version to 2023.4.0b5 2023-04-02 20:57:16 -04:00
J. Nick Koston
e10e3ee7cc Fix memory churn in state templates (#90685)
* Fix memory churn in state templates

The LRU for state templates was limited to 512 states. As soon
as it was exaused, system performance would tank as each template
that iterated all states would have to create and GC any state
> 512

* does it scale?

* avoid copy on all

* comment

* preen

* cover

* cover

* comments

* comments

* comments

* preen

* preen
2023-04-02 20:57:07 -04:00
Maciej Bieniek
83b7018be2 Fix default sensor entity name for PM1 (#90684)
Fix PM1 text
2023-04-02 20:57:06 -04:00
J. Nick Koston
6d967ac535 Bump zeroconf to 0.53.0 (#90682) 2023-04-02 20:57:05 -04:00
Paulus Schoutsen
77bc745bed Fix frontend test (#90679) 2023-04-02 20:57:04 -04:00
Patrick ZAJDA
8fe7b01baa Add entity name translations for Nest sensors (#90677)
Signed-off-by: Patrick ZAJDA <patrick@zajda.fr>
2023-04-02 20:57:04 -04:00
J. Nick Koston
5e5888b37a Bump zeroconf to 0.52.0 (#90660)
* Bump zeroconf to 0.52.0

Switch to using the new ip_addresses_by_version which avoids
all the ip address conversions

* updates
2023-04-02 20:57:03 -04:00
Maciej Bieniek
90de51fff3 Add entity name translations to Airly (#90656)
Add entity name translations
2023-04-02 20:55:38 -04:00
Maciej Bieniek
89230b75be Add entity name translations to GIOS (#90655)
* Add entity name translations

* Update tests
2023-04-02 20:55:37 -04:00
J. Nick Koston
cbe3cabf0a Add object source logger to profiler (#90650)
* Add object source logger to profiler

* fixes

* cleanup

* tweaks

* logging

* logging

* too intensive

* adjust

* Update homeassistant/bootstrap.py

* fixes

* fixes

* coverage
2023-04-02 20:55:36 -04:00
Maciej Bieniek
c259c1afe3 Add entity name translations to Brother (#90634)
* Add entity name translations

* Fix sensor name

* Update tests

* Suggested change
2023-04-02 20:55:36 -04:00
mletenay
1ff93518b5 Update goodwe library to v0.2.30 (#90607) 2023-04-02 20:55:34 -04:00
Paulus Schoutsen
aa6cf3d208 Bumped version to 2023.4.0b4 2023-04-01 15:23:53 -04:00
Bram Kragten
2a28d40dc8 Update frontend to 20230401.0 (#90646) 2023-04-01 15:23:45 -04:00
Jan Bouwhuis
c006b3b1df Fix mqtt device_tracker is not reloading yaml (#90639) 2023-04-01 15:23:44 -04:00
nono
bacd77a03a Fix Rest switch init was not retrying if unreachable at setup (#90627)
* Fix Rest switch init was not retrying if unreachable at setup

* pass error log to platformnotready
prevents spamming the same message in logs.
2023-04-01 15:23:43 -04:00
J. Nick Koston
75694307e2 Bump zeroconf to 0.51.0 (#90622)
* Bump zeroconf to 0.50.0

changelog: https://github.com/python-zeroconf/python-zeroconf/compare/0.47.4...0.50.0

* bump to 51
2023-04-01 15:23:42 -04:00
J. Nick Koston
1189b2ad70 Small speed up to _collection_changed (#90621)
attrgetter builds a fast method which happens in native code
4664a7cf68/Modules/_operator.c (L1413)
2023-04-01 15:23:42 -04:00
Joakim Sørensen
d5d5bb0732 Only limit stats to started add-ons (#90611) 2023-04-01 15:23:41 -04:00
J. Nick Koston
6242dd2214 Avoid sorting domain/all states in templates (#90608) 2023-04-01 15:23:40 -04:00
Paulus Schoutsen
03f085d7be Bumped version to 2023.4.0b3 2023-03-31 15:41:37 -04:00
Raman Gupta
b3348c3e6f Bump zwave-js-server-python to 0.47.3 (#90606)
* Bump zwave-js-server-python to 0.47.2

* Bump zwave-js-server-python to 0.47.3
2023-03-31 15:41:33 -04:00
puddly
590db0fa74 Perform an energy scan when downloading ZHA diagnostics (#90605) 2023-03-31 15:41:32 -04:00
puddly
f56ccf90d9 Fix ZHA definition error on received command (#90602)
* Fix use of deprecated command schema access

* Add a unit test
2023-03-31 15:41:31 -04:00
Bram Kragten
c63f8e714e Update frontend to 20230331.0 (#90594) 2023-03-31 15:41:30 -04:00
starkillerOG
a20771f571 Bump reolink-aio to 0.5.9 (#90590) 2023-03-31 15:41:29 -04:00
Franck Nijhof
2d482f1f57 Raise on invalid (dis)arm code in manual mqtt alarm (#90584) 2023-03-31 15:41:28 -04:00
Erik Montnemery
499962f4ee Tweak yalexs_ble translations (#90582) 2023-03-31 15:41:27 -04:00
Franck Nijhof
88a407361c Raise on invalid (dis)arm code in manual alarm (#90579) 2023-03-31 15:41:26 -04:00
Franck Nijhof
89dc6db5a7 Add arming/disarming state to Verisure (#90577) 2023-03-31 15:41:25 -04:00
J. Nick Koston
de9e7e47fe Make sonos activity check a background task (#90553)
Ensures the task is canceled at shutdown if the device
is offline and the ping is still in progress
2023-03-31 15:41:24 -04:00
epenet
ab66664f20 Allow removal of sensor settings in scrape (#90412)
* Allow removal of sensor settings in scrape

* Adjust

* Adjust

* Add comment

* Simplify

* Simplify

* Adjust

* Don't allow empty string

* Only allow None

* Use default as None

* Use sentinel "none"

* Not needed

* Adjust unit of measurement

* Add translation keys for "none"

* Use translations

* Sort

* Add enum and timestamp

* Use translation references

* Remove default and set suggested_values

* Disallow enum device class

* Adjust tests

* Adjust _strip_sentinel
2023-03-31 15:41:23 -04:00
345 changed files with 8725 additions and 3941 deletions

View File

@@ -228,8 +228,6 @@ build.json @home-assistant/supervisor
/homeassistant/components/cups/ @fabaff
/homeassistant/components/daikin/ @fredrike
/tests/components/daikin/ @fredrike
/homeassistant/components/darksky/ @fabaff
/tests/components/darksky/ @fabaff
/homeassistant/components/debugpy/ @frenck
/tests/components/debugpy/ @frenck
/homeassistant/components/deconz/ @Kane610

View File

@@ -239,6 +239,7 @@ async def load_registries(hass: core.HomeAssistant) -> None:
# Load the registries and cache the result of platform.uname().processor
entity.async_setup(hass)
template.async_setup(hass)
await asyncio.gather(
area_registry.async_load(hass),
device_registry.async_load(hass),

View File

@@ -68,7 +68,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_CAQI,
icon="mdi:air-filter",
name=ATTR_API_CAQI,
translation_key="caqi",
native_unit_of_measurement="CAQI",
suggested_display_precision=0,
attrs=lambda data: {
@@ -80,7 +80,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_PM1,
device_class=SensorDeviceClass.PM1,
name="PM1.0",
translation_key="pm1",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
@@ -88,7 +88,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_PM25,
device_class=SensorDeviceClass.PM25,
name="PM2.5",
translation_key="pm25",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
@@ -100,7 +100,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_PM10,
device_class=SensorDeviceClass.PM10,
name=ATTR_API_PM10,
translation_key="pm10",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
@@ -112,7 +112,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_HUMIDITY,
device_class=SensorDeviceClass.HUMIDITY,
name=ATTR_API_HUMIDITY.capitalize(),
translation_key="humidity",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=1,
@@ -120,7 +120,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_PRESSURE,
device_class=SensorDeviceClass.PRESSURE,
name=ATTR_API_PRESSURE.capitalize(),
translation_key="pressure",
native_unit_of_measurement=UnitOfPressure.HPA,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
@@ -128,14 +128,14 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_TEMPERATURE,
device_class=SensorDeviceClass.TEMPERATURE,
name=ATTR_API_TEMPERATURE.capitalize(),
translation_key="temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=1,
),
AirlySensorEntityDescription(
key=ATTR_API_CO,
name="Carbon monoxide",
translation_key="co",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
@@ -147,7 +147,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_NO2,
device_class=SensorDeviceClass.NITROGEN_DIOXIDE,
name="Nitrogen dioxide",
translation_key="no2",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
@@ -159,7 +159,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_SO2,
device_class=SensorDeviceClass.SULPHUR_DIOXIDE,
name="Sulphur dioxide",
translation_key="so2",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
@@ -171,7 +171,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
AirlySensorEntityDescription(
key=ATTR_API_O3,
device_class=SensorDeviceClass.OZONE,
name="Ozone",
translation_key="o3",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,

View File

@@ -26,5 +26,42 @@
"requests_remaining": "Remaining allowed requests",
"requests_per_day": "Allowed requests per day"
}
},
"entity": {
"sensor": {
"caqi": {
"name": "Common air quality index"
},
"pm1": {
"name": "[%key:component::sensor::entity_component::pm1::name%]"
},
"pm25": {
"name": "[%key:component::sensor::entity_component::pm25::name%]"
},
"pm10": {
"name": "[%key:component::sensor::entity_component::pm10::name%]"
},
"humidity": {
"name": "[%key:component::sensor::entity_component::humidity::name%]"
},
"pressure": {
"name": "[%key:component::sensor::entity_component::pressure::name%]"
},
"temperature": {
"name": "[%key:component::sensor::entity_component::temperature::name%]"
},
"co": {
"name": "[%key:component::sensor::entity_component::carbon_monoxide::name%]"
},
"no2": {
"name": "[%key:component::sensor::entity_component::nitrogen_dioxide::name%]"
},
"so2": {
"name": "[%key:component::sensor::entity_component::sulphur_dioxide::name%]"
},
"o3": {
"name": "[%key:component::sensor::entity_component::ozone::name%]"
}
}
}
}

View File

@@ -7,5 +7,5 @@
"integration_type": "hub",
"iot_class": "cloud_push",
"loggers": ["aioambient"],
"requirements": ["aioambient==2021.11.0"]
"requirements": ["aioambient==2023.04.0"]
}

View File

@@ -28,7 +28,7 @@ async def async_setup(hass: HomeAssistant, _: ConfigType) -> bool:
# Send every day
async_track_time_interval(
hass, analytics.send_analytics, INTERVAL, "analytics daily"
hass, analytics.send_analytics, INTERVAL, name="analytics daily"
)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, start_schedule)

View File

@@ -38,7 +38,10 @@ class AugustSubscriberMixin:
def _async_setup_listeners(self):
"""Create interval and stop listeners."""
self._unsub_interval = async_track_time_interval(
self._hass, self._async_refresh, self._update_interval, "august refresh"
self._hass,
self._async_refresh,
self._update_interval,
name="august refresh",
)
@callback

View File

@@ -101,7 +101,7 @@ class BaseHaScanner(ABC):
self.hass,
self._async_scanner_watchdog,
SCANNER_WATCHDOG_INTERVAL,
f"{self.name} Bluetooth scanner watchdog",
name=f"{self.name} Bluetooth scanner watchdog",
)
@hass_callback
@@ -230,7 +230,7 @@ class BaseHaRemoteScanner(BaseHaScanner):
self.hass,
self._async_expire_devices,
timedelta(seconds=30),
f"{self.name} Bluetooth scanner device expire",
name=f"{self.name} Bluetooth scanner device expire",
)
cancel_stop = self.hass.bus.async_listen(
EVENT_HOMEASSISTANT_STOP, self._async_save_history
@@ -345,12 +345,27 @@ class BaseHaRemoteScanner(BaseHaScanner):
tx_power=NO_RSSI_VALUE if tx_power is None else tx_power,
platform_data=(),
)
device = BLEDevice(
address=address,
name=local_name,
details=self._details | details,
rssi=rssi, # deprecated, will be removed in newer bleak
)
if prev_discovery:
#
# Bleak updates the BLEDevice via create_or_update_device.
# We need to do the same to ensure integrations that already
# have the BLEDevice object get the updated details when they
# change.
#
# https://github.com/hbldh/bleak/blob/222618b7747f0467dbb32bd3679f8cfaa19b1668/bleak/backends/scanner.py#L203
#
device = prev_device
device.name = local_name
device.details = self._details | details
# pylint: disable-next=protected-access
device._rssi = rssi # deprecated, will be removed in newer bleak
else:
device = BLEDevice(
address=address,
name=local_name,
details=self._details | details,
rssi=rssi, # deprecated, will be removed in newer bleak
)
self._discovered_device_advertisement_datas[address] = (
device,
advertisement_data,

View File

@@ -276,7 +276,7 @@ class BluetoothManager:
self.hass,
self._async_check_unavailable,
timedelta(seconds=UNAVAILABLE_TRACK_SECONDS),
"Bluetooth manager unavailable tracking",
name="Bluetooth manager unavailable tracking",
)
@hass_callback

View File

@@ -10,9 +10,10 @@ from .wrappers import HaBleakClientWrapper, HaBleakScannerWrapper
ORIGINAL_BLEAK_SCANNER = bleak.BleakScanner
ORIGINAL_BLEAK_CLIENT = bleak.BleakClient
ORIGINAL_BLEAK_RETRY_CONNECTOR_CLIENT = (
ORIGINAL_BLEAK_RETRY_CONNECTOR_CLIENT_WITH_SERVICE_CACHE = (
bleak_retry_connector.BleakClientWithServiceCache
)
ORIGINAL_BLEAK_RETRY_CONNECTOR_CLIENT = bleak_retry_connector.BleakClient
def install_multiple_bleak_catcher() -> None:
@@ -23,6 +24,7 @@ def install_multiple_bleak_catcher() -> None:
bleak.BleakScanner = HaBleakScannerWrapper # type: ignore[misc, assignment]
bleak.BleakClient = HaBleakClientWrapper # type: ignore[misc]
bleak_retry_connector.BleakClientWithServiceCache = HaBleakClientWithServiceCache # type: ignore[misc,assignment] # noqa: E501
bleak_retry_connector.BleakClient = HaBleakClientWrapper # type: ignore[misc] # noqa: E501
def uninstall_multiple_bleak_catcher() -> None:
@@ -30,6 +32,9 @@ def uninstall_multiple_bleak_catcher() -> None:
bleak.BleakScanner = ORIGINAL_BLEAK_SCANNER # type: ignore[misc]
bleak.BleakClient = ORIGINAL_BLEAK_CLIENT # type: ignore[misc]
bleak_retry_connector.BleakClientWithServiceCache = ( # type: ignore[misc]
ORIGINAL_BLEAK_RETRY_CONNECTOR_CLIENT_WITH_SERVICE_CACHE
)
bleak_retry_connector.BleakClient = ( # type: ignore[misc]
ORIGINAL_BLEAK_RETRY_CONNECTOR_CLIENT
)

View File

@@ -70,6 +70,7 @@ async def async_setup_scanner( # noqa: C901
yaml_path = hass.config.path(YAML_DEVICES)
devs_to_track: set[str] = set()
devs_no_track: set[str] = set()
devs_advertise_time: dict[str, float] = {}
devs_track_battery = {}
interval: timedelta = config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)
# if track new devices is true discover new devices
@@ -178,6 +179,7 @@ async def async_setup_scanner( # noqa: C901
"""Update from a ble callback."""
mac = service_info.address
if mac in devs_to_track:
devs_advertise_time[mac] = service_info.time
now = dt_util.utcnow()
hass.async_create_task(async_see_device(mac, service_info.name))
if (
@@ -205,7 +207,9 @@ async def async_setup_scanner( # noqa: C901
# there have been no callbacks because the RSSI or
# other properties have not changed.
for service_info in bluetooth.async_discovered_service_info(hass, False):
_async_update_ble(service_info, bluetooth.BluetoothChange.ADVERTISEMENT)
# Only call _async_update_ble if the advertisement time has changed
if service_info.time != devs_advertise_time.get(service_info.address):
_async_update_ble(service_info, bluetooth.BluetoothChange.ADVERTISEMENT)
cancels = [
bluetooth.async_register_callback(

View File

@@ -177,7 +177,7 @@ class BondEntity(Entity):
self.hass,
self._async_update_if_bpup_not_alive,
_FALLBACK_SCAN_INTERVAL,
f"Bond {self.entity_id} fallback polling",
name=f"Bond {self.entity_id} fallback polling",
)
)

View File

@@ -36,14 +36,14 @@ class BraviaTVButtonDescription(
BUTTONS: tuple[BraviaTVButtonDescription, ...] = (
BraviaTVButtonDescription(
key="reboot",
name="Reboot",
translation_key="restart",
device_class=ButtonDeviceClass.RESTART,
entity_category=EntityCategory.CONFIG,
press_action=lambda coordinator: coordinator.async_reboot_device(),
),
BraviaTVButtonDescription(
key="terminate_apps",
name="Terminate apps",
translation_key="terminate_apps",
entity_category=EntityCategory.CONFIG,
press_action=lambda coordinator: coordinator.async_terminate_apps(),
),

View File

@@ -44,5 +44,15 @@
"not_bravia_device": "The device is not a Bravia TV.",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
}
},
"entity": {
"button": {
"restart": {
"name": "[%key:component::button::entity_component::restart::name%]"
},
"terminate_apps": {
"name": "Terminate apps"
}
}
}
}

View File

@@ -25,61 +25,61 @@ from .entity import BroadlinkEntity
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key="temperature",
name="Temperature",
translation_key="temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="air_quality",
name="Air quality",
translation_key="air_quality",
),
SensorEntityDescription(
key="humidity",
name="Humidity",
translation_key="humidity",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="light",
name="Light",
translation_key="light",
),
SensorEntityDescription(
key="noise",
name="Noise",
translation_key="noise",
),
SensorEntityDescription(
key="power",
name="Current power",
translation_key="power",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="volt",
name="Voltage",
translation_key="voltage",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="current",
name="Current",
translation_key="current",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="overload",
name="Overload",
translation_key="overload",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="totalconsum",
name="Total consumption",
translation_key="total_consumption",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,

View File

@@ -43,5 +43,39 @@
"invalid_host": "[%key:common::config_flow::error::invalid_host%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
}
},
"entity": {
"sensor": {
"temperature": {
"name": "[%key:component::sensor::entity_component::temperature::name%]"
},
"air_quality": {
"name": "[%key:component::sensor::entity_component::aqi::name%]"
},
"humidity": {
"name": "[%key:component::sensor::entity_component::humidity::name%]"
},
"light": {
"name": "[%key:component::sensor::entity_component::illuminance::name%]"
},
"noise": {
"name": "Noise"
},
"power": {
"name": "[%key:component::sensor::entity_component::power::name%]"
},
"voltage": {
"name": "[%key:component::sensor::entity_component::voltage::name%]"
},
"current": {
"name": "[%key:component::sensor::entity_component::current::name%]"
},
"overload": {
"name": "Overload"
},
"total_consumption": {
"name": "Total consumption"
}
}
}
}

View File

@@ -53,14 +53,14 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="status",
icon="mdi:printer",
name="Status",
translation_key="status",
entity_category=EntityCategory.DIAGNOSTIC,
value=lambda data: data.status,
),
BrotherSensorEntityDescription(
key="page_counter",
icon="mdi:file-document-outline",
name="Page counter",
translation_key="page_counter",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -69,7 +69,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="bw_counter",
icon="mdi:file-document-outline",
name="B/W counter",
translation_key="bw_pages",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -78,7 +78,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="color_counter",
icon="mdi:file-document-outline",
name="Color counter",
translation_key="color_pages",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -87,7 +87,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="duplex_unit_pages_counter",
icon="mdi:file-document-outline",
name="Duplex unit pages counter",
translation_key="duplex_unit_page_counter",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -96,7 +96,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="drum_remaining_life",
icon="mdi:chart-donut",
name="Drum remaining life",
translation_key="drum_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -105,7 +105,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="drum_remaining_pages",
icon="mdi:chart-donut",
name="Drum remaining pages",
translation_key="drum_remaining_pages",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -114,7 +114,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="drum_counter",
icon="mdi:chart-donut",
name="Drum counter",
translation_key="drum_page_counter",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -123,7 +123,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="black_drum_remaining_life",
icon="mdi:chart-donut",
name="Black drum remaining life",
translation_key="black_drum_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -132,7 +132,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="black_drum_remaining_pages",
icon="mdi:chart-donut",
name="Black drum remaining pages",
translation_key="black_drum_remaining_pages",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -141,7 +141,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="black_drum_counter",
icon="mdi:chart-donut",
name="Black drum counter",
translation_key="black_drum_page_counter",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -150,7 +150,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="cyan_drum_remaining_life",
icon="mdi:chart-donut",
name="Cyan drum remaining life",
translation_key="cyan_drum_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -159,7 +159,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="cyan_drum_remaining_pages",
icon="mdi:chart-donut",
name="Cyan drum remaining pages",
translation_key="cyan_drum_remaining_pages",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -168,7 +168,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="cyan_drum_counter",
icon="mdi:chart-donut",
name="Cyan drum counter",
translation_key="cyan_drum_page_counter",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -177,7 +177,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="magenta_drum_remaining_life",
icon="mdi:chart-donut",
name="Magenta drum remaining life",
translation_key="magenta_drum_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -186,7 +186,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="magenta_drum_remaining_pages",
icon="mdi:chart-donut",
name="Magenta drum remaining pages",
translation_key="magenta_drum_remaining_pages",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -195,7 +195,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="magenta_drum_counter",
icon="mdi:chart-donut",
name="Magenta drum counter",
translation_key="magenta_drum_page_counter",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -204,7 +204,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="yellow_drum_remaining_life",
icon="mdi:chart-donut",
name="Yellow drum remaining life",
translation_key="yellow_drum_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -213,7 +213,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="yellow_drum_remaining_pages",
icon="mdi:chart-donut",
name="Yellow drum remaining pages",
translation_key="yellow_drum_remaining_pages",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -222,7 +222,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="yellow_drum_counter",
icon="mdi:chart-donut",
name="Yellow drum counter",
translation_key="yellow_drum_page_counter",
native_unit_of_measurement=UNIT_PAGES,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -231,7 +231,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="belt_unit_remaining_life",
icon="mdi:current-ac",
name="Belt unit remaining life",
translation_key="belt_unit_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -240,7 +240,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="fuser_remaining_life",
icon="mdi:water-outline",
name="Fuser remaining life",
translation_key="fuser_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -249,7 +249,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="laser_remaining_life",
icon="mdi:spotlight-beam",
name="Laser remaining life",
translation_key="laser_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -258,7 +258,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="pf_kit_1_remaining_life",
icon="mdi:printer-3d",
name="PF Kit 1 remaining life",
translation_key="pf_kit_1_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -267,7 +267,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="pf_kit_mp_remaining_life",
icon="mdi:printer-3d",
name="PF Kit MP remaining life",
translation_key="pf_kit_mp_remaining_life",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -276,7 +276,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="black_toner_remaining",
icon="mdi:printer-3d-nozzle",
name="Black toner remaining",
translation_key="black_toner_remaining",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -285,7 +285,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="cyan_toner_remaining",
icon="mdi:printer-3d-nozzle",
name="Cyan toner remaining",
translation_key="cyan_toner_remaining",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -294,7 +294,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="magenta_toner_remaining",
icon="mdi:printer-3d-nozzle",
name="Magenta toner remaining",
translation_key="magenta_toner_remaining",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -303,7 +303,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="yellow_toner_remaining",
icon="mdi:printer-3d-nozzle",
name="Yellow toner remaining",
translation_key="yellow_toner_remaining",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -312,7 +312,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="black_ink_remaining",
icon="mdi:printer-3d-nozzle",
name="Black ink remaining",
translation_key="black_ink_remaining",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -321,7 +321,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="cyan_ink_remaining",
icon="mdi:printer-3d-nozzle",
name="Cyan ink remaining",
translation_key="cyan_ink_remaining",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -330,7 +330,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="magenta_ink_remaining",
icon="mdi:printer-3d-nozzle",
name="Magenta ink remaining",
translation_key="magenta_ink_remaining",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -339,7 +339,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
BrotherSensorEntityDescription(
key="yellow_ink_remaining",
icon="mdi:printer-3d-nozzle",
name="Yellow ink remaining",
translation_key="yellow_ink_remaining",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -347,7 +347,7 @@ SENSOR_TYPES: tuple[BrotherSensorEntityDescription, ...] = (
),
BrotherSensorEntityDescription(
key="uptime",
name="Uptime",
translation_key="last_restart",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.TIMESTAMP,
entity_category=EntityCategory.DIAGNOSTIC,

View File

@@ -25,5 +25,111 @@
"unsupported_model": "This printer model is not supported.",
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
}
},
"entity": {
"sensor": {
"status": {
"name": "Status"
},
"page_counter": {
"name": "Page counter"
},
"bw_pages": {
"name": "B/W pages"
},
"color_pages": {
"name": "Color pages"
},
"duplex_unit_page_counter": {
"name": "Duplex unit page counter"
},
"drum_remaining_life": {
"name": "Drum remaining life"
},
"drum_remaining_pages": {
"name": "Drum remaining pages"
},
"drum_page_counter": {
"name": "Drum page counter"
},
"black_drum_remaining_life": {
"name": "Black drum remaining life"
},
"black_drum_remaining_pages": {
"name": "Black drum remaining pages"
},
"black_drum_page_counter": {
"name": "Black drum page counter"
},
"cyan_drum_remaining_life": {
"name": "Cyan drum remaining life"
},
"cyan_drum_remaining_pages": {
"name": "Cyan drum remaining pages"
},
"cyan_drum_page_counter": {
"name": "Cyan drum page counter"
},
"magenta_drum_remaining_life": {
"name": "Magenta drum remaining life"
},
"magenta_drum_remaining_pages": {
"name": "Magenta drum remaining pages"
},
"magenta_drum_page_counter": {
"name": "Magenta drum page counter"
},
"yellow_drum_remaining_life": {
"name": "Yellow drum remaining life"
},
"yellow_drum_remaining_pages": {
"name": "Yellow drum remaining pages"
},
"yellow_drum_page_counter": {
"name": "Yellow drum page counter"
},
"belt_unit_remaining_life": {
"name": "Belt unit remaining life"
},
"fuser_remaining_life": {
"name": "Fuser remaining life"
},
"laser_remaining_life": {
"name": "Laser remaining life"
},
"pf_kit_1_remaining_life": {
"name": "PF Kit 1 remaining life"
},
"pf_kit_mp_remaining_life": {
"name": "PF Kit MP remaining life"
},
"black_toner_remaining": {
"name": "Black toner remaining"
},
"cyan_toner_remaining": {
"name": "Cyan toner remaining"
},
"magenta_toner_remaining": {
"name": "Magenta toner remaining"
},
"yellow_toner_remaining": {
"name": "Yellow toner remaining"
},
"black_ink_remaining": {
"name": "Black ink remaining"
},
"cyan_ink_remaining": {
"name": "Cyan ink remaining"
},
"magenta_ink_remaining": {
"name": "Magenta ink remaining"
},
"yellow_ink_remaining": {
"name": "Yellow ink remaining"
},
"last_restart": {
"name": "Last restart"
}
}
}
}

View File

@@ -67,6 +67,13 @@ SCAN_INTERVAL = datetime.timedelta(seconds=60)
# Don't support rrules more often than daily
VALID_FREQS = {"DAILY", "WEEKLY", "MONTHLY", "YEARLY"}
# Ensure events created in Home Assistant have a positive duration
MIN_NEW_EVENT_DURATION = datetime.timedelta(seconds=1)
# Events must have a non-negative duration e.g. Google Calendar can create zero
# duration events in the UI.
MIN_EVENT_DURATION = datetime.timedelta(seconds=0)
def _has_timezone(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
"""Assert that all datetime values have a timezone."""
@@ -116,17 +123,18 @@ def _as_local_timezone(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]
return validate
def _has_duration(
start_key: str, end_key: str
def _has_min_duration(
start_key: str, end_key: str, min_duration: datetime.timedelta
) -> Callable[[dict[str, Any]], dict[str, Any]]:
"""Verify that the time span between start and end is positive."""
"""Verify that the time span between start and end has a minimum duration."""
def validate(obj: dict[str, Any]) -> dict[str, Any]:
"""Test that all keys in the dict are in order."""
if (start := obj.get(start_key)) and (end := obj.get(end_key)):
duration = end - start
if duration.total_seconds() <= 0:
raise vol.Invalid(f"Expected positive event duration ({start}, {end})")
if duration < min_duration:
raise vol.Invalid(
f"Expected minimum event duration of {min_duration} ({start}, {end})"
)
return obj
return validate
@@ -204,8 +212,8 @@ CREATE_EVENT_SCHEMA = vol.All(
),
_has_consistent_timezone(EVENT_START_DATETIME, EVENT_END_DATETIME),
_as_local_timezone(EVENT_START_DATETIME, EVENT_END_DATETIME),
_has_duration(EVENT_START_DATE, EVENT_END_DATE),
_has_duration(EVENT_START_DATETIME, EVENT_END_DATETIME),
_has_min_duration(EVENT_START_DATE, EVENT_END_DATE, MIN_NEW_EVENT_DURATION),
_has_min_duration(EVENT_START_DATETIME, EVENT_END_DATETIME, MIN_NEW_EVENT_DURATION),
)
WEBSOCKET_EVENT_SCHEMA = vol.Schema(
@@ -221,7 +229,7 @@ WEBSOCKET_EVENT_SCHEMA = vol.Schema(
_has_same_type(EVENT_START, EVENT_END),
_has_consistent_timezone(EVENT_START, EVENT_END),
_as_local_timezone(EVENT_START, EVENT_END),
_has_duration(EVENT_START, EVENT_END),
_has_min_duration(EVENT_START, EVENT_END, MIN_NEW_EVENT_DURATION),
)
)
@@ -236,9 +244,8 @@ CALENDAR_EVENT_SCHEMA = vol.Schema(
},
_has_same_type("start", "end"),
_has_timezone("start", "end"),
_has_consistent_timezone("start", "end"),
_as_local_timezone("start", "end"),
_has_duration("start", "end"),
_has_min_duration("start", "end", MIN_EVENT_DURATION),
),
extra=vol.ALLOW_EXTRA,
)
@@ -346,6 +353,16 @@ class CalendarEvent:
f"Failed to validate CalendarEvent: {err}"
) from err
# It is common to set a start an end date to be the same thing for
# an all day event, but that is not a valid duration. Fix to have a
# duration of one day.
if (
not isinstance(self.start, datetime.datetime)
and not isinstance(self.end, datetime.datetime)
and self.start == self.end
):
self.end = self.start + datetime.timedelta(days=1)
def _event_dict_factory(obj: Iterable[tuple[str, Any]]) -> dict[str, str]:
"""Convert CalendarEvent dataclass items to dictionary of attributes."""

View File

@@ -380,7 +380,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
entity.async_write_ha_state()
unsub = async_track_time_interval(
hass, update_tokens, TOKEN_CHANGE_INTERVAL, "Camera update tokens"
hass, update_tokens, TOKEN_CHANGE_INTERVAL, name="Camera update tokens"
)
@callback

View File

@@ -14,6 +14,6 @@
"documentation": "https://www.home-assistant.io/integrations/cast",
"iot_class": "local_polling",
"loggers": ["casttube", "pychromecast"],
"requirements": ["pychromecast==13.0.6"],
"requirements": ["pychromecast==13.0.7"],
"zeroconf": ["_googlecast._tcp.local."]
}

View File

@@ -137,8 +137,11 @@ class CommandSensor(SensorEntity):
_LOGGER.warning("Unable to parse output as JSON: %s", value)
else:
_LOGGER.warning("Empty reply found when expecting JSON data")
if self._value_template is None:
self._attr_native_value = None
return
elif self._value_template is not None:
if self._value_template is not None:
self._attr_native_value = (
self._value_template.async_render_with_possible_json_value(
value,

View File

@@ -32,6 +32,7 @@ from .const import DEFAULT_EXPOSED_ATTRIBUTES, DEFAULT_EXPOSED_DOMAINS, DOMAIN
_LOGGER = logging.getLogger(__name__)
_DEFAULT_ERROR_TEXT = "Sorry, I couldn't understand that"
_ENTITY_REGISTRY_UPDATE_FIELDS = ["aliases", "name", "original_name"]
REGEX_TYPE = type(re.compile(""))
@@ -450,8 +451,10 @@ class DefaultAgent(AbstractConversationAgent):
@core.callback
def _async_handle_entity_registry_changed(self, event: core.Event) -> None:
"""Clear names list cache when an entity changes aliases."""
if event.data["action"] == "update" and "aliases" not in event.data["changes"]:
"""Clear names list cache when an entity registry entry has changed."""
if event.data["action"] == "update" and not any(
field in event.data["changes"] for field in _ENTITY_REGISTRY_UPDATE_FIELDS
):
return
self._slot_lists = None

View File

@@ -1 +0,0 @@
"""The darksky component."""

View File

@@ -1,9 +0,0 @@
{
"domain": "darksky",
"name": "Dark Sky",
"codeowners": ["@fabaff"],
"documentation": "https://www.home-assistant.io/integrations/darksky",
"iot_class": "cloud_polling",
"loggers": ["forecastio"],
"requirements": ["python-forecastio==1.4.0"]
}

View File

@@ -1,927 +0,0 @@
"""Support for Dark Sky weather service."""
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import timedelta
import logging
from typing import Literal, NamedTuple
import forecastio
from requests.exceptions import ConnectionError as ConnectError, HTTPError, Timeout
import voluptuous as vol
from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import (
CONF_API_KEY,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_MONITORED_CONDITIONS,
CONF_NAME,
CONF_SCAN_INTERVAL,
DEGREE,
PERCENTAGE,
UV_INDEX,
UnitOfLength,
UnitOfPrecipitationDepth,
UnitOfPressure,
UnitOfSpeed,
UnitOfTemperature,
UnitOfVolumetricFlux,
)
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import Throttle
from homeassistant.util.unit_system import METRIC_SYSTEM
_LOGGER = logging.getLogger(__name__)
CONF_FORECAST = "forecast"
CONF_HOURLY_FORECAST = "hourly_forecast"
CONF_LANGUAGE = "language"
CONF_UNITS = "units"
DEFAULT_LANGUAGE = "en"
DEFAULT_NAME = "Dark Sky"
SCAN_INTERVAL = timedelta(seconds=300)
DEPRECATED_SENSOR_TYPES = {
"apparent_temperature_max",
"apparent_temperature_min",
"temperature_max",
"temperature_min",
}
MAP_UNIT_SYSTEM: dict[
Literal["si", "us", "ca", "uk", "uk2"],
Literal["si_unit", "us_unit", "ca_unit", "uk_unit", "uk2_unit"],
] = {
"si": "si_unit",
"us": "us_unit",
"ca": "ca_unit",
"uk": "uk_unit",
"uk2": "uk2_unit",
}
@dataclass
class DarkskySensorEntityDescription(SensorEntityDescription):
"""Describes Darksky sensor entity."""
si_unit: str | None = None
us_unit: str | None = None
ca_unit: str | None = None
uk_unit: str | None = None
uk2_unit: str | None = None
forecast_mode: list[str] = field(default_factory=list)
SENSOR_TYPES: dict[str, DarkskySensorEntityDescription] = {
"summary": DarkskySensorEntityDescription(
key="summary",
name="Summary",
forecast_mode=["currently", "hourly", "daily"],
),
"minutely_summary": DarkskySensorEntityDescription(
key="minutely_summary",
name="Minutely Summary",
forecast_mode=[],
),
"hourly_summary": DarkskySensorEntityDescription(
key="hourly_summary",
name="Hourly Summary",
forecast_mode=[],
),
"daily_summary": DarkskySensorEntityDescription(
key="daily_summary",
name="Daily Summary",
forecast_mode=[],
),
"icon": DarkskySensorEntityDescription(
key="icon",
name="Icon",
forecast_mode=["currently", "hourly", "daily"],
),
"nearest_storm_distance": DarkskySensorEntityDescription(
key="nearest_storm_distance",
name="Nearest Storm Distance",
si_unit=UnitOfLength.KILOMETERS,
us_unit=UnitOfLength.MILES,
ca_unit=UnitOfLength.KILOMETERS,
uk_unit=UnitOfLength.KILOMETERS,
uk2_unit=UnitOfLength.MILES,
icon="mdi:weather-lightning",
forecast_mode=["currently"],
),
"nearest_storm_bearing": DarkskySensorEntityDescription(
key="nearest_storm_bearing",
name="Nearest Storm Bearing",
si_unit=DEGREE,
us_unit=DEGREE,
ca_unit=DEGREE,
uk_unit=DEGREE,
uk2_unit=DEGREE,
icon="mdi:weather-lightning",
forecast_mode=["currently"],
),
"precip_type": DarkskySensorEntityDescription(
key="precip_type",
name="Precip",
icon="mdi:weather-pouring",
forecast_mode=["currently", "minutely", "hourly", "daily"],
),
"precip_intensity": DarkskySensorEntityDescription(
key="precip_intensity",
name="Precip Intensity",
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
icon="mdi:weather-rainy",
forecast_mode=["currently", "minutely", "hourly", "daily"],
),
"precip_probability": DarkskySensorEntityDescription(
key="precip_probability",
name="Precip Probability",
si_unit=PERCENTAGE,
us_unit=PERCENTAGE,
ca_unit=PERCENTAGE,
uk_unit=PERCENTAGE,
uk2_unit=PERCENTAGE,
icon="mdi:water-percent",
forecast_mode=["currently", "minutely", "hourly", "daily"],
),
"precip_accumulation": DarkskySensorEntityDescription(
key="precip_accumulation",
name="Precip Accumulation",
device_class=SensorDeviceClass.PRECIPITATION,
si_unit=UnitOfPrecipitationDepth.CENTIMETERS,
us_unit=UnitOfPrecipitationDepth.INCHES,
ca_unit=UnitOfPrecipitationDepth.CENTIMETERS,
uk_unit=UnitOfPrecipitationDepth.CENTIMETERS,
uk2_unit=UnitOfPrecipitationDepth.CENTIMETERS,
icon="mdi:weather-snowy",
forecast_mode=["hourly", "daily"],
),
"temperature": DarkskySensorEntityDescription(
key="temperature",
name="Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["currently", "hourly"],
),
"apparent_temperature": DarkskySensorEntityDescription(
key="apparent_temperature",
name="Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["currently", "hourly"],
),
"dew_point": DarkskySensorEntityDescription(
key="dew_point",
name="Dew Point",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["currently", "hourly", "daily"],
),
"wind_speed": DarkskySensorEntityDescription(
key="wind_speed",
name="Wind Speed",
device_class=SensorDeviceClass.WIND_SPEED,
si_unit=UnitOfSpeed.METERS_PER_SECOND,
us_unit=UnitOfSpeed.MILES_PER_HOUR,
ca_unit=UnitOfSpeed.KILOMETERS_PER_HOUR,
uk_unit=UnitOfSpeed.MILES_PER_HOUR,
uk2_unit=UnitOfSpeed.MILES_PER_HOUR,
forecast_mode=["currently", "hourly", "daily"],
),
"wind_bearing": DarkskySensorEntityDescription(
key="wind_bearing",
name="Wind Bearing",
si_unit=DEGREE,
us_unit=DEGREE,
ca_unit=DEGREE,
uk_unit=DEGREE,
uk2_unit=DEGREE,
icon="mdi:compass",
forecast_mode=["currently", "hourly", "daily"],
),
"wind_gust": DarkskySensorEntityDescription(
key="wind_gust",
name="Wind Gust",
device_class=SensorDeviceClass.WIND_SPEED,
si_unit=UnitOfSpeed.METERS_PER_SECOND,
us_unit=UnitOfSpeed.MILES_PER_HOUR,
ca_unit=UnitOfSpeed.KILOMETERS_PER_HOUR,
uk_unit=UnitOfSpeed.MILES_PER_HOUR,
uk2_unit=UnitOfSpeed.MILES_PER_HOUR,
icon="mdi:weather-windy-variant",
forecast_mode=["currently", "hourly", "daily"],
),
"cloud_cover": DarkskySensorEntityDescription(
key="cloud_cover",
name="Cloud Coverage",
si_unit=PERCENTAGE,
us_unit=PERCENTAGE,
ca_unit=PERCENTAGE,
uk_unit=PERCENTAGE,
uk2_unit=PERCENTAGE,
icon="mdi:weather-partly-cloudy",
forecast_mode=["currently", "hourly", "daily"],
),
"humidity": DarkskySensorEntityDescription(
key="humidity",
name="Humidity",
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
si_unit=PERCENTAGE,
us_unit=PERCENTAGE,
ca_unit=PERCENTAGE,
uk_unit=PERCENTAGE,
uk2_unit=PERCENTAGE,
forecast_mode=["currently", "hourly", "daily"],
),
"pressure": DarkskySensorEntityDescription(
key="pressure",
name="Pressure",
device_class=SensorDeviceClass.PRESSURE,
si_unit=UnitOfPressure.MBAR,
us_unit=UnitOfPressure.MBAR,
ca_unit=UnitOfPressure.MBAR,
uk_unit=UnitOfPressure.MBAR,
uk2_unit=UnitOfPressure.MBAR,
forecast_mode=["currently", "hourly", "daily"],
),
"visibility": DarkskySensorEntityDescription(
key="visibility",
name="Visibility",
si_unit=UnitOfLength.KILOMETERS,
us_unit=UnitOfLength.MILES,
ca_unit=UnitOfLength.KILOMETERS,
uk_unit=UnitOfLength.KILOMETERS,
uk2_unit=UnitOfLength.MILES,
icon="mdi:eye",
forecast_mode=["currently", "hourly", "daily"],
),
"ozone": DarkskySensorEntityDescription(
key="ozone",
name="Ozone",
device_class=SensorDeviceClass.OZONE,
si_unit="DU",
us_unit="DU",
ca_unit="DU",
uk_unit="DU",
uk2_unit="DU",
forecast_mode=["currently", "hourly", "daily"],
),
"apparent_temperature_max": DarkskySensorEntityDescription(
key="apparent_temperature_max",
name="Daily High Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["daily"],
),
"apparent_temperature_high": DarkskySensorEntityDescription(
key="apparent_temperature_high",
name="Daytime High Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["daily"],
),
"apparent_temperature_min": DarkskySensorEntityDescription(
key="apparent_temperature_min",
name="Daily Low Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["daily"],
),
"apparent_temperature_low": DarkskySensorEntityDescription(
key="apparent_temperature_low",
name="Overnight Low Apparent Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["daily"],
),
"temperature_max": DarkskySensorEntityDescription(
key="temperature_max",
name="Daily High Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["daily"],
),
"temperature_high": DarkskySensorEntityDescription(
key="temperature_high",
name="Daytime High Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["daily"],
),
"temperature_min": DarkskySensorEntityDescription(
key="temperature_min",
name="Daily Low Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["daily"],
),
"temperature_low": DarkskySensorEntityDescription(
key="temperature_low",
name="Overnight Low Temperature",
device_class=SensorDeviceClass.TEMPERATURE,
si_unit=UnitOfTemperature.CELSIUS,
us_unit=UnitOfTemperature.FAHRENHEIT,
ca_unit=UnitOfTemperature.CELSIUS,
uk_unit=UnitOfTemperature.CELSIUS,
uk2_unit=UnitOfTemperature.CELSIUS,
forecast_mode=["daily"],
),
"precip_intensity_max": DarkskySensorEntityDescription(
key="precip_intensity_max",
name="Daily Max Precip Intensity",
si_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
us_unit=UnitOfVolumetricFlux.INCHES_PER_HOUR,
ca_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
uk2_unit=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
icon="mdi:thermometer",
forecast_mode=["daily"],
),
"uv_index": DarkskySensorEntityDescription(
key="uv_index",
name="UV Index",
si_unit=UV_INDEX,
us_unit=UV_INDEX,
ca_unit=UV_INDEX,
uk_unit=UV_INDEX,
uk2_unit=UV_INDEX,
icon="mdi:weather-sunny",
forecast_mode=["currently", "hourly", "daily"],
),
"moon_phase": DarkskySensorEntityDescription(
key="moon_phase",
name="Moon Phase",
icon="mdi:weather-night",
forecast_mode=["daily"],
),
"sunrise_time": DarkskySensorEntityDescription(
key="sunrise_time",
name="Sunrise",
icon="mdi:white-balance-sunny",
forecast_mode=["daily"],
),
"sunset_time": DarkskySensorEntityDescription(
key="sunset_time",
name="Sunset",
icon="mdi:weather-night",
forecast_mode=["daily"],
),
"alerts": DarkskySensorEntityDescription(
key="alerts",
name="Alerts",
icon="mdi:alert-circle-outline",
forecast_mode=[],
),
}
class ConditionPicture(NamedTuple):
"""Entity picture and icon for condition."""
entity_picture: str
icon: str
CONDITION_PICTURES: dict[str, ConditionPicture] = {
"clear-day": ConditionPicture(
entity_picture="/static/images/darksky/weather-sunny.svg",
icon="mdi:weather-sunny",
),
"clear-night": ConditionPicture(
entity_picture="/static/images/darksky/weather-night.svg",
icon="mdi:weather-night",
),
"rain": ConditionPicture(
entity_picture="/static/images/darksky/weather-pouring.svg",
icon="mdi:weather-pouring",
),
"snow": ConditionPicture(
entity_picture="/static/images/darksky/weather-snowy.svg",
icon="mdi:weather-snowy",
),
"sleet": ConditionPicture(
entity_picture="/static/images/darksky/weather-hail.svg",
icon="mdi:weather-snowy-rainy",
),
"wind": ConditionPicture(
entity_picture="/static/images/darksky/weather-windy.svg",
icon="mdi:weather-windy",
),
"fog": ConditionPicture(
entity_picture="/static/images/darksky/weather-fog.svg",
icon="mdi:weather-fog",
),
"cloudy": ConditionPicture(
entity_picture="/static/images/darksky/weather-cloudy.svg",
icon="mdi:weather-cloudy",
),
"partly-cloudy-day": ConditionPicture(
entity_picture="/static/images/darksky/weather-partlycloudy.svg",
icon="mdi:weather-partly-cloudy",
),
"partly-cloudy-night": ConditionPicture(
entity_picture="/static/images/darksky/weather-cloudy.svg",
icon="mdi:weather-night-partly-cloudy",
),
}
# Language Supported Codes
LANGUAGE_CODES = [
"ar",
"az",
"be",
"bg",
"bn",
"bs",
"ca",
"cs",
"da",
"de",
"el",
"en",
"ja",
"ka",
"kn",
"ko",
"eo",
"es",
"et",
"fi",
"fr",
"he",
"hi",
"hr",
"hu",
"id",
"is",
"it",
"kw",
"lv",
"ml",
"mr",
"nb",
"nl",
"pa",
"pl",
"pt",
"ro",
"ru",
"sk",
"sl",
"sr",
"sv",
"ta",
"te",
"tet",
"tr",
"uk",
"ur",
"x-pig-latin",
"zh",
"zh-tw",
]
ALLOWED_UNITS = ["auto", "si", "us", "ca", "uk", "uk2"]
ALERTS_ATTRS = ["time", "description", "expires", "severity", "uri", "regions", "title"]
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_MONITORED_CONDITIONS): vol.All(
cv.ensure_list, [vol.In(SENSOR_TYPES)]
),
vol.Required(CONF_API_KEY): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_UNITS): vol.In(ALLOWED_UNITS),
vol.Optional(CONF_LANGUAGE, default=DEFAULT_LANGUAGE): vol.In(LANGUAGE_CODES),
vol.Inclusive(
CONF_LATITUDE, "coordinates", "Latitude and longitude must exist together"
): cv.latitude,
vol.Inclusive(
CONF_LONGITUDE, "coordinates", "Latitude and longitude must exist together"
): cv.longitude,
vol.Optional(CONF_FORECAST): vol.All(cv.ensure_list, [vol.Range(min=0, max=7)]),
vol.Optional(CONF_HOURLY_FORECAST): vol.All(
cv.ensure_list, [vol.Range(min=0, max=48)]
),
}
)
def setup_platform(
hass: HomeAssistant,
config: ConfigType,
add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Dark Sky sensor."""
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
language = config.get(CONF_LANGUAGE)
interval = config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL)
if CONF_UNITS in config:
units = config[CONF_UNITS]
elif hass.config.units is METRIC_SYSTEM:
units = "si"
else:
units = "us"
forecast_data = DarkSkyData(
api_key=config.get(CONF_API_KEY),
latitude=latitude,
longitude=longitude,
units=units,
language=language,
interval=interval,
)
forecast_data.update()
forecast_data.update_currently()
# If connection failed don't setup platform.
if forecast_data.data is None:
return
name = config.get(CONF_NAME)
forecast = config.get(CONF_FORECAST)
forecast_hour = config.get(CONF_HOURLY_FORECAST)
sensors: list[SensorEntity] = []
for variable in config[CONF_MONITORED_CONDITIONS]:
if variable in DEPRECATED_SENSOR_TYPES:
_LOGGER.warning("Monitored condition %s is deprecated", variable)
description = SENSOR_TYPES[variable]
if not description.forecast_mode or "currently" in description.forecast_mode:
if variable == "alerts":
sensors.append(DarkSkyAlertSensor(forecast_data, description, name))
else:
sensors.append(DarkSkySensor(forecast_data, description, name))
if forecast is not None and "daily" in description.forecast_mode:
sensors.extend(
[
DarkSkySensor(
forecast_data, description, name, forecast_day=forecast_day
)
for forecast_day in forecast
]
)
if forecast_hour is not None and "hourly" in description.forecast_mode:
sensors.extend(
[
DarkSkySensor(
forecast_data, description, name, forecast_hour=forecast_h
)
for forecast_h in forecast_hour
]
)
add_entities(sensors, True)
class DarkSkySensor(SensorEntity):
"""Implementation of a Dark Sky sensor."""
_attr_attribution = "Powered by Dark Sky"
entity_description: DarkskySensorEntityDescription
def __init__(
self,
forecast_data,
description: DarkskySensorEntityDescription,
name,
forecast_day=None,
forecast_hour=None,
) -> None:
"""Initialize the sensor."""
self.entity_description = description
self.forecast_data = forecast_data
self.forecast_day = forecast_day
self.forecast_hour = forecast_hour
self._icon: str | None = None
if forecast_day is not None:
self._attr_name = f"{name} {description.name} {forecast_day}d"
elif forecast_hour is not None:
self._attr_name = f"{name} {description.name} {forecast_hour}h"
else:
self._attr_name = f"{name} {description.name}"
@property
def unit_system(self):
"""Return the unit system of this entity."""
return self.forecast_data.unit_system
@property
def entity_picture(self) -> str | None:
"""Return the entity picture to use in the frontend, if any."""
if self._icon is None or "summary" not in self.entity_description.key:
return None
if self._icon in CONDITION_PICTURES:
return CONDITION_PICTURES[self._icon].entity_picture
return None
def update_unit_of_measurement(self) -> None:
"""Update units based on unit system."""
unit_key = MAP_UNIT_SYSTEM.get(self.unit_system, "si_unit")
self._attr_native_unit_of_measurement = getattr(
self.entity_description, unit_key
)
@property
def icon(self) -> str | None:
"""Icon to use in the frontend, if any."""
if (
"summary" in self.entity_description.key
and self._icon in CONDITION_PICTURES
):
return CONDITION_PICTURES[self._icon].icon
return self.entity_description.icon
def update(self) -> None:
"""Get the latest data from Dark Sky and updates the states."""
# Call the API for new forecast data. Each sensor will re-trigger this
# same exact call, but that's fine. We cache results for a short period
# of time to prevent hitting API limits. Note that Dark Sky will
# charge users for too many calls in 1 day, so take care when updating.
self.forecast_data.update()
self.update_unit_of_measurement()
sensor_type = self.entity_description.key
if sensor_type == "minutely_summary":
self.forecast_data.update_minutely()
minutely = self.forecast_data.data_minutely
self._attr_native_value = getattr(minutely, "summary", "")
self._icon = getattr(minutely, "icon", "")
elif sensor_type == "hourly_summary":
self.forecast_data.update_hourly()
hourly = self.forecast_data.data_hourly
self._attr_native_value = getattr(hourly, "summary", "")
self._icon = getattr(hourly, "icon", "")
elif self.forecast_hour is not None:
self.forecast_data.update_hourly()
hourly = self.forecast_data.data_hourly
if hasattr(hourly, "data"):
self._attr_native_value = self.get_state(
hourly.data[self.forecast_hour]
)
else:
self._attr_native_value = 0
elif sensor_type == "daily_summary":
self.forecast_data.update_daily()
daily = self.forecast_data.data_daily
self._attr_native_value = getattr(daily, "summary", "")
self._icon = getattr(daily, "icon", "")
elif self.forecast_day is not None:
self.forecast_data.update_daily()
daily = self.forecast_data.data_daily
if hasattr(daily, "data"):
self._attr_native_value = self.get_state(daily.data[self.forecast_day])
else:
self._attr_native_value = 0
else:
self.forecast_data.update_currently()
currently = self.forecast_data.data_currently
self._attr_native_value = self.get_state(currently)
def get_state(self, data):
"""Return a new state based on the type.
If the sensor type is unknown, the current state is returned.
"""
sensor_type = self.entity_description.key
lookup_type = convert_to_camel(sensor_type)
if (state := getattr(data, lookup_type, None)) is None:
return None
if "summary" in sensor_type:
self._icon = getattr(data, "icon", "")
# Some state data needs to be rounded to whole values or converted to
# percentages
if sensor_type in {"precip_probability", "cloud_cover", "humidity"}:
return round(state * 100, 1)
if sensor_type in {
"dew_point",
"temperature",
"apparent_temperature",
"temperature_low",
"apparent_temperature_low",
"temperature_min",
"apparent_temperature_min",
"temperature_high",
"apparent_temperature_high",
"temperature_max",
"apparent_temperature_max",
"precip_accumulation",
"pressure",
"ozone",
"uvIndex",
}:
return round(state, 1)
return state
class DarkSkyAlertSensor(SensorEntity):
"""Implementation of a Dark Sky sensor."""
entity_description: DarkskySensorEntityDescription
_attr_native_value: int | None
def __init__(
self, forecast_data, description: DarkskySensorEntityDescription, name
) -> None:
"""Initialize the sensor."""
self.entity_description = description
self.forecast_data = forecast_data
self._alerts = None
self._attr_name = f"{name} {description.name}"
@property
def icon(self):
"""Icon to use in the frontend, if any."""
if self._attr_native_value is not None and self._attr_native_value > 0:
return "mdi:alert-circle"
return "mdi:alert-circle-outline"
@property
def extra_state_attributes(self):
"""Return the state attributes."""
return self._alerts
def update(self) -> None:
"""Get the latest data from Dark Sky and updates the states."""
# Call the API for new forecast data. Each sensor will re-trigger this
# same exact call, but that's fine. We cache results for a short period
# of time to prevent hitting API limits. Note that Dark Sky will
# charge users for too many calls in 1 day, so take care when updating.
self.forecast_data.update()
self.forecast_data.update_alerts()
alerts = self.forecast_data.data_alerts
self._attr_native_value = self.get_state(alerts)
def get_state(self, data):
"""Return a new state based on the type.
If the sensor type is unknown, the current state is returned.
"""
alerts = {}
if data is None:
self._alerts = alerts
return data
multiple_alerts = len(data) > 1
for i, alert in enumerate(data):
for attr in ALERTS_ATTRS:
if multiple_alerts:
dkey = f"{attr}_{i!s}"
else:
dkey = attr
alerts[dkey] = getattr(alert, attr)
self._alerts = alerts
return len(data)
def convert_to_camel(data):
"""Convert snake case (foo_bar_bat) to camel case (fooBarBat).
This is not pythonic, but needed for certain situations.
"""
components = data.split("_")
capital_components = "".join(x.title() for x in components[1:])
return f"{components[0]}{capital_components}"
class DarkSkyData:
"""Get the latest data from Darksky."""
def __init__(self, api_key, latitude, longitude, units, language, interval):
"""Initialize the data object."""
self._api_key = api_key
self.latitude = latitude
self.longitude = longitude
self.units = units
self.language = language
self._connect_error = False
self.data = None
self.unit_system = None
self.data_currently = None
self.data_minutely = None
self.data_hourly = None
self.data_daily = None
self.data_alerts = None
# Apply throttling to methods using configured interval
self.update = Throttle(interval)(self._update)
self.update_currently = Throttle(interval)(self._update_currently)
self.update_minutely = Throttle(interval)(self._update_minutely)
self.update_hourly = Throttle(interval)(self._update_hourly)
self.update_daily = Throttle(interval)(self._update_daily)
self.update_alerts = Throttle(interval)(self._update_alerts)
def _update(self):
"""Get the latest data from Dark Sky."""
try:
self.data = forecastio.load_forecast(
self._api_key,
self.latitude,
self.longitude,
units=self.units,
lang=self.language,
)
if self._connect_error:
self._connect_error = False
_LOGGER.info("Reconnected to Dark Sky")
except (ConnectError, HTTPError, Timeout, ValueError) as error:
if not self._connect_error:
self._connect_error = True
_LOGGER.error("Unable to connect to Dark Sky: %s", error)
self.data = None
self.unit_system = self.data and self.data.json["flags"]["units"]
def _update_currently(self):
"""Update currently data."""
self.data_currently = self.data and self.data.currently()
def _update_minutely(self):
"""Update minutely data."""
self.data_minutely = self.data and self.data.minutely()
def _update_hourly(self):
"""Update hourly data."""
self.data_hourly = self.data and self.data.hourly()
def _update_daily(self):
"""Update daily data."""
self.data_daily = self.data and self.data.daily()
def _update_alerts(self):
"""Update alerts data."""
self.data_alerts = self.data and self.data.alerts()

View File

@@ -1,281 +0,0 @@
"""Support for retrieving meteorological data from Dark Sky."""
from __future__ import annotations
from datetime import timedelta
import logging
import forecastio
from requests.exceptions import ConnectionError as ConnectError, HTTPError, Timeout
import voluptuous as vol
from homeassistant.components.weather import (
ATTR_CONDITION_CLEAR_NIGHT,
ATTR_CONDITION_CLOUDY,
ATTR_CONDITION_FOG,
ATTR_CONDITION_HAIL,
ATTR_CONDITION_LIGHTNING,
ATTR_CONDITION_PARTLYCLOUDY,
ATTR_CONDITION_RAINY,
ATTR_CONDITION_SNOWY,
ATTR_CONDITION_SNOWY_RAINY,
ATTR_CONDITION_SUNNY,
ATTR_CONDITION_WINDY,
ATTR_FORECAST_CONDITION,
ATTR_FORECAST_NATIVE_PRECIPITATION,
ATTR_FORECAST_NATIVE_TEMP,
ATTR_FORECAST_NATIVE_TEMP_LOW,
ATTR_FORECAST_NATIVE_WIND_SPEED,
ATTR_FORECAST_TIME,
ATTR_FORECAST_WIND_BEARING,
PLATFORM_SCHEMA,
WeatherEntity,
)
from homeassistant.const import (
CONF_API_KEY,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_MODE,
CONF_NAME,
UnitOfLength,
UnitOfPrecipitationDepth,
UnitOfPressure,
UnitOfSpeed,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import Throttle
from homeassistant.util.dt import utc_from_timestamp
_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = "Powered by Dark Sky"
FORECAST_MODE = ["hourly", "daily"]
MAP_CONDITION = {
"clear-day": ATTR_CONDITION_SUNNY,
"clear-night": ATTR_CONDITION_CLEAR_NIGHT,
"rain": ATTR_CONDITION_RAINY,
"snow": ATTR_CONDITION_SNOWY,
"sleet": ATTR_CONDITION_SNOWY_RAINY,
"wind": ATTR_CONDITION_WINDY,
"fog": ATTR_CONDITION_FOG,
"cloudy": ATTR_CONDITION_CLOUDY,
"partly-cloudy-day": ATTR_CONDITION_PARTLYCLOUDY,
"partly-cloudy-night": ATTR_CONDITION_PARTLYCLOUDY,
"hail": ATTR_CONDITION_HAIL,
"thunderstorm": ATTR_CONDITION_LIGHTNING,
"tornado": None,
}
CONF_UNITS = "units"
DEFAULT_NAME = "Dark Sky"
PLATFORM_SCHEMA = vol.All(
cv.removed(CONF_UNITS),
PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_API_KEY): cv.string,
vol.Optional(CONF_LATITUDE): cv.latitude,
vol.Optional(CONF_LONGITUDE): cv.longitude,
vol.Optional(CONF_MODE, default="hourly"): vol.In(FORECAST_MODE),
vol.Optional(CONF_UNITS): vol.In(["auto", "si", "us", "ca", "uk", "uk2"]),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
),
)
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=3)
def setup_platform(
hass: HomeAssistant,
config: ConfigType,
add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Dark Sky weather."""
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
name = config.get(CONF_NAME)
mode = config.get(CONF_MODE)
units = "si"
dark_sky = DarkSkyData(config.get(CONF_API_KEY), latitude, longitude, units)
add_entities([DarkSkyWeather(name, dark_sky, mode)], True)
class DarkSkyWeather(WeatherEntity):
"""Representation of a weather condition."""
_attr_native_precipitation_unit = UnitOfPrecipitationDepth.MILLIMETERS
_attr_native_pressure_unit = UnitOfPressure.MBAR
_attr_native_temperature_unit = UnitOfTemperature.CELSIUS
_attr_native_visibility_unit = UnitOfLength.KILOMETERS
_attr_native_wind_speed_unit = UnitOfSpeed.METERS_PER_SECOND
def __init__(self, name, dark_sky, mode):
"""Initialize Dark Sky weather."""
self._name = name
self._dark_sky = dark_sky
self._mode = mode
self._ds_data = None
self._ds_currently = None
self._ds_hourly = None
self._ds_daily = None
@property
def available(self) -> bool:
"""Return if weather data is available from Dark Sky."""
return self._ds_data is not None
@property
def attribution(self):
"""Return the attribution."""
return ATTRIBUTION
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def native_temperature(self):
"""Return the temperature."""
return self._ds_currently.get("temperature")
@property
def humidity(self):
"""Return the humidity."""
return round(self._ds_currently.get("humidity") * 100.0, 2)
@property
def native_wind_speed(self):
"""Return the wind speed."""
return self._ds_currently.get("windSpeed")
@property
def wind_bearing(self):
"""Return the wind bearing."""
return self._ds_currently.get("windBearing")
@property
def ozone(self):
"""Return the ozone level."""
return self._ds_currently.get("ozone")
@property
def native_pressure(self):
"""Return the pressure."""
return self._ds_currently.get("pressure")
@property
def native_visibility(self):
"""Return the visibility."""
return self._ds_currently.get("visibility")
@property
def condition(self):
"""Return the weather condition."""
return MAP_CONDITION.get(self._ds_currently.get("icon"))
@property
def forecast(self):
"""Return the forecast array."""
# Per conversation with Joshua Reyes of Dark Sky, to get the total
# forecasted precipitation, you have to multiple the intensity by
# the hours for the forecast interval
def calc_precipitation(intensity, hours):
amount = None
if intensity is not None:
amount = round((intensity * hours), 1)
return amount if amount > 0 else None
data = None
if self._mode == "daily":
data = [
{
ATTR_FORECAST_TIME: utc_from_timestamp(
entry.d.get("time")
).isoformat(),
ATTR_FORECAST_NATIVE_TEMP: entry.d.get("temperatureHigh"),
ATTR_FORECAST_NATIVE_TEMP_LOW: entry.d.get("temperatureLow"),
ATTR_FORECAST_NATIVE_PRECIPITATION: calc_precipitation(
entry.d.get("precipIntensity"), 24
),
ATTR_FORECAST_NATIVE_WIND_SPEED: entry.d.get("windSpeed"),
ATTR_FORECAST_WIND_BEARING: entry.d.get("windBearing"),
ATTR_FORECAST_CONDITION: MAP_CONDITION.get(entry.d.get("icon")),
}
for entry in self._ds_daily.data
]
else:
data = [
{
ATTR_FORECAST_TIME: utc_from_timestamp(
entry.d.get("time")
).isoformat(),
ATTR_FORECAST_NATIVE_TEMP: entry.d.get("temperature"),
ATTR_FORECAST_NATIVE_PRECIPITATION: calc_precipitation(
entry.d.get("precipIntensity"), 1
),
ATTR_FORECAST_CONDITION: MAP_CONDITION.get(entry.d.get("icon")),
}
for entry in self._ds_hourly.data
]
return data
def update(self) -> None:
"""Get the latest data from Dark Sky."""
self._dark_sky.update()
self._ds_data = self._dark_sky.data
currently = self._dark_sky.currently
self._ds_currently = currently.d if currently else {}
self._ds_hourly = self._dark_sky.hourly
self._ds_daily = self._dark_sky.daily
class DarkSkyData:
"""Get the latest data from Dark Sky."""
def __init__(self, api_key, latitude, longitude, units):
"""Initialize the data object."""
self._api_key = api_key
self.latitude = latitude
self.longitude = longitude
self.requested_units = units
self.data = None
self.currently = None
self.hourly = None
self.daily = None
self._connect_error = False
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Get the latest data from Dark Sky."""
try:
self.data = forecastio.load_forecast(
self._api_key, self.latitude, self.longitude, units=self.requested_units
)
self.currently = self.data.currently()
self.hourly = self.data.hourly()
self.daily = self.data.daily()
if self._connect_error:
self._connect_error = False
_LOGGER.info("Reconnected to Dark Sky")
except (ConnectError, HTTPError, Timeout, ValueError) as error:
if not self._connect_error:
self._connect_error = True
_LOGGER.error("Unable to connect to Dark Sky. %s", error)
self.data = None

View File

@@ -348,7 +348,7 @@ class ScannerEntity(BaseTrackerEntity):
self.mac_address,
self.unique_id,
)
if self.is_connected:
if self.is_connected and self.ip_address:
_async_connected_device_registered(
hass,
self.mac_address,
@@ -405,7 +405,7 @@ class ScannerEntity(BaseTrackerEntity):
"""Return the device state attributes."""
attr: dict[str, StateType] = {}
attr.update(super().state_attributes)
if self.ip_address is not None:
if self.ip_address:
attr[ATTR_IP] = self.ip_address
if self.mac_address is not None:
attr[ATTR_MAC] = self.mac_address

View File

@@ -427,7 +427,7 @@ def async_setup_scanner_platform(
hass,
async_device_tracker_scan,
interval,
f"device_tracker {platform} legacy scan",
name=f"device_tracker {platform} legacy scan",
)
hass.async_create_task(async_device_tracker_scan(None))

View File

@@ -260,7 +260,10 @@ class NetworkWatcher(WatcherBase):
"""Start scanning for new devices on the network."""
self._discover_hosts = DiscoverHosts()
self._unsub = async_track_time_interval(
self.hass, self.async_start_discover, SCAN_INTERVAL, "DHCP network watcher"
self.hass,
self.async_start_discover,
SCAN_INTERVAL,
name="DHCP network watcher",
)
self.async_start_discover()

View File

@@ -7,5 +7,5 @@
"iot_class": "local_push",
"loggers": ["aiodiscover", "dnspython", "pyroute2", "scapy"],
"quality_scale": "internal",
"requirements": ["scapy==2.5.0", "aiodiscover==1.4.15"]
"requirements": ["scapy==2.5.0", "aiodiscover==1.4.16"]
}

View File

@@ -48,49 +48,49 @@ class DSMRReaderSensorEntityDescription(SensorEntityDescription):
SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
DSMRReaderSensorEntityDescription(
key="dsmr/reading/electricity_delivered_1",
name="Low tariff usage",
translation_key="low_tariff_usage",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/electricity_returned_1",
name="Low tariff returned",
translation_key="low_tariff_returned",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/electricity_delivered_2",
name="High tariff usage",
translation_key="high_tariff_usage",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/electricity_returned_2",
name="High tariff returned",
translation_key="high_tariff_returned",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/electricity_currently_delivered",
name="Current power usage",
translation_key="current_power_usage",
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
state_class=SensorStateClass.MEASUREMENT,
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/electricity_currently_returned",
name="Current power return",
translation_key="current_power_return",
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
state_class=SensorStateClass.MEASUREMENT,
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_currently_delivered_l1",
name="Current power usage L1",
translation_key="current_power_usage_l1",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
@@ -98,7 +98,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_currently_delivered_l2",
name="Current power usage L2",
translation_key="current_power_usage_l2",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
@@ -106,7 +106,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_currently_delivered_l3",
name="Current power usage L3",
translation_key="current_power_usage_l3",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
@@ -114,7 +114,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_currently_returned_l1",
name="Current power return L1",
translation_key="current_power_return_l1",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
@@ -122,7 +122,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_currently_returned_l2",
name="Current power return L2",
translation_key="current_power_return_l2",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
@@ -130,7 +130,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_currently_returned_l3",
name="Current power return L3",
translation_key="current_power_return_l3",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
@@ -138,7 +138,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/extra_device_delivered",
name="Gas meter usage",
translation_key="gas_meter_usage",
entity_registry_enabled_default=False,
icon="mdi:fire",
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
@@ -146,7 +146,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_voltage_l1",
name="Current voltage L1",
translation_key="current_voltage_l1",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.VOLTAGE,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
@@ -154,7 +154,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_voltage_l2",
name="Current voltage L2",
translation_key="current_voltage_l2",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.VOLTAGE,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
@@ -162,7 +162,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_voltage_l3",
name="Current voltage L3",
translation_key="current_voltage_l3",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.VOLTAGE,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
@@ -170,7 +170,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_power_current_l1",
name="Phase power current L1",
translation_key="phase_power_current_l1",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
@@ -178,7 +178,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_power_current_l2",
name="Phase power current L2",
translation_key="phase_power_current_l2",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
@@ -186,7 +186,7 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/phase_power_current_l3",
name="Phase power current L3",
translation_key="phase_power_current_l3",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
@@ -194,384 +194,386 @@ SENSORS: tuple[DSMRReaderSensorEntityDescription, ...] = (
),
DSMRReaderSensorEntityDescription(
key="dsmr/reading/timestamp",
name="Telegram timestamp",
translation_key="telegram_timestamp",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.TIMESTAMP,
state=dt_util.parse_datetime,
),
DSMRReaderSensorEntityDescription(
key="dsmr/consumption/gas/delivered",
name="Gas usage",
translation_key="gas_usage",
device_class=SensorDeviceClass.GAS,
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/consumption/gas/currently_delivered",
name="Current gas usage",
translation_key="current_gas_usage",
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
state_class=SensorStateClass.MEASUREMENT,
),
DSMRReaderSensorEntityDescription(
key="dsmr/consumption/gas/read_at",
name="Gas meter read",
translation_key="gas_meter_read",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.TIMESTAMP,
state=dt_util.parse_datetime,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/electricity1",
name="Low tariff usage (daily)",
translation_key="daily_low_tariff_usage",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/electricity2",
name="High tariff usage (daily)",
translation_key="daily_high_tariff_usage",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/electricity1_returned",
name="Low tariff return (daily)",
translation_key="daily_low_tariff_return",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/electricity2_returned",
name="High tariff return (daily)",
translation_key="daily_high_tariff_return",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/electricity_merged",
name="Power usage total (daily)",
translation_key="daily_power_usage_total",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/electricity_returned_merged",
name="Power return total (daily)",
translation_key="daily_power_return_total",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/electricity1_cost",
name="Low tariff cost (daily)",
translation_key="daily_low_tariff_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/electricity2_cost",
name="High tariff cost (daily)",
translation_key="daily_high_tariff_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/electricity_cost_merged",
name="Power total cost (daily)",
translation_key="daily_power_total_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/gas",
name="Gas usage (daily)",
translation_key="daily_gas_usage",
icon="mdi:counter",
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/gas_cost",
name="Gas cost",
translation_key="gas_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/total_cost",
name="Total cost",
translation_key="total_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/energy_supplier_price_electricity_delivered_1",
name="Low tariff delivered price",
translation_key="low_tariff_delivered_price",
icon="mdi:currency-eur",
native_unit_of_measurement=PRICE_EUR_KWH,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/energy_supplier_price_electricity_delivered_2",
name="High tariff delivered price",
translation_key="high_tariff_delivered_price",
icon="mdi:currency-eur",
native_unit_of_measurement=PRICE_EUR_KWH,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/energy_supplier_price_electricity_returned_1",
name="Low tariff returned price",
translation_key="low_tariff_returned_price",
icon="mdi:currency-eur",
native_unit_of_measurement=PRICE_EUR_KWH,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/energy_supplier_price_electricity_returned_2",
name="High tariff returned price",
translation_key="high_tariff_returned_price",
icon="mdi:currency-eur",
native_unit_of_measurement=PRICE_EUR_KWH,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/energy_supplier_price_gas",
name="Gas price",
translation_key="gas_price",
icon="mdi:currency-eur",
native_unit_of_measurement=PRICE_EUR_M3,
),
DSMRReaderSensorEntityDescription(
key="dsmr/day-consumption/fixed_cost",
name="Current day fixed cost",
translation_key="current_day_fixed_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/dsmr_version",
name="DSMR version",
translation_key="dsmr_version",
entity_registry_enabled_default=False,
icon="mdi:alert-circle",
state=dsmr_transform,
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/electricity_tariff",
name="Electricity tariff",
translation_key="electricity_tariff",
device_class=SensorDeviceClass.ENUM,
options=["low", "high"],
icon="mdi:flash",
state=tariff_transform,
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/power_failure_count",
name="Power failure count",
translation_key="power_failure_count",
entity_registry_enabled_default=False,
icon="mdi:flash",
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/long_power_failure_count",
name="Long power failure count",
translation_key="long_power_failure_count",
entity_registry_enabled_default=False,
icon="mdi:flash",
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/voltage_sag_count_l1",
name="Voltage sag L1",
translation_key="voltage_sag_l1",
entity_registry_enabled_default=False,
icon="mdi:flash",
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/voltage_sag_count_l2",
name="Voltage sag L2",
translation_key="voltage_sag_l2",
entity_registry_enabled_default=False,
icon="mdi:flash",
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/voltage_sag_count_l3",
name="Voltage sag L3",
translation_key="voltage_sag_l3",
entity_registry_enabled_default=False,
icon="mdi:flash",
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/voltage_swell_count_l1",
name="Voltage swell L1",
translation_key="voltage_swell_l1",
entity_registry_enabled_default=False,
icon="mdi:flash",
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/voltage_swell_count_l2",
name="Voltage swell L2",
translation_key="voltage_swell_l2",
entity_registry_enabled_default=False,
icon="mdi:flash",
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/voltage_swell_count_l3",
name="Voltage swell L3",
translation_key="voltage_swell_l3",
entity_registry_enabled_default=False,
icon="mdi:flash",
),
DSMRReaderSensorEntityDescription(
key="dsmr/meter-stats/rejected_telegrams",
name="Rejected telegrams",
translation_key="rejected_telegrams",
entity_registry_enabled_default=False,
icon="mdi:flash",
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/electricity1",
name="Current month low tariff usage",
translation_key="current_month_low_tariff_usage",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/electricity2",
name="Current month high tariff usage",
translation_key="current_month_high_tariff_usage",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/electricity1_returned",
name="Current month low tariff returned",
translation_key="current_month_low_tariff_returned",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/electricity2_returned",
name="Current month high tariff returned",
translation_key="current_month_high_tariff_returned",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/electricity_merged",
name="Current month power usage total",
translation_key="current_month_power_usage_total",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/electricity_returned_merged",
name="Current month power return total",
translation_key="current_month_power_return_total",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/electricity1_cost",
name="Current month low tariff cost",
translation_key="current_month_low_tariff_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/electricity2_cost",
name="Current month high tariff cost",
translation_key="current_month_high_tariff_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/electricity_cost_merged",
name="Current month power total cost",
translation_key="current_month_power_total_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/gas",
name="Current month gas usage",
translation_key="current_month_gas_usage",
icon="mdi:counter",
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/gas_cost",
name="Current month gas cost",
translation_key="current_month_gas_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/fixed_cost",
name="Current month fixed cost",
translation_key="current_month_fixed_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-month/total_cost",
name="Current month total cost",
translation_key="current_month_total_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/electricity1",
name="Current year low tariff usage",
translation_key="current_year_low_tariff_usage",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/electricity2",
name="Current year high tariff usage",
translation_key="current_year_high_tariff_usage",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/electricity1_returned",
name="Current year low tariff returned",
translation_key="current_year_low_tariff_returned",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/electricity2_returned",
name="Current year high tariff returned",
translation_key="current_year_high_tariff_returned",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/electricity_merged",
name="Current year power usage total",
translation_key="current_year_power_usage_total",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/electricity_returned_merged",
name="Current year power returned total",
translation_key="current_year_power_returned_total",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/electricity1_cost",
name="Current year low tariff cost",
translation_key="current_year_low_tariff_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/electricity2_cost",
name="Current year high tariff cost",
translation_key="current_year_high_tariff_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/electricity_cost_merged",
name="Current year power total cost",
translation_key="current_year_power_total_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/gas",
name="Current year gas usage",
translation_key="current_year_gas_usage",
icon="mdi:counter",
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/gas_cost",
name="Current year gas cost",
translation_key="current_year_gas_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/fixed_cost",
name="Current year fixed cost",
translation_key="current_year_fixed_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/current-year/total_cost",
name="Current year total cost",
translation_key="current_year_total_cost",
icon="mdi:currency-eur",
native_unit_of_measurement=CURRENCY_EURO,
),
DSMRReaderSensorEntityDescription(
key="dsmr/consumption/quarter-hour-peak-electricity/average_delivered",
name="Previous quarter-hour peak usage",
translation_key="previous_quarter_hour_peak_usage",
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
),
DSMRReaderSensorEntityDescription(
key="dsmr/consumption/quarter-hour-peak-electricity/read_at_start",
name="Quarter-hour peak start time",
translation_key="quarter_hour_peak_start_time",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.TIMESTAMP,
state=dt_util.parse_datetime,
),
DSMRReaderSensorEntityDescription(
key="dsmr/consumption/quarter-hour-peak-electricity/read_at_end",
name="Quarter-hour peak end time",
translation_key="quarter_hour_peak_end_time",
entity_registry_enabled_default=False,
device_class=SensorDeviceClass.TIMESTAMP,
state=dt_util.parse_datetime,

View File

@@ -23,6 +23,7 @@ async def async_setup_entry(
class DSMRSensor(SensorEntity):
"""Representation of a DSMR sensor that is updated via MQTT."""
_attr_has_entity_name = True
entity_description: DSMRReaderSensorEntityDescription
def __init__(

View File

@@ -8,5 +8,256 @@
"description": "Make sure to configure the 'split topic' data sources in DSMR Reader."
}
}
},
"entity": {
"sensor": {
"low_tariff_usage": {
"name": "Low tariff usage"
},
"low_tariff_returned": {
"name": "Low tariff returned"
},
"high_tariff_usage": {
"name": "High tariff usage"
},
"high_tariff_returned": {
"name": "High tariff returned"
},
"current_power_usage": {
"name": "Current power usage"
},
"current_power_return": {
"name": "Current power return"
},
"current_power_usage_l1": {
"name": "Current power usage L1"
},
"current_power_usage_l2": {
"name": "Current power usage L2"
},
"current_power_usage_l3": {
"name": "Current power usage L3"
},
"current_power_return_l1": {
"name": "Current power return L1"
},
"current_power_return_l2": {
"name": "Current power return L2"
},
"current_power_return_l3": {
"name": "Current power return L3"
},
"gas_meter_usage": {
"name": "Gas meter usage"
},
"current_voltage_l1": {
"name": "Current voltage L1"
},
"current_voltage_l2": {
"name": "Current voltage L2"
},
"current_voltage_l3": {
"name": "Current voltage L3"
},
"phase_power_current_l1": {
"name": "Phase power current L1"
},
"phase_power_current_l2": {
"name": "Phase power current L2"
},
"phase_power_current_l3": {
"name": "Phase power current L3"
},
"telegram_timestamp": {
"name": "Telegram timestamp"
},
"gas_usage": {
"name": "Gas usage"
},
"current_gas_usage": {
"name": "Current gas usage"
},
"gas_meter_read": {
"name": "Gas meter read"
},
"daily_low_tariff_usage": {
"name": "Low tariff usage (daily)"
},
"daily_high_tariff_usage": {
"name": "High tariff usage (daily)"
},
"daily_low_tariff_return": {
"name": "Low tariff return (daily)"
},
"daily_high_tariff_return": {
"name": "High tariff return (daily)"
},
"daily_power_usage_total": {
"name": "Power usage total (daily)"
},
"daily_power_return_total": {
"name": "Power return total (daily)"
},
"daily_low_tariff_cost": {
"name": "Low tariff cost (daily)"
},
"daily_high_tariff_cost": {
"name": "High tariff cost (daily)"
},
"daily_power_total_cost": {
"name": "Power total cost (daily)"
},
"daily_gas_usage": {
"name": "Gas usage (daily)"
},
"gas_cost": {
"name": "Gas cost"
},
"total_cost": {
"name": "Total cost"
},
"low_tariff_delivered_price": {
"name": "Low tariff delivered price"
},
"high_tariff_delivered_price": {
"name": "High tariff delivered price"
},
"low_tariff_returned_price": {
"name": "Low tariff returned price"
},
"high_tariff_returned_price": {
"name": "High tariff returned price"
},
"gas_price": {
"name": "Gas Price"
},
"current_day_fixed_cost": {
"name": "Current day fixed cost"
},
"dsmr_version": {
"name": "DSMR version"
},
"electricity_tariff": {
"name": "Electricity tariff",
"state": {
"low": "Low",
"high": "High"
}
},
"power_failure_count": {
"name": "Power failure count"
},
"long_power_failure_count": {
"name": "Long power failure count"
},
"voltage_sag_l1": {
"name": "Voltage sag L1"
},
"voltage_sag_l2": {
"name": "Voltage sag L2"
},
"voltage_sag_l3": {
"name": "Voltage sag L3"
},
"voltage_swell_l1": {
"name": "Voltage swell L1"
},
"voltage_swell_l2": {
"name": "Voltage swell L2"
},
"voltage_swell_l3": {
"name": "Voltage swell L3"
},
"rejected_telegrams": {
"name": "Rejected telegrams"
},
"current_month_low_tariff_usage": {
"name": "Current month low tariff usage"
},
"current_month_high_tariff_usage": {
"name": "Current month high tariff usage"
},
"current_month_low_tariff_returned": {
"name": "Current month low tariff returned"
},
"current_month_high_tariff_returned": {
"name": "Current month high tariff returned"
},
"current_month_power_usage_total": {
"name": "Current month power usage total"
},
"current_month_power_return_total": {
"name": "Current month power return total"
},
"current_month_low_tariff_cost": {
"name": "Current month low tariff cost"
},
"current_month_high_tariff_cost": {
"name": "Current month high tariff cost"
},
"current_month_power_total_cost": {
"name": "Current month power total cost"
},
"current_month_gas_usage": {
"name": "Current month gas usage"
},
"current_month_gas_cost": {
"name": "Current month gas cost"
},
"current_month_fixed_cost": {
"name": "Current month fixed cost"
},
"current_month_total_cost": {
"name": "Current month total cost"
},
"current_year_low_tariff_usage": {
"name": "Current year low tariff usage"
},
"current_year_high_tariff_usage": {
"name": "Current year high tariff usage"
},
"current_year_low_tariff_returned": {
"name": "Current year low tariff returned"
},
"current_year_high_tariff_returned": {
"name": "Current year high tariff returned"
},
"current_year_power_usage_total": {
"name": "Current year power usage total"
},
"current_year_power_returned_total": {
"name": "Current year power returned total"
},
"current_year_low_tariff_cost": {
"name": "Current year low tariff cost"
},
"current_year_high_tariff_cost": {
"name": "Current year high tariff cost"
},
"current_year_power_total_cost": {
"name": "Current year power total cost"
},
"current_year_gas_usage": {
"name": "Current year gas usage"
},
"current_year_gas_cost": {
"name": "Current year gas cost"
},
"current_year_fixed_cost": {
"name": "Current year fixed cost"
},
"current_year_total_cost": {
"name": "Current year total cost"
},
"previous_quarter_hour_peak_usage": {
"name": "Previous quarter-hour peak usage"
},
"quarter_hour_peak_start_time": {
"name": "Quarter-hour peak start time"
},
"quarter_hour_peak_end_time": {
"name": "Quarter-hour peak end time"
}
}
}
}

View File

@@ -7,5 +7,5 @@
"integration_type": "hub",
"iot_class": "local_push",
"loggers": ["sml"],
"requirements": ["pysml==0.0.9"]
"requirements": ["pysml==0.0.10"]
}

View File

@@ -290,7 +290,7 @@ async def async_setup_platform(
hass,
DOMAIN,
"deprecated_yaml",
breaks_in_ha_version="2023.2.0",
breaks_in_ha_version="2023.6.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml",

View File

@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
"iot_class": "cloud_polling",
"loggers": ["env_canada"],
"requirements": ["env_canada==0.5.29"]
"requirements": ["env_canada==0.5.33"]
}

View File

@@ -345,11 +345,19 @@ async def async_setup_entry( # noqa: C901
disconnect_cb()
entry_data.disconnect_callbacks = []
entry_data.available = False
# Clear out the states so that we will always dispatch
# Mark state as stale so that we will always dispatch
# the next state update of that type when the device reconnects
for state_keys in entry_data.state.values():
state_keys.clear()
entry_data.async_update_device_state(hass)
entry_data.stale_state = {
(type(entity_state), key)
for state_dict in entry_data.state.values()
for key, entity_state in state_dict.items()
}
if not hass.is_stopping:
# Avoid marking every esphome entity as unavailable on shutdown
# since it generates a lot of state changed events and database
# writes when we already know we're shutting down and the state
# will be cleared anyway.
entry_data.async_update_device_state(hass)
async def on_connect_error(err: Exception) -> None:
"""Start reauth flow if appropriate connect error type."""

View File

@@ -70,6 +70,10 @@ class RuntimeEntryData:
client: APIClient
store: Store
state: dict[type[EntityState], dict[int, EntityState]] = field(default_factory=dict)
# When the disconnect callback is called, we mark all states
# as stale so we will always dispatch a state update when the
# device reconnects. This is the same format as state_subscriptions.
stale_state: set[tuple[type[EntityState], int]] = field(default_factory=set)
info: dict[str, dict[int, EntityInfo]] = field(default_factory=dict)
# A second list of EntityInfo objects
@@ -206,9 +210,11 @@ class RuntimeEntryData:
"""Distribute an update of state information to the target."""
key = state.key
state_type = type(state)
stale_state = self.stale_state
current_state_by_type = self.state[state_type]
current_state = current_state_by_type.get(key, _SENTINEL)
if current_state == state:
subscription_key = (state_type, key)
if current_state == state and subscription_key not in stale_state:
_LOGGER.debug(
"%s: ignoring duplicate update with and key %s: %s",
self.name,
@@ -222,8 +228,8 @@ class RuntimeEntryData:
key,
state,
)
stale_state.discard(subscription_key)
current_state_by_type[key] = state
subscription_key = (state_type, key)
if subscription_key in self.state_subscriptions:
self.state_subscriptions[subscription_key]()

View File

@@ -14,6 +14,6 @@
"integration_type": "device",
"iot_class": "local_push",
"loggers": ["aioesphomeapi", "noiseprotocol"],
"requirements": ["aioesphomeapi==13.6.0", "esphome-dashboard-api==1.2.3"],
"requirements": ["aioesphomeapi==13.6.1", "esphome-dashboard-api==1.2.3"],
"zeroconf": ["_esphomelib._tcp.local."]
}

View File

@@ -95,6 +95,7 @@ HA_OPMODES_HVAC = {
HVACMode.COOL: 2,
HVACMode.AUTO: 3,
HVACMode.FAN_ONLY: 6,
HVACMode.DRY: 8,
}
TARGET_TEMP_ACTIONS = (

View File

@@ -9,7 +9,9 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN, LOGGER
DATA_SCHEMA = vol.Schema({vol.Required("username"): str, vol.Required("password"): str})
DATA_SCHEMA = vol.Schema(
{vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
)
async def validate_input(hass: core.HomeAssistant, data):
@@ -20,18 +22,11 @@ async def validate_input(hass: core.HomeAssistant, data):
session = async_get_clientsession(hass)
try:
api = await async_get_api(
data[CONF_USERNAME], data[CONF_PASSWORD], session=session
)
await async_get_api(data[CONF_USERNAME], data[CONF_PASSWORD], session=session)
except RequestError as request_error:
LOGGER.error("Error connecting to the Flo API: %s", request_error)
raise CannotConnect from request_error
user_info = await api.user.get_info()
a_location_id = user_info["locations"][0]["id"]
location_info = await api.location.get_info(a_location_id)
return {"title": location_info["nickname"]}
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for flo."""
@@ -45,8 +40,10 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
await self.async_set_unique_id(user_input[CONF_USERNAME])
self._abort_if_unique_id_configured()
try:
info = await validate_input(self.hass, user_input)
return self.async_create_entry(title=info["title"], data=user_input)
await validate_input(self.hass, user_input)
return self.async_create_entry(
title=user_input[CONF_USERNAME], data=user_input
)
except CannotConnect:
errors["base"] = "cannot_connect"

View File

@@ -51,5 +51,5 @@
"iot_class": "local_push",
"loggers": ["flux_led"],
"quality_scale": "platinum",
"requirements": ["flux_led==0.28.36"]
"requirements": ["flux_led==0.28.37"]
}

View File

@@ -38,14 +38,14 @@ class FritzBinarySensorEntityDescription(
SENSOR_TYPES: tuple[FritzBinarySensorEntityDescription, ...] = (
FritzBinarySensorEntityDescription(
key="is_connected",
name="Connection",
translation_key="is_connected",
device_class=BinarySensorDeviceClass.CONNECTIVITY,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda status, _: bool(status.is_connected),
),
FritzBinarySensorEntityDescription(
key="is_linked",
name="Link",
translation_key="is_linked",
device_class=BinarySensorDeviceClass.PLUG,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda status, _: bool(status.is_linked),

View File

@@ -39,28 +39,28 @@ class FritzButtonDescription(ButtonEntityDescription, FritzButtonDescriptionMixi
BUTTONS: Final = [
FritzButtonDescription(
key="firmware_update",
name="Firmware Update",
translation_key="firmware_update",
device_class=ButtonDeviceClass.UPDATE,
entity_category=EntityCategory.CONFIG,
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_firmware_update(),
),
FritzButtonDescription(
key="reboot",
name="Reboot",
translation_key="reboot",
device_class=ButtonDeviceClass.RESTART,
entity_category=EntityCategory.CONFIG,
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_reboot(),
),
FritzButtonDescription(
key="reconnect",
name="Reconnect",
translation_key="reconnect",
device_class=ButtonDeviceClass.RESTART,
entity_category=EntityCategory.CONFIG,
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_reconnect(),
),
FritzButtonDescription(
key="cleanup",
name="Cleanup",
translation_key="cleanup",
icon="mdi:broom",
entity_category=EntityCategory.CONFIG,
press_action=lambda avm_wrapper: avm_wrapper.async_trigger_cleanup(),
@@ -86,6 +86,7 @@ class FritzButton(ButtonEntity):
"""Defines a Fritz!Box base button."""
entity_description: FritzButtonDescription
_attr_has_entity_name = True
def __init__(
self,
@@ -97,11 +98,11 @@ class FritzButton(ButtonEntity):
self.entity_description = description
self.avm_wrapper = avm_wrapper
self._attr_name = f"{device_friendly_name} {description.name}"
self._attr_unique_id = f"{self.avm_wrapper.unique_id}-{description.key}"
self._attr_device_info = DeviceInfo(
connections={(CONNECTION_NETWORK_MAC, avm_wrapper.mac)}
connections={(CONNECTION_NETWORK_MAC, avm_wrapper.mac)},
name=device_friendly_name,
)
async def async_press(self) -> None:

View File

@@ -1043,7 +1043,6 @@ class FritzBoxBaseCoordinatorEntity(update_coordinator.CoordinatorEntity):
)
self.entity_description = description
self._device_name = device_name
self._attr_name = description.name
self._attr_unique_id = f"{avm_wrapper.unique_id}-{description.key}"
@property

View File

@@ -7,7 +7,7 @@
"documentation": "https://www.home-assistant.io/integrations/fritz",
"iot_class": "local_polling",
"loggers": ["fritzconnection"],
"requirements": ["fritzconnection==1.11.0", "xmltodict==0.13.0"],
"requirements": ["fritzconnection==1.12.0", "xmltodict==0.13.0"],
"ssdp": [
{
"st": "urn:schemas-upnp-org:device:fritzbox:1"

View File

@@ -152,20 +152,20 @@ class FritzSensorEntityDescription(SensorEntityDescription, FritzEntityDescripti
SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
FritzSensorEntityDescription(
key="external_ip",
name="External IP",
translation_key="external_ip",
icon="mdi:earth",
value_fn=_retrieve_external_ip_state,
),
FritzSensorEntityDescription(
key="external_ipv6",
name="External IPv6",
translation_key="external_ipv6",
icon="mdi:earth",
value_fn=_retrieve_external_ipv6_state,
is_suitable=lambda info: info.ipv6_active,
),
FritzSensorEntityDescription(
key="device_uptime",
name="Device Uptime",
translation_key="device_uptime",
device_class=SensorDeviceClass.TIMESTAMP,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=_retrieve_device_uptime_state,
@@ -173,14 +173,14 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="connection_uptime",
name="Connection Uptime",
translation_key="connection_uptime",
device_class=SensorDeviceClass.TIMESTAMP,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=_retrieve_connection_uptime_state,
),
FritzSensorEntityDescription(
key="kb_s_sent",
name="Upload Throughput",
translation_key="kb_s_sent",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfDataRate.KILOBYTES_PER_SECOND,
device_class=SensorDeviceClass.DATA_RATE,
@@ -189,7 +189,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="kb_s_received",
name="Download Throughput",
translation_key="kb_s_received",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfDataRate.KILOBYTES_PER_SECOND,
device_class=SensorDeviceClass.DATA_RATE,
@@ -198,7 +198,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="max_kb_s_sent",
name="Max Connection Upload Throughput",
translation_key="max_kb_s_sent",
native_unit_of_measurement=UnitOfDataRate.KILOBITS_PER_SECOND,
device_class=SensorDeviceClass.DATA_RATE,
icon="mdi:upload",
@@ -207,7 +207,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="max_kb_s_received",
name="Max Connection Download Throughput",
translation_key="max_kb_s_received",
native_unit_of_measurement=UnitOfDataRate.KILOBITS_PER_SECOND,
device_class=SensorDeviceClass.DATA_RATE,
icon="mdi:download",
@@ -216,7 +216,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="gb_sent",
name="GB sent",
translation_key="gb_sent",
state_class=SensorStateClass.TOTAL_INCREASING,
native_unit_of_measurement=UnitOfInformation.GIGABYTES,
device_class=SensorDeviceClass.DATA_SIZE,
@@ -225,7 +225,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="gb_received",
name="GB received",
translation_key="gb_received",
state_class=SensorStateClass.TOTAL_INCREASING,
native_unit_of_measurement=UnitOfInformation.GIGABYTES,
device_class=SensorDeviceClass.DATA_SIZE,
@@ -234,7 +234,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="link_kb_s_sent",
name="Link Upload Throughput",
translation_key="link_kb_s_sent",
native_unit_of_measurement=UnitOfDataRate.KILOBITS_PER_SECOND,
device_class=SensorDeviceClass.DATA_RATE,
icon="mdi:upload",
@@ -242,7 +242,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="link_kb_s_received",
name="Link Download Throughput",
translation_key="link_kb_s_received",
native_unit_of_measurement=UnitOfDataRate.KILOBITS_PER_SECOND,
device_class=SensorDeviceClass.DATA_RATE,
icon="mdi:download",
@@ -250,7 +250,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="link_noise_margin_sent",
name="Link Upload Noise Margin",
translation_key="link_noise_margin_sent",
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS,
icon="mdi:upload",
value_fn=_retrieve_link_noise_margin_sent_state,
@@ -258,7 +258,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="link_noise_margin_received",
name="Link Download Noise Margin",
translation_key="link_noise_margin_received",
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS,
icon="mdi:download",
value_fn=_retrieve_link_noise_margin_received_state,
@@ -266,7 +266,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="link_attenuation_sent",
name="Link Upload Power Attenuation",
translation_key="link_attenuation_sent",
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS,
icon="mdi:upload",
value_fn=_retrieve_link_attenuation_sent_state,
@@ -274,7 +274,7 @@ SENSOR_TYPES: tuple[FritzSensorEntityDescription, ...] = (
),
FritzSensorEntityDescription(
key="link_attenuation_received",
name="Link Download Power Attenuation",
translation_key="link_attenuation_received",
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS,
icon="mdi:download",
value_fn=_retrieve_link_attenuation_received_state,

View File

@@ -52,5 +52,39 @@
}
}
}
},
"entity": {
"binary_sensor": {
"is_connected": { "name": "Connection" },
"is_linked": { "name": "Link" }
},
"button": {
"cleanup": { "name": "Cleanup" },
"firmware_update": { "name": "Firmware update" },
"reboot": {
"name": "[%key:component::button::entity_component::restart::name%]"
},
"reconnect": { "name": "Reconnect" }
},
"sensor": {
"connection_uptime": { "name": "Connection uptime" },
"device_uptime": { "name": "Last restart" },
"external_ip": { "name": "External IP" },
"external_ipv6": { "name": "External IPv6" },
"gb_received": { "name": "GB received" },
"gb_sent": { "name": "GB sent" },
"kb_s_received": { "name": "Download throughput" },
"kb_s_sent": { "name": "Upload throughput" },
"link_attenuation_received": {
"name": "Link download power attenuation"
},
"link_attenuation_sent": { "name": "Link upload power attenuation" },
"link_kb_s_received": { "name": "Link download throughput" },
"link_kb_s_sent": { "name": "Link upload throughput" },
"link_noise_margin_received": { "name": "Link download noise margin" },
"link_noise_margin_sent": { "name": "Link upload noise margin" },
"max_kb_s_received": { "name": "Max connection download throughput" },
"max_kb_s_sent": { "name": "Max connection upload throughput" }
}
}
}

View File

@@ -113,8 +113,8 @@ class FritzBoxEntity(CoordinatorEntity[FritzboxDataUpdateCoordinator], ABC):
self.ain = ain
if entity_description is not None:
self._attr_has_entity_name = True
self.entity_description = entity_description
self._attr_name = f"{self.data.name} {entity_description.name}"
self._attr_unique_id = f"{ain}_{entity_description.key}"
else:
self._attr_name = self.data.name

View File

@@ -40,14 +40,14 @@ class FritzBinarySensorEntityDescription(
BINARY_SENSOR_TYPES: Final[tuple[FritzBinarySensorEntityDescription, ...]] = (
FritzBinarySensorEntityDescription(
key="alarm",
name="Alarm",
translation_key="alarm",
device_class=BinarySensorDeviceClass.WINDOW,
suitable=lambda device: device.has_alarm, # type: ignore[no-any-return]
is_on=lambda device: device.alert_state, # type: ignore[no-any-return]
),
FritzBinarySensorEntityDescription(
key="lock",
name="Button Lock on Device",
translation_key="lock",
device_class=BinarySensorDeviceClass.LOCK,
entity_category=EntityCategory.CONFIG,
suitable=lambda device: device.lock is not None,
@@ -55,7 +55,7 @@ BINARY_SENSOR_TYPES: Final[tuple[FritzBinarySensorEntityDescription, ...]] = (
),
FritzBinarySensorEntityDescription(
key="device_lock",
name="Button Lock via UI",
translation_key="device_lock",
device_class=BinarySensorDeviceClass.LOCK,
entity_category=EntityCategory.CONFIG,
suitable=lambda device: device.device_lock is not None,
@@ -87,17 +87,6 @@ class FritzboxBinarySensor(FritzBoxDeviceEntity, BinarySensorEntity):
entity_description: FritzBinarySensorEntityDescription
def __init__(
self,
coordinator: FritzboxDataUpdateCoordinator,
ain: str,
entity_description: FritzBinarySensorEntityDescription,
) -> None:
"""Initialize the FritzBox entity."""
super().__init__(coordinator, ain, entity_description)
self._attr_name = f"{self.data.name} {entity_description.name}"
self._attr_unique_id = f"{ain}_{entity_description.key}"
@property
def is_on(self) -> bool | None:
"""Return true if sensor is on."""

View File

@@ -91,7 +91,7 @@ def value_scheduled_preset(device: FritzhomeDevice) -> str:
SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
FritzSensorEntityDescription(
key="temperature",
name="Temperature",
translation_key="temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
@@ -101,7 +101,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
),
FritzSensorEntityDescription(
key="humidity",
name="Humidity",
translation_key="humidity",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
@@ -110,7 +110,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
),
FritzSensorEntityDescription(
key="battery",
name="Battery",
translation_key="battery",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.BATTERY,
entity_category=EntityCategory.DIAGNOSTIC,
@@ -119,7 +119,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
),
FritzSensorEntityDescription(
key="power_consumption",
name="Power Consumption",
translation_key="power_consumption",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -128,7 +128,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
),
FritzSensorEntityDescription(
key="voltage",
name="Voltage",
translation_key="voltage",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -137,7 +137,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
),
FritzSensorEntityDescription(
key="electric_current",
name="Electric Current",
translation_key="electric_current",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
@@ -146,7 +146,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
),
FritzSensorEntityDescription(
key="total_energy",
name="Total Energy",
translation_key="total_energy",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
@@ -156,7 +156,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
# Thermostat Sensors
FritzSensorEntityDescription(
key="comfort_temperature",
name="Comfort Temperature",
translation_key="comfort_temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
suitable=suitable_comfort_temperature,
@@ -164,7 +164,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
),
FritzSensorEntityDescription(
key="eco_temperature",
name="Eco Temperature",
translation_key="eco_temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
suitable=suitable_eco_temperature,
@@ -172,7 +172,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
),
FritzSensorEntityDescription(
key="nextchange_temperature",
name="Next Scheduled Temperature",
translation_key="nextchange_temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
suitable=suitable_nextchange_temperature,
@@ -180,20 +180,20 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = (
),
FritzSensorEntityDescription(
key="nextchange_time",
name="Next Scheduled Change Time",
translation_key="nextchange_time",
device_class=SensorDeviceClass.TIMESTAMP,
suitable=suitable_nextchange_time,
native_value=lambda device: utc_from_timestamp(device.nextchange_endperiod),
),
FritzSensorEntityDescription(
key="nextchange_preset",
name="Next Scheduled Preset",
translation_key="nextchange_preset",
suitable=suitable_nextchange_temperature,
native_value=value_nextchange_preset,
),
FritzSensorEntityDescription(
key="scheduled_preset",
name="Current Scheduled Preset",
translation_key="scheduled_preset",
suitable=suitable_nextchange_temperature,
native_value=value_scheduled_preset,
),

View File

@@ -36,5 +36,41 @@
"error": {
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
}
},
"entity": {
"binary_sensor": {
"alarm": { "name": "Alarm" },
"device_lock": { "name": "Button lock via UI" },
"lock": { "name": "Button lock on device" }
},
"sensor": {
"battery": {
"name": "[%key:component::sensor::entity_component::battery::name%]"
},
"comfort_temperature": { "name": "Comfort temperature" },
"eco_temperature": { "name": "Eco temperature" },
"electric_current": {
"name": "[%key:component::sensor::entity_component::current::name%]"
},
"humidity": {
"name": "[%key:component::sensor::entity_component::humidity::name%]"
},
"nextchange_preset": { "name": "Next scheduled preset" },
"nextchange_temperature": { "name": "Next scheduled temperature" },
"nextchange_time": { "name": "Next scheduled change time" },
"power_consumption": {
"name": "[%key:component::sensor::entity_component::power::name%]"
},
"scheduled_preset": { "name": "Current scheduled preset" },
"temperature": {
"name": "[%key:component::sensor::entity_component::temperature::name%]"
},
"total_energy": {
"name": "[%key:component::sensor::entity_component::energy::name%]"
},
"voltage": {
"name": "[%key:component::sensor::entity_component::voltage::name%]"
}
}
}
}

View File

@@ -7,5 +7,5 @@
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["fritzconnection"],
"requirements": ["fritzconnection==1.11.0"]
"requirements": ["fritzconnection==1.12.0"]
}

View File

@@ -89,28 +89,24 @@ class FroniusSensorEntityDescription(SensorEntityDescription):
INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
FroniusSensorEntityDescription(
key="energy_day",
name="Energy day",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
FroniusSensorEntityDescription(
key="energy_year",
name="Energy year",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
FroniusSensorEntityDescription(
key="energy_total",
name="Energy total",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
FroniusSensorEntityDescription(
key="frequency_ac",
name="Frequency AC",
default_value=0,
native_unit_of_measurement=UnitOfFrequency.HERTZ,
device_class=SensorDeviceClass.FREQUENCY,
@@ -119,7 +115,6 @@ INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="current_ac",
name="Current AC",
default_value=0,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
@@ -127,7 +122,6 @@ INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="current_dc",
name="Current DC",
default_value=0,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
@@ -136,7 +130,6 @@ INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="current_dc_2",
name="Current DC 2",
default_value=0,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
@@ -145,7 +138,6 @@ INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_ac",
name="Power AC",
default_value=0,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
@@ -153,7 +145,6 @@ INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_ac",
name="Voltage AC",
default_value=0,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
@@ -162,7 +153,6 @@ INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_dc",
name="Voltage DC",
default_value=0,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
@@ -171,7 +161,6 @@ INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_dc_2",
name="Voltage DC 2",
default_value=0,
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
@@ -181,28 +170,23 @@ INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
# device status entities
FroniusSensorEntityDescription(
key="inverter_state",
name="Inverter state",
entity_category=EntityCategory.DIAGNOSTIC,
),
FroniusSensorEntityDescription(
key="error_code",
name="Error code",
entity_category=EntityCategory.DIAGNOSTIC,
),
FroniusSensorEntityDescription(
key="status_code",
name="Status code",
entity_category=EntityCategory.DIAGNOSTIC,
),
FroniusSensorEntityDescription(
key="led_state",
name="LED state",
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
),
FroniusSensorEntityDescription(
key="led_color",
name="LED color",
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
),
@@ -211,19 +195,16 @@ INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
LOGGER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
FroniusSensorEntityDescription(
key="co2_factor",
name="CO₂ factor",
state_class=SensorStateClass.MEASUREMENT,
icon="mdi:molecule-co2",
),
FroniusSensorEntityDescription(
key="cash_factor",
name="Grid export tariff",
state_class=SensorStateClass.MEASUREMENT,
icon="mdi:cash-plus",
),
FroniusSensorEntityDescription(
key="delivery_factor",
name="Grid import tariff",
state_class=SensorStateClass.MEASUREMENT,
icon="mdi:cash-minus",
),
@@ -232,7 +213,6 @@ LOGGER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
FroniusSensorEntityDescription(
key="current_ac_phase_1",
name="Current AC phase 1",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
@@ -240,7 +220,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="current_ac_phase_2",
name="Current AC phase 2",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
@@ -248,7 +227,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="current_ac_phase_3",
name="Current AC phase 3",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
@@ -256,7 +234,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="energy_reactive_ac_consumed",
name="Energy reactive AC consumed",
native_unit_of_measurement=ENERGY_VOLT_AMPERE_REACTIVE_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
icon="mdi:lightning-bolt-outline",
@@ -264,7 +241,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="energy_reactive_ac_produced",
name="Energy reactive AC produced",
native_unit_of_measurement=ENERGY_VOLT_AMPERE_REACTIVE_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
icon="mdi:lightning-bolt-outline",
@@ -272,7 +248,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="energy_real_ac_minus",
name="Energy real AC minus",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
@@ -280,7 +255,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="energy_real_ac_plus",
name="Energy real AC plus",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
@@ -288,33 +262,28 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="energy_real_consumed",
name="Energy real consumed",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
FroniusSensorEntityDescription(
key="energy_real_produced",
name="Energy real produced",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
FroniusSensorEntityDescription(
key="frequency_phase_average",
name="Frequency phase average",
native_unit_of_measurement=UnitOfFrequency.HERTZ,
device_class=SensorDeviceClass.FREQUENCY,
state_class=SensorStateClass.MEASUREMENT,
),
FroniusSensorEntityDescription(
key="meter_location",
name="Meter location",
entity_category=EntityCategory.DIAGNOSTIC,
),
FroniusSensorEntityDescription(
key="power_apparent_phase_1",
name="Power apparent phase 1",
native_unit_of_measurement=UnitOfApparentPower.VOLT_AMPERE,
device_class=SensorDeviceClass.APPARENT_POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -323,7 +292,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_apparent_phase_2",
name="Power apparent phase 2",
native_unit_of_measurement=UnitOfApparentPower.VOLT_AMPERE,
device_class=SensorDeviceClass.APPARENT_POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -332,7 +300,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_apparent_phase_3",
name="Power apparent phase 3",
native_unit_of_measurement=UnitOfApparentPower.VOLT_AMPERE,
device_class=SensorDeviceClass.APPARENT_POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -341,7 +308,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_apparent",
name="Power apparent",
native_unit_of_measurement=UnitOfApparentPower.VOLT_AMPERE,
device_class=SensorDeviceClass.APPARENT_POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -350,34 +316,29 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_factor_phase_1",
name="Power factor phase 1",
device_class=SensorDeviceClass.POWER_FACTOR,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
FroniusSensorEntityDescription(
key="power_factor_phase_2",
name="Power factor phase 2",
device_class=SensorDeviceClass.POWER_FACTOR,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
FroniusSensorEntityDescription(
key="power_factor_phase_3",
name="Power factor phase 3",
device_class=SensorDeviceClass.POWER_FACTOR,
state_class=SensorStateClass.MEASUREMENT,
entity_registry_enabled_default=False,
),
FroniusSensorEntityDescription(
key="power_factor",
name="Power factor",
device_class=SensorDeviceClass.POWER_FACTOR,
state_class=SensorStateClass.MEASUREMENT,
),
FroniusSensorEntityDescription(
key="power_reactive_phase_1",
name="Power reactive phase 1",
native_unit_of_measurement=POWER_VOLT_AMPERE_REACTIVE,
device_class=SensorDeviceClass.REACTIVE_POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -386,7 +347,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_reactive_phase_2",
name="Power reactive phase 2",
native_unit_of_measurement=POWER_VOLT_AMPERE_REACTIVE,
device_class=SensorDeviceClass.REACTIVE_POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -395,7 +355,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_reactive_phase_3",
name="Power reactive phase 3",
native_unit_of_measurement=POWER_VOLT_AMPERE_REACTIVE,
device_class=SensorDeviceClass.REACTIVE_POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -404,7 +363,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_reactive",
name="Power reactive",
native_unit_of_measurement=POWER_VOLT_AMPERE_REACTIVE,
device_class=SensorDeviceClass.REACTIVE_POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -413,7 +371,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_real_phase_1",
name="Power real phase 1",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -421,7 +378,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_real_phase_2",
name="Power real phase 2",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -429,7 +385,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_real_phase_3",
name="Power real phase 3",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
@@ -437,14 +392,12 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_real",
name="Power real",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
),
FroniusSensorEntityDescription(
key="voltage_ac_phase_1",
name="Voltage AC phase 1",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -452,7 +405,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_ac_phase_2",
name="Voltage AC phase 2",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -460,7 +412,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_ac_phase_3",
name="Voltage AC phase 3",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -468,7 +419,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_ac_phase_to_phase_12",
name="Voltage AC phase 1-2",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -476,7 +426,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_ac_phase_to_phase_23",
name="Voltage AC phase 2-3",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -484,7 +433,6 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_ac_phase_to_phase_31",
name="Voltage AC phase 3-1",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -495,38 +443,32 @@ METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
OHMPILOT_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
FroniusSensorEntityDescription(
key="energy_real_ac_consumed",
name="Energy consumed",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
FroniusSensorEntityDescription(
key="power_real_ac",
name="Power",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
),
FroniusSensorEntityDescription(
key="temperature_channel_1",
name="Temperature channel 1",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
),
FroniusSensorEntityDescription(
key="error_code",
name="Error code",
entity_category=EntityCategory.DIAGNOSTIC,
),
FroniusSensorEntityDescription(
key="state_code",
name="State code",
entity_category=EntityCategory.DIAGNOSTIC,
),
FroniusSensorEntityDescription(
key="state_message",
name="State message",
entity_category=EntityCategory.DIAGNOSTIC,
),
]
@@ -534,7 +476,6 @@ OHMPILOT_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
FroniusSensorEntityDescription(
key="energy_day",
name="Energy day",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
@@ -542,7 +483,6 @@ POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="energy_year",
name="Energy year",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
@@ -550,7 +490,6 @@ POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="energy_total",
name="Energy total",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
@@ -558,12 +497,10 @@ POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="meter_mode",
name="Meter mode",
entity_category=EntityCategory.DIAGNOSTIC,
),
FroniusSensorEntityDescription(
key="power_battery",
name="Power battery",
default_value=0,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
@@ -571,7 +508,6 @@ POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_grid",
name="Power grid",
default_value=0,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
@@ -579,7 +515,6 @@ POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_load",
name="Power load",
default_value=0,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
@@ -587,7 +522,6 @@ POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="power_photovoltaics",
name="Power photovoltaics",
default_value=0,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
@@ -595,7 +529,6 @@ POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="relative_autonomy",
name="Relative autonomy",
default_value=0,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -603,7 +536,6 @@ POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="relative_self_consumption",
name="Relative self consumption",
default_value=0,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -614,19 +546,16 @@ POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
STORAGE_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
FroniusSensorEntityDescription(
key="capacity_maximum",
name="Capacity maximum",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
entity_category=EntityCategory.DIAGNOSTIC,
),
FroniusSensorEntityDescription(
key="capacity_designed",
name="Capacity designed",
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
entity_category=EntityCategory.DIAGNOSTIC,
),
FroniusSensorEntityDescription(
key="current_dc",
name="Current DC",
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
@@ -634,7 +563,6 @@ STORAGE_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_dc",
name="Voltage DC",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -642,7 +570,6 @@ STORAGE_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_dc_maximum_cell",
name="Voltage DC maximum cell",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -651,7 +578,6 @@ STORAGE_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="voltage_dc_minimum_cell",
name="Voltage DC minimum cell",
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
@@ -660,14 +586,12 @@ STORAGE_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
),
FroniusSensorEntityDescription(
key="state_of_charge",
name="State of charge",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT,
),
FroniusSensorEntityDescription(
key="temperature_cell",
name="Temperature cell",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
@@ -696,6 +620,7 @@ class _FroniusSensorEntity(CoordinatorEntity["FroniusCoordinatorBase"], SensorEn
)
self.solar_net_id = solar_net_id
self._attr_native_value = self._get_entity_value()
self._attr_translation_key = self.entity_description.key
def _device_data(self) -> dict[str, Any]:
"""Extract information for SolarNet device from coordinator data."""

View File

@@ -21,5 +21,219 @@
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"invalid_host": "[%key:common::config_flow::error::invalid_host%]"
}
},
"entity": {
"sensor": {
"energy_day": {
"name": "Energy day"
},
"energy_year": {
"name": "Energy year"
},
"energy_total": {
"name": "Total energy"
},
"frequency_ac": {
"name": "[%key:component::sensor::entity_component::frequency::name%]"
},
"current_ac": {
"name": "AC current"
},
"current_dc": {
"name": "DC current"
},
"current_dc_2": {
"name": "DC current 2"
},
"power_ac": {
"name": "AC power"
},
"voltage_ac": {
"name": "AC voltage"
},
"voltage_dc": {
"name": "DC voltage"
},
"voltage_dc_2": {
"name": "DC voltage 2"
},
"inverter_state": {
"name": "Inverter state"
},
"error_code": {
"name": "Error code"
},
"status_code": {
"name": "Status code"
},
"led_state": {
"name": "LED state"
},
"led_color": {
"name": "LED color"
},
"co2_factor": {
"name": "CO₂ factor"
},
"cash_factor": {
"name": "Grid export tariff"
},
"delivery_factor": {
"name": "Grid import tariff"
},
"current_ac_phase_1": {
"name": "Current phase 1"
},
"current_ac_phase_2": {
"name": "Current phase 2"
},
"current_ac_phase_3": {
"name": "Current phase 3"
},
"energy_reactive_ac_consumed": {
"name": "Reactive energy consumed"
},
"energy_reactive_ac_produced": {
"name": "Reactive energy produced"
},
"energy_real_ac_minus": {
"name": "Real energy minus"
},
"energy_real_ac_plus": {
"name": "Real energy plus"
},
"energy_real_consumed": {
"name": "Real energy consumed"
},
"energy_real_produced": {
"name": "Real energy produced"
},
"frequency_phase_average": {
"name": "Frequency phase average"
},
"meter_location": {
"name": "Meter location"
},
"power_apparent_phase_1": {
"name": "Apparent power phase 1"
},
"power_apparent_phase_2": {
"name": "Apparent power phase 2"
},
"power_apparent_phase_3": {
"name": "Apparent power phase 3"
},
"power_apparent": {
"name": "[%key:component::sensor::entity_component::apparent_power::name%]"
},
"power_factor_phase_1": {
"name": "Power factor phase 1"
},
"power_factor_phase_2": {
"name": "Power factor phase 2"
},
"power_factor_phase_3": {
"name": "Power factor phase 3"
},
"power_factor": {
"name": "[%key:component::sensor::entity_component::power_factor::name%]"
},
"power_reactive_phase_1": {
"name": "Reactive power phase 1"
},
"power_reactive_phase_2": {
"name": "Reactive power phase 2"
},
"power_reactive_phase_3": {
"name": "Reactive power phase 3"
},
"power_reactive": {
"name": "Reactive power"
},
"power_real_phase_1": {
"name": "Real power phase 1"
},
"power_real_phase_2": {
"name": "Real power phase 2"
},
"power_real_phase_3": {
"name": "Real power phase 3"
},
"power_real": {
"name": "Real power"
},
"voltage_ac_phase_1": {
"name": "Voltage phase 1"
},
"voltage_ac_phase_2": {
"name": "Voltage phase 2"
},
"voltage_ac_phase_3": {
"name": "Voltage phase 3"
},
"voltage_ac_phase_to_phase_12": {
"name": "Voltage phase 1-2"
},
"voltage_ac_phase_to_phase_23": {
"name": "Voltage phase 2-3"
},
"voltage_ac_phase_to_phase_31": {
"name": "Voltage phase 3-1"
},
"energy_real_ac_consumed": {
"name": "Energy consumed"
},
"power_real_ac": {
"name": "[%key:component::sensor::entity_component::power::name%]"
},
"temperature_channel_1": {
"name": "[%key:component::sensor::entity_component::temperature::name%]"
},
"state_code": {
"name": "State code"
},
"state_message": {
"name": "State message"
},
"meter_mode": {
"name": "Meter mode"
},
"power_battery": {
"name": "Power battery"
},
"power_grid": {
"name": "Power grid"
},
"power_load": {
"name": "Power load"
},
"power_photovoltaics": {
"name": "Power photovoltaics"
},
"relative_autonomy": {
"name": "Relative autonomy"
},
"relative_self_consumption": {
"name": "Relative self consumption"
},
"capacity_maximum": {
"name": "Maximum capacity "
},
"capacity_designed": {
"name": "Designed capacity"
},
"voltage_dc_maximum_cell": {
"name": "Maximum cell voltage"
},
"voltage_dc_minimum_cell": {
"name": "Minimum cell voltage"
},
"state_of_charge": {
"name": "State of charge"
},
"temperature_cell": {
"name": "[%key:component::sensor::entity_component::temperature::name%]"
}
}
}
}

View File

@@ -20,5 +20,5 @@
"documentation": "https://www.home-assistant.io/integrations/frontend",
"integration_type": "system",
"quality_scale": "internal",
"requirements": ["home-assistant-frontend==20230330.0"]
"requirements": ["home-assistant-frontend==20230411.1"]
}

View File

@@ -60,7 +60,6 @@ class GiosSensorEntityDescription(SensorEntityDescription, GiosSensorRequiredKey
SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
GiosSensorEntityDescription(
key=ATTR_AQI,
name="AQI",
value=lambda sensors: sensors.aqi.value if sensors.aqi else None,
icon="mdi:air-filter",
device_class=SensorDeviceClass.ENUM,
@@ -69,35 +68,34 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
),
GiosSensorEntityDescription(
key=ATTR_C6H6,
name="C6H6",
value=lambda sensors: sensors.c6h6.value if sensors.c6h6 else None,
suggested_display_precision=0,
icon="mdi:molecule",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
translation_key="c6h6",
),
GiosSensorEntityDescription(
key=ATTR_CO,
name="CO",
value=lambda sensors: sensors.co.value if sensors.co else None,
suggested_display_precision=0,
icon="mdi:molecule",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
translation_key="co",
),
GiosSensorEntityDescription(
key=ATTR_NO2,
name="NO2",
value=lambda sensors: sensors.no2.value if sensors.no2 else None,
suggested_display_precision=0,
device_class=SensorDeviceClass.NITROGEN_DIOXIDE,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
translation_key="no2",
),
GiosSensorEntityDescription(
key=ATTR_NO2,
subkey="index",
name="NO2 index",
value=lambda sensors: sensors.no2.index if sensors.no2 else None,
icon="mdi:molecule",
device_class=SensorDeviceClass.ENUM,
@@ -106,17 +104,16 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
),
GiosSensorEntityDescription(
key=ATTR_O3,
name="O3",
value=lambda sensors: sensors.o3.value if sensors.o3 else None,
suggested_display_precision=0,
device_class=SensorDeviceClass.OZONE,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
translation_key="o3",
),
GiosSensorEntityDescription(
key=ATTR_O3,
subkey="index",
name="O3 index",
value=lambda sensors: sensors.o3.index if sensors.o3 else None,
icon="mdi:molecule",
device_class=SensorDeviceClass.ENUM,
@@ -125,17 +122,16 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
),
GiosSensorEntityDescription(
key=ATTR_PM10,
name="PM10",
value=lambda sensors: sensors.pm10.value if sensors.pm10 else None,
suggested_display_precision=0,
device_class=SensorDeviceClass.PM10,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
translation_key="pm10",
),
GiosSensorEntityDescription(
key=ATTR_PM10,
subkey="index",
name="PM10 index",
value=lambda sensors: sensors.pm10.index if sensors.pm10 else None,
icon="mdi:molecule",
device_class=SensorDeviceClass.ENUM,
@@ -144,17 +140,16 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
),
GiosSensorEntityDescription(
key=ATTR_PM25,
name="PM2.5",
value=lambda sensors: sensors.pm25.value if sensors.pm25 else None,
suggested_display_precision=0,
device_class=SensorDeviceClass.PM25,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
translation_key="pm25",
),
GiosSensorEntityDescription(
key=ATTR_PM25,
subkey="index",
name="PM2.5 index",
value=lambda sensors: sensors.pm25.index if sensors.pm25 else None,
icon="mdi:molecule",
device_class=SensorDeviceClass.ENUM,
@@ -163,17 +158,16 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
),
GiosSensorEntityDescription(
key=ATTR_SO2,
name="SO2",
value=lambda sensors: sensors.so2.value if sensors.so2 else None,
suggested_display_precision=0,
device_class=SensorDeviceClass.SULPHUR_DIOXIDE,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=SensorStateClass.MEASUREMENT,
translation_key="so2",
),
GiosSensorEntityDescription(
key=ATTR_SO2,
subkey="index",
name="SO2 index",
value=lambda sensors: sensors.so2.index if sensors.so2 else None,
icon="mdi:molecule",
device_class=SensorDeviceClass.ENUM,

View File

@@ -26,6 +26,7 @@
"entity": {
"sensor": {
"aqi": {
"name": "[%key:component::sensor::entity_component::aqi::name%]",
"state": {
"very_bad": "Very bad",
"bad": "Bad",
@@ -35,7 +36,17 @@
"very_good": "Very good"
}
},
"c6h6": {
"name": "Benzene"
},
"co": {
"name": "[%key:component::sensor::entity_component::carbon_monoxide::name%]"
},
"no2": {
"name": "[%key:component::sensor::entity_component::nitrogen_dioxide::name%]"
},
"no2_index": {
"name": "Nitrogen dioxide index",
"state": {
"very_bad": "[%key:component::gios::entity::sensor::aqi::state::very_bad%]",
"bad": "[%key:component::gios::entity::sensor::aqi::state::bad%]",
@@ -45,7 +56,11 @@
"very_good": "[%key:component::gios::entity::sensor::aqi::state::very_good%]"
}
},
"o3": {
"name": "[%key:component::sensor::entity_component::ozone::name%]"
},
"o3_index": {
"name": "Ozone index",
"state": {
"very_bad": "[%key:component::gios::entity::sensor::aqi::state::very_bad%]",
"bad": "[%key:component::gios::entity::sensor::aqi::state::bad%]",
@@ -55,7 +70,11 @@
"very_good": "[%key:component::gios::entity::sensor::aqi::state::very_good%]"
}
},
"pm10": {
"name": "[%key:component::sensor::entity_component::pm10::name%]"
},
"pm10_index": {
"name": "Particulate matter 10 μm index",
"state": {
"very_bad": "[%key:component::gios::entity::sensor::aqi::state::very_bad%]",
"bad": "[%key:component::gios::entity::sensor::aqi::state::bad%]",
@@ -65,7 +84,11 @@
"very_good": "[%key:component::gios::entity::sensor::aqi::state::very_good%]"
}
},
"pm25": {
"name": "[%key:component::sensor::entity_component::pm25::name%]"
},
"pm25_index": {
"name": "Particulate matter 2.5 μm index",
"state": {
"very_bad": "[%key:component::gios::entity::sensor::aqi::state::very_bad%]",
"bad": "[%key:component::gios::entity::sensor::aqi::state::bad%]",
@@ -75,7 +98,11 @@
"very_good": "[%key:component::gios::entity::sensor::aqi::state::very_good%]"
}
},
"so2": {
"name": "[%key:component::sensor::entity_component::sulphur_dioxide::name%]"
},
"so2_index": {
"name": "Sulphur dioxide index",
"state": {
"very_bad": "[%key:component::gios::entity::sensor::aqi::state::very_bad%]",
"bad": "[%key:component::gios::entity::sensor::aqi::state::bad%]",

View File

@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/goodwe",
"iot_class": "local_polling",
"loggers": ["goodwe"],
"requirements": ["goodwe==0.2.29"]
"requirements": ["goodwe==0.2.30"]
}

View File

@@ -285,17 +285,18 @@ async def async_setup_add_event_service(
raise ValueError(
"Missing required fields to set start or end date/datetime"
)
event = Event(
summary=call.data[EVENT_SUMMARY],
description=call.data[EVENT_DESCRIPTION],
start=start,
end=end,
)
if location := call.data.get(EVENT_LOCATION):
event.location = location
try:
await calendar_service.async_create_event(
call.data[EVENT_CALENDAR_ID],
Event(
summary=call.data[EVENT_SUMMARY],
description=call.data[EVENT_DESCRIPTION],
location=call.data[EVENT_LOCATION],
start=start,
end=end,
),
event,
)
except ApiException as err:
raise HomeAssistantError(str(err)) from err

View File

@@ -508,9 +508,10 @@ class GoogleCalendarEntity(
"start": start,
"end": end,
EVENT_DESCRIPTION: kwargs.get(EVENT_DESCRIPTION),
EVENT_LOCATION: kwargs.get(EVENT_LOCATION),
}
)
if location := kwargs.get(EVENT_LOCATION):
event.location = location
if rrule := kwargs.get(EVENT_RRULE):
event.recurrence = [f"{RRULE_PREFIX}{rrule}"]
@@ -597,18 +598,20 @@ async def async_create_event(entity: GoogleCalendarEntity, call: ServiceCall) ->
if start is None or end is None:
raise ValueError("Missing required fields to set start or end date/datetime")
event = Event(
summary=call.data[EVENT_SUMMARY],
description=call.data[EVENT_DESCRIPTION],
start=start,
end=end,
)
if location := call.data.get(EVENT_LOCATION):
event.location = location
try:
await cast(
CalendarSyncUpdateCoordinator, entity.coordinator
).sync.api.async_create_event(
entity.calendar_id,
Event(
summary=call.data[EVENT_SUMMARY],
description=call.data[EVENT_DESCRIPTION],
location=call.data[EVENT_LOCATION],
start=start,
end=end,
),
event,
)
except ApiException as err:
raise HomeAssistantError(str(err)) from err

View File

@@ -7,5 +7,5 @@
"documentation": "https://www.home-assistant.io/integrations/calendar.google/",
"iot_class": "cloud_polling",
"loggers": ["googleapiclient"],
"requirements": ["gcal-sync==4.1.2", "oauth2client==4.1.3"]
"requirements": ["gcal-sync==4.1.4", "oauth2client==4.1.3"]
}

View File

@@ -20,7 +20,7 @@ LANG_TO_BROADCAST_COMMAND = {
"it": ("Trasmetti {0}", "Trasmetti in {1} {0}"),
"ja": ("{0}とブロードキャストして", "{0}{1}にブロードキャストして"),
"ko": ("{0} 라고 방송해 줘", "{0} 라고 {1}에 방송해 줘"),
"pt": ("Transmite {0}", "Transmite para {1} {0}"),
"pt": ("Transmitir {0}", "Transmitir {0} para {1}"),
}

View File

@@ -870,23 +870,25 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
self.hassio.get_os_info(),
)
addons = [
addon
for addon in self.hass.data[DATA_SUPERVISOR_INFO].get("addons", [])
if addon[ATTR_STATE] == ATTR_STARTED
all_addons = self.hass.data[DATA_SUPERVISOR_INFO].get("addons", [])
started_addons = [
addon for addon in all_addons if addon[ATTR_STATE] == ATTR_STARTED
]
stats_data = await asyncio.gather(
*[self._update_addon_stats(addon[ATTR_SLUG]) for addon in addons]
*[self._update_addon_stats(addon[ATTR_SLUG]) for addon in started_addons]
)
self.hass.data[DATA_ADDONS_STATS] = dict(stats_data)
self.hass.data[DATA_ADDONS_CHANGELOGS] = dict(
await asyncio.gather(
*[self._update_addon_changelog(addon[ATTR_SLUG]) for addon in addons]
*[
self._update_addon_changelog(addon[ATTR_SLUG])
for addon in all_addons
]
)
)
self.hass.data[DATA_ADDONS_INFO] = dict(
await asyncio.gather(
*[self._update_addon_info(addon[ATTR_SLUG]) for addon in addons]
*[self._update_addon_info(addon[ATTR_SLUG]) for addon in all_addons]
)
)

View File

@@ -151,7 +151,7 @@ class DeviceWithPrograms(HomeConnectDevice):
programs_available = self.appliance.get_programs_available()
except (HomeConnectError, ValueError):
_LOGGER.debug("Unable to fetch available programs. Probably offline")
programs_available = None
programs_available = []
return programs_available
def get_program_switches(self):

View File

@@ -272,7 +272,8 @@ class HKDevice:
self.hass,
self.async_update_available_state,
timedelta(seconds=BLE_AVAILABILITY_CHECK_INTERVAL),
f"HomeKit Controller {self.unique_id} BLE availability check poll",
name=f"HomeKit Controller {self.unique_id} BLE availability "
"check poll",
)
)
# BLE devices always get an RSSI sensor as well
@@ -290,7 +291,7 @@ class HKDevice:
self.hass,
self.async_request_update,
self.pairing.poll_interval,
f"HomeKit Controller {self.unique_id} availability check poll",
name=f"HomeKit Controller {self.unique_id} availability check poll",
)
)

View File

@@ -14,6 +14,6 @@
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
"iot_class": "local_push",
"loggers": ["aiohomekit", "commentjson"],
"requirements": ["aiohomekit==2.6.1"],
"requirements": ["aiohomekit==2.6.3"],
"zeroconf": ["_hap._tcp.local.", "_hap._udp.local."]
}

View File

@@ -1,4 +1,5 @@
"""Support for HomeWizard buttons."""
from homeassistant.components.button import ButtonEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
@@ -16,7 +17,7 @@ async def async_setup_entry(
) -> None:
"""Set up the Identify button."""
coordinator: HWEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
if coordinator.data.features.has_identify:
if coordinator.supports_identify():
async_add_entities([HomeWizardIdentifyButton(coordinator, entry)])

View File

@@ -4,7 +4,6 @@ from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from homewizard_energy.features import Features
from homewizard_energy.models import Data, Device, State, System
from homeassistant.const import Platform
@@ -30,6 +29,5 @@ class DeviceResponseEntry:
device: Device
data: Data
features: Features
state: State | None
state: State | None = None
system: System | None = None

View File

@@ -4,7 +4,9 @@ from __future__ import annotations
import logging
from homewizard_energy import HomeWizardEnergy
from homewizard_energy.errors import DisabledError, RequestError
from homewizard_energy.const import SUPPORTS_IDENTIFY, SUPPORTS_STATE, SUPPORTS_SYSTEM
from homewizard_energy.errors import DisabledError, RequestError, UnsupportedError
from homewizard_energy.models import Device
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@@ -22,6 +24,8 @@ class HWEnergyDeviceUpdateCoordinator(DataUpdateCoordinator[DeviceResponseEntry]
api: HomeWizardEnergy
api_disabled: bool = False
_unsupported_error: bool = False
def __init__(
self,
hass: HomeAssistant,
@@ -39,12 +43,24 @@ class HWEnergyDeviceUpdateCoordinator(DataUpdateCoordinator[DeviceResponseEntry]
data = DeviceResponseEntry(
device=await self.api.device(),
data=await self.api.data(),
features=await self.api.features(),
state=await self.api.state(),
)
if data.features.has_system:
data.system = await self.api.system()
try:
if self.supports_state(data.device):
data.state = await self.api.state()
if self.supports_system(data.device):
data.system = await self.api.system()
except UnsupportedError as ex:
# Old firmware, ignore
if not self._unsupported_error:
self._unsupported_error = True
_LOGGER.warning(
"%s is running an outdated firmware version (%s). Contact HomeWizard support to update your device",
self.entry.title,
ex,
)
except RequestError as ex:
raise UpdateFailed(ex) from ex
@@ -61,4 +77,27 @@ class HWEnergyDeviceUpdateCoordinator(DataUpdateCoordinator[DeviceResponseEntry]
self.api_disabled = False
self.data = data
return data
def supports_state(self, device: Device | None = None) -> bool:
"""Return True if the device supports state."""
if device is None:
device = self.data.device
return device.product_type in SUPPORTS_STATE
def supports_system(self, device: Device | None = None) -> bool:
"""Return True if the device supports system."""
if device is None:
device = self.data.device
return device.product_type in SUPPORTS_SYSTEM
def supports_identify(self, device: Device | None = None) -> bool:
"""Return True if the device supports identify."""
if device is None:
device = self.data.device
return device.product_type in SUPPORTS_IDENTIFY

View File

@@ -8,6 +8,6 @@
"iot_class": "local_polling",
"loggers": ["homewizard_energy"],
"quality_scale": "platinum",
"requirements": ["python-homewizard-energy==1.8.0"],
"requirements": ["python-homewizard-energy==2.0.1"],
"zeroconf": ["_hwenergy._tcp.local."]
}

View File

@@ -20,7 +20,7 @@ async def async_setup_entry(
) -> None:
"""Set up numbers for device."""
coordinator: HWEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
if coordinator.data.state:
if coordinator.supports_state():
async_add_entities([HWEnergyNumberEntity(coordinator, entry)])

View File

@@ -27,7 +27,7 @@ from .helpers import homewizard_exception_handler
class HomeWizardEntityDescriptionMixin:
"""Mixin values for HomeWizard entities."""
create_fn: Callable[[DeviceResponseEntry], bool]
create_fn: Callable[[HWEnergyDeviceUpdateCoordinator], bool]
available_fn: Callable[[DeviceResponseEntry], bool]
is_on_fn: Callable[[DeviceResponseEntry], bool | None]
set_fn: Callable[[HomeWizardEnergy, bool], Awaitable[Any]]
@@ -46,7 +46,7 @@ SWITCHES = [
HomeWizardSwitchEntityDescription(
key="power_on",
device_class=SwitchDeviceClass.OUTLET,
create_fn=lambda data: data.state is not None,
create_fn=lambda coordinator: coordinator.supports_state(),
available_fn=lambda data: data.state is not None and not data.state.switch_lock,
is_on_fn=lambda data: data.state.power_on if data.state else None,
set_fn=lambda api, active: api.state_set(power_on=active),
@@ -57,7 +57,7 @@ SWITCHES = [
entity_category=EntityCategory.CONFIG,
icon="mdi:lock",
icon_off="mdi:lock-open",
create_fn=lambda data: data.state is not None,
create_fn=lambda coordinator: coordinator.supports_state(),
available_fn=lambda data: data.state is not None,
is_on_fn=lambda data: data.state.switch_lock if data.state else None,
set_fn=lambda api, active: api.state_set(switch_lock=active),
@@ -68,7 +68,7 @@ SWITCHES = [
entity_category=EntityCategory.CONFIG,
icon="mdi:cloud",
icon_off="mdi:cloud-off-outline",
create_fn=lambda data: data.system is not None,
create_fn=lambda coordinator: coordinator.supports_system(),
available_fn=lambda data: data.system is not None,
is_on_fn=lambda data: data.system.cloud_enabled if data.system else None,
set_fn=lambda api, active: api.system_set(cloud_enabled=active),
@@ -91,7 +91,7 @@ async def async_setup_entry(
entry=entry,
)
for description in SWITCHES
if description.available_fn(coordinator.data)
if description.create_fn(coordinator)
)

View File

@@ -1,9 +1,11 @@
"""Support for Honeywell (US) Total Connect Comfort climate systems."""
from __future__ import annotations
import asyncio
import datetime
from typing import Any
from aiohttp import ClientConnectionError
import aiosomecomfort
from homeassistant.components.climate import (
@@ -421,10 +423,7 @@ class HoneywellUSThermostat(ClimateEntity):
try:
await self._device.refresh()
self._attr_available = True
except (
aiosomecomfort.SomeComfortError,
OSError,
):
except aiosomecomfort.SomeComfortError:
try:
await self._data.client.login()
@@ -433,5 +432,12 @@ class HoneywellUSThermostat(ClimateEntity):
await self.hass.async_create_task(
self.hass.config_entries.async_reload(self._data.entry_id)
)
except aiosomecomfort.SomeComfortError:
except (
aiosomecomfort.SomeComfortError,
ClientConnectionError,
asyncio.TimeoutError,
):
self._attr_available = False
except (ClientConnectionError, asyncio.TimeoutError):
self._attr_available = False

View File

@@ -8,7 +8,7 @@ import email
import logging
from typing import Any
from aioimaplib import AUTH, IMAP4_SSL, SELECTED, AioImapException
from aioimaplib import AUTH, IMAP4_SSL, NONAUTH, SELECTED, AioImapException
import async_timeout
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
@@ -36,10 +36,12 @@ async def connect_to_server(data: Mapping[str, Any]) -> IMAP4_SSL:
"""Connect to imap server and return client."""
client = IMAP4_SSL(data[CONF_SERVER], data[CONF_PORT])
await client.wait_hello_from_server()
await client.login(data[CONF_USERNAME], data[CONF_PASSWORD])
if client.protocol.state != AUTH:
if client.protocol.state == NONAUTH:
await client.login(data[CONF_USERNAME], data[CONF_PASSWORD])
if client.protocol.state not in {AUTH, SELECTED}:
raise InvalidAuth("Invalid username or password")
await client.select(data[CONF_FOLDER])
if client.protocol.state == AUTH:
await client.select(data[CONF_FOLDER])
if client.protocol.state != SELECTED:
raise InvalidFolder(f"Folder {data[CONF_FOLDER]} is invalid")
return client
@@ -192,7 +194,11 @@ class ImapDataUpdateCoordinator(DataUpdateCoordinator[int | None]):
if count
else None
)
if count and last_message_id is not None:
if (
count
and last_message_id is not None
and self._last_message_id != last_message_id
):
self._last_message_id = last_message_id
await self._async_process_event(last_message_id)
@@ -207,10 +213,9 @@ class ImapDataUpdateCoordinator(DataUpdateCoordinator[int | None]):
await self.imap_client.stop_wait_server_push()
await self.imap_client.close()
await self.imap_client.logout()
except (AioImapException, asyncio.TimeoutError) as ex:
except (AioImapException, asyncio.TimeoutError):
if log_error:
self.async_set_update_error(ex)
_LOGGER.warning("Error while cleaning up imap connection")
_LOGGER.debug("Error while cleaning up imap connection")
self.imap_client = None
async def shutdown(self, *_) -> None:
@@ -234,18 +239,18 @@ class ImapPollingDataUpdateCoordinator(ImapDataUpdateCoordinator):
UpdateFailed,
asyncio.TimeoutError,
) as ex:
self.async_set_update_error(ex)
await self._cleanup()
self.async_set_update_error(ex)
raise UpdateFailed() from ex
except InvalidFolder as ex:
_LOGGER.warning("Selected mailbox folder is invalid")
self.async_set_update_error(ex)
await self._cleanup()
self.async_set_update_error(ex)
raise ConfigEntryError("Selected mailbox folder is invalid.") from ex
except InvalidAuth as ex:
_LOGGER.warning("Username or password incorrect, starting reauthentication")
self.async_set_update_error(ex)
await self._cleanup()
self.async_set_update_error(ex)
raise ConfigEntryAuthFailed() from ex
@@ -274,30 +279,30 @@ class ImapPushDataUpdateCoordinator(ImapDataUpdateCoordinator):
try:
number_of_messages = await self._async_fetch_number_of_messages()
except InvalidAuth as ex:
await self._cleanup()
_LOGGER.warning(
"Username or password incorrect, starting reauthentication"
)
self.config_entry.async_start_reauth(self.hass)
self.async_set_update_error(ex)
await self._cleanup()
await asyncio.sleep(BACKOFF_TIME)
except InvalidFolder as ex:
_LOGGER.warning("Selected mailbox folder is invalid")
await self._cleanup()
self.config_entry.async_set_state(
self.hass,
ConfigEntryState.SETUP_ERROR,
"Selected mailbox folder is invalid.",
)
self.async_set_update_error(ex)
await self._cleanup()
await asyncio.sleep(BACKOFF_TIME)
except (
UpdateFailed,
AioImapException,
asyncio.TimeoutError,
) as ex:
self.async_set_update_error(ex)
await self._cleanup()
self.async_set_update_error(ex)
await asyncio.sleep(BACKOFF_TIME)
continue
else:
@@ -310,12 +315,11 @@ class ImapPushDataUpdateCoordinator(ImapDataUpdateCoordinator):
await idle
except (AioImapException, asyncio.TimeoutError):
_LOGGER.warning(
_LOGGER.debug(
"Lost %s (will attempt to reconnect after %s s)",
self.config_entry.data[CONF_SERVER],
BACKOFF_TIME,
)
self.async_set_update_error(UpdateFailed("Lost connection"))
await self._cleanup()
await asyncio.sleep(BACKOFF_TIME)

View File

@@ -17,7 +17,7 @@
"iot_class": "local_push",
"loggers": ["pyinsteon", "pypubsub"],
"requirements": [
"pyinsteon==1.4.0",
"pyinsteon==1.4.2",
"insteon-frontend-home-assistant==0.3.4"
],
"usb": [

View File

@@ -142,8 +142,11 @@ class ControllerDevice(ClimateEntity):
# If mode RAS, or mode master with CtrlZone 13 then can set master temperature,
# otherwise the unit determines which zone to use as target. See interface manual p. 8
# It appears some systems may have a different numbering system, so will trigger
# this if the control zone is > total zones.
if (
controller.ras_mode == "master" and controller.zone_ctrl == 13
controller.ras_mode == "master"
and controller.zone_ctrl > controller.zones_total
) or controller.ras_mode == "RAS":
self._attr_supported_features |= ClimateEntityFeature.TARGET_TEMPERATURE

View File

@@ -7,5 +7,5 @@
"integration_type": "service",
"iot_class": "local_polling",
"loggers": ["aiopyarr"],
"requirements": ["aiopyarr==22.11.0"]
"requirements": ["aiopyarr==23.4.0"]
}

View File

@@ -41,7 +41,7 @@
"loggers": ["aiolifx", "aiolifx_effects", "bitstring"],
"quality_scale": "platinum",
"requirements": [
"aiolifx==0.8.9",
"aiolifx==0.8.10",
"aiolifx_effects==0.3.2",
"aiolifx_themes==0.4.5"
]

View File

@@ -12,5 +12,5 @@
"integration_type": "hub",
"iot_class": "cloud_push",
"loggers": ["pylitterbot"],
"requirements": ["pylitterbot==2023.1.2"]
"requirements": ["pylitterbot==2023.4.0"]
}

View File

@@ -3,6 +3,8 @@ from __future__ import annotations
from typing import Any
from aiolivisi.const import CAPABILITY_CONFIG
from homeassistant.components.climate import (
ClimateEntity,
ClimateEntityFeature,
@@ -65,8 +67,6 @@ class LivisiClimate(LivisiEntity, ClimateEntity):
_attr_hvac_mode = HVACMode.HEAT
_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
_attr_target_temperature_high = MAX_TEMPERATURE
_attr_target_temperature_low = MIN_TEMPERATURE
def __init__(
self,
@@ -83,6 +83,10 @@ class LivisiClimate(LivisiEntity, ClimateEntity):
self._temperature_capability = self.capabilities["RoomTemperature"]
self._humidity_capability = self.capabilities["RoomHumidity"]
config = device.get(CAPABILITY_CONFIG, {}).get("RoomSetpoint", {})
self._attr_max_temp = config.get("maxTemperature", MAX_TEMPERATURE)
self._attr_min_temp = config.get("minTemperature", MIN_TEMPERATURE)
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
response = await self.aio_livisi.async_vrcc_set_temperature(

View File

@@ -2,7 +2,7 @@
from __future__ import annotations
from datetime import datetime
from datetime import date, datetime, timedelta
import logging
from typing import Any
@@ -186,14 +186,23 @@ def _parse_event(event: dict[str, Any]) -> Event:
def _get_calendar_event(event: Event) -> CalendarEvent:
"""Return a CalendarEvent from an API event."""
start: datetime | date
end: datetime | date
if isinstance(event.start, datetime) and isinstance(event.end, datetime):
start = dt_util.as_local(event.start)
end = dt_util.as_local(event.end)
if (end - start) <= timedelta(seconds=0):
end = start + timedelta(minutes=30)
else:
start = event.start
end = event.end
if (end - start) < timedelta(days=0):
end = start + timedelta(days=1)
return CalendarEvent(
summary=event.summary,
start=dt_util.as_local(event.start)
if isinstance(event.start, datetime)
else event.start,
end=dt_util.as_local(event.end)
if isinstance(event.end, datetime)
else event.end,
start=start,
end=end,
description=event.description,
uid=event.uid,
rrule=event.rrule.as_rrule_str() if event.rrule else None,

View File

@@ -32,42 +32,42 @@ from .const import ATTR_SENSOR_ID, CONF_SENSOR_ID, DOMAIN
SENSORS: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key="temperature",
name="Temperature",
translation_key="temperature",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="humidity",
name="Humidity",
translation_key="humidity",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="pressure",
name="Pressure",
translation_key="pressure",
native_unit_of_measurement=UnitOfPressure.PA,
device_class=SensorDeviceClass.PRESSURE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="pressure_at_sealevel",
name="Pressure at sealevel",
translation_key="pressure_at_sealevel",
native_unit_of_measurement=UnitOfPressure.PA,
device_class=SensorDeviceClass.PRESSURE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="P1",
name="PM10",
translation_key="pm10",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM10,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="P2",
name="PM2.5",
translation_key="pm25",
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM25,
state_class=SensorStateClass.MEASUREMENT,

View File

@@ -13,5 +13,25 @@
"invalid_sensor": "Sensor not available or invalid",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
}
},
"entity": {
"sensor": {
"humidity": {
"name": "[%key:component::sensor::entity_component::humidity::name%]"
},
"pressure": {
"name": "[%key:component::sensor::entity_component::pressure::name%]"
},
"pressure_at_sealevel": { "name": "Pressure at sealevel" },
"pm10": {
"name": "[%key:component::sensor::entity_component::pm10::name%]"
},
"pm25": {
"name": "[%key:component::sensor::entity_component::pm25::name%]"
},
"temperature": {
"name": "[%key:component::sensor::entity_component::temperature::name%]"
}
}
}
}

View File

@@ -29,6 +29,7 @@ from homeassistant.const import (
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_track_point_in_time
@@ -285,56 +286,34 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity):
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
if not self._async_validate_code(code, STATE_ALARM_DISARMED):
return
self._async_validate_code(code, STATE_ALARM_DISARMED)
self._state = STATE_ALARM_DISARMED
self._state_ts = dt_util.utcnow()
self.async_write_ha_state()
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_HOME
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_HOME)
self._async_update_state(STATE_ALARM_ARMED_HOME)
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_AWAY
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_AWAY)
self._async_update_state(STATE_ALARM_ARMED_AWAY)
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_NIGHT
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_NIGHT)
self._async_update_state(STATE_ALARM_ARMED_NIGHT)
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
"""Send arm vacation command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_VACATION
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_VACATION)
self._async_update_state(STATE_ALARM_ARMED_VACATION)
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
"""Send arm custom bypass command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_CUSTOM_BYPASS
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_CUSTOM_BYPASS)
self._async_update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS)
async def async_alarm_trigger(self, code: str | None = None) -> None:
@@ -383,18 +362,22 @@ class ManualAlarm(alarm.AlarmControlPanelEntity, RestoreEntity):
def _async_validate_code(self, code, state):
"""Validate given code."""
if self._code is None:
return True
if (
state != STATE_ALARM_DISARMED and not self.code_arm_required
) or self._code is None:
return
if isinstance(self._code, str):
alarm_code = self._code
else:
alarm_code = self._code.async_render(
parse_result=False, from_state=self._state, to_state=state
)
check = not alarm_code or code == alarm_code
if not check:
_LOGGER.warning("Invalid code given for %s", state)
return check
if not alarm_code or code == alarm_code:
return
raise HomeAssistantError("Invalid alarm code provided")
@property
def extra_state_attributes(self) -> dict[str, Any]:

View File

@@ -29,6 +29,7 @@ from homeassistant.const import (
STATE_ALARM_TRIGGERED,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import (
@@ -345,56 +346,34 @@ class ManualMQTTAlarm(alarm.AlarmControlPanelEntity):
async def async_alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command."""
if not self._async_validate_code(code, STATE_ALARM_DISARMED):
return
self._async_validate_code(code, STATE_ALARM_DISARMED)
self._state = STATE_ALARM_DISARMED
self._state_ts = dt_util.utcnow()
self.async_schedule_update_ha_state()
async def async_alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_HOME
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_HOME)
self._async_update_state(STATE_ALARM_ARMED_HOME)
async def async_alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_AWAY
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_AWAY)
self._async_update_state(STATE_ALARM_ARMED_AWAY)
async def async_alarm_arm_night(self, code: str | None = None) -> None:
"""Send arm night command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_NIGHT
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_NIGHT)
self._async_update_state(STATE_ALARM_ARMED_NIGHT)
async def async_alarm_arm_vacation(self, code: str | None = None) -> None:
"""Send arm vacation command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_VACATION
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_VACATION)
self._async_update_state(STATE_ALARM_ARMED_VACATION)
async def async_alarm_arm_custom_bypass(self, code: str | None = None) -> None:
"""Send arm custom bypass command."""
if self.code_arm_required and not self._async_validate_code(
code, STATE_ALARM_ARMED_CUSTOM_BYPASS
):
return
self._async_validate_code(code, STATE_ALARM_ARMED_CUSTOM_BYPASS)
self._async_update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS)
async def async_alarm_trigger(self, code: str | None = None) -> None:
@@ -436,18 +415,22 @@ class ManualMQTTAlarm(alarm.AlarmControlPanelEntity):
def _async_validate_code(self, code, state):
"""Validate given code."""
if self._code is None:
return True
if (
state != STATE_ALARM_DISARMED and not self.code_arm_required
) or self._code is None:
return
if isinstance(self._code, str):
alarm_code = self._code
else:
alarm_code = self._code.async_render(
from_state=self._state, to_state=state, parse_result=False
)
check = not alarm_code or code == alarm_code
if not check:
_LOGGER.warning("Invalid code given for %s", state)
return check
if not alarm_code or code == alarm_code:
return
raise HomeAssistantError("Invalid alarm code provided")
@property
def extra_state_attributes(self) -> dict[str, Any]:

View File

@@ -48,7 +48,10 @@ class LocalSource(MediaSource):
@callback
def async_full_path(self, source_dir_id: str, location: str) -> Path:
"""Return full path."""
return Path(self.hass.config.media_dirs[source_dir_id], location)
base_path = self.hass.config.media_dirs[source_dir_id]
full_path = Path(base_path, location)
full_path.relative_to(base_path)
return full_path
@callback
def async_parse_identifier(self, item: MediaSourceItem) -> tuple[str, str]:
@@ -65,6 +68,9 @@ class LocalSource(MediaSource):
except ValueError as err:
raise Unresolvable("Invalid path.") from err
if Path(location).is_absolute():
raise Unresolvable("Invalid path.")
return source_dir_id, location
async def async_resolve_media(self, item: MediaSourceItem) -> PlayMedia:

View File

@@ -113,6 +113,7 @@ RELOADABLE_PLATFORMS = [
Platform.CAMERA,
Platform.CLIMATE,
Platform.COVER,
Platform.DEVICE_TRACKER,
Platform.FAN,
Platform.HUMIDIFIER,
Platform.LIGHT,

View File

@@ -41,15 +41,6 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the MQTT state feed."""
# Make sure MQTT is available and the entry is loaded
if not hass.config_entries.async_entries(
mqtt.DOMAIN
) or not await hass.config_entries.async_wait_component(
hass.config_entries.async_entries(mqtt.DOMAIN)[0]
):
_LOGGER.error("MQTT integration is not available")
return False
conf: ConfigType = config[DOMAIN]
publish_filter = convert_include_exclude_filter(conf)
base_topic: str = conf[CONF_BASE_TOPIC]

View File

@@ -23,7 +23,7 @@ _LOGGER = logging.getLogger(__name__)
RESTART_BUTTON: ButtonEntityDescription = ButtonEntityDescription(
key="restart",
name="Restart",
translation_key="restart",
device_class=ButtonDeviceClass.RESTART,
entity_category=EntityCategory.CONFIG,
)

View File

@@ -89,7 +89,7 @@ class NAMSensorEntityDescription(SensorEntityDescription, NAMSensorRequiredKeysM
SENSORS: tuple[NAMSensorEntityDescription, ...] = (
NAMSensorEntityDescription(
key=ATTR_BME280_HUMIDITY,
name="BME280 humidity",
translation_key="bme280_humidity",
suggested_display_precision=1,
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
@@ -98,7 +98,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_BME280_PRESSURE,
name="BME280 pressure",
translation_key="bme280_pressure",
suggested_display_precision=0,
native_unit_of_measurement=UnitOfPressure.HPA,
device_class=SensorDeviceClass.PRESSURE,
@@ -107,7 +107,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_BME280_TEMPERATURE,
name="BME280 temperature",
translation_key="bme280_temperature",
suggested_display_precision=1,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
@@ -116,7 +116,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_BMP180_PRESSURE,
name="BMP180 pressure",
translation_key="bmp180_pressure",
suggested_display_precision=0,
native_unit_of_measurement=UnitOfPressure.HPA,
device_class=SensorDeviceClass.PRESSURE,
@@ -125,7 +125,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_BMP180_TEMPERATURE,
name="BMP180 temperature",
translation_key="bmp180_temperature",
suggested_display_precision=1,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
@@ -134,7 +134,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_BMP280_PRESSURE,
name="BMP280 pressure",
translation_key="bmp280_pressure",
suggested_display_precision=0,
native_unit_of_measurement=UnitOfPressure.HPA,
device_class=SensorDeviceClass.PRESSURE,
@@ -143,7 +143,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_BMP280_TEMPERATURE,
name="BMP280 temperature",
translation_key="bmp280_temperature",
suggested_display_precision=1,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
@@ -152,7 +152,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_HECA_HUMIDITY,
name="HECA humidity",
translation_key="heca_humidity",
suggested_display_precision=1,
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
@@ -161,7 +161,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_HECA_TEMPERATURE,
name="HECA temperature",
translation_key="heca_temperature",
suggested_display_precision=1,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
@@ -170,7 +170,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_MHZ14A_CARBON_DIOXIDE,
name="MH-Z14A carbon dioxide",
translation_key="mhz14a_carbon_dioxide",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
device_class=SensorDeviceClass.CO2,
@@ -179,22 +179,21 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_PMSX003_CAQI,
name="PMSx003 CAQI",
translation_key="pmsx003_caqi",
icon="mdi:air-filter",
value=lambda sensors: sensors.pms_caqi,
),
NAMSensorEntityDescription(
key=ATTR_PMSX003_CAQI_LEVEL,
name="PMSx003 CAQI level",
translation_key="pmsx003_caqi_level",
icon="mdi:air-filter",
device_class=SensorDeviceClass.ENUM,
options=["very_low", "low", "medium", "high", "very_high"],
translation_key="caqi_level",
value=lambda sensors: sensors.pms_caqi_level,
),
NAMSensorEntityDescription(
key=ATTR_PMSX003_P0,
name="PMSx003 particulate matter 1.0",
translation_key="pmsx003_pm1",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM1,
@@ -203,7 +202,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_PMSX003_P1,
name="PMSx003 particulate matter 10",
translation_key="pmsx003_pm10",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM10,
@@ -212,7 +211,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_PMSX003_P2,
name="PMSx003 particulate matter 2.5",
translation_key="pmsx003_pm25",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM25,
@@ -221,22 +220,21 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_SDS011_CAQI,
name="SDS011 CAQI",
translation_key="sds011_caqi",
icon="mdi:air-filter",
value=lambda sensors: sensors.sds011_caqi,
),
NAMSensorEntityDescription(
key=ATTR_SDS011_CAQI_LEVEL,
name="SDS011 CAQI level",
translation_key="sds011_caqi_level",
icon="mdi:air-filter",
device_class=SensorDeviceClass.ENUM,
options=["very_low", "low", "medium", "high", "very_high"],
translation_key="caqi_level",
value=lambda sensors: sensors.sds011_caqi_level,
),
NAMSensorEntityDescription(
key=ATTR_SDS011_P1,
name="SDS011 particulate matter 10",
translation_key="sds011_pm10",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM10,
@@ -245,7 +243,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_SDS011_P2,
name="SDS011 particulate matter 2.5",
translation_key="sds011_pm25",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM25,
@@ -254,7 +252,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_SHT3X_HUMIDITY,
name="SHT3X humidity",
translation_key="sht3x_humidity",
suggested_display_precision=1,
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
@@ -263,7 +261,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_SHT3X_TEMPERATURE,
name="SHT3X temperature",
translation_key="sht3x_temperature",
suggested_display_precision=1,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
@@ -272,22 +270,21 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_SPS30_CAQI,
name="SPS30 CAQI",
translation_key="sps30_caqi",
icon="mdi:air-filter",
value=lambda sensors: sensors.sps30_caqi,
),
NAMSensorEntityDescription(
key=ATTR_SPS30_CAQI_LEVEL,
name="SPS30 CAQI level",
translation_key="sps30_caqi_level",
icon="mdi:air-filter",
device_class=SensorDeviceClass.ENUM,
options=["very_low", "low", "medium", "high", "very_high"],
translation_key="caqi_level",
value=lambda sensors: sensors.sps30_caqi_level,
),
NAMSensorEntityDescription(
key=ATTR_SPS30_P0,
name="SPS30 particulate matter 1.0",
translation_key="sps30_pm1",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM1,
@@ -296,7 +293,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_SPS30_P1,
name="SPS30 particulate matter 10",
translation_key="sps30_pm10",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM10,
@@ -305,7 +302,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_SPS30_P2,
name="SPS30 particulate matter 2.5",
translation_key="sps30_pm25",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
device_class=SensorDeviceClass.PM25,
@@ -314,7 +311,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_SPS30_P4,
name="SPS30 particulate matter 4.0",
translation_key="sps30_pm4",
suggested_display_precision=0,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
icon="mdi:molecule",
@@ -323,7 +320,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_DHT22_HUMIDITY,
name="DHT22 humidity",
translation_key="dht22_humidity",
suggested_display_precision=1,
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
@@ -332,7 +329,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_DHT22_TEMPERATURE,
name="DHT22 temperature",
translation_key="dht22_temperature",
suggested_display_precision=1,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
@@ -341,7 +338,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_SIGNAL_STRENGTH,
name="Signal strength",
translation_key="signal_strength",
suggested_display_precision=0,
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
@@ -352,7 +349,7 @@ SENSORS: tuple[NAMSensorEntityDescription, ...] = (
),
NAMSensorEntityDescription(
key=ATTR_UPTIME,
name="Uptime",
translation_key="last_restart",
device_class=SensorDeviceClass.TIMESTAMP,
entity_registry_enabled_default=False,
entity_category=EntityCategory.DIAGNOSTIC,

View File

@@ -39,8 +39,47 @@
}
},
"entity": {
"button": {
"restart": {
"name": "[%key:component::button::entity_component::restart::name%]"
}
},
"sensor": {
"caqi_level": {
"bme280_humidity": {
"name": "BME280 humidity"
},
"bme280_pressure": {
"name": "BME280 pressure"
},
"bme280_temperature": {
"name": "BME280 temperature"
},
"bmp180_pressure": {
"name": "BMP180 pressure"
},
"bmp180_temperature": {
"name": "BMP180 temperature"
},
"bmp280_pressure": {
"name": "BMP280 pressure"
},
"bmp280_temperature": {
"name": "BMP280 temperature"
},
"heca_humidity": {
"name": "HECA humidity"
},
"heca_temperature": {
"name": "HECA temperature"
},
"mhz14a_carbon_dioxide": {
"name": "MH-Z14A carbon dioxide"
},
"pmsx003_caqi": {
"name": "PMSx003 common air quality index"
},
"pmsx003_caqi_level": {
"name": "PMSx003 common air quality index level",
"state": {
"very_low": "Very low",
"low": "Low",
@@ -48,6 +87,77 @@
"high": "High",
"very_high": "Very high"
}
},
"pmsx003_pm1": {
"name": "PMSx003 particulate matter 1 μm"
},
"pmsx003_pm10": {
"name": "PMSx003 particulate matter 10 μm"
},
"pmsx003_pm25": {
"name": "PMSx003 particulate matter 2.5 μm"
},
"sds011_caqi": {
"name": "SDS011 common air quality index"
},
"sds011_caqi_level": {
"name": "SDS011 common air quality index level",
"state": {
"very_low": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::very_low%]",
"low": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::low%]",
"medium": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::medium%]",
"high": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::high%]",
"very_high": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::very_high%]"
}
},
"sds011_pm10": {
"name": "SDS011 particulate matter 10 μm"
},
"sds011_pm25": {
"name": "SDS011 particulate matter 2.5 μm"
},
"sht3x_humidity": {
"name": "SHT3X humidity"
},
"sht3x_temperature": {
"name": "SHT3X temperature"
},
"sps30_caqi": {
"name": "SPS30 common air quality index"
},
"sps30_caqi_level": {
"name": "SPS30 common air quality index level",
"state": {
"very_low": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::very_low%]",
"low": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::low%]",
"medium": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::medium%]",
"high": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::high%]",
"very_high": "[%key:component::nam::entity::sensor::pmsx003_caqi_level::state::very_high%]"
}
},
"sps30_pm1": {
"name": "SPS30 particulate matter 1 μm"
},
"sps30_pm10": {
"name": "SPS30 particulate matter 10 μm"
},
"sps30_pm25": {
"name": "SPS30 particulate matter 2.5 μm"
},
"sps30_pm4": {
"name": "SPS30 Particulate matter 4 μm"
},
"dht22_humidity": {
"name": "DHT22 humidity"
},
"dht22_temperature": {
"name": "DHT22 temperature"
},
"signal_strength": {
"name": "[%key:component::sensor::entity_component::signal_strength::name%]"
},
"last_restart": {
"name": "Last restart"
}
}
}

View File

@@ -79,7 +79,7 @@ class TemperatureSensor(SensorBase):
_attr_device_class = SensorDeviceClass.TEMPERATURE
_attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
_attr_name = "Temperature"
_attr_translation_key = "temperature"
@property
def native_value(self) -> float:
@@ -96,7 +96,7 @@ class HumiditySensor(SensorBase):
_attr_device_class = SensorDeviceClass.HUMIDITY
_attr_native_unit_of_measurement = PERCENTAGE
_attr_name = "Humidity"
_attr_translation_key = "humidity"
@property
def native_value(self) -> int:

View File

@@ -98,5 +98,15 @@
"title": "Nest Authentication Credentials must be updated",
"description": "To improve security and reduce phishing risk Google has deprecated the authentication method used by Home Assistant.\n\n**This requires action by you to resolve** ([more info]({more_info_url}))\n\n1. Visit the integrations page\n1. Click Reconfigure on the Nest integration.\n1. Home Assistant will walk you through the steps to upgrade to Web Authentication.\n\nSee the Nest [integration instructions]({documentation_url}) for troubleshooting information."
}
},
"entity": {
"sensor": {
"temperature": {
"name": "[%key:component::sensor::entity_component::temperature::name%]"
},
"humidity": {
"name": "[%key:component::sensor::entity_component::humidity::name%]"
}
}
}
}

View File

@@ -43,14 +43,14 @@ SENSORS = (
NextDnsBinarySensorEntityDescription[ConnectionStatus](
key="this_device_nextdns_connection_status",
entity_category=EntityCategory.DIAGNOSTIC,
name="This device NextDNS connection status",
translation_key="device_connection_status",
device_class=BinarySensorDeviceClass.CONNECTIVITY,
state=lambda data, _: data.connected,
),
NextDnsBinarySensorEntityDescription[ConnectionStatus](
key="this_device_profile_connection_status",
entity_category=EntityCategory.DIAGNOSTIC,
name="This device profile connection status",
translation_key="device_profile_connection_status",
device_class=BinarySensorDeviceClass.CONNECTIVITY,
state=lambda data, profile_id: profile_id == data.profile_id,
),

View File

@@ -15,7 +15,7 @@ PARALLEL_UPDATES = 1
CLEAR_LOGS_BUTTON = ButtonEntityDescription(
key="clear_logs",
name="Clear logs",
translation_key="clear_logs",
entity_category=EntityCategory.CONFIG,
)

View File

@@ -60,7 +60,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
coordinator_type=ATTR_STATUS,
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:dns",
name="DNS queries",
translation_key="all_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.all_queries,
@@ -70,7 +70,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
coordinator_type=ATTR_STATUS,
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:dns",
name="DNS queries blocked",
translation_key="blocked_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.blocked_queries,
@@ -80,7 +80,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
coordinator_type=ATTR_STATUS,
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:dns",
name="DNS queries relayed",
translation_key="relayed_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.relayed_queries,
@@ -90,7 +90,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
coordinator_type=ATTR_STATUS,
entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:dns",
name="DNS queries blocked ratio",
translation_key="blocked_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.blocked_queries_ratio,
@@ -101,7 +101,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:dns",
name="DNS-over-HTTPS queries",
translation_key="doh_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.doh_queries,
@@ -112,7 +112,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:dns",
name="DNS-over-HTTP/3 queries",
translation_key="doh3_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.doh3_queries,
@@ -123,7 +123,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:dns",
name="DNS-over-TLS queries",
translation_key="dot_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.dot_queries,
@@ -134,7 +134,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:dns",
name="DNS-over-QUIC queries",
translation_key="doq_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.doq_queries,
@@ -145,7 +145,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:dns",
name="TCP queries",
translation_key="tcp_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.tcp_queries,
@@ -156,7 +156,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:dns",
name="UDP queries",
translation_key="udp_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.udp_queries,
@@ -167,7 +167,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_registry_enabled_default=False,
icon="mdi:dns",
entity_category=EntityCategory.DIAGNOSTIC,
name="DNS-over-HTTPS queries ratio",
translation_key="doh_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.doh_queries_ratio,
@@ -178,7 +178,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_registry_enabled_default=False,
icon="mdi:dns",
entity_category=EntityCategory.DIAGNOSTIC,
name="DNS-over-HTTP/3 queries ratio",
translation_key="doh3_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.doh3_queries_ratio,
@@ -189,7 +189,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:dns",
name="DNS-over-TLS queries ratio",
translation_key="dot_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.dot_queries_ratio,
@@ -200,7 +200,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_registry_enabled_default=False,
icon="mdi:dns",
entity_category=EntityCategory.DIAGNOSTIC,
name="DNS-over-QUIC queries ratio",
translation_key="doq_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.doq_queries_ratio,
@@ -211,7 +211,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:dns",
name="TCP queries ratio",
translation_key="tcp_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.tcp_queries_ratio,
@@ -222,7 +222,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:dns",
name="UDP queries ratio",
translation_key="udp_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.udp_queries_ratio,
@@ -233,7 +233,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:lock",
name="Encrypted queries",
translation_key="encrypted_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.encrypted_queries,
@@ -244,7 +244,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:lock-open",
name="Unencrypted queries",
translation_key="unencrypted_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.unencrypted_queries,
@@ -255,7 +255,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:lock",
name="Encrypted queries ratio",
translation_key="encrypted_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.encrypted_queries_ratio,
@@ -266,7 +266,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:ip",
name="IPv4 queries",
translation_key="ipv4_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.ipv4_queries,
@@ -277,7 +277,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:ip",
name="IPv6 queries",
translation_key="ipv6_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.ipv6_queries,
@@ -288,7 +288,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:ip",
name="IPv6 queries ratio",
translation_key="ipv6_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.ipv6_queries_ratio,
@@ -299,7 +299,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:lock-check",
name="DNSSEC validated queries",
translation_key="validated_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.validated_queries,
@@ -310,7 +310,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:lock-alert",
name="DNSSEC not validated queries",
translation_key="not_validated_queries",
native_unit_of_measurement="queries",
state_class=SensorStateClass.TOTAL,
value=lambda data: data.not_validated_queries,
@@ -321,7 +321,7 @@ SENSORS: tuple[NextDnsSensorEntityDescription, ...] = (
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
icon="mdi:lock-check",
name="DNSSEC validated queries ratio",
translation_key="validated_queries_ratio",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
value=lambda data: data.validated_queries_ratio,

View File

@@ -25,5 +25,294 @@
"info": {
"can_reach_server": "Reach server"
}
},
"entity": {
"binary_sensor": {
"device_connection_status": {
"name": "Device connection status"
},
"device_profile_connection_status": {
"name": "Device profile connection status"
}
},
"button": {
"clear_logs": {
"name": "Clear logs"
}
},
"sensor": {
"all_queries": {
"name": "DNS queries"
},
"blocked_queries": {
"name": "DNS queries blocked"
},
"blocked_queries_ratio": {
"name": "DNS queries blocked ratio"
},
"doh3_queries": {
"name": "DNS-over-HTTP/3 queries"
},
"doh3_queries_ratio": {
"name": "DNS-over-HTTP/3 queries ratio"
},
"doh_queries": {
"name": "DNS-over-HTTPS queries"
},
"doh_queries_ratio": {
"name": "DNS-over-HTTPS queries ratio"
},
"doq_queries": {
"name": "DNS-over-QUIC queries"
},
"doq_queries_ratio": {
"name": "DNS-over-QUIC queries ratio"
},
"dot_queries": {
"name": "DNS-over-TLS queries"
},
"dot_queries_ratio": {
"name": "DNS-over-TLS queries ratio"
},
"encrypted_queries": {
"name": "Encrypted queries"
},
"encrypted_queries_ratio": {
"name": "Encrypted queries ratio"
},
"ipv4_queries": {
"name": "IPv4 queries"
},
"ipv6_queries": {
"name": "IPv6 queries"
},
"ipv6_queries_ratio": {
"name": "IPv6 queries ratio"
},
"not_validated_queries": {
"name": "DNSSEC not validated queries"
},
"relayed_queries": {
"name": "DNS queries relayed"
},
"tcp_queries": {
"name": "TCP queries"
},
"tcp_queries_ratio": {
"name": "TCP queries ratio"
},
"udp_queries": {
"name": "UDP queries"
},
"udp_queries_ratio": {
"name": "UDP queries ratio"
},
"unencrypted_queries": {
"name": "Unencrypted queries"
},
"validated_queries": {
"name": "DNSSEC validated queries"
},
"validated_queries_ratio": {
"name": "DNSSEC validated queries ratio"
}
},
"switch": {
"ai_threat_detection": {
"name": "AI-Driven threat detection"
},
"allow_affiliate": {
"name": "Allow affiliate & tracking links"
},
"anonymized_ecs": {
"name": "Anonymized EDNS client subnet"
},
"block_9gag": {
"name": "Block 9GAG"
},
"block_amazon": {
"name": "Block Amazon"
},
"block_blizzard": {
"name": "Block Blizzard"
},
"block_bypass_methods": {
"name": "Block bypass methods"
},
"block_csam": {
"name": "Block child sexual abuse material"
},
"block_dailymotion": {
"name": "Block Dailymotion"
},
"block_dating": {
"name": "Block dating"
},
"block_ddns": {
"name": "Block dynamic DNS hostnames"
},
"block_discord": {
"name": "Block Discord"
},
"block_disguised_trackers": {
"name": "Block disguised third-party trackers"
},
"block_disneyplus": {
"name": "Block Disney Plus"
},
"block_ebay": {
"name": "Block eBay"
},
"block_facebook": {
"name": "Block Facebook"
},
"block_fortnite": {
"name": "Block Fortnite"
},
"block_gambling": {
"name": "Block gambling"
},
"block_hulu": {
"name": "Block Hulu"
},
"block_imgur": {
"name": "Block Imgur"
},
"block_instagram": {
"name": "Block Instagram"
},
"block_leagueoflegends": {
"name": "Block League of Legends"
},
"block_messenger": {
"name": "Block Messenger"
},
"block_minecraft": {
"name": "Block Minecraft"
},
"block_netflix": {
"name": "Block Netflix"
},
"block_nrd": {
"name": "Block newly registered domains"
},
"block_page": {
"name": "Block page"
},
"block_parked_domains": {
"name": "Block parked domains"
},
"block_pinterest": {
"name": "Block Pinterest"
},
"block_piracy": {
"name": "Block piracy"
},
"block_porn": {
"name": "Block porn"
},
"block_primevideo": {
"name": "Block Prime Video"
},
"block_reddit": {
"name": "Block Reddit"
},
"block_roblox": {
"name": "Block Roblox"
},
"block_signal": {
"name": "Block Signal"
},
"block_skype": {
"name": "Block Skype"
},
"block_snapchat": {
"name": "Block Snapchat"
},
"block_social_networks": {
"name": "Block social networks"
},
"block_spotify": {
"name": "Block Spotify"
},
"block_steam": {
"name": "Block Steam"
},
"block_telegram": {
"name": "Block Telegram"
},
"block_tiktok": {
"name": "Block TikTok"
},
"block_tinder": {
"name": "Block Tinder"
},
"block_tumblr": {
"name": "Block Tumblr"
},
"block_twitch": {
"name": "Block Twitch"
},
"block_twitter": {
"name": "Block Twitter"
},
"block_vimeo": {
"name": "Block Vimeo"
},
"block_vk": {
"name": "Block VK"
},
"block_whatsapp": {
"name": "Block WhatsApp"
},
"block_xboxlive": {
"name": "Block Xbox Live"
},
"block_youtube": {
"name": "Block YouTube"
},
"block_zoom": {
"name": "Block Zoom"
},
"cache_boost": {
"name": "Cache boost"
},
"cname_flattening": {
"name": "CNAME flattening"
},
"cryptojacking_protection": {
"name": "Cryptojacking protection"
},
"dga_protection": {
"name": "Domain generation algorithms protection"
},
"dns_rebinding_protection": {
"name": "DNS rebinding protection"
},
"google_safe_browsing": {
"name": "Google safe browsing"
},
"idn_homograph_attacks_protection": {
"name": "IDN homograph attacks protection"
},
"logs": {
"name": "Logs"
},
"safesearch": {
"name": "Force SafeSearch"
},
"threat_intelligence_feeds": {
"name": "Threat intelligence feeds"
},
"typosquatting_protection": {
"name": "Typosquatting protection"
},
"web3": {
"name": "Web3"
},
"youtube_restricted_mode": {
"name": "Force YouTube restricted mode"
}
}
}
}

View File

@@ -41,156 +41,156 @@ class NextDnsSwitchEntityDescription(
SWITCHES = (
NextDnsSwitchEntityDescription[Settings](
key="block_page",
name="Block page",
translation_key="block_page",
entity_category=EntityCategory.CONFIG,
icon="mdi:web-cancel",
state=lambda data: data.block_page,
),
NextDnsSwitchEntityDescription[Settings](
key="cache_boost",
name="Cache boost",
translation_key="cache_boost",
entity_category=EntityCategory.CONFIG,
icon="mdi:memory",
state=lambda data: data.cache_boost,
),
NextDnsSwitchEntityDescription[Settings](
key="cname_flattening",
name="CNAME flattening",
translation_key="cname_flattening",
entity_category=EntityCategory.CONFIG,
icon="mdi:tournament",
state=lambda data: data.cname_flattening,
),
NextDnsSwitchEntityDescription[Settings](
key="anonymized_ecs",
name="Anonymized EDNS client subnet",
translation_key="anonymized_ecs",
entity_category=EntityCategory.CONFIG,
icon="mdi:incognito",
state=lambda data: data.anonymized_ecs,
),
NextDnsSwitchEntityDescription[Settings](
key="logs",
name="Logs",
translation_key="logs",
entity_category=EntityCategory.CONFIG,
icon="mdi:file-document-outline",
state=lambda data: data.logs,
),
NextDnsSwitchEntityDescription[Settings](
key="web3",
name="Web3",
translation_key="web3",
entity_category=EntityCategory.CONFIG,
icon="mdi:web",
state=lambda data: data.web3,
),
NextDnsSwitchEntityDescription[Settings](
key="allow_affiliate",
name="Allow affiliate & tracking links",
translation_key="allow_affiliate",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.allow_affiliate,
),
NextDnsSwitchEntityDescription[Settings](
key="block_disguised_trackers",
name="Block disguised third-party trackers",
translation_key="block_disguised_trackers",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.block_disguised_trackers,
),
NextDnsSwitchEntityDescription[Settings](
key="ai_threat_detection",
name="AI-Driven threat detection",
translation_key="ai_threat_detection",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.ai_threat_detection,
),
NextDnsSwitchEntityDescription[Settings](
key="block_csam",
name="Block child sexual abuse material",
translation_key="block_csam",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.block_csam,
),
NextDnsSwitchEntityDescription[Settings](
key="block_ddns",
name="Block dynamic DNS hostnames",
translation_key="block_ddns",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.block_ddns,
),
NextDnsSwitchEntityDescription[Settings](
key="block_nrd",
name="Block newly registered domains",
translation_key="block_nrd",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.block_nrd,
),
NextDnsSwitchEntityDescription[Settings](
key="block_parked_domains",
name="Block parked domains",
translation_key="block_parked_domains",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.block_parked_domains,
),
NextDnsSwitchEntityDescription[Settings](
key="cryptojacking_protection",
name="Cryptojacking protection",
translation_key="cryptojacking_protection",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.cryptojacking_protection,
),
NextDnsSwitchEntityDescription[Settings](
key="dga_protection",
name="Domain generation algorithms protection",
translation_key="dga_protection",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.dga_protection,
),
NextDnsSwitchEntityDescription[Settings](
key="dns_rebinding_protection",
name="DNS rebinding protection",
translation_key="dns_rebinding_protection",
entity_category=EntityCategory.CONFIG,
icon="mdi:dns",
state=lambda data: data.dns_rebinding_protection,
),
NextDnsSwitchEntityDescription[Settings](
key="google_safe_browsing",
name="Google safe browsing",
translation_key="google_safe_browsing",
entity_category=EntityCategory.CONFIG,
icon="mdi:google",
state=lambda data: data.google_safe_browsing,
),
NextDnsSwitchEntityDescription[Settings](
key="idn_homograph_attacks_protection",
name="IDN homograph attacks protection",
translation_key="idn_homograph_attacks_protection",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.idn_homograph_attacks_protection,
),
NextDnsSwitchEntityDescription[Settings](
key="threat_intelligence_feeds",
name="Threat intelligence feeds",
translation_key="threat_intelligence_feeds",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.threat_intelligence_feeds,
),
NextDnsSwitchEntityDescription[Settings](
key="typosquatting_protection",
name="Typosquatting protection",
translation_key="typosquatting_protection",
entity_category=EntityCategory.CONFIG,
icon="mdi:keyboard-outline",
state=lambda data: data.typosquatting_protection,
),
NextDnsSwitchEntityDescription[Settings](
key="block_bypass_methods",
name="Block bypass methods",
translation_key="block_bypass_methods",
entity_category=EntityCategory.CONFIG,
state=lambda data: data.block_bypass_methods,
),
NextDnsSwitchEntityDescription[Settings](
key="safesearch",
name="Force SafeSearch",
translation_key="safesearch",
entity_category=EntityCategory.CONFIG,
icon="mdi:search-web",
state=lambda data: data.safesearch,
),
NextDnsSwitchEntityDescription[Settings](
key="youtube_restricted_mode",
name="Force YouTube restricted mode",
translation_key="youtube_restricted_mode",
entity_category=EntityCategory.CONFIG,
icon="mdi:youtube",
state=lambda data: data.youtube_restricted_mode,
),
NextDnsSwitchEntityDescription[Settings](
key="block_9gag",
name="Block 9GAG",
translation_key="block_9gag",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:file-gif-box",
@@ -198,7 +198,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_amazon",
name="Block Amazon",
translation_key="block_amazon",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:cart-outline",
@@ -206,7 +206,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_blizzard",
name="Block Blizzard",
translation_key="block_blizzard",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:sword-cross",
@@ -214,7 +214,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_dailymotion",
name="Block Dailymotion",
translation_key="block_dailymotion",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:movie-search-outline",
@@ -222,7 +222,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_discord",
name="Block Discord",
translation_key="block_discord",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:message-text",
@@ -230,7 +230,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_disneyplus",
name="Block Disney Plus",
translation_key="block_disneyplus",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:movie-search-outline",
@@ -238,7 +238,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_ebay",
name="Block eBay",
translation_key="block_ebay",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:basket-outline",
@@ -246,7 +246,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_facebook",
name="Block Facebook",
translation_key="block_facebook",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:facebook",
@@ -254,7 +254,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_fortnite",
name="Block Fortnite",
translation_key="block_fortnite",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:tank",
@@ -270,7 +270,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_imgur",
name="Block Imgur",
translation_key="block_imgur",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:camera-image",
@@ -278,7 +278,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_instagram",
name="Block Instagram",
translation_key="block_instagram",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:instagram",
@@ -286,7 +286,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_leagueoflegends",
name="Block League of Legends",
translation_key="block_leagueoflegends",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:sword",
@@ -294,7 +294,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_messenger",
name="Block Messenger",
translation_key="block_messenger",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:message-text",
@@ -302,7 +302,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_minecraft",
name="Block Minecraft",
translation_key="block_minecraft",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:minecraft",
@@ -310,7 +310,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_netflix",
name="Block Netflix",
translation_key="block_netflix",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:netflix",
@@ -318,7 +318,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_pinterest",
name="Block Pinterest",
translation_key="block_pinterest",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:pinterest",
@@ -326,7 +326,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_primevideo",
name="Block Prime Video",
translation_key="block_primevideo",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:filmstrip",
@@ -334,7 +334,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_reddit",
name="Block Reddit",
translation_key="block_reddit",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:reddit",
@@ -342,7 +342,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_roblox",
name="Block Roblox",
translation_key="block_roblox",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:robot",
@@ -350,7 +350,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_signal",
name="Block Signal",
translation_key="block_signal",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:chat-outline",
@@ -358,7 +358,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_skype",
name="Block Skype",
translation_key="block_skype",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:skype",
@@ -366,7 +366,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_snapchat",
name="Block Snapchat",
translation_key="block_snapchat",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:snapchat",
@@ -374,7 +374,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_spotify",
name="Block Spotify",
translation_key="block_spotify",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:spotify",
@@ -382,7 +382,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_steam",
name="Block Steam",
translation_key="block_steam",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:steam",
@@ -390,7 +390,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_telegram",
name="Block Telegram",
translation_key="block_telegram",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:send-outline",
@@ -398,7 +398,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_tiktok",
name="Block TikTok",
translation_key="block_tiktok",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:music-note",
@@ -406,7 +406,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_tinder",
name="Block Tinder",
translation_key="block_tinder",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:fire",
@@ -414,7 +414,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_tumblr",
name="Block Tumblr",
translation_key="block_tumblr",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:image-outline",
@@ -422,7 +422,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_twitch",
name="Block Twitch",
translation_key="block_twitch",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:twitch",
@@ -430,7 +430,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_twitter",
name="Block Twitter",
translation_key="block_twitter",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:twitter",
@@ -438,7 +438,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_vimeo",
name="Block Vimeo",
translation_key="block_vimeo",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:vimeo",
@@ -446,7 +446,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_vk",
name="Block VK",
translation_key="block_vk",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:power-socket-eu",
@@ -454,7 +454,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_whatsapp",
name="Block WhatsApp",
translation_key="block_whatsapp",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:whatsapp",
@@ -462,7 +462,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_xboxlive",
name="Block Xbox Live",
translation_key="block_xboxlive",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:microsoft-xbox",
@@ -470,7 +470,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_youtube",
name="Block YouTube",
translation_key="block_youtube",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:youtube",
@@ -478,7 +478,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_zoom",
name="Block Zoom",
translation_key="block_zoom",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:video",
@@ -486,7 +486,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_dating",
name="Block dating",
translation_key="block_dating",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:candelabra",
@@ -494,7 +494,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_gambling",
name="Block gambling",
translation_key="block_gambling",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:slot-machine",
@@ -502,7 +502,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_piracy",
name="Block piracy",
translation_key="block_piracy",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:pirate",
@@ -510,7 +510,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_porn",
name="Block porn",
translation_key="block_porn",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:movie-off",
@@ -518,7 +518,7 @@ SWITCHES = (
),
NextDnsSwitchEntityDescription[Settings](
key="block_social_networks",
name="Block social networks",
translation_key="block_social_networks",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
icon="mdi:facebook",

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