mirror of
https://github.com/home-assistant/core.git
synced 2026-04-17 23:18:58 +02:00
Compare commits
68 Commits
2026.4.0b6
...
2026.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b981ece163 | ||
|
|
7ea931fdc8 | ||
|
|
f3038a20af | ||
|
|
de234c7190 | ||
|
|
399681984f | ||
|
|
5ca14ca7d7 | ||
|
|
ac53cfa85a | ||
|
|
02f1a9c3a9 | ||
|
|
f93fdceac9 | ||
|
|
711a89f7b8 | ||
|
|
19e58c554e | ||
|
|
feb6c2bfe6 | ||
|
|
6bb91422ff | ||
|
|
3bd699285b | ||
|
|
6d10305197 | ||
|
|
42a9c8488d | ||
|
|
c6c273559e | ||
|
|
f7394ce302 | ||
|
|
175dec6f1a | ||
|
|
d137761cb5 | ||
|
|
8055cbc58d | ||
|
|
c9dff27590 | ||
|
|
c913a858b6 | ||
|
|
4ed33a804e | ||
|
|
8bf5674826 | ||
|
|
b8a0b0083b | ||
|
|
a57c101b5e | ||
|
|
957b8c1c52 | ||
|
|
bb002d051b | ||
|
|
2b2fd4ac92 | ||
|
|
f4c270629b | ||
|
|
0e5fc44af3 | ||
|
|
803531125b | ||
|
|
c70ddd559b | ||
|
|
c06d898b00 | ||
|
|
c6233d02e8 | ||
|
|
37e69cad16 | ||
|
|
b14e729b2d | ||
|
|
87e0f2d36c | ||
|
|
ae60135a08 | ||
|
|
3ed2dccbec | ||
|
|
689ee7c1e7 | ||
|
|
12d6d7ef88 | ||
|
|
4f88c5ed29 | ||
|
|
35826dfd14 | ||
|
|
12dc33eabc | ||
|
|
9650aea6a1 | ||
|
|
aaff319e70 | ||
|
|
d9babc37f0 | ||
|
|
a616de7452 | ||
|
|
817d3e1178 | ||
|
|
e353ed1e2e | ||
|
|
96b7210bca | ||
|
|
22a6968a08 | ||
|
|
ce8519c1b1 | ||
|
|
871d9ee0b4 | ||
|
|
11d9f236b9 | ||
|
|
8be6f441dd | ||
|
|
d432092296 | ||
|
|
4d168023a2 | ||
|
|
d4d639dfa2 | ||
|
|
92375078c0 | ||
|
|
fc6efac559 | ||
|
|
a9e1bbd5ab | ||
|
|
dcf6416ae9 | ||
|
|
df6b2ba0cd | ||
|
|
19166e7938 | ||
|
|
3472a2bfbf |
2
.github/workflows/builder.yml
vendored
2
.github/workflows/builder.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
|
||||
- name: Get information
|
||||
id: info
|
||||
uses: home-assistant/actions/helpers/info@master # zizmor: ignore[unpinned-uses]
|
||||
uses: home-assistant/actions/helpers/info@5f5b077d63a1e4c53019231409a0c4d791fb74e5 # zizmor: ignore[unpinned-uses]
|
||||
|
||||
- name: Get version
|
||||
id: version
|
||||
|
||||
@@ -174,7 +174,6 @@ homeassistant.components.dnsip.*
|
||||
homeassistant.components.doorbird.*
|
||||
homeassistant.components.dormakaba_dkey.*
|
||||
homeassistant.components.downloader.*
|
||||
homeassistant.components.dropbox.*
|
||||
homeassistant.components.droplet.*
|
||||
homeassistant.components.dsmr.*
|
||||
homeassistant.components.duckdns.*
|
||||
|
||||
2
CODEOWNERS
generated
2
CODEOWNERS
generated
@@ -401,8 +401,6 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/dremel_3d_printer/ @tkdrob
|
||||
/homeassistant/components/drop_connect/ @ChandlerSystems @pfrazer
|
||||
/tests/components/drop_connect/ @ChandlerSystems @pfrazer
|
||||
/homeassistant/components/dropbox/ @bdr99
|
||||
/tests/components/dropbox/ @bdr99
|
||||
/homeassistant/components/droplet/ @sarahseidman
|
||||
/tests/components/droplet/ @sarahseidman
|
||||
/homeassistant/components/dsmr/ @Robbie1221
|
||||
|
||||
@@ -238,7 +238,9 @@ DEFAULT_INTEGRATIONS = {
|
||||
"timer",
|
||||
#
|
||||
# Base platforms:
|
||||
*BASE_PLATFORMS,
|
||||
# Note: Calendar and todo are not included to prevent them from registering
|
||||
# their frontend panels when there are no calendar or todo integrations.
|
||||
*(BASE_PLATFORMS - {"calendar", "todo"}),
|
||||
#
|
||||
# Integrations providing triggers and conditions for base platforms:
|
||||
"air_quality",
|
||||
|
||||
5
homeassistant/brands/bega.json
Normal file
5
homeassistant/brands/bega.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"domain": "bega",
|
||||
"name": "BEGA",
|
||||
"iot_standards": ["zigbee"]
|
||||
}
|
||||
@@ -1,25 +1,18 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the value should match on the targeted entities.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"trigger_behavior_description": "The behavior of the targeted entities to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_threshold_changed_description": "Which changes to trigger on and threshold values.",
|
||||
"trigger_threshold_crossed_description": "Which threshold crossing to trigger on and threshold values.",
|
||||
"trigger_threshold_name": "Threshold configuration"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_threshold_name": "Threshold type"
|
||||
},
|
||||
"conditions": {
|
||||
"is_co2_value": {
|
||||
"description": "Tests the carbon dioxide level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -29,7 +22,6 @@
|
||||
"description": "Tests if one or more carbon monoxide sensors are cleared.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -39,7 +31,6 @@
|
||||
"description": "Tests if one or more carbon monoxide sensors are detecting carbon monoxide.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -49,11 +40,9 @@
|
||||
"description": "Tests the carbon monoxide level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -63,7 +52,6 @@
|
||||
"description": "Tests if one or more gas sensors are cleared.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -73,7 +61,6 @@
|
||||
"description": "Tests if one or more gas sensors are detecting gas.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -83,11 +70,9 @@
|
||||
"description": "Tests the nitrous oxide level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -97,11 +82,9 @@
|
||||
"description": "Tests the nitrogen dioxide level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -111,11 +94,9 @@
|
||||
"description": "Tests the nitrogen monoxide level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -125,11 +106,9 @@
|
||||
"description": "Tests the ozone level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -139,11 +118,9 @@
|
||||
"description": "Tests the PM10 level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -153,11 +130,9 @@
|
||||
"description": "Tests the PM1 level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -167,11 +142,9 @@
|
||||
"description": "Tests the PM2.5 level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -181,11 +154,9 @@
|
||||
"description": "Tests the PM4 level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -195,7 +166,6 @@
|
||||
"description": "Tests if one or more smoke sensors are cleared.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -205,7 +175,6 @@
|
||||
"description": "Tests if one or more smoke sensors are detecting smoke.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -215,11 +184,9 @@
|
||||
"description": "Tests the sulphur dioxide level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -229,11 +196,9 @@
|
||||
"description": "Tests the volatile organic compounds ratio of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -243,11 +208,9 @@
|
||||
"description": "Tests the volatile organic compounds level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -275,7 +238,6 @@
|
||||
"description": "Triggers after one or more carbon dioxide levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -285,11 +247,9 @@
|
||||
"description": "Triggers after one or more carbon dioxide levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -299,7 +259,6 @@
|
||||
"description": "Triggers after one or more carbon monoxide levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -309,7 +268,6 @@
|
||||
"description": "Triggers after one or more carbon monoxide sensors stop detecting carbon monoxide.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -319,11 +277,9 @@
|
||||
"description": "Triggers after one or more carbon monoxide levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -333,7 +289,6 @@
|
||||
"description": "Triggers after one or more carbon monoxide sensors start detecting carbon monoxide.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -343,7 +298,6 @@
|
||||
"description": "Triggers after one or more gas sensors stop detecting gas.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -353,7 +307,6 @@
|
||||
"description": "Triggers after one or more gas sensors start detecting gas.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -363,7 +316,6 @@
|
||||
"description": "Triggers after one or more nitrous oxide levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -373,11 +325,9 @@
|
||||
"description": "Triggers after one or more nitrous oxide levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -387,7 +337,6 @@
|
||||
"description": "Triggers after one or more nitrogen dioxide levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -397,11 +346,9 @@
|
||||
"description": "Triggers after one or more nitrogen dioxide levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -411,7 +358,6 @@
|
||||
"description": "Triggers after one or more nitrogen monoxide levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -421,11 +367,9 @@
|
||||
"description": "Triggers after one or more nitrogen monoxide levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -435,7 +379,6 @@
|
||||
"description": "Triggers after one or more ozone levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -445,11 +388,9 @@
|
||||
"description": "Triggers after one or more ozone levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -459,7 +400,6 @@
|
||||
"description": "Triggers after one or more PM10 levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -469,11 +409,9 @@
|
||||
"description": "Triggers after one or more PM10 levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -483,7 +421,6 @@
|
||||
"description": "Triggers after one or more PM1 levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -493,11 +430,9 @@
|
||||
"description": "Triggers after one or more PM1 levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -507,7 +442,6 @@
|
||||
"description": "Triggers after one or more PM2.5 levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -517,11 +451,9 @@
|
||||
"description": "Triggers after one or more PM2.5 levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -531,7 +463,6 @@
|
||||
"description": "Triggers after one or more PM4 levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -541,11 +472,9 @@
|
||||
"description": "Triggers after one or more PM4 levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -555,7 +484,6 @@
|
||||
"description": "Triggers after one or more smoke sensors stop detecting smoke.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -565,7 +493,6 @@
|
||||
"description": "Triggers after one or more smoke sensors start detecting smoke.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -575,7 +502,6 @@
|
||||
"description": "Triggers after one or more sulphur dioxide levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -585,11 +511,9 @@
|
||||
"description": "Triggers after one or more sulphur dioxide levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -599,7 +523,6 @@
|
||||
"description": "Triggers after one or more volatile organic compound levels change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -609,11 +532,9 @@
|
||||
"description": "Triggers after one or more volatile organic compounds levels cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -623,7 +544,6 @@
|
||||
"description": "Triggers after one or more volatile organic compound ratios change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -633,11 +553,9 @@
|
||||
"description": "Triggers after one or more volatile organic compounds ratios cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::air_quality::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::air_quality::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted alarms.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted alarms to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_armed": {
|
||||
"description": "Tests if one or more alarms are armed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more alarms are armed in away mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -30,7 +26,6 @@
|
||||
"description": "Tests if one or more alarms are armed in home mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -40,7 +35,6 @@
|
||||
"description": "Tests if one or more alarms are armed in night mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -50,7 +44,6 @@
|
||||
"description": "Tests if one or more alarms are armed in vacation mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -60,7 +53,6 @@
|
||||
"description": "Tests if one or more alarms are disarmed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -70,7 +62,6 @@
|
||||
"description": "Tests if one or more alarms are triggered.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -242,7 +233,6 @@
|
||||
"description": "Triggers after one or more alarms become armed, regardless of the mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -252,7 +242,6 @@
|
||||
"description": "Triggers after one or more alarms become armed in away mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -262,7 +251,6 @@
|
||||
"description": "Triggers after one or more alarms become armed in home mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -272,7 +260,6 @@
|
||||
"description": "Triggers after one or more alarms become armed in night mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -282,7 +269,6 @@
|
||||
"description": "Triggers after one or more alarms become armed in vacation mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -292,7 +278,6 @@
|
||||
"description": "Triggers after one or more alarms become disarmed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -302,7 +287,6 @@
|
||||
"description": "Triggers after one or more alarms become triggered.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::alarm_control_panel::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::alarm_control_panel::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["aioamazondevices"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["aioamazondevices==13.3.1"]
|
||||
"requirements": ["aioamazondevices==13.3.2"]
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["arcam"],
|
||||
"requirements": ["arcam-fmj==1.8.2"],
|
||||
"requirements": ["arcam-fmj==1.8.3"],
|
||||
"ssdp": [
|
||||
{
|
||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1",
|
||||
|
||||
@@ -91,6 +91,7 @@ SENSORS: tuple[ArcamFmjSensorEntityDescription, ...] = (
|
||||
value_fn=lambda state: (
|
||||
vp.colorspace.name.lower()
|
||||
if (vp := state.get_incoming_video_parameters()) is not None
|
||||
and vp.colorspace is not None
|
||||
else None
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted Assist satellites.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted Assist satellites to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_idle": {
|
||||
"description": "Tests if one or more Assist satellites are idle.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::assist_satellite::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::assist_satellite::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more Assist satellites are listening.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::assist_satellite::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::assist_satellite::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -30,7 +26,6 @@
|
||||
"description": "Tests if one or more Assist satellites are processing.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::assist_satellite::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::assist_satellite::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -40,7 +35,6 @@
|
||||
"description": "Tests if one or more Assist satellites are responding.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::assist_satellite::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::assist_satellite::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -81,7 +75,7 @@
|
||||
},
|
||||
"services": {
|
||||
"announce": {
|
||||
"description": "Lets a satellite announce a message.",
|
||||
"description": "Lets an Assist satellite announce a message.",
|
||||
"fields": {
|
||||
"media_id": {
|
||||
"description": "The media ID to announce instead of using text-to-speech.",
|
||||
@@ -100,10 +94,10 @@
|
||||
"name": "Preannounce media ID"
|
||||
}
|
||||
},
|
||||
"name": "Announce"
|
||||
"name": "Announce on satellite"
|
||||
},
|
||||
"ask_question": {
|
||||
"description": "Asks a question and gets the user's response.",
|
||||
"description": "Lets an Assist satellite ask a question and get the user's response.",
|
||||
"fields": {
|
||||
"answers": {
|
||||
"description": "Possible answers to the question.",
|
||||
@@ -130,10 +124,10 @@
|
||||
"name": "Question media ID"
|
||||
}
|
||||
},
|
||||
"name": "Ask question"
|
||||
"name": "Ask question on satellite"
|
||||
},
|
||||
"start_conversation": {
|
||||
"description": "Starts a conversation from a satellite.",
|
||||
"description": "Starts a conversation from an Assist satellite.",
|
||||
"fields": {
|
||||
"extra_system_prompt": {
|
||||
"description": "Provide background information to the AI about the request.",
|
||||
@@ -156,46 +150,42 @@
|
||||
"name": "Message"
|
||||
}
|
||||
},
|
||||
"name": "Start conversation"
|
||||
"name": "Start conversation on satellite"
|
||||
}
|
||||
},
|
||||
"title": "Assist satellite",
|
||||
"triggers": {
|
||||
"idle": {
|
||||
"description": "Triggers after one or more voice assistant satellites become idle after having processed a command.",
|
||||
"description": "Triggers after one or more Assist satellites become idle after having processed a command.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::assist_satellite::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::assist_satellite::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Satellite became idle"
|
||||
},
|
||||
"listening": {
|
||||
"description": "Triggers after one or more voice assistant satellites start listening for a command from someone.",
|
||||
"description": "Triggers after one or more Assist satellites start listening for a command from someone.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::assist_satellite::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::assist_satellite::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Satellite started listening"
|
||||
},
|
||||
"processing": {
|
||||
"description": "Triggers after one or more voice assistant satellites start processing a command after having heard it.",
|
||||
"description": "Triggers after one or more Assist satellites start processing a command after having heard it.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::assist_satellite::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::assist_satellite::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Satellite started processing"
|
||||
},
|
||||
"responding": {
|
||||
"description": "Triggers after one or more voice assistant satellites start responding to a command after having processed it, or start announcing something.",
|
||||
"description": "Triggers after one or more Assist satellites start responding to a command after having processed it, or start announcing something.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::assist_satellite::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::assist_satellite::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -122,7 +122,9 @@ _EXPERIMENTAL_CONDITION_PLATFORMS = {
|
||||
"alarm_control_panel",
|
||||
"assist_satellite",
|
||||
"battery",
|
||||
"calendar",
|
||||
"climate",
|
||||
"counter",
|
||||
"cover",
|
||||
"device_tracker",
|
||||
"door",
|
||||
@@ -147,6 +149,7 @@ _EXPERIMENTAL_CONDITION_PLATFORMS = {
|
||||
"switch",
|
||||
"temperature",
|
||||
"text",
|
||||
"timer",
|
||||
"vacuum",
|
||||
"valve",
|
||||
"water_heater",
|
||||
|
||||
@@ -12,7 +12,7 @@ import hashlib
|
||||
import io
|
||||
from itertools import chain
|
||||
import json
|
||||
from pathlib import Path, PurePath
|
||||
from pathlib import Path, PurePath, PureWindowsPath
|
||||
import shutil
|
||||
import sys
|
||||
import tarfile
|
||||
@@ -1957,7 +1957,10 @@ class CoreBackupReaderWriter(BackupReaderWriter):
|
||||
suggested_filename: str,
|
||||
) -> WrittenBackup:
|
||||
"""Receive a backup."""
|
||||
temp_file = Path(self.temp_backup_dir, suggested_filename)
|
||||
safe_filename = PureWindowsPath(suggested_filename).name
|
||||
if not safe_filename or safe_filename == "..":
|
||||
safe_filename = "backup.tar"
|
||||
temp_file = Path(self.temp_backup_dir, safe_filename)
|
||||
|
||||
async_add_executor_job = self._hass.async_add_executor_job
|
||||
await async_add_executor_job(make_backup_dir, self.temp_backup_dir)
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted batteries.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"trigger_behavior_description": "The behavior of the targeted batteries to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_threshold_changed_description": "Which changes to trigger on and threshold values.",
|
||||
"trigger_threshold_crossed_description": "Which threshold crossing to trigger on and threshold values.",
|
||||
"trigger_threshold_name": "Threshold configuration"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_threshold_name": "Threshold type"
|
||||
},
|
||||
"conditions": {
|
||||
"is_charging": {
|
||||
"description": "Tests if one or more batteries are charging.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -25,11 +19,9 @@
|
||||
"description": "Tests the battery level of one or more batteries.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::battery::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::battery::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -39,7 +31,6 @@
|
||||
"description": "Tests if one or more batteries are low.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -49,7 +40,6 @@
|
||||
"description": "Tests if one or more batteries are not charging.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -59,7 +49,6 @@
|
||||
"description": "Tests if one or more batteries are not low.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -87,7 +76,6 @@
|
||||
"description": "Triggers after the battery level of one or more batteries changes.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::battery::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::battery::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -97,11 +85,9 @@
|
||||
"description": "Triggers after the battery level of one or more batteries crosses a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::battery::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::battery::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -111,7 +97,6 @@
|
||||
"description": "Triggers after one or more batteries become low.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -121,7 +106,6 @@
|
||||
"description": "Triggers after one or more batteries are no longer low.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -131,7 +115,6 @@
|
||||
"description": "Triggers after one or more batteries start charging.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -141,7 +124,6 @@
|
||||
"description": "Triggers after one or more batteries stop charging.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::battery::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::battery::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
41
homeassistant/components/bmw_connected_drive/__init__.py
Normal file
41
homeassistant/components/bmw_connected_drive/__init__.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""The BMW Connected Drive integration."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
|
||||
DOMAIN = "bmw_connected_drive"
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up BMW Connected Drive from a config entry."""
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
DOMAIN,
|
||||
is_fixable=False,
|
||||
severity=ir.IssueSeverity.ERROR,
|
||||
translation_key="integration_removed",
|
||||
translation_placeholders={
|
||||
"entries": "/config/integrations/integration/bmw_connected_drive",
|
||||
"custom_component_url": "https://github.com/kvanbiesen/bmw-cardata-ha",
|
||||
},
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
return True
|
||||
|
||||
|
||||
async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
"""Remove a config entry."""
|
||||
if not hass.config_entries.async_loaded_entries(DOMAIN):
|
||||
ir.async_delete_issue(hass, DOMAIN, DOMAIN)
|
||||
# Remove any remaining disabled or ignored entries
|
||||
for _entry in hass.config_entries.async_entries(DOMAIN):
|
||||
hass.async_create_task(hass.config_entries.async_remove(_entry.entry_id))
|
||||
@@ -0,0 +1,9 @@
|
||||
"""The BMW Connected Drive integration config flow."""
|
||||
|
||||
from homeassistant.config_entries import ConfigFlow
|
||||
|
||||
from . import DOMAIN
|
||||
|
||||
|
||||
class BMWConnectedDriveConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for BMW Connected Drive."""
|
||||
10
homeassistant/components/bmw_connected_drive/manifest.json
Normal file
10
homeassistant/components/bmw_connected_drive/manifest.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "bmw_connected_drive",
|
||||
"name": "BMW Connected Drive",
|
||||
"codeowners": [],
|
||||
"documentation": "https://www.home-assistant.io/integrations/bmw_connected_drive",
|
||||
"integration_type": "system",
|
||||
"iot_class": "cloud_polling",
|
||||
"quality_scale": "legacy",
|
||||
"requirements": []
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"issues": {
|
||||
"integration_removed": {
|
||||
"description": "The BMW Connected Drive integration has been removed from Home Assistant.\n\nIn September 2025, BMW blocked third-party access to their servers by adding additional security measures. For EU-registered cars, a community-developed [custom component]({custom_component_url}) using BMW's CarData API is available as an alternative.\n\nTo resolve this issue, please remove the (now defunct) integration entries from your Home Assistant setup. [Click here to see your existing BMW Connected Drive integration entries]({entries}).",
|
||||
"title": "The BMW Connected Drive integration has been removed"
|
||||
}
|
||||
}
|
||||
}
|
||||
16
homeassistant/components/calendar/condition.py
Normal file
16
homeassistant/components/calendar/condition.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""Provides conditions for calendars."""
|
||||
|
||||
from homeassistant.const import STATE_ON
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.condition import Condition, make_entity_state_condition
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
CONDITIONS: dict[str, type[Condition]] = {
|
||||
"is_event_active": make_entity_state_condition(DOMAIN, STATE_ON),
|
||||
}
|
||||
|
||||
|
||||
async def async_get_conditions(hass: HomeAssistant) -> dict[str, type[Condition]]:
|
||||
"""Return the calendar conditions."""
|
||||
return CONDITIONS
|
||||
14
homeassistant/components/calendar/conditions.yaml
Normal file
14
homeassistant/components/calendar/conditions.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
is_event_active:
|
||||
target:
|
||||
entity:
|
||||
- domain: calendar
|
||||
fields:
|
||||
behavior:
|
||||
required: true
|
||||
default: any
|
||||
selector:
|
||||
select:
|
||||
translation_key: condition_behavior
|
||||
options:
|
||||
- all
|
||||
- any
|
||||
@@ -1,4 +1,9 @@
|
||||
{
|
||||
"conditions": {
|
||||
"is_event_active": {
|
||||
"condition": "mdi:calendar-check"
|
||||
}
|
||||
},
|
||||
"entity_component": {
|
||||
"_": {
|
||||
"default": "mdi:calendar",
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_name": "Condition passes if"
|
||||
},
|
||||
"conditions": {
|
||||
"is_event_active": {
|
||||
"description": "Tests if one or more calendars have an active event.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"name": "[%key:component::calendar::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Calendar event is active"
|
||||
}
|
||||
},
|
||||
"entity_component": {
|
||||
"_": {
|
||||
"name": "[%key:component::calendar::title%]",
|
||||
@@ -46,6 +60,12 @@
|
||||
}
|
||||
},
|
||||
"selector": {
|
||||
"condition_behavior": {
|
||||
"options": {
|
||||
"all": "All",
|
||||
"any": "Any"
|
||||
}
|
||||
},
|
||||
"trigger_offset_type": {
|
||||
"options": {
|
||||
"after": "After",
|
||||
|
||||
@@ -30,6 +30,7 @@ class ChessConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
client = ChessComClient(session=session)
|
||||
try:
|
||||
user = await client.get_player(user_input[CONF_USERNAME])
|
||||
await client.get_player_stats(user_input[CONF_USERNAME])
|
||||
except NotFoundError:
|
||||
errors["base"] = "player_not_found"
|
||||
except Exception:
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted climate-control devices.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"trigger_behavior_description": "The behavior of the targeted climates to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_threshold_changed_description": "Which changes to trigger on and threshold values.",
|
||||
"trigger_threshold_crossed_description": "Which threshold crossing to trigger on and threshold values.",
|
||||
"trigger_threshold_name": "Threshold configuration"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_threshold_name": "Threshold type"
|
||||
},
|
||||
"conditions": {
|
||||
"is_cooling": {
|
||||
"description": "Tests if one or more climate-control devices are cooling.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -25,7 +19,6 @@
|
||||
"description": "Tests if one or more climate-control devices are drying.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -35,7 +28,6 @@
|
||||
"description": "Tests if one or more climate-control devices are heating.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -45,7 +37,6 @@
|
||||
"description": "Tests if one or more climate-control devices are set to a specific HVAC mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::condition_behavior_name%]"
|
||||
},
|
||||
"hvac_mode": {
|
||||
@@ -59,7 +50,6 @@
|
||||
"description": "Tests if one or more climate-control devices are off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -69,7 +59,6 @@
|
||||
"description": "Tests if one or more climate-control devices are on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -79,11 +68,9 @@
|
||||
"description": "Tests the humidity setpoint of one or more climate-control devices.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::climate::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::climate::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -93,11 +80,9 @@
|
||||
"description": "Tests the temperature setpoint of one or more climate-control devices.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::climate::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::climate::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -398,7 +383,6 @@
|
||||
"description": "Triggers after the mode of one or more climate-control devices changes.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_behavior_name%]"
|
||||
},
|
||||
"hvac_mode": {
|
||||
@@ -412,7 +396,6 @@
|
||||
"description": "Triggers after one or more climate-control devices start cooling.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -422,7 +405,6 @@
|
||||
"description": "Triggers after one or more climate-control devices start drying.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -432,7 +414,6 @@
|
||||
"description": "Triggers after one or more climate-control devices start heating.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -442,7 +423,6 @@
|
||||
"description": "Triggers after the humidity setpoint of one or more climate-control devices changes.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::climate::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -452,11 +432,9 @@
|
||||
"description": "Triggers after the humidity setpoint of one or more climate-control devices crosses a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::climate::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -466,7 +444,6 @@
|
||||
"description": "Triggers after the temperature setpoint of one or more climate-control devices changes.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::climate::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -476,11 +453,9 @@
|
||||
"description": "Triggers after the temperature setpoint of one or more climate-control devices crosses a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::climate::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -490,7 +465,6 @@
|
||||
"description": "Triggers after one or more climate-control devices turn off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -500,7 +474,6 @@
|
||||
"description": "Triggers after one or more climate-control devices turn on, regardless of the mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::climate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::climate::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
15
homeassistant/components/counter/condition.py
Normal file
15
homeassistant/components/counter/condition.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""Provides conditions for counters."""
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.condition import Condition, make_entity_numerical_condition
|
||||
|
||||
DOMAIN = "counter"
|
||||
|
||||
CONDITIONS: dict[str, type[Condition]] = {
|
||||
"is_value": make_entity_numerical_condition(DOMAIN),
|
||||
}
|
||||
|
||||
|
||||
async def async_get_conditions(hass: HomeAssistant) -> dict[str, type[Condition]]:
|
||||
"""Return the conditions for counters."""
|
||||
return CONDITIONS
|
||||
25
homeassistant/components/counter/conditions.yaml
Normal file
25
homeassistant/components/counter/conditions.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
is_value:
|
||||
target:
|
||||
entity:
|
||||
- domain: counter
|
||||
fields:
|
||||
behavior:
|
||||
required: true
|
||||
default: any
|
||||
selector:
|
||||
select:
|
||||
translation_key: condition_behavior
|
||||
options:
|
||||
- all
|
||||
- any
|
||||
threshold:
|
||||
required: true
|
||||
selector:
|
||||
numeric_threshold:
|
||||
entity:
|
||||
- domain: counter
|
||||
- domain: input_number
|
||||
- domain: number
|
||||
mode: is
|
||||
number:
|
||||
mode: box
|
||||
@@ -1,4 +1,9 @@
|
||||
{
|
||||
"conditions": {
|
||||
"is_value": {
|
||||
"condition": "mdi:counter"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"decrement": {
|
||||
"service": "mdi:numeric-negative-1"
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
{
|
||||
"common": {
|
||||
"trigger_behavior_description": "The behavior of the targeted counters to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_value": {
|
||||
"description": "Tests the value of one or more counters.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"name": "Condition passes if"
|
||||
},
|
||||
"threshold": {
|
||||
"name": "Threshold type"
|
||||
}
|
||||
},
|
||||
"name": "Counter value"
|
||||
}
|
||||
},
|
||||
"entity_component": {
|
||||
"_": {
|
||||
@@ -30,6 +43,12 @@
|
||||
}
|
||||
},
|
||||
"selector": {
|
||||
"condition_behavior": {
|
||||
"options": {
|
||||
"all": "All",
|
||||
"any": "Any"
|
||||
}
|
||||
},
|
||||
"trigger_behavior": {
|
||||
"options": {
|
||||
"any": "Any",
|
||||
@@ -76,7 +95,6 @@
|
||||
"description": "Triggers after one or more counters reach their maximum value.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::counter::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::counter::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -86,7 +104,6 @@
|
||||
"description": "Triggers after one or more counters reach their minimum value.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::counter::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::counter::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -96,7 +113,6 @@
|
||||
"description": "Triggers after one or more counters are reset.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::counter::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::counter::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted covers.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted covers to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"awning_is_closed": {
|
||||
"description": "Tests if one or more awnings are closed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more awnings are open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -30,7 +26,6 @@
|
||||
"description": "Tests if one or more blinds are closed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -40,7 +35,6 @@
|
||||
"description": "Tests if one or more blinds are open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -50,7 +44,6 @@
|
||||
"description": "Tests if one or more curtains are closed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -60,7 +53,6 @@
|
||||
"description": "Tests if one or more curtains are open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -70,7 +62,6 @@
|
||||
"description": "Tests if one or more shades are closed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -80,7 +71,6 @@
|
||||
"description": "Tests if one or more shades are open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -90,7 +80,6 @@
|
||||
"description": "Tests if one or more shutters are closed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -100,7 +89,6 @@
|
||||
"description": "Tests if one or more shutters are open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -265,7 +253,6 @@
|
||||
"description": "Triggers after one or more awnings close.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -275,7 +262,6 @@
|
||||
"description": "Triggers after one or more awnings open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -285,7 +271,6 @@
|
||||
"description": "Triggers after one or more blinds close.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -295,7 +280,6 @@
|
||||
"description": "Triggers after one or more blinds open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -305,7 +289,6 @@
|
||||
"description": "Triggers after one or more curtains close.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -315,7 +298,6 @@
|
||||
"description": "Triggers after one or more curtains open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -325,7 +307,6 @@
|
||||
"description": "Triggers after one or more shades close.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -335,7 +316,6 @@
|
||||
"description": "Triggers after one or more shades open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -345,7 +325,6 @@
|
||||
"description": "Triggers after one or more shutters close.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -355,7 +334,6 @@
|
||||
"description": "Triggers after one or more shutters open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::cover::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::cover::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"services": {
|
||||
"set_value": {
|
||||
"description": "Sets the date.",
|
||||
"description": "Sets the value of a date.",
|
||||
"fields": {
|
||||
"date": {
|
||||
"description": "The date to set.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"services": {
|
||||
"set_value": {
|
||||
"description": "Sets the date/time for a datetime entity.",
|
||||
"description": "Sets the value of a date/time.",
|
||||
"fields": {
|
||||
"datetime": {
|
||||
"description": "The date/time to set. The time zone of the Home Assistant instance is assumed.",
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted device trackers.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted device trackers to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_home": {
|
||||
"description": "Tests if one or more device trackers are home.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::device_tracker::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::device_tracker::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more device trackers are not home.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::device_tracker::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::device_tracker::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -129,7 +125,6 @@
|
||||
"description": "Triggers when one or more device trackers enter home.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::device_tracker::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::device_tracker::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -139,7 +134,6 @@
|
||||
"description": "Triggers when one or more device trackers leave home.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::device_tracker::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::device_tracker::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted doors.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted doors to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_closed": {
|
||||
"description": "Tests if one or more doors are closed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::door::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::door::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more doors are open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::door::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::door::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -48,7 +44,6 @@
|
||||
"description": "Triggers after one or more doors close.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::door::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::door::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -58,7 +53,6 @@
|
||||
"description": "Triggers after one or more doors open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::door::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::door::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
"""The Dropbox integration."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from python_dropbox_api import (
|
||||
DropboxAPIClient,
|
||||
DropboxAuthException,
|
||||
DropboxUnknownException,
|
||||
)
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import aiohttp_client
|
||||
from homeassistant.helpers.config_entry_oauth2_flow import (
|
||||
ImplementationUnavailableError,
|
||||
OAuth2Session,
|
||||
async_get_config_entry_implementation,
|
||||
)
|
||||
|
||||
from .auth import DropboxConfigEntryAuth
|
||||
from .const import DATA_BACKUP_AGENT_LISTENERS, DOMAIN
|
||||
|
||||
type DropboxConfigEntry = ConfigEntry[DropboxAPIClient]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: DropboxConfigEntry) -> bool:
|
||||
"""Set up Dropbox from a config entry."""
|
||||
try:
|
||||
oauth2_implementation = await async_get_config_entry_implementation(hass, entry)
|
||||
except ImplementationUnavailableError as err:
|
||||
raise ConfigEntryNotReady(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="oauth2_implementation_unavailable",
|
||||
) from err
|
||||
oauth2_session = OAuth2Session(hass, entry, oauth2_implementation)
|
||||
|
||||
auth = DropboxConfigEntryAuth(
|
||||
aiohttp_client.async_get_clientsession(hass), oauth2_session
|
||||
)
|
||||
|
||||
client = DropboxAPIClient(auth)
|
||||
|
||||
try:
|
||||
await client.get_account_info()
|
||||
except DropboxAuthException as err:
|
||||
raise ConfigEntryAuthFailed from err
|
||||
except (DropboxUnknownException, TimeoutError) as err:
|
||||
raise ConfigEntryNotReady from err
|
||||
|
||||
entry.runtime_data = client
|
||||
|
||||
def async_notify_backup_listeners() -> None:
|
||||
for listener in hass.data.get(DATA_BACKUP_AGENT_LISTENERS, []):
|
||||
listener()
|
||||
|
||||
entry.async_on_unload(entry.async_on_state_change(async_notify_backup_listeners))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: DropboxConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
return True
|
||||
@@ -1,38 +0,0 @@
|
||||
"""Application credentials platform for the Dropbox integration."""
|
||||
|
||||
from homeassistant.components.application_credentials import ClientCredential
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.config_entry_oauth2_flow import (
|
||||
AbstractOAuth2Implementation,
|
||||
LocalOAuth2ImplementationWithPkce,
|
||||
)
|
||||
|
||||
from .const import OAUTH2_AUTHORIZE, OAUTH2_SCOPES, OAUTH2_TOKEN
|
||||
|
||||
|
||||
async def async_get_auth_implementation(
|
||||
hass: HomeAssistant, auth_domain: str, credential: ClientCredential
|
||||
) -> AbstractOAuth2Implementation:
|
||||
"""Return custom auth implementation."""
|
||||
return DropboxOAuth2Implementation(
|
||||
hass,
|
||||
auth_domain,
|
||||
credential.client_id,
|
||||
OAUTH2_AUTHORIZE,
|
||||
OAUTH2_TOKEN,
|
||||
credential.client_secret,
|
||||
)
|
||||
|
||||
|
||||
class DropboxOAuth2Implementation(LocalOAuth2ImplementationWithPkce):
|
||||
"""Custom Dropbox OAuth2 implementation to add the necessary authorize url parameters."""
|
||||
|
||||
@property
|
||||
def extra_authorize_data(self) -> dict:
|
||||
"""Extra data that needs to be appended to the authorize url."""
|
||||
data: dict = {
|
||||
"token_access_type": "offline",
|
||||
"scope": " ".join(OAUTH2_SCOPES),
|
||||
}
|
||||
data.update(super().extra_authorize_data)
|
||||
return data
|
||||
@@ -1,44 +0,0 @@
|
||||
"""Authentication for Dropbox."""
|
||||
|
||||
from typing import cast
|
||||
|
||||
from aiohttp import ClientSession
|
||||
from python_dropbox_api import Auth
|
||||
|
||||
from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session
|
||||
|
||||
|
||||
class DropboxConfigEntryAuth(Auth):
|
||||
"""Provide Dropbox authentication tied to an OAuth2 based config entry."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
websession: ClientSession,
|
||||
oauth_session: OAuth2Session,
|
||||
) -> None:
|
||||
"""Initialize DropboxConfigEntryAuth."""
|
||||
super().__init__(websession)
|
||||
self._oauth_session = oauth_session
|
||||
|
||||
async def async_get_access_token(self) -> str:
|
||||
"""Return a valid access token."""
|
||||
await self._oauth_session.async_ensure_token_valid()
|
||||
|
||||
return cast(str, self._oauth_session.token["access_token"])
|
||||
|
||||
|
||||
class DropboxConfigFlowAuth(Auth):
|
||||
"""Provide authentication tied to a fixed token for the config flow."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
websession: ClientSession,
|
||||
token: str,
|
||||
) -> None:
|
||||
"""Initialize DropboxConfigFlowAuth."""
|
||||
super().__init__(websession)
|
||||
self._token = token
|
||||
|
||||
async def async_get_access_token(self) -> str:
|
||||
"""Return the fixed access token."""
|
||||
return self._token
|
||||
@@ -1,230 +0,0 @@
|
||||
"""Backup platform for the Dropbox integration."""
|
||||
|
||||
from collections.abc import AsyncIterator, Callable, Coroutine
|
||||
from functools import wraps
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, Concatenate
|
||||
|
||||
from python_dropbox_api import (
|
||||
DropboxAPIClient,
|
||||
DropboxAuthException,
|
||||
DropboxFileOrFolderNotFoundException,
|
||||
DropboxUnknownException,
|
||||
)
|
||||
|
||||
from homeassistant.components.backup import (
|
||||
AgentBackup,
|
||||
BackupAgent,
|
||||
BackupAgentError,
|
||||
BackupNotFound,
|
||||
suggested_filename,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
|
||||
from . import DropboxConfigEntry
|
||||
from .const import DATA_BACKUP_AGENT_LISTENERS, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _suggested_filenames(backup: AgentBackup) -> tuple[str, str]:
|
||||
"""Return the suggested filenames for the backup and metadata."""
|
||||
base_name = suggested_filename(backup).rsplit(".", 1)[0]
|
||||
return f"{base_name}.tar", f"{base_name}.metadata.json"
|
||||
|
||||
|
||||
async def _async_string_iterator(content: str) -> AsyncIterator[bytes]:
|
||||
"""Yield a string as a single bytes chunk."""
|
||||
yield content.encode()
|
||||
|
||||
|
||||
def handle_backup_errors[_R, **P](
|
||||
func: Callable[Concatenate[DropboxBackupAgent, P], Coroutine[Any, Any, _R]],
|
||||
) -> Callable[Concatenate[DropboxBackupAgent, P], Coroutine[Any, Any, _R]]:
|
||||
"""Handle backup errors."""
|
||||
|
||||
@wraps(func)
|
||||
async def wrapper(
|
||||
self: DropboxBackupAgent, *args: P.args, **kwargs: P.kwargs
|
||||
) -> _R:
|
||||
try:
|
||||
return await func(self, *args, **kwargs)
|
||||
except DropboxFileOrFolderNotFoundException as err:
|
||||
raise BackupNotFound(
|
||||
f"Failed to {func.__name__.removeprefix('async_').replace('_', ' ')}"
|
||||
) from err
|
||||
except DropboxAuthException as err:
|
||||
self._entry.async_start_reauth(self._hass)
|
||||
raise BackupAgentError("Authentication error") from err
|
||||
except DropboxUnknownException as err:
|
||||
_LOGGER.error(
|
||||
"Error during %s: %s",
|
||||
func.__name__,
|
||||
err,
|
||||
)
|
||||
_LOGGER.debug("Full error: %s", err, exc_info=True)
|
||||
raise BackupAgentError(
|
||||
f"Failed to {func.__name__.removeprefix('async_').replace('_', ' ')}"
|
||||
) from err
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
async def async_get_backup_agents(
|
||||
hass: HomeAssistant,
|
||||
**kwargs: Any,
|
||||
) -> list[BackupAgent]:
|
||||
"""Return a list of backup agents."""
|
||||
entries = hass.config_entries.async_loaded_entries(DOMAIN)
|
||||
return [DropboxBackupAgent(hass, entry) for entry in entries]
|
||||
|
||||
|
||||
@callback
|
||||
def async_register_backup_agents_listener(
|
||||
hass: HomeAssistant,
|
||||
*,
|
||||
listener: Callable[[], None],
|
||||
**kwargs: Any,
|
||||
) -> Callable[[], None]:
|
||||
"""Register a listener to be called when agents are added or removed.
|
||||
|
||||
:return: A function to unregister the listener.
|
||||
"""
|
||||
hass.data.setdefault(DATA_BACKUP_AGENT_LISTENERS, []).append(listener)
|
||||
|
||||
@callback
|
||||
def remove_listener() -> None:
|
||||
"""Remove the listener."""
|
||||
hass.data[DATA_BACKUP_AGENT_LISTENERS].remove(listener)
|
||||
if not hass.data[DATA_BACKUP_AGENT_LISTENERS]:
|
||||
del hass.data[DATA_BACKUP_AGENT_LISTENERS]
|
||||
|
||||
return remove_listener
|
||||
|
||||
|
||||
class DropboxBackupAgent(BackupAgent):
|
||||
"""Backup agent for the Dropbox integration."""
|
||||
|
||||
domain = DOMAIN
|
||||
|
||||
def __init__(self, hass: HomeAssistant, entry: DropboxConfigEntry) -> None:
|
||||
"""Initialize the backup agent."""
|
||||
super().__init__()
|
||||
self._hass = hass
|
||||
self._entry = entry
|
||||
self.name = entry.title
|
||||
assert entry.unique_id
|
||||
self.unique_id = entry.unique_id
|
||||
self._api: DropboxAPIClient = entry.runtime_data
|
||||
|
||||
async def _async_get_backups(self) -> list[tuple[AgentBackup, str]]:
|
||||
"""Get backups and their corresponding file names."""
|
||||
files = await self._api.list_folder("")
|
||||
|
||||
tar_files = {f.name for f in files if f.name.endswith(".tar")}
|
||||
metadata_files = [f for f in files if f.name.endswith(".metadata.json")]
|
||||
|
||||
backups: list[tuple[AgentBackup, str]] = []
|
||||
for metadata_file in metadata_files:
|
||||
tar_name = metadata_file.name.removesuffix(".metadata.json") + ".tar"
|
||||
if tar_name not in tar_files:
|
||||
_LOGGER.warning(
|
||||
"Found metadata file '%s' without matching backup file",
|
||||
metadata_file.name,
|
||||
)
|
||||
continue
|
||||
|
||||
metadata_stream = self._api.download_file(f"/{metadata_file.name}")
|
||||
raw = b"".join([chunk async for chunk in metadata_stream])
|
||||
try:
|
||||
data = json.loads(raw)
|
||||
backup = AgentBackup.from_dict(data)
|
||||
except (json.JSONDecodeError, ValueError, TypeError, KeyError) as err:
|
||||
_LOGGER.warning(
|
||||
"Skipping invalid metadata file '%s': %s",
|
||||
metadata_file.name,
|
||||
err,
|
||||
)
|
||||
continue
|
||||
backups.append((backup, tar_name))
|
||||
|
||||
return backups
|
||||
|
||||
@handle_backup_errors
|
||||
async def async_upload_backup(
|
||||
self,
|
||||
*,
|
||||
open_stream: Callable[[], Coroutine[Any, Any, AsyncIterator[bytes]]],
|
||||
backup: AgentBackup,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Upload a backup."""
|
||||
backup_filename, metadata_filename = _suggested_filenames(backup)
|
||||
backup_path = f"/{backup_filename}"
|
||||
metadata_path = f"/{metadata_filename}"
|
||||
|
||||
file_stream = await open_stream()
|
||||
await self._api.upload_file(backup_path, file_stream)
|
||||
|
||||
metadata_stream = _async_string_iterator(json.dumps(backup.as_dict()))
|
||||
|
||||
try:
|
||||
await self._api.upload_file(metadata_path, metadata_stream)
|
||||
except (
|
||||
DropboxAuthException,
|
||||
DropboxUnknownException,
|
||||
):
|
||||
await self._api.delete_file(backup_path)
|
||||
raise
|
||||
|
||||
@handle_backup_errors
|
||||
async def async_list_backups(self, **kwargs: Any) -> list[AgentBackup]:
|
||||
"""List backups."""
|
||||
return [backup for backup, _ in await self._async_get_backups()]
|
||||
|
||||
@handle_backup_errors
|
||||
async def async_download_backup(
|
||||
self,
|
||||
backup_id: str,
|
||||
**kwargs: Any,
|
||||
) -> AsyncIterator[bytes]:
|
||||
"""Download a backup file."""
|
||||
backups = await self._async_get_backups()
|
||||
for backup, filename in backups:
|
||||
if backup.backup_id == backup_id:
|
||||
return self._api.download_file(f"/{filename}")
|
||||
|
||||
raise BackupNotFound(f"Backup {backup_id} not found")
|
||||
|
||||
@handle_backup_errors
|
||||
async def async_get_backup(
|
||||
self,
|
||||
backup_id: str,
|
||||
**kwargs: Any,
|
||||
) -> AgentBackup:
|
||||
"""Return a backup."""
|
||||
backups = await self._async_get_backups()
|
||||
|
||||
for backup, _ in backups:
|
||||
if backup.backup_id == backup_id:
|
||||
return backup
|
||||
|
||||
raise BackupNotFound(f"Backup {backup_id} not found")
|
||||
|
||||
@handle_backup_errors
|
||||
async def async_delete_backup(
|
||||
self,
|
||||
backup_id: str,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Delete a backup file."""
|
||||
backups = await self._async_get_backups()
|
||||
for backup, tar_filename in backups:
|
||||
if backup.backup_id == backup_id:
|
||||
metadata_filename = tar_filename.removesuffix(".tar") + ".metadata.json"
|
||||
await self._api.delete_file(f"/{tar_filename}")
|
||||
await self._api.delete_file(f"/{metadata_filename}")
|
||||
return
|
||||
|
||||
raise BackupNotFound(f"Backup {backup_id} not found")
|
||||
@@ -1,60 +0,0 @@
|
||||
"""Config flow for Dropbox."""
|
||||
|
||||
from collections.abc import Mapping
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from python_dropbox_api import DropboxAPIClient
|
||||
|
||||
from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_TOKEN
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.config_entry_oauth2_flow import AbstractOAuth2FlowHandler
|
||||
|
||||
from .auth import DropboxConfigFlowAuth
|
||||
from .const import DOMAIN
|
||||
|
||||
|
||||
class DropboxConfigFlow(AbstractOAuth2FlowHandler, domain=DOMAIN):
|
||||
"""Config flow to handle Dropbox OAuth2 authentication."""
|
||||
|
||||
DOMAIN = DOMAIN
|
||||
|
||||
@property
|
||||
def logger(self) -> logging.Logger:
|
||||
"""Return logger."""
|
||||
return logging.getLogger(__name__)
|
||||
|
||||
async def async_oauth_create_entry(self, data: dict[str, Any]) -> ConfigFlowResult:
|
||||
"""Create an entry for the flow, or update existing entry."""
|
||||
access_token = data[CONF_TOKEN][CONF_ACCESS_TOKEN]
|
||||
|
||||
auth = DropboxConfigFlowAuth(async_get_clientsession(self.hass), access_token)
|
||||
|
||||
client = DropboxAPIClient(auth)
|
||||
account_info = await client.get_account_info()
|
||||
|
||||
await self.async_set_unique_id(account_info.account_id)
|
||||
if self.source == SOURCE_REAUTH:
|
||||
self._abort_if_unique_id_mismatch(reason="wrong_account")
|
||||
return self.async_update_reload_and_abort(
|
||||
self._get_reauth_entry(), data=data
|
||||
)
|
||||
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
return self.async_create_entry(title=account_info.email, data=data)
|
||||
|
||||
async def async_step_reauth(
|
||||
self, entry_data: Mapping[str, Any]
|
||||
) -> ConfigFlowResult:
|
||||
"""Perform reauth upon an API authentication error."""
|
||||
return await self.async_step_reauth_confirm()
|
||||
|
||||
async def async_step_reauth_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Dialog that informs the user that reauth is required."""
|
||||
if user_input is None:
|
||||
return self.async_show_form(step_id="reauth_confirm")
|
||||
return await self.async_step_user()
|
||||
@@ -1,19 +0,0 @@
|
||||
"""Constants for the Dropbox integration."""
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
from homeassistant.util.hass_dict import HassKey
|
||||
|
||||
DOMAIN = "dropbox"
|
||||
|
||||
OAUTH2_AUTHORIZE = "https://www.dropbox.com/oauth2/authorize"
|
||||
OAUTH2_TOKEN = "https://api.dropboxapi.com/oauth2/token"
|
||||
OAUTH2_SCOPES = [
|
||||
"account_info.read",
|
||||
"files.content.read",
|
||||
"files.content.write",
|
||||
]
|
||||
|
||||
DATA_BACKUP_AGENT_LISTENERS: HassKey[list[Callable[[], None]]] = HassKey(
|
||||
f"{DOMAIN}.backup_agent_listeners"
|
||||
)
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"domain": "dropbox",
|
||||
"name": "Dropbox",
|
||||
"after_dependencies": ["backup"],
|
||||
"codeowners": ["@bdr99"],
|
||||
"config_flow": true,
|
||||
"dependencies": ["application_credentials"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/dropbox",
|
||||
"integration_type": "service",
|
||||
"iot_class": "cloud_polling",
|
||||
"quality_scale": "bronze",
|
||||
"requirements": ["python-dropbox-api==0.1.3"]
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
rules:
|
||||
# Bronze
|
||||
action-setup:
|
||||
status: exempt
|
||||
comment: Integration does not register any actions.
|
||||
appropriate-polling:
|
||||
status: exempt
|
||||
comment: Integration does not poll.
|
||||
brands: done
|
||||
common-modules:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities or coordinators.
|
||||
config-flow-test-coverage: done
|
||||
config-flow: done
|
||||
dependency-transparency: done
|
||||
docs-actions:
|
||||
status: exempt
|
||||
comment: Integration does not register any actions.
|
||||
docs-high-level-description: done
|
||||
docs-installation-instructions: done
|
||||
docs-removal-instructions: done
|
||||
entity-event-setup:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
entity-unique-id:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
has-entity-name:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
runtime-data: done
|
||||
test-before-configure: done
|
||||
test-before-setup: done
|
||||
unique-config-entry: done
|
||||
|
||||
# Silver
|
||||
action-exceptions:
|
||||
status: exempt
|
||||
comment: Integration does not register any actions.
|
||||
config-entry-unloading: done
|
||||
docs-configuration-parameters:
|
||||
status: exempt
|
||||
comment: Integration does not have any configuration parameters.
|
||||
docs-installation-parameters: done
|
||||
entity-unavailable:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
integration-owner: done
|
||||
log-when-unavailable: todo
|
||||
parallel-updates:
|
||||
status: exempt
|
||||
comment: Integration does not make any entity updates.
|
||||
reauthentication-flow: done
|
||||
test-coverage: done
|
||||
|
||||
# Gold
|
||||
devices:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
diagnostics:
|
||||
status: exempt
|
||||
comment: Integration does not have any data to diagnose.
|
||||
discovery-update-info:
|
||||
status: exempt
|
||||
comment: Integration is a service.
|
||||
discovery:
|
||||
status: exempt
|
||||
comment: Integration is a service.
|
||||
docs-data-update:
|
||||
status: exempt
|
||||
comment: Integration does not update any data.
|
||||
docs-examples:
|
||||
status: exempt
|
||||
comment: Integration only provides backup functionality.
|
||||
docs-known-limitations: todo
|
||||
docs-supported-devices:
|
||||
status: exempt
|
||||
comment: Integration does not support any devices.
|
||||
docs-supported-functions: done
|
||||
docs-troubleshooting: todo
|
||||
docs-use-cases: done
|
||||
dynamic-devices:
|
||||
status: exempt
|
||||
comment: Integration does not use any devices.
|
||||
entity-category:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
entity-device-class:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
entity-disabled-by-default:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
entity-translations:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
exception-translations: todo
|
||||
icon-translations:
|
||||
status: exempt
|
||||
comment: Integration does not have any entities.
|
||||
reconfiguration-flow: todo
|
||||
repair-issues:
|
||||
status: exempt
|
||||
comment: Integration does not have any repairs.
|
||||
stale-devices:
|
||||
status: exempt
|
||||
comment: Integration does not have any devices.
|
||||
|
||||
# Platinum
|
||||
async-dependency: done
|
||||
inject-websession: done
|
||||
strict-typing: done
|
||||
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]",
|
||||
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
||||
"authorize_url_timeout": "[%key:common::config_flow::abort::oauth2_authorize_url_timeout%]",
|
||||
"missing_configuration": "[%key:common::config_flow::abort::oauth2_missing_configuration%]",
|
||||
"no_url_available": "[%key:common::config_flow::abort::oauth2_no_url_available%]",
|
||||
"oauth_error": "[%key:common::config_flow::abort::oauth2_error%]",
|
||||
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]",
|
||||
"oauth_timeout": "[%key:common::config_flow::abort::oauth2_timeout%]",
|
||||
"oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
|
||||
"user_rejected_authorize": "[%key:common::config_flow::abort::oauth2_user_rejected_authorize%]",
|
||||
"wrong_account": "Wrong account: Please authenticate with the correct account."
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "[%key:common::config_flow::create_entry::authenticated%]"
|
||||
},
|
||||
"step": {
|
||||
"pick_implementation": {
|
||||
"title": "[%key:common::config_flow::title::oauth2_pick_implementation%]"
|
||||
},
|
||||
"reauth_confirm": {
|
||||
"description": "The Dropbox integration needs to re-authenticate your account.",
|
||||
"title": "[%key:common::config_flow::title::reauth%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
"oauth2_implementation_unavailable": {
|
||||
"message": "[%key:common::exceptions::oauth2_implementation_unavailable::message%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted fans.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted fans to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_off": {
|
||||
"description": "Tests if one or more fans are off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::fan::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::fan::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more fans are on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::fan::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::fan::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -199,7 +195,6 @@
|
||||
"description": "Triggers after one or more fans turn off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::fan::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::fan::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -209,7 +204,6 @@
|
||||
"description": "Triggers after one or more fans turn on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::fan::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::fan::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,9 +10,11 @@ from requests.exceptions import RequestException
|
||||
from homeassistant.components.image import ImageEntity
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util, slugify
|
||||
|
||||
from .const import DOMAIN, Platform
|
||||
from .coordinator import AvmWrapper, FritzConfigEntry
|
||||
from .entity import FritzBoxBaseEntity
|
||||
|
||||
@@ -22,6 +24,32 @@ _LOGGER = logging.getLogger(__name__)
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
|
||||
async def _migrate_to_new_unique_id(
|
||||
hass: HomeAssistant, avm_wrapper: AvmWrapper, ssid: str
|
||||
) -> None:
|
||||
"""Migrate old unique id to new unique id."""
|
||||
|
||||
old_unique_id = slugify(f"{avm_wrapper.unique_id}-{ssid}-qr-code")
|
||||
new_unique_id = f"{avm_wrapper.unique_id}-guest_wifi_qr_code"
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
entity_id = entity_registry.async_get_entity_id(
|
||||
Platform.IMAGE,
|
||||
DOMAIN,
|
||||
old_unique_id,
|
||||
)
|
||||
|
||||
if entity_id is None:
|
||||
return
|
||||
|
||||
entity_registry.async_update_entity(entity_id, new_unique_id=new_unique_id)
|
||||
_LOGGER.debug(
|
||||
"Migrating guest Wi-Fi image unique_id from [%s] to [%s]",
|
||||
old_unique_id,
|
||||
new_unique_id,
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: FritzConfigEntry,
|
||||
@@ -34,6 +62,8 @@ async def async_setup_entry(
|
||||
avm_wrapper.fritz_guest_wifi.get_info
|
||||
)
|
||||
|
||||
await _migrate_to_new_unique_id(hass, avm_wrapper, guest_wifi_info["NewSSID"])
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
FritzGuestWifiQRImage(
|
||||
@@ -60,7 +90,7 @@ class FritzGuestWifiQRImage(FritzBoxBaseEntity, ImageEntity):
|
||||
) -> None:
|
||||
"""Initialize the image entity."""
|
||||
self._attr_name = ssid
|
||||
self._attr_unique_id = slugify(f"{avm_wrapper.unique_id}-{ssid}-qr-code")
|
||||
self._attr_unique_id = f"{avm_wrapper.unique_id}-guest_wifi_qr_code"
|
||||
self._current_qr_bytes: bytes | None = None
|
||||
super().__init__(avm_wrapper, device_friendly_name)
|
||||
ImageEntity.__init__(self, hass)
|
||||
|
||||
@@ -21,5 +21,5 @@
|
||||
"integration_type": "system",
|
||||
"preview_features": { "winter_mode": {} },
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["home-assistant-frontend==20260325.2"]
|
||||
"requirements": ["home-assistant-frontend==20260325.6"]
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted garage doors.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted garage doors to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_closed": {
|
||||
"description": "Tests if one or more garage doors are closed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::garage_door::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::garage_door::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more garage doors are open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::garage_door::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::garage_door::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -48,7 +44,6 @@
|
||||
"description": "Triggers after one or more garage doors close.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::garage_door::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::garage_door::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -58,7 +53,6 @@
|
||||
"description": "Triggers after one or more garage doors open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::garage_door::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::garage_door::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted gates.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted gates to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_closed": {
|
||||
"description": "Tests if one or more gates are closed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::gate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::gate::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more gates are open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::gate::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::gate::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -48,7 +44,6 @@
|
||||
"description": "Triggers after one or more gates close.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::gate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::gate::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -58,7 +53,6 @@
|
||||
"description": "Triggers after one or more gates open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::gate::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::gate::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/holiday",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["holidays==0.84", "babel==2.15.0"]
|
||||
"requirements": ["holidays==0.93", "babel==2.15.0"]
|
||||
}
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted humidifiers.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"trigger_behavior_description": "The behavior of the targeted humidifiers to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_drying": {
|
||||
"description": "Tests if one or more humidifiers are drying.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -22,7 +18,6 @@
|
||||
"description": "Tests if one or more humidifiers are humidifying.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -32,7 +27,6 @@
|
||||
"description": "Tests if one or more humidifiers are set to a specific mode.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::condition_behavior_name%]"
|
||||
},
|
||||
"mode": {
|
||||
@@ -46,7 +40,6 @@
|
||||
"description": "Tests if one or more humidifiers are off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -56,7 +49,6 @@
|
||||
"description": "Tests if one or more humidifiers are on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -66,11 +58,9 @@
|
||||
"description": "Tests the target humidity of one or more humidifiers.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::humidifier::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::humidifier::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -219,7 +209,6 @@
|
||||
"description": "Triggers after the operation mode of one or more humidifiers changes.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::trigger_behavior_name%]"
|
||||
},
|
||||
"mode": {
|
||||
@@ -233,7 +222,6 @@
|
||||
"description": "Triggers after one or more humidifiers start drying.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -243,7 +231,6 @@
|
||||
"description": "Triggers after one or more humidifiers start humidifying.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -253,7 +240,6 @@
|
||||
"description": "Triggers after one or more humidifiers turn off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -263,7 +249,6 @@
|
||||
"description": "Triggers after one or more humidifiers turn on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidifier::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::humidifier::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted entities.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"trigger_behavior_description": "The behavior of the targeted entities to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_threshold_changed_description": "Which changes to trigger on and threshold values.",
|
||||
"trigger_threshold_crossed_description": "Which threshold crossing to trigger on and threshold values.",
|
||||
"trigger_threshold_name": "Threshold configuration"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_threshold_name": "Threshold type"
|
||||
},
|
||||
"conditions": {
|
||||
"is_value": {
|
||||
"description": "Tests if a relative humidity value is above a threshold, below a threshold, or in a range of values.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidity::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::humidity::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::humidity::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::humidity::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -47,7 +40,6 @@
|
||||
"description": "Triggers after one or more relative humidity values change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::humidity::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::humidity::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -57,11 +49,9 @@
|
||||
"description": "Triggers after one or more relative humidity values cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::humidity::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::humidity::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::humidity::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::humidity::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted entities.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"trigger_behavior_description": "The behavior of the targeted entities to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_threshold_changed_description": "Which changes to trigger on and threshold values.",
|
||||
"trigger_threshold_crossed_description": "Which threshold crossing to trigger on and threshold values.",
|
||||
"trigger_threshold_name": "Threshold configuration"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_threshold_name": "Threshold type"
|
||||
},
|
||||
"conditions": {
|
||||
"is_detected": {
|
||||
"description": "Tests if light is currently detected.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::illuminance::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::illuminance::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -25,7 +19,6 @@
|
||||
"description": "Tests if light is currently not detected.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::illuminance::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::illuminance::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -35,11 +28,9 @@
|
||||
"description": "Tests the illuminance value.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::illuminance::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::illuminance::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::illuminance::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::illuminance::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -67,7 +58,6 @@
|
||||
"description": "Triggers after one or more illuminance values change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::illuminance::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::illuminance::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -77,7 +67,6 @@
|
||||
"description": "Triggers after one or more light sensors stop detecting light.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::illuminance::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::illuminance::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -87,11 +76,9 @@
|
||||
"description": "Triggers after one or more illuminance values cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::illuminance::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::illuminance::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::illuminance::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::illuminance::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -101,7 +88,6 @@
|
||||
"description": "Triggers after one or more light sensors start detecting light.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::illuminance::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::illuminance::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -23,7 +23,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: IstaConfigEntry) -> bool
|
||||
ista = PyEcotrendIsta(
|
||||
entry.data[CONF_EMAIL],
|
||||
entry.data[CONF_PASSWORD],
|
||||
_LOGGER,
|
||||
)
|
||||
|
||||
coordinator = IstaCoordinator(hass, entry, ista)
|
||||
|
||||
@@ -51,7 +51,6 @@ class IstaConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
ista = PyEcotrendIsta(
|
||||
user_input[CONF_EMAIL],
|
||||
user_input[CONF_PASSWORD],
|
||||
_LOGGER,
|
||||
)
|
||||
try:
|
||||
await self.hass.async_add_executor_job(ista.login)
|
||||
@@ -102,7 +101,6 @@ class IstaConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
ista = PyEcotrendIsta(
|
||||
user_input[CONF_EMAIL],
|
||||
user_input[CONF_PASSWORD],
|
||||
_LOGGER,
|
||||
)
|
||||
|
||||
def get_consumption_units() -> set[str]:
|
||||
|
||||
@@ -94,10 +94,8 @@ class IstaCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
result = self.ista.get_consumption_unit_details()
|
||||
|
||||
return {
|
||||
consumption_unit: next(
|
||||
details
|
||||
for details in result["consumptionUnits"]
|
||||
if details["id"] == consumption_unit
|
||||
)
|
||||
consumption_unit: details
|
||||
for consumption_unit in self.ista.get_uuids()
|
||||
for details in result["consumptionUnits"]
|
||||
if details["id"] == consumption_unit
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted lawn mowers.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted lawn mowers to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_docked": {
|
||||
"description": "Tests if one or more lawn mowers are docked.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more lawn mowers are encountering an error.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -30,7 +26,6 @@
|
||||
"description": "Tests if one or more lawn mowers are mowing.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -40,7 +35,6 @@
|
||||
"description": "Tests if one or more lawn mowers are paused.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -50,7 +44,6 @@
|
||||
"description": "Tests if one or more lawn mowers are returning to the dock.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -104,7 +97,6 @@
|
||||
"description": "Triggers after one or more lawn mowers have returned to dock.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -114,7 +106,6 @@
|
||||
"description": "Triggers after one or more lawn mowers encounter an error.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -124,7 +115,6 @@
|
||||
"description": "Triggers after one or more lawn mowers pause mowing.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -134,7 +124,6 @@
|
||||
"description": "Triggers after one or more lawn mowers start mowing.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -144,7 +133,6 @@
|
||||
"description": "Triggers after one or more lawn mowers start returning to dock.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lawn_mower::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::lawn_mower::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -36,5 +36,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/led_ble",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["bluetooth-data-tools==1.28.4", "led-ble==1.1.7"]
|
||||
"requirements": ["bluetooth-data-tools==1.28.4", "led-ble==1.1.8"]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted lights.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"field_brightness_description": "Number indicating brightness, where 0 turns the light off, 1 is the minimum brightness, and 255 is the maximum brightness.",
|
||||
"field_brightness_name": "Brightness value",
|
||||
"field_brightness_pct_description": "Number indicating the percentage of full brightness, where 0 turns the light off, 1 is the minimum brightness, and 100 is the maximum brightness.",
|
||||
@@ -37,22 +35,17 @@
|
||||
"field_xy_color_description": "Color in XY-format. A list of two decimal numbers between 0 and 1.",
|
||||
"field_xy_color_name": "XY-color",
|
||||
"section_advanced_fields_name": "Advanced options",
|
||||
"trigger_behavior_description": "The behavior of the targeted lights to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_threshold_changed_description": "Which changes to trigger on and threshold values.",
|
||||
"trigger_threshold_crossed_description": "Which threshold crossing to trigger on and threshold values.",
|
||||
"trigger_threshold_name": "Threshold configuration"
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_threshold_name": "Threshold type"
|
||||
},
|
||||
"conditions": {
|
||||
"is_brightness": {
|
||||
"description": "Tests the brightness of one or more lights.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::light::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::light::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::light::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::light::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -62,7 +55,6 @@
|
||||
"description": "Tests if one or more lights are off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::light::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::light::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -72,7 +64,6 @@
|
||||
"description": "Tests if one or more lights are on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::light::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::light::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -513,7 +504,6 @@
|
||||
"description": "Triggers after the brightness of one or more lights changes.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::light::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::light::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -523,11 +513,9 @@
|
||||
"description": "Triggers after the brightness of one or more lights crosses a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::light::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::light::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::light::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::light::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -537,7 +525,6 @@
|
||||
"description": "Triggers after one or more lights turn off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::light::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::light::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -547,7 +534,6 @@
|
||||
"description": "Triggers after one or more lights turn on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::light::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::light::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted locks.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted locks to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_jammed": {
|
||||
"description": "Tests if one or more locks are jammed.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lock::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::lock::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more locks are locked.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lock::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::lock::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -30,7 +26,6 @@
|
||||
"description": "Tests if one or more locks are open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lock::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::lock::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -40,7 +35,6 @@
|
||||
"description": "Tests if one or more locks are unlocked.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lock::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::lock::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -151,7 +145,6 @@
|
||||
"description": "Triggers after one or more locks jam.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lock::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::lock::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -161,7 +154,6 @@
|
||||
"description": "Triggers after one or more locks lock.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lock::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::lock::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -171,7 +163,6 @@
|
||||
"description": "Triggers after one or more locks open.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lock::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::lock::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -181,7 +172,6 @@
|
||||
"description": "Triggers after one or more locks unlock.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::lock::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::lock::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -323,7 +323,11 @@ DISCOVERY_SCHEMAS = [
|
||||
required_attributes=(
|
||||
clusters.FanControl.Attributes.FanMode,
|
||||
clusters.FanControl.Attributes.PercentCurrent,
|
||||
clusters.FanControl.Attributes.PercentSetting,
|
||||
),
|
||||
# PercentSetting SHALL be null when FanMode is Auto (spec 4.4.6.3),
|
||||
# so allow null values to not block discovery in that state.
|
||||
allow_none_value=True,
|
||||
optional_attributes=(
|
||||
clusters.FanControl.Attributes.SpeedSetting,
|
||||
clusters.FanControl.Attributes.RockSetting,
|
||||
|
||||
@@ -168,10 +168,15 @@ class MatterWaterHeater(MatterEntity, WaterHeaterEntity):
|
||||
self._attr_target_temperature = self._get_temperature_in_degrees(
|
||||
clusters.Thermostat.Attributes.OccupiedHeatingSetpoint
|
||||
)
|
||||
system_mode = self.get_matter_attribute_value(
|
||||
clusters.Thermostat.Attributes.SystemMode
|
||||
)
|
||||
boost_state = self.get_matter_attribute_value(
|
||||
clusters.WaterHeaterManagement.Attributes.BoostState
|
||||
)
|
||||
if boost_state == clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive:
|
||||
if system_mode == clusters.Thermostat.Enums.SystemModeEnum.kOff:
|
||||
self._attr_current_operation = STATE_OFF
|
||||
elif boost_state == clusters.WaterHeaterManagement.Enums.BoostStateEnum.kActive:
|
||||
self._attr_current_operation = STATE_HIGH_DEMAND
|
||||
else:
|
||||
self._attr_current_operation = STATE_ECO
|
||||
@@ -218,6 +223,7 @@ DISCOVERY_SCHEMAS = [
|
||||
clusters.Thermostat.Attributes.AbsMinHeatSetpointLimit,
|
||||
clusters.Thermostat.Attributes.AbsMaxHeatSetpointLimit,
|
||||
clusters.Thermostat.Attributes.LocalTemperature,
|
||||
clusters.Thermostat.Attributes.SystemMode,
|
||||
clusters.WaterHeaterManagement.Attributes.FeatureMap,
|
||||
),
|
||||
optional_attributes=(
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted media players.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted media players to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_not_playing": {
|
||||
"description": "Tests if one or more media players are not playing.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::media_player::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::media_player::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more media players are off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::media_player::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::media_player::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -30,7 +26,6 @@
|
||||
"description": "Tests if one or more media players are on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::media_player::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::media_player::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -40,7 +35,6 @@
|
||||
"description": "Tests if one or more media players are paused.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::media_player::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::media_player::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -50,7 +44,6 @@
|
||||
"description": "Tests if one or more media players are playing.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::media_player::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::media_player::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -267,7 +260,7 @@
|
||||
},
|
||||
"clear_playlist": {
|
||||
"description": "Removes all items from a media player's playlist.",
|
||||
"name": "Clear playlist"
|
||||
"name": "Clear media player playlist"
|
||||
},
|
||||
"join": {
|
||||
"description": "Groups media players together for synchronous playback. Only works on supported multiroom audio systems.",
|
||||
@@ -277,44 +270,44 @@
|
||||
"name": "Group members"
|
||||
}
|
||||
},
|
||||
"name": "Join"
|
||||
"name": "Join media players"
|
||||
},
|
||||
"media_next_track": {
|
||||
"description": "Selects the next track.",
|
||||
"name": "Next"
|
||||
"description": "Selects the next track on a media player.",
|
||||
"name": "Next track"
|
||||
},
|
||||
"media_pause": {
|
||||
"description": "Pauses playback on a media player.",
|
||||
"name": "[%key:common::action::pause%]"
|
||||
"name": "Pause media"
|
||||
},
|
||||
"media_play": {
|
||||
"description": "Starts playback on a media player.",
|
||||
"name": "Play"
|
||||
"name": "Play media"
|
||||
},
|
||||
"media_play_pause": {
|
||||
"description": "Toggles play/pause on a media player.",
|
||||
"name": "Play/Pause"
|
||||
"name": "Play/Pause media"
|
||||
},
|
||||
"media_previous_track": {
|
||||
"description": "Selects the previous track.",
|
||||
"name": "Previous"
|
||||
"description": "Selects the previous track on a media player.",
|
||||
"name": "Previous track"
|
||||
},
|
||||
"media_seek": {
|
||||
"description": "Allows you to go to a different part of the media that is currently playing.",
|
||||
"description": "Allows you to go to a different part of the media that is currently playing on a media player.",
|
||||
"fields": {
|
||||
"seek_position": {
|
||||
"description": "Target position in the currently playing media. The format is platform dependent.",
|
||||
"name": "Position"
|
||||
}
|
||||
},
|
||||
"name": "Seek"
|
||||
"name": "Seek media"
|
||||
},
|
||||
"media_stop": {
|
||||
"description": "Stops playback on a media player.",
|
||||
"name": "[%key:common::action::stop%]"
|
||||
"name": "Stop media"
|
||||
},
|
||||
"play_media": {
|
||||
"description": "Starts playing specified media.",
|
||||
"description": "Starts playing specified media on a media player.",
|
||||
"fields": {
|
||||
"announce": {
|
||||
"description": "If the media should be played as an announcement.",
|
||||
@@ -332,14 +325,14 @@
|
||||
"name": "Play media"
|
||||
},
|
||||
"repeat_set": {
|
||||
"description": "Sets the repeat mode.",
|
||||
"description": "Sets the repeat mode of a media player.",
|
||||
"fields": {
|
||||
"repeat": {
|
||||
"description": "Whether the media (one or all) should be played in a loop or not.",
|
||||
"name": "Repeat mode"
|
||||
}
|
||||
},
|
||||
"name": "Set repeat"
|
||||
"name": "Set media player repeat"
|
||||
},
|
||||
"search_media": {
|
||||
"description": "Searches the available media.",
|
||||
@@ -364,14 +357,14 @@
|
||||
"name": "Search media"
|
||||
},
|
||||
"select_sound_mode": {
|
||||
"description": "Selects a specific sound mode.",
|
||||
"description": "Selects a specific sound mode of a media player.",
|
||||
"fields": {
|
||||
"sound_mode": {
|
||||
"description": "Name of the sound mode to switch to.",
|
||||
"name": "Sound mode"
|
||||
}
|
||||
},
|
||||
"name": "Select sound mode"
|
||||
"name": "Select media player sound mode"
|
||||
},
|
||||
"select_source": {
|
||||
"description": "Sends a media player the command to change the input source.",
|
||||
@@ -381,37 +374,37 @@
|
||||
"name": "Source"
|
||||
}
|
||||
},
|
||||
"name": "Select source"
|
||||
"name": "Select media player source"
|
||||
},
|
||||
"shuffle_set": {
|
||||
"description": "Enables or disables the shuffle mode.",
|
||||
"description": "Enables or disables the shuffle mode of a media player.",
|
||||
"fields": {
|
||||
"shuffle": {
|
||||
"description": "Whether the media should be played in randomized order or not.",
|
||||
"name": "Shuffle mode"
|
||||
}
|
||||
},
|
||||
"name": "Set shuffle"
|
||||
"name": "Set media player shuffle"
|
||||
},
|
||||
"toggle": {
|
||||
"description": "Toggles a media player on/off.",
|
||||
"name": "[%key:common::action::toggle%]"
|
||||
"name": "Toggle media player"
|
||||
},
|
||||
"turn_off": {
|
||||
"description": "Turns off the power of a media player.",
|
||||
"name": "[%key:common::action::turn_off%]"
|
||||
"name": "Turn off media player"
|
||||
},
|
||||
"turn_on": {
|
||||
"description": "Turns on the power of a media player.",
|
||||
"name": "[%key:common::action::turn_on%]"
|
||||
"name": "Turn on media player"
|
||||
},
|
||||
"unjoin": {
|
||||
"description": "Removes a media player from a group. Only works on platforms which support player groups.",
|
||||
"name": "Unjoin"
|
||||
"name": "Unjoin media player"
|
||||
},
|
||||
"volume_down": {
|
||||
"description": "Turns down the volume of a media player.",
|
||||
"name": "Turn down volume"
|
||||
"name": "Turn down media player volume"
|
||||
},
|
||||
"volume_mute": {
|
||||
"description": "Mutes or unmutes a media player.",
|
||||
@@ -421,7 +414,7 @@
|
||||
"name": "Muted"
|
||||
}
|
||||
},
|
||||
"name": "Mute/unmute volume"
|
||||
"name": "Mute/unmute media player"
|
||||
},
|
||||
"volume_set": {
|
||||
"description": "Sets the volume level of a media player.",
|
||||
@@ -431,11 +424,11 @@
|
||||
"name": "Level"
|
||||
}
|
||||
},
|
||||
"name": "Set volume"
|
||||
"name": "Set media player volume"
|
||||
},
|
||||
"volume_up": {
|
||||
"description": "Turns up the volume of a media player.",
|
||||
"name": "Turn up volume"
|
||||
"name": "Turn up media player volume"
|
||||
}
|
||||
},
|
||||
"title": "Media player",
|
||||
@@ -444,7 +437,6 @@
|
||||
"description": "Triggers after one or more media players stop playing media.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::media_player::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::media_player::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted entities.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"trigger_behavior_description": "The behavior of the targeted entities to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_threshold_changed_description": "Which changes to trigger on and threshold values.",
|
||||
"trigger_threshold_crossed_description": "Which threshold crossing to trigger on and threshold values.",
|
||||
"trigger_threshold_name": "Threshold configuration"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_threshold_name": "Threshold type"
|
||||
},
|
||||
"conditions": {
|
||||
"is_detected": {
|
||||
"description": "Tests if one or more moisture sensors are detecting moisture.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::moisture::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::moisture::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -25,7 +19,6 @@
|
||||
"description": "Tests if one or more moisture sensors are not detecting moisture.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::moisture::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::moisture::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -35,11 +28,9 @@
|
||||
"description": "Tests the moisture level of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::moisture::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::moisture::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::moisture::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::moisture::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -67,7 +58,6 @@
|
||||
"description": "Triggers after one or more moisture content values change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::moisture::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::moisture::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -77,7 +67,6 @@
|
||||
"description": "Triggers after one or more moisture sensors stop detecting moisture.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::moisture::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::moisture::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -87,11 +76,9 @@
|
||||
"description": "Triggers after one or more moisture content values cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::moisture::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::moisture::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::moisture::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::moisture::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -101,7 +88,6 @@
|
||||
"description": "Triggers after one or more moisture sensors start detecting moisture.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::moisture::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::moisture::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted motion sensors.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted motion sensors to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_detected": {
|
||||
"description": "Tests if one or more motion sensors are detecting motion.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::motion::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::motion::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more motion sensors are not detecting motion.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::motion::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::motion::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -48,7 +44,6 @@
|
||||
"description": "Triggers after one or more motion sensors stop detecting motion.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::motion::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::motion::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -58,7 +53,6 @@
|
||||
"description": "Triggers after one or more motion sensors start detecting motion.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::motion::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::motion::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -87,19 +87,18 @@ NUMBERS: tuple[NRGkickNumberEntityDescription, ...] = (
|
||||
int(value)
|
||||
),
|
||||
),
|
||||
NRGkickNumberEntityDescription(
|
||||
key="phase_count",
|
||||
translation_key="phase_count",
|
||||
native_min_value=1,
|
||||
native_max_value=3,
|
||||
native_step=1,
|
||||
mode=NumberMode.SLIDER,
|
||||
value_fn=lambda data: data.control.get(CONTROL_KEY_PHASE_COUNT),
|
||||
set_value_fn=lambda coordinator, value: coordinator.api.set_phase_count(
|
||||
int(value)
|
||||
),
|
||||
max_value_fn=_get_phase_count_max,
|
||||
),
|
||||
)
|
||||
|
||||
PHASE_COUNT_DESCRIPTION = NRGkickNumberEntityDescription(
|
||||
key="phase_count",
|
||||
translation_key="phase_count",
|
||||
native_min_value=1,
|
||||
native_max_value=3,
|
||||
native_step=1,
|
||||
mode=NumberMode.SLIDER,
|
||||
value_fn=lambda data: data.control.get(CONTROL_KEY_PHASE_COUNT),
|
||||
set_value_fn=lambda coordinator, value: coordinator.api.set_phase_count(int(value)),
|
||||
max_value_fn=_get_phase_count_max,
|
||||
)
|
||||
|
||||
|
||||
@@ -111,9 +110,11 @@ async def async_setup_entry(
|
||||
"""Set up NRGkick number entities based on a config entry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
||||
async_add_entities(
|
||||
entities: list[NRGkickNumber] = [
|
||||
NRGkickNumber(coordinator, description) for description in NUMBERS
|
||||
)
|
||||
]
|
||||
entities.append(NRGkickPhaseCountNumber(coordinator, PHASE_COUNT_DESCRIPTION))
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class NRGkickNumber(NRGkickEntity, NumberEntity):
|
||||
@@ -153,3 +154,26 @@ class NRGkickNumber(NRGkickEntity, NumberEntity):
|
||||
await self._async_call_api(
|
||||
self.entity_description.set_value_fn(self.coordinator, value)
|
||||
)
|
||||
|
||||
|
||||
class NRGkickPhaseCountNumber(NRGkickNumber):
|
||||
"""Phase count number entity with optimistic state.
|
||||
|
||||
The device briefly reports 0 phases while switching. This subclass
|
||||
caches the last valid value to avoid exposing the transient state.
|
||||
"""
|
||||
|
||||
_last_phase_count: float | None = None
|
||||
|
||||
@property
|
||||
def native_value(self) -> float | None:
|
||||
"""Return the current value, filtering transient zeros."""
|
||||
value = super().native_value
|
||||
if value is not None and value != 0:
|
||||
self._last_phase_count = value
|
||||
return self._last_phase_count
|
||||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Set phase count with optimistic update."""
|
||||
self._last_phase_count = int(value)
|
||||
await super().async_set_native_value(value)
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted occupancy sensors.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted occupancy sensors to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_detected": {
|
||||
"description": "Tests if one or more occupancy sensors are detecting occupancy.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::occupancy::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::occupancy::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more occupancy sensors are not detecting occupancy.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::occupancy::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::occupancy::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -48,7 +44,6 @@
|
||||
"description": "Triggers after one or more occupancy sensors stop detecting occupancy.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::occupancy::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::occupancy::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -58,7 +53,6 @@
|
||||
"description": "Triggers after one or more occupancy sensors start detecting occupancy.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::occupancy::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::occupancy::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted persons.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted persons to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_home": {
|
||||
"description": "Tests if one or more persons are home.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::person::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::person::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more persons are not home.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::person::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::person::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -80,7 +76,6 @@
|
||||
"description": "Triggers when one or more persons enter home.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::person::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::person::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -90,7 +85,6 @@
|
||||
"description": "Triggers when one or more persons leave home.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::person::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::person::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the power value should match on the targeted entities.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"trigger_behavior_description": "The behavior of the targeted entities to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_threshold_changed_description": "Which changes to trigger on and threshold values.",
|
||||
"trigger_threshold_crossed_description": "Which threshold crossing to trigger on and threshold values.",
|
||||
"trigger_threshold_name": "Threshold configuration"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_threshold_name": "Threshold type"
|
||||
},
|
||||
"conditions": {
|
||||
"is_value": {
|
||||
"description": "Tests the power value of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::power::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::power::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::power::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::power::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -47,7 +40,6 @@
|
||||
"description": "Triggers after one or more power values change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::power::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::power::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -57,11 +49,9 @@
|
||||
"description": "Triggers after one or more power values cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::power::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::power::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::power::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::power::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ VM_CONTAINER_RUNNING = "running"
|
||||
STORAGE_ACTIVE = 1
|
||||
STORAGE_SHARED = 1
|
||||
STORAGE_ENABLED = 1
|
||||
STATUS_OK = "ok"
|
||||
STATUS_OK = "OK"
|
||||
|
||||
AUTH_PAM = "pam"
|
||||
AUTH_PVE = "pve"
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
"services": {
|
||||
"disable": {
|
||||
"description": "Stops the recording of events and state changes.",
|
||||
"name": "[%key:common::action::disable%]"
|
||||
"name": "Disable Recorder"
|
||||
},
|
||||
"enable": {
|
||||
"description": "Starts the recording of events and state changes.",
|
||||
"name": "[%key:common::action::enable%]"
|
||||
"name": "Enable Recorder"
|
||||
},
|
||||
"get_statistics": {
|
||||
"description": "Retrieves statistics data for entities within a specific time period.",
|
||||
@@ -46,7 +46,7 @@
|
||||
"name": "Units"
|
||||
}
|
||||
},
|
||||
"name": "Get statistics"
|
||||
"name": "Get Recorder statistics"
|
||||
},
|
||||
"purge": {
|
||||
"description": "Starts purge task - to clean up old data from your database.",
|
||||
@@ -64,7 +64,7 @@
|
||||
"name": "Repack"
|
||||
}
|
||||
},
|
||||
"name": "Purge"
|
||||
"name": "Purge Recorder database"
|
||||
},
|
||||
"purge_entities": {
|
||||
"description": "Starts a purge task to remove the data related to specific entities from your database.",
|
||||
@@ -86,7 +86,7 @@
|
||||
"name": "[%key:component::recorder::services::purge::fields::keep_days::name%]"
|
||||
}
|
||||
},
|
||||
"name": "Purge entities"
|
||||
"name": "Purge Recorder entities"
|
||||
}
|
||||
},
|
||||
"system_health": {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"common": {
|
||||
"trigger_behavior_description": "The behavior of the targeted remotes to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"device_automation": {
|
||||
"action_type": {
|
||||
@@ -132,7 +131,6 @@
|
||||
"description": "Triggers when one or more remotes turn off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::remote::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::remote::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -142,7 +140,6 @@
|
||||
"description": "Triggers when one or more remotes turn on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::remote::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::remote::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -128,9 +128,8 @@ class RingCam(RingEntity[RingDoorBell], Camera):
|
||||
self._device = self._get_coordinator_data().get_video_device(
|
||||
self._device.device_api_id
|
||||
)
|
||||
|
||||
history_data = self._device.last_history
|
||||
if history_data and self._device.has_subscription:
|
||||
if history_data:
|
||||
self._last_event = history_data[0]
|
||||
# will call async_update to update the attributes and get the
|
||||
# video url from the api
|
||||
@@ -155,16 +154,13 @@ class RingCam(RingEntity[RingDoorBell], Camera):
|
||||
self, width: int | None = None, height: int | None = None
|
||||
) -> bytes | None:
|
||||
"""Return a still image response from the camera."""
|
||||
if self._video_url is None:
|
||||
if not self._device.has_subscription:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="no_subscription",
|
||||
)
|
||||
return None
|
||||
# For live_view cameras, get a fresh snapshot
|
||||
if self.entity_description.key == "live_view":
|
||||
return await self._async_get_fresh_snapshot()
|
||||
|
||||
# For last_recording cameras, use the cached video frame
|
||||
key = (width, height)
|
||||
if not (image := self._images.get(key)):
|
||||
if not (image := self._images.get(key)) and self._video_url is not None:
|
||||
image = await ffmpeg.async_get_image(
|
||||
self.hass,
|
||||
self._video_url,
|
||||
@@ -177,6 +173,11 @@ class RingCam(RingEntity[RingDoorBell], Camera):
|
||||
|
||||
return image
|
||||
|
||||
@exception_wrap
|
||||
async def _async_get_fresh_snapshot(self) -> bytes | None:
|
||||
"""Get a fresh snapshot from the camera."""
|
||||
return await self._device.async_get_snapshot()
|
||||
|
||||
async def handle_async_mjpeg_stream(
|
||||
self, request: web.Request
|
||||
) -> web.StreamResponse | None:
|
||||
|
||||
@@ -151,9 +151,6 @@
|
||||
"api_timeout": {
|
||||
"message": "Timeout communicating with Ring API"
|
||||
},
|
||||
"no_subscription": {
|
||||
"message": "Ring Protect subscription required for snapshots"
|
||||
},
|
||||
"sdp_m_line_index_required": {
|
||||
"message": "Error negotiating stream for {device}"
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
"name": "Reset side brush consumable"
|
||||
},
|
||||
"shutdown": {
|
||||
"name": "Shutdown"
|
||||
"name": "Shut down"
|
||||
},
|
||||
"start": {
|
||||
"name": "Start"
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted schedules.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted schedules to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_off": {
|
||||
"description": "Tests if one or more schedule blocks are currently not active.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::schedule::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::schedule::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more schedule blocks are currently active.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::schedule::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::schedule::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -79,7 +75,6 @@
|
||||
"description": "Triggers when a schedule block ends.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::schedule::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::schedule::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -89,7 +84,6 @@
|
||||
"description": "Triggers when a schedule block starts.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::schedule::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::schedule::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -19,7 +19,6 @@ is_option_selected:
|
||||
required: true
|
||||
selector:
|
||||
state:
|
||||
attribute: options
|
||||
hide_states:
|
||||
- unavailable
|
||||
- unknown
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
"description": "Tests if one or more dropdowns have a specific option selected.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "Whether the condition should pass when any or all targeted entities match.",
|
||||
"name": "Behavior"
|
||||
"name": "Condition passes if"
|
||||
},
|
||||
"option": {
|
||||
"description": "The options to check for.",
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted sirens.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted sirens to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_off": {
|
||||
"description": "Tests if one or more sirens are off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::siren::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::siren::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more sirens are on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::siren::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::siren::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -90,7 +86,6 @@
|
||||
"description": "Triggers after one or more sirens turn off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::siren::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::siren::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -100,7 +95,6 @@
|
||||
"description": "Triggers after one or more sirens turn on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::siren::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::siren::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -38,5 +38,5 @@
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["pysmartthings"],
|
||||
"quality_scale": "bronze",
|
||||
"requirements": ["pysmartthings==3.7.2"]
|
||||
"requirements": ["pysmartthings==3.7.3"]
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "service",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["pysmhi"],
|
||||
"requirements": ["pysmhi==1.1.0"]
|
||||
"requirements": ["pysmhi==2.0.0"]
|
||||
}
|
||||
|
||||
@@ -56,6 +56,21 @@ FORESTDRY_MAP = {
|
||||
"5": "very_dry",
|
||||
"6": "extremely_dry",
|
||||
}
|
||||
PRECIPITATION_CATEGORY_MAP = {
|
||||
0: "no_precipitation",
|
||||
1: "rain",
|
||||
2: "thunderstorm",
|
||||
3: "freezing_rain",
|
||||
4: "mixed_ice",
|
||||
5: "snow",
|
||||
6: "wet_snow",
|
||||
7: "rain_snow_mixed",
|
||||
8: "ice_pellets",
|
||||
9: "graupel",
|
||||
10: "hail",
|
||||
11: "drizzle",
|
||||
12: "freezing_drizzle",
|
||||
}
|
||||
|
||||
|
||||
def get_percentage_values(entity: SMHIWeatherSensor, key: str) -> int | None:
|
||||
@@ -68,6 +83,14 @@ def get_percentage_values(entity: SMHIWeatherSensor, key: str) -> int | None:
|
||||
return None
|
||||
|
||||
|
||||
def get_precipitation_category(entity: SMHIWeatherSensor) -> str | None:
|
||||
"""Return the precipitation category."""
|
||||
value: int | None = entity.coordinator.current.get("precipitation_category")
|
||||
if value in PRECIPITATION_CATEGORY_MAP:
|
||||
return PRECIPITATION_CATEGORY_MAP[value]
|
||||
return None
|
||||
|
||||
|
||||
def get_fire_index_value(entity: SMHIFireSensor, key: str) -> str:
|
||||
"""Return index value as string."""
|
||||
value: int | None = entity.coordinator.fire_current.get(key) # type: ignore[assignment]
|
||||
@@ -128,11 +151,9 @@ WEATHER_SENSOR_DESCRIPTIONS: tuple[SMHIWeatherEntityDescription, ...] = (
|
||||
SMHIWeatherEntityDescription(
|
||||
key="precipitation_category",
|
||||
translation_key="precipitation_category",
|
||||
value_fn=lambda entity: str(
|
||||
get_percentage_values(entity, "precipitation_category")
|
||||
),
|
||||
value_fn=get_precipitation_category,
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=["0", "1", "2", "3", "4", "5", "6"],
|
||||
options=[*PRECIPITATION_CATEGORY_MAP.values()],
|
||||
),
|
||||
SMHIWeatherEntityDescription(
|
||||
key="frozen_precipitation",
|
||||
|
||||
@@ -95,13 +95,19 @@
|
||||
"precipitation_category": {
|
||||
"name": "Precipitation category",
|
||||
"state": {
|
||||
"0": "No precipitation",
|
||||
"1": "Snow",
|
||||
"2": "Snow and rain",
|
||||
"3": "Rain",
|
||||
"4": "Drizzle",
|
||||
"5": "Freezing rain",
|
||||
"6": "Freezing drizzle"
|
||||
"drizzle": "Drizzle",
|
||||
"freezing_drizzle": "Freezing drizzle",
|
||||
"freezing_rain": "Freezing rain",
|
||||
"graupel": "Graupel",
|
||||
"hail": "Hail",
|
||||
"ice_pellets": "Ice pellets",
|
||||
"mixed_ice": "Mixed/ice",
|
||||
"no_precipitation": "No precipitation",
|
||||
"rain": "Rain",
|
||||
"rain_snow_mixed": "Mixture of rain and snow",
|
||||
"snow": "Snow",
|
||||
"thunderstorm": "Thunderstorm",
|
||||
"wet_snow": "Wet snow"
|
||||
}
|
||||
},
|
||||
"rate_of_spread": {
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["solarlog_cli"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["solarlog_cli==0.7.0"]
|
||||
"requirements": ["solarlog_cli==0.7.1"]
|
||||
}
|
||||
|
||||
@@ -417,6 +417,7 @@ class SonosDiscoveryManager:
|
||||
)
|
||||
new_coordinator.setup(soco)
|
||||
c_dict[soco.household_id] = new_coordinator
|
||||
c_dict[soco.household_id].add_speaker(soco)
|
||||
speaker.setup(self.entry)
|
||||
except (OSError, SoCoException, Timeout) as ex:
|
||||
_LOGGER.warning("Failed to add SonosSpeaker using %s: %s", soco, ex)
|
||||
|
||||
@@ -99,3 +99,7 @@ class SonosAlarms(SonosHouseholdCoordinator):
|
||||
)
|
||||
self.last_processed_event_id = self.alarms.last_id
|
||||
return True
|
||||
|
||||
def add_speaker(self, soco: SoCo) -> None:
|
||||
"""Update any skipped alarms when speaker is added."""
|
||||
self.alarms.update_skipped(soco)
|
||||
|
||||
@@ -85,3 +85,6 @@ class SonosHouseholdCoordinator:
|
||||
def update_cache(self, soco: SoCo, update_id: int | None = None) -> bool:
|
||||
"""Update the cache of the household-level feature and return if cache has changed."""
|
||||
raise NotImplementedError
|
||||
|
||||
def add_speaker(self, soco: SoCo) -> None:
|
||||
"""Additional processing when a speaker is added if needed."""
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"quality_scale": "bronze",
|
||||
"requirements": [
|
||||
"defusedxml==0.7.1",
|
||||
"soco==0.30.14",
|
||||
"soco==0.30.15",
|
||||
"sonos-websocket==0.1.3"
|
||||
],
|
||||
"ssdp": [
|
||||
|
||||
@@ -132,7 +132,8 @@ class SonosMedia:
|
||||
|
||||
self.artist = track_info.get("artist")
|
||||
self.album_name = track_info.get("album")
|
||||
self.title = track_info.get("title")
|
||||
title = track_info.get("title") or ""
|
||||
self.title = title.strip() or None
|
||||
self.image_url = track_info.get("album_art")
|
||||
|
||||
playlist_position = int(track_info.get("playlist_position", -1))
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "service",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["srpenergy"],
|
||||
"requirements": ["srpenergy==1.3.6"]
|
||||
"requirements": ["srpenergy==1.3.8"]
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the state should match on the targeted switches.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"trigger_behavior_description": "The behavior of the targeted switches to trigger on.",
|
||||
"trigger_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"trigger_behavior_name": "Trigger when"
|
||||
},
|
||||
"conditions": {
|
||||
"is_off": {
|
||||
"description": "Tests if one or more switches are off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::switch::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::switch::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -20,7 +17,6 @@
|
||||
"description": "Tests if one or more switches are on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::switch::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::switch::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -104,7 +100,6 @@
|
||||
"description": "Triggers after one or more switches turn off.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::switch::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::switch::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
@@ -114,7 +109,6 @@
|
||||
"description": "Triggers after one or more switches turn on.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::switch::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::switch::common::trigger_behavior_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@ import os
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple
|
||||
|
||||
from psutil import Process
|
||||
from psutil._common import sbattery, sdiskusage, shwtemp, snetio, snicaddr, sswap
|
||||
from psutil._ntuples import sbattery, sdiskusage, shwtemp, snetio, snicaddr, sswap
|
||||
import psutil_home_assistant as ha_psutil
|
||||
|
||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/systemmonitor",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["psutil"],
|
||||
"requirements": ["psutil-home-assistant==0.0.1", "psutil==7.1.2"],
|
||||
"requirements": ["psutil-home-assistant==0.0.1", "psutil==7.2.2"],
|
||||
"single_config_entry": true
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import os
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from psutil._common import sfan, shwtemp
|
||||
from psutil._ntuples import sfan, shwtemp
|
||||
import psutil_home_assistant as ha_psutil
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "How the temperature should match on the targeted entities.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_threshold_description": "What to test for and threshold values.",
|
||||
"condition_threshold_name": "Threshold configuration",
|
||||
"trigger_behavior_description": "The behavior of the targeted entities to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_threshold_changed_description": "Which changes to trigger on and threshold values.",
|
||||
"trigger_threshold_crossed_description": "Which threshold crossing to trigger on and threshold values.",
|
||||
"trigger_threshold_name": "Threshold configuration"
|
||||
"condition_behavior_name": "Condition passes if",
|
||||
"condition_threshold_name": "Threshold type",
|
||||
"trigger_behavior_name": "Trigger when",
|
||||
"trigger_threshold_name": "Threshold type"
|
||||
},
|
||||
"conditions": {
|
||||
"is_value": {
|
||||
"description": "Tests the temperature of one or more entities.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::temperature::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::temperature::common::condition_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::temperature::common::condition_threshold_description%]",
|
||||
"name": "[%key:component::temperature::common::condition_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -47,7 +40,6 @@
|
||||
"description": "Triggers after one or more temperatures change.",
|
||||
"fields": {
|
||||
"threshold": {
|
||||
"description": "[%key:component::temperature::common::trigger_threshold_changed_description%]",
|
||||
"name": "[%key:component::temperature::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
@@ -57,11 +49,9 @@
|
||||
"description": "Triggers after one or more temperatures cross a threshold.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::temperature::common::trigger_behavior_description%]",
|
||||
"name": "[%key:component::temperature::common::trigger_behavior_name%]"
|
||||
},
|
||||
"threshold": {
|
||||
"description": "[%key:component::temperature::common::trigger_threshold_crossed_description%]",
|
||||
"name": "[%key:component::temperature::common::trigger_threshold_name%]"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -52,7 +52,7 @@ VEHICLE_DESCRIPTIONS: tuple[TeslaFleetNumberVehicleEntityDescription, ...] = (
|
||||
mode=NumberMode.AUTO,
|
||||
max_key="charge_state_charge_current_request_max",
|
||||
func=lambda api, value: api.set_charging_amps(value),
|
||||
scopes=[Scope.VEHICLE_CHARGING_CMDS],
|
||||
scopes=[Scope.VEHICLE_CHARGING_CMDS, Scope.VEHICLE_CMDS],
|
||||
),
|
||||
TeslaFleetNumberVehicleEntityDescription(
|
||||
key="charge_state_charge_limit_soc",
|
||||
|
||||
@@ -30,4 +30,8 @@ class TeslaUserImplementation(AuthImplementation):
|
||||
@property
|
||||
def extra_authorize_data(self) -> dict[str, Any]:
|
||||
"""Extra data that needs to be appended to the authorize url."""
|
||||
return {"prompt": "login", "scope": " ".join(SCOPES)}
|
||||
return {
|
||||
"prompt": "login",
|
||||
"prompt_missing_scopes": "true",
|
||||
"scope": " ".join(SCOPES),
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
"title": "[%key:common::config_flow::title::oauth2_pick_implementation%]"
|
||||
},
|
||||
"reauth_confirm": {
|
||||
"description": "The {name} integration needs to re-authenticate your account",
|
||||
"description": "The {name} integration needs to re-authenticate your account. Reauthentication refreshes the Tesla API permissions granted to Home Assistant, including any newly enabled scopes.",
|
||||
"title": "[%key:common::config_flow::title::reauth%]"
|
||||
},
|
||||
"registration_complete": {
|
||||
@@ -60,7 +60,7 @@
|
||||
"data_description": {
|
||||
"qr_code": "Scan this QR code with your phone to set up the virtual key."
|
||||
},
|
||||
"description": "To enable command signing, you must open the Tesla app, select your vehicle, and then visit the following URL to set up a virtual key. You must repeat this process for each vehicle.\n\n{virtual_key_url}",
|
||||
"description": "To enable command signing, you must open the Tesla app, select your vehicle, and then visit the following URL to set up a virtual key. You must repeat this process for each vehicle.\n\n{virtual_key_url}\n\nIf you later enable additional Tesla API permissions, reauthenticate the integration to refresh the granted scopes.",
|
||||
"title": "Command signing"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_behavior_description": "The behavior of the targeted texts to check.",
|
||||
"condition_behavior_name": "Behavior"
|
||||
"condition_behavior_name": "Condition passes if"
|
||||
},
|
||||
"conditions": {
|
||||
"is_equal_to": {
|
||||
"description": "Tests if one or more texts are equal to a specified value.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::text::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::text::common::condition_behavior_name%]"
|
||||
},
|
||||
"value": {
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
},
|
||||
"services": {
|
||||
"set_value": {
|
||||
"description": "Sets the time.",
|
||||
"description": "Sets the value of a time entity.",
|
||||
"fields": {
|
||||
"time": {
|
||||
"description": "The time to set.",
|
||||
"name": "Time"
|
||||
}
|
||||
},
|
||||
"name": "Set Time"
|
||||
"name": "Set time"
|
||||
}
|
||||
},
|
||||
"title": "Time"
|
||||
|
||||
17
homeassistant/components/timer/condition.py
Normal file
17
homeassistant/components/timer/condition.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""Provides conditions for timers."""
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.condition import Condition, make_entity_state_condition
|
||||
|
||||
from . import DOMAIN, STATUS_ACTIVE, STATUS_IDLE, STATUS_PAUSED
|
||||
|
||||
CONDITIONS: dict[str, type[Condition]] = {
|
||||
"is_active": make_entity_state_condition(DOMAIN, STATUS_ACTIVE),
|
||||
"is_paused": make_entity_state_condition(DOMAIN, STATUS_PAUSED),
|
||||
"is_idle": make_entity_state_condition(DOMAIN, STATUS_IDLE),
|
||||
}
|
||||
|
||||
|
||||
async def async_get_conditions(hass: HomeAssistant) -> dict[str, type[Condition]]:
|
||||
"""Return the timer conditions."""
|
||||
return CONDITIONS
|
||||
18
homeassistant/components/timer/conditions.yaml
Normal file
18
homeassistant/components/timer/conditions.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
.condition_common: &condition_common
|
||||
target:
|
||||
entity:
|
||||
- domain: timer
|
||||
fields:
|
||||
behavior:
|
||||
required: true
|
||||
default: any
|
||||
selector:
|
||||
select:
|
||||
translation_key: condition_behavior
|
||||
options:
|
||||
- all
|
||||
- any
|
||||
|
||||
is_active: *condition_common
|
||||
is_paused: *condition_common
|
||||
is_idle: *condition_common
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user