mirror of
https://github.com/home-assistant/core.git
synced 2026-06-29 18:16:13 +02:00
Compare commits
194 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d36c6f7f8 | |||
| e0ee456bfa | |||
| ebeb98dd83 | |||
| 49cff5f980 | |||
| c24186e571 | |||
| c9ea8baf61 | |||
| f21426dfa6 | |||
| a450999646 | |||
| 5b8ff19d8d | |||
| 25d505bcf3 | |||
| 91cb829881 | |||
| 4fdc4e6219 | |||
| ca7ae00c7e | |||
| ff460901b7 | |||
| 30512f08a8 | |||
| 9dd1a59d50 | |||
| 91aded4474 | |||
| 543eab3354 | |||
| 47b331a869 | |||
| 696dd45803 | |||
| f92239877f | |||
| 45ceb13937 | |||
| c5aeee8097 | |||
| bfc750b608 | |||
| 60f3bb58a0 | |||
| f56e13c249 | |||
| fed2df4f7b | |||
| 8662982236 | |||
| c618496c95 | |||
| 40ef9828c4 | |||
| ac92775538 | |||
| 4fbff0bd82 | |||
| a076fcea2d | |||
| d3f6fff3be | |||
| ea55fa2a2a | |||
| cb35849a63 | |||
| e701afd7a7 | |||
| 3c285f766a | |||
| 680b652ef2 | |||
| bf09fa8c0d | |||
| 1469429510 | |||
| 476224c6f0 | |||
| 7053d81920 | |||
| 1b2776d1f0 | |||
| f8a61d760c | |||
| e65d491849 | |||
| efd615a461 | |||
| 6e5e16c29d | |||
| a1f78fbab4 | |||
| f774c211a5 | |||
| 3e23c9d13f | |||
| 4c26f53358 | |||
| f5cae385fd | |||
| 3aa68c93a7 | |||
| d57539bfa3 | |||
| ac0377885f | |||
| b9676496d5 | |||
| 7435d6fe54 | |||
| 57f7c4305a | |||
| 24b1f5d1cf | |||
| 915230df44 | |||
| ca9735bb5d | |||
| 9cecc5516f | |||
| e75b7fb83b | |||
| 089bcd9183 | |||
| 363d477dac | |||
| 16772c1ecf | |||
| d1007086bd | |||
| 566f004401 | |||
| 41c9a124b1 | |||
| dc9750a5cd | |||
| 1e43debac6 | |||
| d319440508 | |||
| 09c815205b | |||
| 87809394ef | |||
| 4cfc1d893e | |||
| 953ebba1f1 | |||
| ee96a2e4f1 | |||
| 5af703b5ed | |||
| 1301d36442 | |||
| 956f3fd821 | |||
| 8797a2ec5e | |||
| 528ea500a9 | |||
| 433ff53630 | |||
| eebb8b5b91 | |||
| e0c881758b | |||
| 46cf3e8289 | |||
| 1d7ea1fc72 | |||
| 9219643803 | |||
| b202a0d7ab | |||
| 67801ab604 | |||
| 227aee5232 | |||
| e465549f03 | |||
| 6efd9093ce | |||
| 7044dae281 | |||
| 9d34e83f71 | |||
| ff45b81145 | |||
| 486385e308 | |||
| 11113ce1f4 | |||
| 31dc1f9519 | |||
| 926900d0ca | |||
| 06b429d0b7 | |||
| 9fb2d14fdb | |||
| 0e6279e273 | |||
| 02ddd4c3f4 | |||
| c147321aba | |||
| f0e75ebb83 | |||
| 7ae85d8d97 | |||
| 43802961e9 | |||
| 97844d7ee0 | |||
| e8e5eedd7e | |||
| bbf7a60a9e | |||
| fac6e8feb6 | |||
| 86d282ac2a | |||
| cb407b8163 | |||
| 61b3dda20f | |||
| 951ec34e7c | |||
| 57a441aa4a | |||
| 1e71607063 | |||
| 952fdec1ad | |||
| c9bc041cac | |||
| 2047042803 | |||
| 9f92c8438e | |||
| a0c6d4fb52 | |||
| f315273404 | |||
| 38baeba81c | |||
| d246a7a7e5 | |||
| 29f12d6e80 | |||
| e01ed866d9 | |||
| 3ce5630809 | |||
| 344ae6f604 | |||
| e8b1acea6c | |||
| 24d6a0420c | |||
| 393424fa88 | |||
| 585dd72366 | |||
| 7e2343243d | |||
| de8ed15ea8 | |||
| 9a21d92908 | |||
| 12ea0c4d77 | |||
| 94c4483735 | |||
| 053efdf662 | |||
| 3c9f55f7b2 | |||
| a46b434930 | |||
| 031e764957 | |||
| d9f0faf365 | |||
| a14e5d8a0c | |||
| f356a1cd0d | |||
| 50c12d85f8 | |||
| a88b43d845 | |||
| b9e59522e3 | |||
| 1484384d63 | |||
| 1d1ab798df | |||
| 926d2f1e21 | |||
| b341228b4b | |||
| 241f850e90 | |||
| 257040ac51 | |||
| e3c17026d0 | |||
| 9e4550dd14 | |||
| 37f441d3da | |||
| 0099100d14 | |||
| e20f74dac5 | |||
| f7aa6ef384 | |||
| 71342ef1f6 | |||
| 544dccd50b | |||
| 5f6508c424 | |||
| 70f3526be3 | |||
| f5f2ecadfd | |||
| a8de57a1c6 | |||
| 8b08f10f78 | |||
| 34679b033a | |||
| 014f785050 | |||
| 1c53ada438 | |||
| a88de3efab | |||
| 10ce428387 | |||
| dae8b60ec4 | |||
| e098cc384c | |||
| 6007bfa1cd | |||
| 16262362e1 | |||
| 01350e8f15 | |||
| 8977fc6f67 | |||
| 6411cc5c48 | |||
| 9ce56183ea | |||
| 5117c0b964 | |||
| 7dd5e188bb | |||
| ec80260c4c | |||
| 10ceac63f6 | |||
| 847f4dc287 | |||
| 8d4c8114d4 | |||
| b6b165fd00 | |||
| 7c99cf6385 | |||
| d6b743b93e | |||
| 0cae5e41b4 | |||
| 6fce245dfa | |||
| 44ba231bf6 |
@@ -54,3 +54,4 @@ This repository contains the core of Home Assistant, a Python 3 based home autom
|
||||
- Keep comments concise. Prefer one short line stating the non-obvious constraint, or no comment at all.
|
||||
- Do not add comments that just restate the code on the following line(s) (e.g. `# Check if initialized` above `if self.initialized:`). Comments should only explain why (non-obvious constraints, surprising behavior, or workarounds), never what. Never add comments that justify a change by referencing what the code looked like before.
|
||||
- Do not add section or divider comments (e.g. `# --- XYZ Triggers ---`) inside or outside of functions, since those can easily become stale and be misleading.
|
||||
- When catching exceptions, try-clauses should be as small as possible, i.e. avoid wrapping large blocks of code in a try-clause, and avoid catching exceptions from functions that are not expected to raise them.
|
||||
|
||||
@@ -12,6 +12,7 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
paths:
|
||||
- "requirements*.txt"
|
||||
- "**/requirements*.txt"
|
||||
- "homeassistant/package_constraints.txt"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -58,6 +59,7 @@ jobs:
|
||||
echo "head_sha=${HEAD_SHA}" >> "${GITHUB_OUTPUT}"
|
||||
- name: Run deterministic checks
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ inputs.pull_request_number || github.event.pull_request.number }}
|
||||
HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
|
||||
run: |
|
||||
|
||||
+54
-125
@@ -1,5 +1,5 @@
|
||||
# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"7b142e96e0f8b454cdcc9c0c25070cf9a52c44d83a6b1fbc3ad6725b6567337c","body_hash":"3894ded07d5934ac5f29d160ffb1f9115cf72b6da8a7e453a4d4f69e8641a48e","compiler_version":"v0.79.6","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.60"}}
|
||||
# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"v0.79.6","version":"v0.79.6"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2","digest":"sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2","digest":"sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2","digest":"sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.25","digest":"sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa"},{"image":"ghcr.io/github/github-mcp-server:v1.1.2","digest":"sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c","pinned_image":"ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c"}]}
|
||||
# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"36a7fc263a2ce868d74a266f23eb7772d82fd397806464384fe087479ddd4a70","body_hash":"bba8c011f2b82bb4d9847a359f43f0e7d91245b280678c20e5112b3c9e77d5cd","compiler_version":"v0.79.6","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.60"}}
|
||||
# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"5c2fe865bb4dc46e1450f6ee0d0541d759aea73a","version":"v0.79.6"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2","digest":"sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2","digest":"sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2","digest":"sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.25","digest":"sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa"},{"image":"ghcr.io/github/github-mcp-server:v1.1.2","digest":"sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c","pinned_image":"ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c"}]}
|
||||
# ___ _ _
|
||||
# / _ \ | | (_)
|
||||
# | |_| | __ _ ___ _ __ | |_ _ ___
|
||||
@@ -36,7 +36,7 @@
|
||||
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
# - github/gh-aw-actions/setup@v0.79.6
|
||||
# - github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
|
||||
#
|
||||
# Container images used:
|
||||
# - ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setup Scripts
|
||||
id: setup
|
||||
uses: github/gh-aw-actions/setup@v0.79.6
|
||||
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
|
||||
with:
|
||||
destination: ${{ runner.temp }}/gh-aw/actions
|
||||
job-name: ${{ github.job }}
|
||||
@@ -344,9 +344,8 @@ jobs:
|
||||
agent:
|
||||
needs:
|
||||
- activation
|
||||
- extract_pr_number
|
||||
- gate
|
||||
if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true'
|
||||
- prepare
|
||||
if: (needs.prepare.outputs.skip != 'true') && (needs.activation.outputs.daily_effective_workflow_exceeded != 'true')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
@@ -383,7 +382,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setup Scripts
|
||||
id: setup
|
||||
uses: github/gh-aw-actions/setup@v0.79.6
|
||||
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
|
||||
with:
|
||||
destination: ${{ runner.temp }}/gh-aw/actions
|
||||
job-name: ${{ github.job }}
|
||||
@@ -489,15 +488,15 @@ jobs:
|
||||
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
|
||||
mkdir -p /tmp/gh-aw/safeoutputs
|
||||
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
|
||||
cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_f496a449c5dccca1_EOF'
|
||||
{"add_comment":{"max":1,"target":"${{ needs.extract_pr_number.outputs.pr_number }}"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}}
|
||||
GH_AW_SAFE_OUTPUTS_CONFIG_f496a449c5dccca1_EOF
|
||||
cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_823c5547a5e52957_EOF'
|
||||
{"add_comment":{"max":1,"target":"${{ needs.prepare.outputs.pr_number }}"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}}
|
||||
GH_AW_SAFE_OUTPUTS_CONFIG_823c5547a5e52957_EOF
|
||||
- name: Generate Safe Outputs Tools
|
||||
env:
|
||||
GH_AW_TOOLS_META_JSON: |
|
||||
{
|
||||
"description_suffixes": {
|
||||
"add_comment": " CONSTRAINTS: Maximum 1 comment(s) can be added. Target: ${{ needs.extract_pr_number.outputs.pr_number }}. Supports reply_to_id for discussion threading."
|
||||
"add_comment": " CONSTRAINTS: Maximum 1 comment(s) can be added. Target: ${{ needs.prepare.outputs.pr_number }}. Supports reply_to_id for discussion threading."
|
||||
},
|
||||
"repo_params": {},
|
||||
"dynamic_tools": []
|
||||
@@ -994,8 +993,7 @@ jobs:
|
||||
- activation
|
||||
- agent
|
||||
- detection
|
||||
- extract_pr_number
|
||||
- gate
|
||||
- prepare
|
||||
- safe_outputs
|
||||
if: >
|
||||
always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||
|
||||
@@ -1018,7 +1016,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setup Scripts
|
||||
id: setup
|
||||
uses: github/gh-aw-actions/setup@v0.79.6
|
||||
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
|
||||
with:
|
||||
destination: ${{ runner.temp }}/gh-aw/actions
|
||||
job-name: ${{ github.job }}
|
||||
@@ -1208,7 +1206,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setup Scripts
|
||||
id: setup
|
||||
uses: github/gh-aw-actions/setup@v0.79.6
|
||||
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
|
||||
with:
|
||||
destination: ${{ runner.temp }}/gh-aw/actions
|
||||
job-name: ${{ github.job }}
|
||||
@@ -1429,111 +1427,6 @@ jobs:
|
||||
}
|
||||
}
|
||||
|
||||
extract_pr_number:
|
||||
needs: gate
|
||||
if: needs.gate.outputs.skip != 'true' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
|
||||
outputs:
|
||||
pr_number: ${{ steps.extract.outputs.pr_number }}
|
||||
steps:
|
||||
- name: Configure GH_HOST for enterprise compatibility
|
||||
id: ghes-host-config
|
||||
shell: bash
|
||||
# zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
|
||||
run: |
|
||||
# Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
|
||||
# GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
|
||||
GH_HOST="${GITHUB_SERVER_URL#https://}"
|
||||
GH_HOST="${GH_HOST#http://}"
|
||||
echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
|
||||
- name: Download deterministic-results artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: check-requirements-deterministic
|
||||
path: /tmp/deterministic
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
- name: Extract PR number from artifact
|
||||
id: extract
|
||||
run: |
|
||||
PR=$(jq -r '.pr_number' /tmp/deterministic/results.json)
|
||||
echo "pr_number=${PR}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
gate:
|
||||
needs: activation
|
||||
if: github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
outputs:
|
||||
skip: ${{ steps.gate.outputs.skip }}
|
||||
steps:
|
||||
- name: Configure GH_HOST for enterprise compatibility
|
||||
id: ghes-host-config
|
||||
shell: bash
|
||||
# zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
|
||||
run: |
|
||||
# Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
|
||||
# GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
|
||||
GH_HOST="${GITHUB_SERVER_URL#https://}"
|
||||
GH_HOST="${GH_HOST#http://}"
|
||||
echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
|
||||
- name: Download deterministic-results artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: check-requirements-deterministic
|
||||
path: /tmp/gate
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
- name: Decide whether requirements changed since the last comment
|
||||
id: gate
|
||||
run: |
|
||||
PR=$(jq -r '.pr_number' /tmp/gate/results.json)
|
||||
HEAD=$(jq -r '.head_sha // empty' /tmp/gate/results.json)
|
||||
if [ -z "${HEAD}" ]; then
|
||||
echo "Artifact has no head_sha; running the agent."
|
||||
exit 0
|
||||
fi
|
||||
# Recover the commit recorded in the most recent requirements-check
|
||||
# comment from the "Checked at commit" link
|
||||
PRIOR=$(gh api --paginate "repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" \
|
||||
--jq '.[] | select(.body | contains("<!-- requirements-check -->")) | .body' \
|
||||
| grep -oiE '/commit/[0-9a-f]{40}' \
|
||||
| grep -oiE '[0-9a-f]{40}' | tail -1 || true)
|
||||
if [ -z "${PRIOR}" ]; then
|
||||
echo "No previous comment with a recorded commit; running the agent."
|
||||
exit 0
|
||||
fi
|
||||
if [ "${PRIOR}" = "${HEAD}" ]; then
|
||||
echo "Head ${HEAD} unchanged since the last comment; skipping the agent."
|
||||
echo "skip=true" >> "${GITHUB_OUTPUT}"
|
||||
exit 0
|
||||
fi
|
||||
# List files changed between the recorded commit and the current head.
|
||||
# Tracked patterns mirror script/check_requirements/diff.py TRACKED_PATTERNS.
|
||||
CHANGED=$(gh api "repos/${GITHUB_REPOSITORY}/compare/${PRIOR}...${HEAD}" \
|
||||
--jq '.files[].filename' 2>/dev/null) || {
|
||||
echo "Could not compare ${PRIOR}...${HEAD}; running the agent."
|
||||
exit 0
|
||||
}
|
||||
TRACKED=$(printf '%s\n' "${CHANGED}" \
|
||||
| grep -Ex 'requirements.*\.txt|homeassistant/package_constraints\.txt' || true)
|
||||
if [ -z "${TRACKED}" ]; then
|
||||
echo "No tracked requirement files changed since ${PRIOR}; skipping the agent."
|
||||
echo "skip=true" >> "${GITHUB_OUTPUT}"
|
||||
else
|
||||
echo "Tracked requirement files changed since ${PRIOR}; running the agent:"
|
||||
printf '%s\n' "${TRACKED}"
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
pre_activation:
|
||||
runs-on: ubuntu-slim
|
||||
outputs:
|
||||
@@ -1545,7 +1438,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setup Scripts
|
||||
id: setup
|
||||
uses: github/gh-aw-actions/setup@v0.79.6
|
||||
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
|
||||
with:
|
||||
destination: ${{ runner.temp }}/gh-aw/actions
|
||||
job-name: ${{ github.job }}
|
||||
@@ -1568,12 +1461,48 @@ jobs:
|
||||
const { main } = require('${{ runner.temp }}/gh-aw/actions/check_membership.cjs');
|
||||
await main();
|
||||
|
||||
prepare:
|
||||
needs: activation
|
||||
if: github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
outputs:
|
||||
pr_number: ${{ steps.prepare.outputs.pr_number }}
|
||||
skip: ${{ steps.prepare.outputs.skip }}
|
||||
steps:
|
||||
- name: Configure GH_HOST for enterprise compatibility
|
||||
id: ghes-host-config
|
||||
shell: bash
|
||||
# zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
|
||||
run: |
|
||||
# Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
|
||||
# GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
|
||||
GH_HOST="${GITHUB_SERVER_URL#https://}"
|
||||
GH_HOST="${GH_HOST#http://}"
|
||||
echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
|
||||
- name: Download deterministic-results artifact
|
||||
id: download
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: check-requirements-deterministic
|
||||
path: /tmp/deterministic
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
- name: Resolve skip and PR number from the artifact
|
||||
id: prepare
|
||||
run: |
|
||||
echo "skip=$(jq -r '.skip_aw' /tmp/deterministic/results.json)" >> "${GITHUB_OUTPUT}"
|
||||
echo "pr_number=$(jq -r '.pr_number' /tmp/deterministic/results.json)" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
safe_outputs:
|
||||
needs:
|
||||
- activation
|
||||
- agent
|
||||
- detection
|
||||
- extract_pr_number
|
||||
- prepare
|
||||
if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success'
|
||||
runs-on: ubuntu-slim
|
||||
permissions:
|
||||
@@ -1609,7 +1538,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setup Scripts
|
||||
id: setup
|
||||
uses: github/gh-aw-actions/setup@v0.79.6
|
||||
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
|
||||
with:
|
||||
destination: ${{ runner.temp }}/gh-aw/actions
|
||||
job-name: ${{ github.job }}
|
||||
@@ -1654,7 +1583,7 @@ jobs:
|
||||
GH_AW_ALLOWED_DOMAINS: "*.pythonhosted.org,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,binstar.org,bootstrap.pypa.io,conda.anaconda.org,conda.binstar.org,files.pythonhosted.org,github.com,host.docker.internal,pip.pypa.io,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.npmjs.org,repo.anaconda.com,repo.continuum.io,telemetry.enterprise.githubcopilot.com"
|
||||
GITHUB_SERVER_URL: ${{ github.server_url }}
|
||||
GITHUB_API_URL: ${{ github.api_url }}
|
||||
GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1,\"target\":\"${{ needs.extract_pr_number.outputs.pr_number }}\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}"
|
||||
GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1,\"target\":\"${{ needs.prepare.outputs.pr_number }}\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}"
|
||||
with:
|
||||
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
||||
@@ -15,94 +15,41 @@ tools:
|
||||
github:
|
||||
toolsets: [repos, pull_requests]
|
||||
min-integrity: unapproved
|
||||
if: needs.prepare.outputs.skip != 'true'
|
||||
safe-outputs:
|
||||
add-comment:
|
||||
max: 1
|
||||
target: "${{ needs.extract_pr_number.outputs.pr_number }}"
|
||||
target: "${{ needs.prepare.outputs.pr_number }}"
|
||||
needs:
|
||||
- extract_pr_number
|
||||
- prepare
|
||||
jobs:
|
||||
gate:
|
||||
# Skip the (token-spending) agent when no tracked requirement file changed
|
||||
prepare:
|
||||
# The deterministic stage always uploads an artifact; its `skip_aw` flag is
|
||||
# true when no tracked requirement file changed since the last comment,
|
||||
# which is our cue to skip the (token-spending) agent. Recover the PR number
|
||||
# to comment on either way.
|
||||
if: github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
pull-requests: read
|
||||
outputs:
|
||||
skip: ${{ steps.gate.outputs.skip }}
|
||||
steps:
|
||||
- name: Download deterministic-results artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: check-requirements-deterministic
|
||||
path: /tmp/gate
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Decide whether requirements changed since the last comment
|
||||
id: gate
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
PR=$(jq -r '.pr_number' /tmp/gate/results.json)
|
||||
HEAD=$(jq -r '.head_sha // empty' /tmp/gate/results.json)
|
||||
if [ -z "${HEAD}" ]; then
|
||||
echo "Artifact has no head_sha; running the agent."
|
||||
exit 0
|
||||
fi
|
||||
# Recover the commit recorded in the most recent requirements-check
|
||||
# comment from the "Checked at commit" link
|
||||
PRIOR=$(gh api --paginate "repos/${GITHUB_REPOSITORY}/issues/${PR}/comments" \
|
||||
--jq '.[] | select(.body | contains("<!-- requirements-check -->")) | .body' \
|
||||
| grep -oiE '/commit/[0-9a-f]{40}' \
|
||||
| grep -oiE '[0-9a-f]{40}' | tail -1 || true)
|
||||
if [ -z "${PRIOR}" ]; then
|
||||
echo "No previous comment with a recorded commit; running the agent."
|
||||
exit 0
|
||||
fi
|
||||
if [ "${PRIOR}" = "${HEAD}" ]; then
|
||||
echo "Head ${HEAD} unchanged since the last comment; skipping the agent."
|
||||
echo "skip=true" >> "${GITHUB_OUTPUT}"
|
||||
exit 0
|
||||
fi
|
||||
# List files changed between the recorded commit and the current head.
|
||||
# Tracked patterns mirror script/check_requirements/diff.py TRACKED_PATTERNS.
|
||||
CHANGED=$(gh api "repos/${GITHUB_REPOSITORY}/compare/${PRIOR}...${HEAD}" \
|
||||
--jq '.files[].filename' 2>/dev/null) || {
|
||||
echo "Could not compare ${PRIOR}...${HEAD}; running the agent."
|
||||
exit 0
|
||||
}
|
||||
TRACKED=$(printf '%s\n' "${CHANGED}" \
|
||||
| grep -Ex 'requirements.*\.txt|homeassistant/package_constraints\.txt' || true)
|
||||
if [ -z "${TRACKED}" ]; then
|
||||
echo "No tracked requirement files changed since ${PRIOR}; skipping the agent."
|
||||
echo "skip=true" >> "${GITHUB_OUTPUT}"
|
||||
else
|
||||
echo "Tracked requirement files changed since ${PRIOR}; running the agent:"
|
||||
printf '%s\n' "${TRACKED}"
|
||||
fi
|
||||
extract_pr_number:
|
||||
needs: gate
|
||||
if: needs.gate.outputs.skip != 'true' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
outputs:
|
||||
pr_number: ${{ steps.extract.outputs.pr_number }}
|
||||
skip: ${{ steps.prepare.outputs.skip }}
|
||||
pr_number: ${{ steps.prepare.outputs.pr_number }}
|
||||
steps:
|
||||
- name: Download deterministic-results artifact
|
||||
id: download
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: check-requirements-deterministic
|
||||
path: /tmp/deterministic
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Extract PR number from artifact
|
||||
id: extract
|
||||
- name: Resolve skip and PR number from the artifact
|
||||
id: prepare
|
||||
run: |
|
||||
PR=$(jq -r '.pr_number' /tmp/deterministic/results.json)
|
||||
echo "pr_number=${PR}" >> "${GITHUB_OUTPUT}"
|
||||
echo "skip=$(jq -r '.skip_aw' /tmp/deterministic/results.json)" >> "${GITHUB_OUTPUT}"
|
||||
echo "pr_number=$(jq -r '.pr_number' /tmp/deterministic/results.json)" >> "${GITHUB_OUTPUT}"
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.workflow_run.id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.15.17
|
||||
rev: v0.15.18
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
args:
|
||||
|
||||
@@ -43,3 +43,4 @@ This repository contains the core of Home Assistant, a Python 3 based home autom
|
||||
- Keep comments concise. Prefer one short line stating the non-obvious constraint, or no comment at all.
|
||||
- Do not add comments that just restate the code on the following line(s) (e.g. `# Check if initialized` above `if self.initialized:`). Comments should only explain why (non-obvious constraints, surprising behavior, or workarounds), never what. Never add comments that justify a change by referencing what the code looked like before.
|
||||
- Do not add section or divider comments (e.g. `# --- XYZ Triggers ---`) inside or outside of functions, since those can easily become stale and be misleading.
|
||||
- When catching exceptions, try-clauses should be as small as possible, i.e. avoid wrapping large blocks of code in a try-clause, and avoid catching exceptions from functions that are not expected to raise them.
|
||||
|
||||
Generated
-2
@@ -181,7 +181,6 @@ CLAUDE.md @home-assistant/core
|
||||
/tests/components/asuswrt/ @kennedyshead @ollo69 @Vaskivskyi
|
||||
/homeassistant/components/atag/ @MatsNL
|
||||
/tests/components/atag/ @MatsNL
|
||||
/homeassistant/components/aten_pe/ @mtdcr
|
||||
/homeassistant/components/atome/ @baqs
|
||||
/homeassistant/components/august/ @bdraco
|
||||
/tests/components/august/ @bdraco
|
||||
@@ -1987,7 +1986,6 @@ CLAUDE.md @home-assistant/core
|
||||
/tests/components/waterfurnace/ @sdague @masterkoppa
|
||||
/homeassistant/components/watergate/ @adam-the-hero
|
||||
/tests/components/watergate/ @adam-the-hero
|
||||
/homeassistant/components/watson_tts/ @rutkai
|
||||
/homeassistant/components/watts/ @theobld-ww @devender-verma-ww @ssi-spyro
|
||||
/tests/components/watts/ @theobld-ww @devender-verma-ww @ssi-spyro
|
||||
/homeassistant/components/watttime/ @bachya
|
||||
|
||||
@@ -66,6 +66,7 @@ from .const import (
|
||||
BASE_PLATFORMS,
|
||||
FORMAT_DATETIME,
|
||||
KEY_DATA_LOGGING as DATA_LOGGING,
|
||||
KEY_DATA_LOGGING_DISABLED_REASON as DATA_LOGGING_DISABLED_REASON,
|
||||
SIGNAL_BOOTSTRAP_INTEGRATIONS,
|
||||
)
|
||||
from .core_config import async_process_ha_core_config
|
||||
@@ -129,6 +130,11 @@ SETUP_ORDER_SORT_KEY = partial(contains, BASE_PLATFORMS)
|
||||
|
||||
|
||||
ERROR_LOG_FILENAME = "home-assistant.log"
|
||||
ENV_DISABLE_LOG_FILE = "HA_DISABLE_LOG_FILE"
|
||||
ENV_DUPLICATE_LOG_FILE = "HA_DUPLICATE_LOG_FILE"
|
||||
ENV_SUPERVISOR = "SUPERVISOR"
|
||||
LOG_FILE_DISABLED_REASON_ENVIRONMENT = "environment"
|
||||
LOG_FILE_DISABLED_REASON_SUPERVISOR = "supervisor"
|
||||
|
||||
# hass.data key for logging information.
|
||||
DATA_REGISTRIES_LOADED: HassKey[None] = HassKey("bootstrap_registries_loaded")
|
||||
@@ -642,10 +648,12 @@ async def async_enable_logging(
|
||||
logger.setLevel(logging.INFO if verbose else logging.WARNING)
|
||||
|
||||
if log_file is None:
|
||||
disabled_log_file_reason = _log_file_disabled_reason()
|
||||
default_log_path = hass.config.path(ERROR_LOG_FILENAME)
|
||||
if "SUPERVISOR" in os.environ and "HA_DUPLICATE_LOG_FILE" not in os.environ:
|
||||
if disabled_log_file_reason:
|
||||
# Rename the default log file if it exists, since previous versions created
|
||||
# it even on Supervisor
|
||||
# it before Supervisor disabled duplicate file logging or
|
||||
# HA_DISABLE_LOG_FILE disabled the log file.
|
||||
def rename_old_file() -> None:
|
||||
"""Rename old log file in executor."""
|
||||
if os.path.isfile(default_log_path):
|
||||
@@ -657,6 +665,7 @@ async def async_enable_logging(
|
||||
else:
|
||||
err_log_path = default_log_path
|
||||
else:
|
||||
disabled_log_file_reason = None
|
||||
err_log_path = os.path.abspath(log_file)
|
||||
|
||||
if err_log_path:
|
||||
@@ -669,10 +678,34 @@ async def async_enable_logging(
|
||||
|
||||
# Save the log file location for access by other components.
|
||||
hass.data[DATA_LOGGING] = err_log_path
|
||||
elif disabled_log_file_reason == LOG_FILE_DISABLED_REASON_ENVIRONMENT:
|
||||
hass.data[DATA_LOGGING_DISABLED_REASON] = disabled_log_file_reason
|
||||
|
||||
async_activate_log_queue_handler(hass)
|
||||
|
||||
|
||||
def _log_file_disabled_reason() -> str | None:
|
||||
"""Return why the log file is disabled."""
|
||||
if ENV_SUPERVISOR in os.environ and ENV_DUPLICATE_LOG_FILE not in os.environ:
|
||||
return LOG_FILE_DISABLED_REASON_SUPERVISOR
|
||||
|
||||
disable_log_file = os.environ.get(ENV_DISABLE_LOG_FILE)
|
||||
if disable_log_file is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
if cv.boolean(disable_log_file):
|
||||
return LOG_FILE_DISABLED_REASON_ENVIRONMENT
|
||||
except vol.Invalid:
|
||||
_LOGGER.warning(
|
||||
"Ignoring invalid %s value: %s. Expected a boolean value: "
|
||||
"1/0, true/false, yes/no, on/off, or enable/disable",
|
||||
ENV_DISABLE_LOG_FILE,
|
||||
disable_log_file,
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def _create_log_file(
|
||||
err_log_path: str, log_rotate_days: int | None
|
||||
) -> RotatingFileHandler | TimedRotatingFileHandler:
|
||||
@@ -734,7 +767,7 @@ def _get_domains(hass: core.HomeAssistant, config: dict[str, Any]) -> set[str]:
|
||||
domains.update(DEFAULT_INTEGRATIONS_RECOVERY_MODE)
|
||||
|
||||
# Add domains depending on if the Supervisor is used or not
|
||||
if "SUPERVISOR" in os.environ:
|
||||
if ENV_SUPERVISOR in os.environ:
|
||||
domains.update(DEFAULT_INTEGRATIONS_SUPERVISOR)
|
||||
|
||||
return domains
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
"azure_event_hub",
|
||||
"azure_service_bus",
|
||||
"azure_storage",
|
||||
"microsoft_face_detect",
|
||||
"microsoft_face_identify",
|
||||
"microsoft_face",
|
||||
"microsoft",
|
||||
"onedrive",
|
||||
"onedrive_for_business",
|
||||
|
||||
@@ -27,7 +27,7 @@ from .const import CONDITIONS_MAP, DOMAIN, FORECAST_MAP
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
API_TIMEOUT: Final[int] = 120
|
||||
WEATHER_UPDATE_INTERVAL = timedelta(minutes=10)
|
||||
WEATHER_UPDATE_INTERVAL = timedelta(minutes=20)
|
||||
|
||||
type AemetConfigEntry = ConfigEntry[AemetData]
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from homeassistant.components.number import (
|
||||
NumberEntity,
|
||||
NumberEntityDescription,
|
||||
)
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory
|
||||
from homeassistant.const import EntityCategory, UnitOfRatio
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -40,7 +40,7 @@ DISPLAY_BRIGHTNESS = AirGradientNumberEntityDescription(
|
||||
native_min_value=0,
|
||||
native_max_value=100,
|
||||
native_step=1,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
value_fn=lambda config: config.display_brightness,
|
||||
set_value_fn=lambda client, value: client.set_display_brightness(value),
|
||||
)
|
||||
@@ -52,7 +52,7 @@ LED_BAR_BRIGHTNESS = AirGradientNumberEntityDescription(
|
||||
native_min_value=0,
|
||||
native_max_value=100,
|
||||
native_step=1,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
value_fn=lambda config: config.led_bar_brightness,
|
||||
set_value_fn=lambda client, value: client.set_led_bar_brightness(value),
|
||||
)
|
||||
|
||||
@@ -19,11 +19,10 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -57,21 +56,21 @@ MEASUREMENT_SENSOR_TYPES: tuple[AirGradientMeasurementSensorEntityDescription, .
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="pm01",
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.pm01,
|
||||
),
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="pm02",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.pm02,
|
||||
),
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="pm10",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.pm10,
|
||||
),
|
||||
@@ -85,7 +84,7 @@ MEASUREMENT_SENSOR_TYPES: tuple[AirGradientMeasurementSensorEntityDescription, .
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.relative_humidity,
|
||||
),
|
||||
@@ -113,7 +112,7 @@ MEASUREMENT_SENSOR_TYPES: tuple[AirGradientMeasurementSensorEntityDescription, .
|
||||
AirGradientMeasurementSensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.rco2,
|
||||
),
|
||||
@@ -144,7 +143,7 @@ MEASUREMENT_SENSOR_TYPES: tuple[AirGradientMeasurementSensorEntityDescription, .
|
||||
key="pm02_raw",
|
||||
translation_key="raw_pm02",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
value_fn=lambda status: status.raw_pm02,
|
||||
@@ -190,7 +189,7 @@ CONFIG_LED_BAR_SENSOR_TYPES: tuple[AirGradientConfigSensorEntityDescription, ...
|
||||
AirGradientConfigSensorEntityDescription(
|
||||
key="led_bar_brightness",
|
||||
translation_key="led_bar_brightness",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
value_fn=lambda config: config.led_bar_brightness,
|
||||
),
|
||||
@@ -216,9 +215,9 @@ CONFIG_DISPLAY_SENSOR_TYPES: tuple[AirGradientConfigSensorEntityDescription, ...
|
||||
AirGradientConfigSensorEntityDescription(
|
||||
key="display_brightness",
|
||||
translation_key="display_brightness",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
value_fn=lambda config: config.display_brightness,
|
||||
value_fn=lambda config: config.led_bar_brightness,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONF_NAME,
|
||||
PERCENTAGE,
|
||||
UnitOfDensity,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -76,14 +76,14 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
|
||||
AirlySensorEntityDescription(
|
||||
key=ATTR_API_PM1,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
AirlySensorEntityDescription(
|
||||
key=ATTR_API_PM25,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
attrs=lambda data: {
|
||||
@@ -94,7 +94,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
|
||||
AirlySensorEntityDescription(
|
||||
key=ATTR_API_PM10,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
attrs=lambda data: {
|
||||
@@ -105,7 +105,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
|
||||
AirlySensorEntityDescription(
|
||||
key=ATTR_API_HUMIDITY,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
@@ -126,7 +126,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
|
||||
AirlySensorEntityDescription(
|
||||
key=ATTR_API_CO,
|
||||
device_class=SensorDeviceClass.CO,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
attrs=lambda data: {
|
||||
@@ -137,7 +137,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
|
||||
AirlySensorEntityDescription(
|
||||
key=ATTR_API_NO2,
|
||||
device_class=SensorDeviceClass.NITROGEN_DIOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
attrs=lambda data: {
|
||||
@@ -148,7 +148,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
|
||||
AirlySensorEntityDescription(
|
||||
key=ATTR_API_SO2,
|
||||
device_class=SensorDeviceClass.SULPHUR_DIOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
attrs=lambda data: {
|
||||
@@ -159,7 +159,7 @@ SENSOR_TYPES: tuple[AirlySensorEntityDescription, ...] = (
|
||||
AirlySensorEntityDescription(
|
||||
key=ATTR_API_O3,
|
||||
device_class=SensorDeviceClass.OZONE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
attrs=lambda data: {
|
||||
|
||||
@@ -12,11 +12,7 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_TIME,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
)
|
||||
from homeassistant.const import ATTR_TIME, UnitOfDensity, UnitOfRatio
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -95,7 +91,7 @@ SENSOR_TYPES: tuple[AirNowEntityDescription, ...] = (
|
||||
AirNowEntityDescription(
|
||||
key=ATTR_API_PM10,
|
||||
translation_key="pm10",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
value_fn=lambda data: data.get(ATTR_API_PM10),
|
||||
@@ -104,7 +100,7 @@ SENSOR_TYPES: tuple[AirNowEntityDescription, ...] = (
|
||||
AirNowEntityDescription(
|
||||
key=ATTR_API_PM25,
|
||||
translation_key="pm25",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
value_fn=lambda data: data.get(ATTR_API_PM25),
|
||||
@@ -113,7 +109,7 @@ SENSOR_TYPES: tuple[AirNowEntityDescription, ...] = (
|
||||
AirNowEntityDescription(
|
||||
key=ATTR_API_O3,
|
||||
translation_key="o3",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda data: data.get(ATTR_API_O3),
|
||||
extra_state_attributes_fn=None,
|
||||
|
||||
@@ -14,9 +14,8 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -59,7 +58,7 @@ SENSOR_TYPES: tuple[AirobotSensorEntityDescription, ...] = (
|
||||
AirobotSensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.hum_air,
|
||||
),
|
||||
@@ -75,7 +74,7 @@ SENSOR_TYPES: tuple[AirobotSensorEntityDescription, ...] = (
|
||||
AirobotSensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda status: status.co2,
|
||||
supported_fn=lambda status: status.has_co2_sensor,
|
||||
|
||||
@@ -8,7 +8,7 @@ from typing import override
|
||||
from aioairq.core import AirQ
|
||||
|
||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||
from homeassistant.const import PERCENTAGE
|
||||
from homeassistant.const import UnitOfRatio
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
@@ -32,7 +32,7 @@ AIRQ_LED_BRIGHTNESS = AirQBrightnessDescription(
|
||||
native_min_value=0.0,
|
||||
native_max_value=100.0,
|
||||
native_step=1.0,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
value=lambda data: data["brightness"],
|
||||
set_value=lambda device, value: device.set_current_brightness(value),
|
||||
)
|
||||
|
||||
@@ -12,13 +12,9 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_GRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfDensity,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -44,70 +40,70 @@ SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
AirQEntityDescription(
|
||||
key="c2h4o",
|
||||
translation_key="acetaldehyde",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("c2h4o"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="nh3_MR100",
|
||||
translation_key="ammonia",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("nh3_MR100"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="ash3",
|
||||
translation_key="arsine",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("ash3"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="br2",
|
||||
translation_key="bromine",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("br2"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="ch4s",
|
||||
translation_key="methanethiol",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("ch4s"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="cl2_M20",
|
||||
translation_key="chlorine",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("cl2_M20"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="clo2",
|
||||
translation_key="chlorine_dioxide",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("clo2"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="co",
|
||||
translation_key="carbon_monoxide",
|
||||
native_unit_of_measurement=CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MILLIGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("co"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("co2"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="cs2",
|
||||
translation_key="carbon_disulfide",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("cs2"),
|
||||
),
|
||||
@@ -122,182 +118,182 @@ SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
AirQEntityDescription(
|
||||
key="ethanol",
|
||||
translation_key="ethanol",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("ethanol"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="c2h4",
|
||||
translation_key="ethylene",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("c2h4"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="ch2o_M10",
|
||||
translation_key="formaldehyde",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("ch2o_M10"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="f2",
|
||||
translation_key="fluorine",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("f2"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="h2s",
|
||||
translation_key="hydrogen_sulfide",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("h2s"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="hcl",
|
||||
translation_key="hydrochloric_acid",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("hcl"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="hcn",
|
||||
translation_key="hydrogen_cyanide",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("hcn"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="hf",
|
||||
translation_key="hydrogen_fluoride",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("hf"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="health",
|
||||
translation_key="health_index",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("health", 0.0) / 10.0,
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("humidity"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="humidity_abs",
|
||||
device_class=SensorDeviceClass.ABSOLUTE_HUMIDITY,
|
||||
native_unit_of_measurement=CONCENTRATION_GRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.GRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("humidity_abs"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="h2_M1000",
|
||||
translation_key="hydrogen",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("h2_M1000"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="h2o2",
|
||||
translation_key="hydrogen_peroxide",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("h2o2"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="ch4_MIPEX",
|
||||
translation_key="methane",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("ch4_MIPEX"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="mold",
|
||||
translation_key="mold",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("mold"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="n2o",
|
||||
device_class=SensorDeviceClass.NITROUS_OXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("n2o"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="no_M250",
|
||||
device_class=SensorDeviceClass.NITROGEN_MONOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("no_M250"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="no2",
|
||||
device_class=SensorDeviceClass.NITROGEN_DIOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("no2"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="acid_M100",
|
||||
translation_key="organic_acid",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("acid_M100"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="oxygen",
|
||||
translation_key="oxygen",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("oxygen"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="o3",
|
||||
device_class=SensorDeviceClass.OZONE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("o3"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="performance",
|
||||
translation_key="performance_index",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("performance", 0.0) / 10.0,
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="ph3",
|
||||
translation_key="hydrogen_phosphide",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("ph3"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="pm1",
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("pm1"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="pm2_5",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("pm2_5"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="pm10",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("pm10"),
|
||||
),
|
||||
@@ -319,42 +315,42 @@ SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
AirQEntityDescription(
|
||||
key="c3h8_MIPEX",
|
||||
translation_key="propane",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("c3h8_MIPEX"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="r32",
|
||||
translation_key="r32",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("r32"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="r454b",
|
||||
translation_key="r454b",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("r454b"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="r454c",
|
||||
translation_key="r454c",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("r454c"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="sih4",
|
||||
translation_key="silicon_hydride",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("sih4"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="so2",
|
||||
device_class=SensorDeviceClass.SULPHUR_DIOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("so2"),
|
||||
),
|
||||
@@ -391,7 +387,7 @@ SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
AirQEntityDescription(
|
||||
key="tvoc",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("tvoc"),
|
||||
),
|
||||
@@ -399,14 +395,14 @@ SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
key="tvoc_ionsc",
|
||||
translation_key="industrial_volatile_organic_compounds",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("tvoc_ionsc"),
|
||||
),
|
||||
AirQEntityDescription(
|
||||
key="virus",
|
||||
translation_key="virus_index",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("virus", 0.0),
|
||||
),
|
||||
|
||||
@@ -11,14 +11,12 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -49,7 +47,7 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
"humidity": SensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
@@ -70,7 +68,7 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
"battery": SensorEntityDescription(
|
||||
key="battery",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
@@ -78,20 +76,20 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
"co2": SensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"voc": SensorEntityDescription(
|
||||
key="voc",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"light": SensorEntityDescription(
|
||||
key="light",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
translation_key="light",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
@@ -126,14 +124,14 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
),
|
||||
"pm1": SensorEntityDescription(
|
||||
key="pm1",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"pm25": SensorEntityDescription(
|
||||
key="pm25",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""Support for airthings ble sensors."""
|
||||
|
||||
from collections.abc import Callable
|
||||
import dataclasses
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
from typing import override
|
||||
|
||||
@@ -13,13 +15,11 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
Platform,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -46,87 +46,108 @@ CONNECTIVITY_MODE_MAP = {
|
||||
AirthingsConnectivityMode.NOT_CONFIGURED.value: "not_configured",
|
||||
}
|
||||
|
||||
SENSORS_MAPPING_TEMPLATE: dict[str, SensorEntityDescription] = {
|
||||
"radon_1day_avg": SensorEntityDescription(
|
||||
|
||||
def get_connectivity_mode(value: str | float | None) -> str | None:
|
||||
"""Get connectivity mode."""
|
||||
if not isinstance(value, str):
|
||||
return None
|
||||
return CONNECTIVITY_MODE_MAP.get(value)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class AirthingsBLESensorEntityDescription(SensorEntityDescription):
|
||||
"""Describes Airthings BLE sensor entity."""
|
||||
|
||||
value_fn: Callable[[str | float | None], str | float | None] = lambda x: x
|
||||
|
||||
|
||||
SENSORS_MAPPING_TEMPLATE: dict[str, AirthingsBLESensorEntityDescription] = {
|
||||
"radon_1day_avg": AirthingsBLESensorEntityDescription(
|
||||
key="radon_1day_avg",
|
||||
translation_key="radon_1day_avg",
|
||||
native_unit_of_measurement=VOLUME_BECQUEREL,
|
||||
suggested_display_precision=0,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"radon_longterm_avg": SensorEntityDescription(
|
||||
"radon_longterm_avg": AirthingsBLESensorEntityDescription(
|
||||
key="radon_longterm_avg",
|
||||
translation_key="radon_longterm_avg",
|
||||
native_unit_of_measurement=VOLUME_BECQUEREL,
|
||||
suggested_display_precision=0,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"radon_1day_level": SensorEntityDescription(
|
||||
"radon_1day_level": AirthingsBLESensorEntityDescription(
|
||||
key="radon_1day_level",
|
||||
translation_key="radon_1day_level",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=["good", "fair", "poor"],
|
||||
value_fn=lambda value: value if value != "unknown" else None,
|
||||
),
|
||||
"radon_longterm_level": SensorEntityDescription(
|
||||
"radon_longterm_level": AirthingsBLESensorEntityDescription(
|
||||
key="radon_longterm_level",
|
||||
translation_key="radon_longterm_level",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=["good", "fair", "poor"],
|
||||
value_fn=lambda value: value if value != "unknown" else None,
|
||||
),
|
||||
"temperature": SensorEntityDescription(
|
||||
"temperature": AirthingsBLESensorEntityDescription(
|
||||
key="temperature",
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
"humidity": SensorEntityDescription(
|
||||
"humidity": AirthingsBLESensorEntityDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
"pressure": SensorEntityDescription(
|
||||
"pressure": AirthingsBLESensorEntityDescription(
|
||||
key="pressure",
|
||||
device_class=SensorDeviceClass.ATMOSPHERIC_PRESSURE,
|
||||
native_unit_of_measurement=UnitOfPressure.MBAR,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
"battery": SensorEntityDescription(
|
||||
"battery": AirthingsBLESensorEntityDescription(
|
||||
key="battery",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"co2": SensorEntityDescription(
|
||||
"co2": AirthingsBLESensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"voc": SensorEntityDescription(
|
||||
"voc": AirthingsBLESensorEntityDescription(
|
||||
key="voc",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"illuminance": SensorEntityDescription(
|
||||
"illuminance": AirthingsBLESensorEntityDescription(
|
||||
key="illuminance",
|
||||
translation_key="illuminance",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"lux": SensorEntityDescription(
|
||||
"lux": AirthingsBLESensorEntityDescription(
|
||||
key="lux",
|
||||
device_class=SensorDeviceClass.ILLUMINANCE,
|
||||
native_unit_of_measurement=LIGHT_LUX,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"noise": SensorEntityDescription(
|
||||
"noise": AirthingsBLESensorEntityDescription(
|
||||
key="noise",
|
||||
translation_key="ambient_noise",
|
||||
device_class=SensorDeviceClass.SOUND_PRESSURE,
|
||||
@@ -134,13 +155,14 @@ SENSORS_MAPPING_TEMPLATE: dict[str, SensorEntityDescription] = {
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
"connectivity_mode": SensorEntityDescription(
|
||||
"connectivity_mode": AirthingsBLESensorEntityDescription(
|
||||
key="connectivity_mode",
|
||||
translation_key="connectivity_mode",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=list(CONNECTIVITY_MODE_MAP.values()),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
value_fn=get_connectivity_mode,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -228,12 +250,13 @@ class AirthingsSensor(
|
||||
"""Airthings BLE sensors for the device."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
entity_description: AirthingsBLESensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: AirthingsBLEDataUpdateCoordinator,
|
||||
airthings_device: AirthingsDevice,
|
||||
entity_description: SensorEntityDescription,
|
||||
entity_description: AirthingsBLESensorEntityDescription,
|
||||
) -> None:
|
||||
"""Populate the airthings entity with relevant data."""
|
||||
super().__init__(coordinator)
|
||||
@@ -272,11 +295,4 @@ class AirthingsSensor(
|
||||
def native_value(self) -> StateType:
|
||||
"""Return the value reported by the sensor."""
|
||||
value = self.coordinator.data.sensors[self.entity_description.key]
|
||||
|
||||
# Map connectivity mode to enum values
|
||||
if self.entity_description.key == "connectivity_mode":
|
||||
if not isinstance(value, str):
|
||||
return None
|
||||
return CONNECTIVITY_MODE_MAP.get(value)
|
||||
|
||||
return value
|
||||
return self.entity_description.value_fn(value)
|
||||
|
||||
@@ -45,13 +45,23 @@
|
||||
"name": "Radon 1-day average"
|
||||
},
|
||||
"radon_1day_level": {
|
||||
"name": "Radon 1-day level"
|
||||
"name": "Radon 1-day level",
|
||||
"state": {
|
||||
"fair": "Fair",
|
||||
"good": "Good",
|
||||
"poor": "Poor"
|
||||
}
|
||||
},
|
||||
"radon_longterm_avg": {
|
||||
"name": "Radon longterm average"
|
||||
},
|
||||
"radon_longterm_level": {
|
||||
"name": "Radon longterm level"
|
||||
"name": "Radon longterm level",
|
||||
"state": {
|
||||
"fair": "[%key:component::airthings_ble::entity::sensor::radon_1day_level::state::fair%]",
|
||||
"good": "[%key:component::airthings_ble::entity::sensor::radon_1day_level::state::good%]",
|
||||
"poor": "[%key:component::airthings_ble::entity::sensor::radon_1day_level::state::poor%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -12,14 +12,13 @@ from homeassistant.const import (
|
||||
ATTR_LATITUDE,
|
||||
ATTR_LONGITUDE,
|
||||
ATTR_STATE,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_COUNTRY,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_SHOW_ON_MAP,
|
||||
CONF_STATE,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -94,12 +93,12 @@ POLLUTANT_LEVELS = {
|
||||
}
|
||||
|
||||
POLLUTANT_UNITS = {
|
||||
"co": CONCENTRATION_PARTS_PER_MILLION,
|
||||
"n2": CONCENTRATION_PARTS_PER_BILLION,
|
||||
"o3": CONCENTRATION_PARTS_PER_BILLION,
|
||||
"p1": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
"p2": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
"s2": CONCENTRATION_PARTS_PER_BILLION,
|
||||
"co": UnitOfRatio.PARTS_PER_MILLION,
|
||||
"n2": UnitOfRatio.PARTS_PER_BILLION,
|
||||
"o3": UnitOfRatio.PARTS_PER_BILLION,
|
||||
"p1": UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
"p2": UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
"s2": UnitOfRatio.PARTS_PER_BILLION,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,10 +11,9 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -57,21 +56,21 @@ SENSOR_DESCRIPTIONS = (
|
||||
key="battery_level",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: status["battery"],
|
||||
),
|
||||
AirVisualProMeasurementDescription(
|
||||
key="carbon_dioxide",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["co2"],
|
||||
),
|
||||
AirVisualProMeasurementDescription(
|
||||
key="humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements[
|
||||
"humidity"
|
||||
@@ -80,21 +79,21 @@ SENSOR_DESCRIPTIONS = (
|
||||
AirVisualProMeasurementDescription(
|
||||
key="particulate_matter_0_1",
|
||||
translation_key="pm01",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["pm0_1"],
|
||||
),
|
||||
AirVisualProMeasurementDescription(
|
||||
key="particulate_matter_1_0",
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["pm1_0"],
|
||||
),
|
||||
AirVisualProMeasurementDescription(
|
||||
key="particulate_matter_2_5",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["pm2_5"],
|
||||
),
|
||||
@@ -110,7 +109,7 @@ SENSOR_DESCRIPTIONS = (
|
||||
AirVisualProMeasurementDescription(
|
||||
key="voc",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda settings, status, measurements, history: measurements["voc"],
|
||||
),
|
||||
|
||||
@@ -35,13 +35,13 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfInformation,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
@@ -141,7 +141,7 @@ WEBSERVER_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
key=AZD_CPU_USAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key="cpu_usage",
|
||||
),
|
||||
@@ -172,19 +172,19 @@ ZONE_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
key=AZD_AQ_PM_1,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
key=AZD_AQ_PM_2P5,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
key=AZD_AQ_PM_10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
@@ -196,20 +196,20 @@ ZONE_SENSOR_TYPES: Final[tuple[SensorEntityDescription, ...]] = (
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key=AZD_HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
key=AZD_THERMOSTAT_BATTERY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_registry_enabled_default=False,
|
||||
key=AZD_THERMOSTAT_COVERAGE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key="thermostat_coverage",
|
||||
),
|
||||
|
||||
@@ -13,7 +13,7 @@ from homeassistant.components.binary_sensor import (
|
||||
BinarySensorEntity,
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.const import EntityCategory, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
import homeassistant.helpers.entity_registry as er
|
||||
@@ -118,7 +118,7 @@ async def async_setup_entry(
|
||||
for serial_num in coordinator.data:
|
||||
unique_id = f"{serial_num}-{sensor_desc.key}"
|
||||
if entity_id := entity_registry.async_get_entity_id(
|
||||
BINARY_SENSOR_DOMAIN, DOMAIN, unique_id
|
||||
Platform.BINARY_SENSOR, DOMAIN, unique_id
|
||||
):
|
||||
_LOGGER.debug("Removing deprecated entity %s", entity_id)
|
||||
entity_registry.async_remove(entity_id)
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["aioamazondevices"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["aioamazondevices==14.1.3"]
|
||||
"requirements": ["aioamazondevices==14.1.8"]
|
||||
}
|
||||
|
||||
@@ -18,13 +18,7 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.const import LIGHT_LUX, UnitOfDensity, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
@@ -97,25 +91,25 @@ SENSORS: Final = (
|
||||
AmazonSensorEntityDescription(
|
||||
key="Humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AmazonSensorEntityDescription(
|
||||
key="PM10",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AmazonSensorEntityDescription(
|
||||
key="PM25",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AmazonSensorEntityDescription(
|
||||
key="CO",
|
||||
device_class=SensorDeviceClass.CO,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AmazonSensorEntityDescription(
|
||||
|
||||
@@ -7,7 +7,7 @@ from aioamazondevices.const.schedules import (
|
||||
NOTIFICATION_TIMER,
|
||||
)
|
||||
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
import homeassistant.helpers.entity_registry as er
|
||||
|
||||
@@ -28,7 +28,7 @@ async def async_update_unique_id(
|
||||
for serial_num in coordinator.data:
|
||||
unique_id = f"{serial_num}-{old_key}"
|
||||
if entity_id := entity_registry.async_get_entity_id(
|
||||
DOMAIN, platform, unique_id
|
||||
platform, DOMAIN, unique_id
|
||||
):
|
||||
_LOGGER.debug("Updating unique_id for %s", entity_id)
|
||||
new_unique_id = unique_id.replace(old_key, new_key)
|
||||
@@ -48,7 +48,7 @@ async def async_remove_entity_from_virtual_group(
|
||||
|
||||
for serial_num in coordinator.data:
|
||||
unique_id = f"{serial_num}-{key}"
|
||||
entity_id = entity_registry.async_get_entity_id(DOMAIN, platform, unique_id)
|
||||
entity_id = entity_registry.async_get_entity_id(platform, DOMAIN, unique_id)
|
||||
is_group = coordinator.data[serial_num].device_family == SPEAKER_GROUP_FAMILY
|
||||
if entity_id and is_group:
|
||||
entity_registry.async_remove(entity_id)
|
||||
@@ -70,7 +70,7 @@ async def async_remove_unsupported_notification_sensors(
|
||||
):
|
||||
unique_id = f"{serial_num}-{notification_key}"
|
||||
entity_id = entity_registry.async_get_entity_id(
|
||||
DOMAIN, SENSOR_DOMAIN, unique_id=unique_id
|
||||
Platform.SENSOR, DOMAIN, unique_id=unique_id
|
||||
)
|
||||
is_unsupported = not coordinator.data[serial_num].notifications_supported
|
||||
|
||||
|
||||
@@ -12,12 +12,11 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -45,7 +44,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key="BME280_humidity",
|
||||
translation_key="humidity",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "BME280"},
|
||||
),
|
||||
@@ -70,7 +69,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key="BME680_humidity",
|
||||
translation_key="humidity",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "BME680"},
|
||||
),
|
||||
@@ -129,7 +128,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key="HTU21D_humidity",
|
||||
translation_key="humidity",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "HTU21D"},
|
||||
),
|
||||
@@ -145,21 +144,21 @@ SENSOR_DESCRIPTIONS = [
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
translation_key="pm_10",
|
||||
key="SDS_P1",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
suggested_display_precision=2,
|
||||
),
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
translation_key="pm_25",
|
||||
key="SDS_P2",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
suggested_display_precision=2,
|
||||
),
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
key="SHT3X_humidity",
|
||||
translation_key="humidity",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "SHT3X"},
|
||||
),
|
||||
@@ -194,7 +193,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
),
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
translation_key="co2",
|
||||
key="CCS_CO2",
|
||||
suggested_display_precision=2,
|
||||
@@ -203,7 +202,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
key="CCS_TVOC",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
suggested_display_precision=2,
|
||||
),
|
||||
AltruistSensorEntityDescription(
|
||||
@@ -215,7 +214,7 @@ SENSOR_DESCRIPTIONS = [
|
||||
AltruistSensorEntityDescription(
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
translation_key="co2",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
key="SCD4x_co2",
|
||||
suggested_display_precision=2,
|
||||
translation_placeholders={"sensor_name": "SCD4x"},
|
||||
|
||||
@@ -10,15 +10,14 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_MAC,
|
||||
DEGREE,
|
||||
PERCENTAGE,
|
||||
UnitOfDensity,
|
||||
UnitOfIrradiance,
|
||||
UnitOfLength,
|
||||
UnitOfPrecipitationDepth,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolumetricFlux,
|
||||
@@ -94,7 +93,7 @@ SENSOR_DESCRIPTIONS = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=2,
|
||||
@@ -134,7 +133,7 @@ SENSOR_DESCRIPTIONS = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=1,
|
||||
@@ -188,14 +187,14 @@ SENSOR_DESCRIPTIONS = (
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25_24H,
|
||||
translation_key="pm25_24h_average",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
suggested_display_precision=1,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=1,
|
||||
|
||||
@@ -11,15 +11,14 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_NAME,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
DEGREE,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
UnitOfDensity,
|
||||
UnitOfIrradiance,
|
||||
UnitOfLength,
|
||||
UnitOfPrecipitationDepth,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolumetricFlux,
|
||||
@@ -157,13 +156,13 @@ SENSOR_DESCRIPTIONS = (
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25_IN_AQIN,
|
||||
translation_key="pm25_indoor_aqin",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25_IN_24H_AQIN,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
translation_key="pm25_indoor_24h_aqin",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
@@ -171,28 +170,28 @@ SENSOR_DESCRIPTIONS = (
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM10_IN_AQIN,
|
||||
translation_key="pm10_indoor_aqin",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM10_IN_24H_AQIN,
|
||||
translation_key="pm10_indoor_24h_aqin",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_CO2_IN_AQIN,
|
||||
translation_key="co2_indoor_aqin",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_CO2_IN_24H_AQIN,
|
||||
translation_key="co2_indoor_24h_aqin",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -206,7 +205,7 @@ SENSOR_DESCRIPTIONS = (
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM_IN_HUMIDITY_AQIN,
|
||||
translation_key="pm_indoor_humidity_aqin",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -250,7 +249,7 @@ SENSOR_DESCRIPTIONS = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -291,83 +290,83 @@ SENSOR_DESCRIPTIONS = (
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY10,
|
||||
translation_key="humidity_10",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY1,
|
||||
translation_key="humidity_1",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY2,
|
||||
translation_key="humidity_2",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY3,
|
||||
translation_key="humidity_3",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY4,
|
||||
translation_key="humidity_4",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY5,
|
||||
translation_key="humidity_5",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY6,
|
||||
translation_key="humidity_6",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY7,
|
||||
translation_key="humidity_7",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY8,
|
||||
translation_key="humidity_8",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY9,
|
||||
translation_key="humidity_9",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_HUMIDITYIN,
|
||||
translation_key="humidity_indoor",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -417,95 +416,95 @@ SENSOR_DESCRIPTIONS = (
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25_24H,
|
||||
translation_key="pm25_24h_average",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25_IN,
|
||||
translation_key="pm25_indoor",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25_IN_24H,
|
||||
translation_key="pm25_indoor_24h_average",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM10,
|
||||
translation_key="soil_humidity_10",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM1,
|
||||
translation_key="soil_humidity_1",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM2,
|
||||
translation_key="soil_humidity_2",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM3,
|
||||
translation_key="soil_humidity_3",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM4,
|
||||
translation_key="soil_humidity_4",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM5,
|
||||
translation_key="soil_humidity_5",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM6,
|
||||
translation_key="soil_humidity_6",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM7,
|
||||
translation_key="soil_humidity_7",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM8,
|
||||
translation_key="soil_humidity_8",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key=TYPE_SOILHUM9,
|
||||
translation_key="soil_humidity_9",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["pyanglianwater"],
|
||||
"quality_scale": "bronze",
|
||||
"requirements": ["pyanglianwater==3.2.2"]
|
||||
"requirements": ["pyanglianwater==3.2.3"]
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
|
||||
):
|
||||
self.options.pop(CONF_LLM_HASS_API)
|
||||
if not errors:
|
||||
return await self.async_step_advanced()
|
||||
return await self.async_step_additional()
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="init",
|
||||
@@ -308,10 +308,10 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
|
||||
errors=errors or None,
|
||||
)
|
||||
|
||||
async def async_step_advanced(
|
||||
async def async_step_additional(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> SubentryFlowResult:
|
||||
"""Manage advanced options."""
|
||||
"""Manage additional options."""
|
||||
errors: dict[str, str] = {}
|
||||
description_placeholders: dict[str, str] = {}
|
||||
|
||||
@@ -360,7 +360,7 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
|
||||
return await self.async_step_model()
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="advanced",
|
||||
step_id="additional",
|
||||
data_schema=self.add_suggested_values_to_schema(
|
||||
vol.Schema(step_schema), self.options
|
||||
),
|
||||
|
||||
@@ -48,16 +48,16 @@
|
||||
"user": "Add AI task"
|
||||
},
|
||||
"step": {
|
||||
"advanced": {
|
||||
"additional": {
|
||||
"data": {
|
||||
"chat_model": "[%key:common::generic::model%]",
|
||||
"prompt_caching": "[%key:component::anthropic::config_subentries::conversation::step::advanced::data::prompt_caching%]"
|
||||
"prompt_caching": "[%key:component::anthropic::config_subentries::conversation::step::additional::data::prompt_caching%]"
|
||||
},
|
||||
"data_description": {
|
||||
"chat_model": "[%key:component::anthropic::config_subentries::conversation::step::advanced::data_description::chat_model%]",
|
||||
"prompt_caching": "[%key:component::anthropic::config_subentries::conversation::step::advanced::data_description::prompt_caching%]"
|
||||
"chat_model": "[%key:component::anthropic::config_subentries::conversation::step::additional::data_description::chat_model%]",
|
||||
"prompt_caching": "[%key:component::anthropic::config_subentries::conversation::step::additional::data_description::prompt_caching%]"
|
||||
},
|
||||
"title": "[%key:component::anthropic::config_subentries::conversation::step::advanced::title%]"
|
||||
"title": "[%key:component::anthropic::config_subentries::conversation::step::additional::title%]"
|
||||
},
|
||||
"init": {
|
||||
"data": {
|
||||
@@ -115,7 +115,7 @@
|
||||
"user": "Add conversation agent"
|
||||
},
|
||||
"step": {
|
||||
"advanced": {
|
||||
"additional": {
|
||||
"data": {
|
||||
"chat_model": "[%key:common::generic::model%]",
|
||||
"prompt_caching": "Caching strategy"
|
||||
@@ -124,7 +124,7 @@
|
||||
"chat_model": "The model to serve the responses.",
|
||||
"prompt_caching": "Optimize your API cost and response times based on your usage."
|
||||
},
|
||||
"title": "Advanced settings"
|
||||
"title": "Additional settings"
|
||||
},
|
||||
"init": {
|
||||
"data": {
|
||||
|
||||
@@ -23,10 +23,9 @@ from homeassistant.const import (
|
||||
ATTR_MODEL,
|
||||
ATTR_NAME,
|
||||
ATTR_SW_VERSION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -62,7 +61,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
key="humidity",
|
||||
name="Humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"pressure": AranetSensorEntityDescription(
|
||||
@@ -83,7 +82,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
key="co2",
|
||||
name="Carbon Dioxide",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"radiation_rate": AranetSensorEntityDescription(
|
||||
@@ -115,7 +114,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
key="battery",
|
||||
name="Battery",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
|
||||
@@ -12,12 +12,7 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.const import UnitOfDensity, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -35,7 +30,7 @@ class ArveDeviceEntityDescription(SensorEntityDescription):
|
||||
SENSORS: tuple[ArveDeviceEntityDescription, ...] = (
|
||||
ArveDeviceEntityDescription(
|
||||
key="CO2",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
value_fn=lambda arve_data: arve_data.co2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
@@ -48,21 +43,21 @@ SENSORS: tuple[ArveDeviceEntityDescription, ...] = (
|
||||
),
|
||||
ArveDeviceEntityDescription(
|
||||
key="Humidity",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
value_fn=lambda arve_data: arve_data.humidity,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ArveDeviceEntityDescription(
|
||||
key="PM10",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
value_fn=lambda arve_data: arve_data.pm10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
ArveDeviceEntityDescription(
|
||||
key="PM25",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
value_fn=lambda arve_data: arve_data.pm25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""The ATEN PE component."""
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"domain": "aten_pe",
|
||||
"name": "ATEN Rack PDU",
|
||||
"codeowners": ["@mtdcr"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/aten_pe",
|
||||
"iot_class": "local_polling",
|
||||
"quality_scale": "legacy",
|
||||
"requirements": ["atenpdu==0.3.6"]
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
"""The ATEN PE switch component."""
|
||||
|
||||
import logging
|
||||
from typing import Any, override
|
||||
|
||||
from atenpdu import AtenPE, AtenPEError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.switch import (
|
||||
PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
|
||||
SwitchDeviceClass,
|
||||
SwitchEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_AUTH_KEY = "auth_key"
|
||||
CONF_COMMUNITY = "community"
|
||||
CONF_PRIV_KEY = "priv_key"
|
||||
DEFAULT_COMMUNITY = "private"
|
||||
DEFAULT_PORT = "161"
|
||||
DEFAULT_USERNAME = "administrator"
|
||||
|
||||
PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||
vol.Optional(CONF_COMMUNITY, default=DEFAULT_COMMUNITY): cv.string,
|
||||
vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string,
|
||||
vol.Optional(CONF_AUTH_KEY): cv.string,
|
||||
vol.Optional(CONF_PRIV_KEY): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the ATEN PE switch."""
|
||||
node = config[CONF_HOST]
|
||||
serv = config[CONF_PORT]
|
||||
|
||||
dev = AtenPE(
|
||||
node=node,
|
||||
serv=serv,
|
||||
community=config[CONF_COMMUNITY],
|
||||
username=config[CONF_USERNAME],
|
||||
authkey=config.get(CONF_AUTH_KEY),
|
||||
privkey=config.get(CONF_PRIV_KEY),
|
||||
)
|
||||
|
||||
try:
|
||||
await hass.async_add_executor_job(dev.initialize)
|
||||
mac = await dev.deviceMAC()
|
||||
outlets = dev.outlets()
|
||||
name = await dev.deviceName()
|
||||
model = await dev.modelName()
|
||||
sw_version = await dev.deviceFWversion()
|
||||
except AtenPEError as exc:
|
||||
_LOGGER.error("Failed to initialize %s:%s: %s", node, serv, str(exc))
|
||||
raise PlatformNotReady from exc
|
||||
|
||||
info = DeviceInfo(
|
||||
connections={(CONNECTION_NETWORK_MAC, mac)},
|
||||
manufacturer="ATEN",
|
||||
model=model,
|
||||
name=name,
|
||||
sw_version=sw_version,
|
||||
)
|
||||
|
||||
async_add_entities(
|
||||
(AtenSwitch(dev, info, mac, outlet.id, outlet.name) for outlet in outlets), True
|
||||
)
|
||||
|
||||
|
||||
class AtenSwitch(SwitchEntity):
|
||||
"""Represents an ATEN PE switch."""
|
||||
|
||||
_attr_device_class = SwitchDeviceClass.OUTLET
|
||||
|
||||
def __init__(
|
||||
self, device: AtenPE, info: DeviceInfo, mac: str, outlet: str, name: str
|
||||
) -> None:
|
||||
"""Initialize an ATEN PE switch."""
|
||||
self._device = device
|
||||
self._outlet = outlet
|
||||
self._attr_device_info = info
|
||||
self._attr_unique_id = f"{mac}-{outlet}"
|
||||
self._attr_name = name or f"Outlet {outlet}"
|
||||
|
||||
@override
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch on."""
|
||||
await self._device.setOutletStatus(self._outlet, "on")
|
||||
self._attr_is_on = True
|
||||
|
||||
@override
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch off."""
|
||||
await self._device.setOutletStatus(self._outlet, "off")
|
||||
self._attr_is_on = False
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Process update from entity."""
|
||||
status = await self._device.displayOutletStatus(self._outlet)
|
||||
if status == "on":
|
||||
self._attr_is_on = True
|
||||
elif status == "off":
|
||||
self._attr_is_on = False
|
||||
@@ -731,17 +731,32 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity):
|
||||
trace_element = TraceElement(variables, trigger_path)
|
||||
trace_append_element(trace_element)
|
||||
|
||||
if (
|
||||
not skip_condition
|
||||
and self._condition is not None
|
||||
and not self._condition.async_check(variables=variables)
|
||||
):
|
||||
self._logger.debug(
|
||||
"Conditions not met, aborting automation. Condition summary: %s",
|
||||
trace_get(clear=False),
|
||||
)
|
||||
script_execution_set("failed_conditions")
|
||||
return None
|
||||
if not skip_condition and self._condition is not None:
|
||||
try:
|
||||
conditions_pass = self._condition.async_check(variables=variables)
|
||||
except (vol.Invalid, HomeAssistantError) as err:
|
||||
self._logger.error(
|
||||
"Error while checking conditions of automation %s: %s",
|
||||
self.entity_id,
|
||||
err,
|
||||
)
|
||||
automation_trace.set_error(err)
|
||||
return None
|
||||
except Exception as err:
|
||||
self._logger.exception(
|
||||
"Unexpected error while checking conditions of automation %s",
|
||||
self.entity_id,
|
||||
)
|
||||
automation_trace.set_error(err)
|
||||
return None
|
||||
|
||||
if not conditions_pass:
|
||||
self._logger.debug(
|
||||
"Conditions not met, aborting automation. Condition summary: %s",
|
||||
trace_get(clear=False),
|
||||
)
|
||||
script_execution_set("failed_conditions")
|
||||
return None
|
||||
|
||||
self.async_set_context(trigger_context)
|
||||
event_data = {
|
||||
@@ -794,7 +809,9 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity):
|
||||
)
|
||||
automation_trace.set_error(err)
|
||||
except Exception as err:
|
||||
self._logger.exception("While executing automation %s", self.entity_id)
|
||||
self._logger.exception(
|
||||
"Unexpected error while executing automation %s", self.entity_id
|
||||
)
|
||||
automation_trace.set_error(err)
|
||||
|
||||
return None
|
||||
|
||||
@@ -17,7 +17,7 @@ from homeassistant.helpers.selector import (
|
||||
TextSelectorType,
|
||||
)
|
||||
|
||||
from .const import DEFAULT_HOST, DOMAIN, SECTION_ADVANCED_SETTINGS
|
||||
from .const import DEFAULT_HOST, DOMAIN, SECTION_ADDITIONAL_SETTINGS
|
||||
|
||||
STEP_USER_DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
@@ -25,7 +25,7 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
|
||||
vol.Required(CONF_PASSWORD): TextSelector(
|
||||
TextSelectorConfig(type=TextSelectorType.PASSWORD)
|
||||
),
|
||||
vol.Required(SECTION_ADVANCED_SETTINGS): section(
|
||||
vol.Required(SECTION_ADDITIONAL_SETTINGS): section(
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_HOST, default=DEFAULT_HOST): TextSelector(
|
||||
@@ -79,7 +79,7 @@ class AutoskopeConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
errors: dict[str, str] = {}
|
||||
if user_input is not None:
|
||||
username = user_input[CONF_USERNAME].lower()
|
||||
host = user_input[SECTION_ADVANCED_SETTINGS][CONF_HOST].lower()
|
||||
host = user_input[SECTION_ADDITIONAL_SETTINGS][CONF_HOST].lower()
|
||||
|
||||
try:
|
||||
cv.url(host)
|
||||
|
||||
@@ -5,5 +5,5 @@ from datetime import timedelta
|
||||
DOMAIN = "autoskope"
|
||||
|
||||
DEFAULT_HOST = "https://portal.autoskope.de"
|
||||
SECTION_ADVANCED_SETTINGS = "advanced_settings"
|
||||
SECTION_ADDITIONAL_SETTINGS = "additional_settings"
|
||||
UPDATE_INTERVAL = timedelta(seconds=60)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
},
|
||||
"description": "Enter your Autoskope credentials.",
|
||||
"sections": {
|
||||
"advanced_settings": {
|
||||
"additional_settings": {
|
||||
"data": {
|
||||
"host": "API endpoint"
|
||||
},
|
||||
|
||||
@@ -16,12 +16,9 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_CONNECTIONS,
|
||||
ATTR_SW_VERSION,
|
||||
CONCENTRATION_GRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -61,7 +58,7 @@ class AwairSensorEntityDescription(SensorEntityDescription):
|
||||
|
||||
SENSOR_TYPE_SCORE = AwairSensorEntityDescription(
|
||||
key=API_SCORE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
translation_key="score",
|
||||
unique_id_tag="score", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
@@ -71,7 +68,7 @@ SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_HUMID,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
unique_id_tag="HUMID", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -93,7 +90,7 @@ SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_VOC,
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
unique_id_tag="VOC", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -107,7 +104,7 @@ SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_CO2,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
unique_id_tag="CO2", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -123,7 +120,7 @@ SENSOR_TYPES: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_ABS_HUMID,
|
||||
device_class=SensorDeviceClass.ABSOLUTE_HUMIDITY,
|
||||
native_unit_of_measurement=CONCENTRATION_GRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.GRAMS_PER_CUBIC_METER,
|
||||
unique_id_tag="absolute_humidity",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
@@ -134,14 +131,14 @@ SENSOR_TYPES_DUST: tuple[AwairSensorEntityDescription, ...] = (
|
||||
AwairSensorEntityDescription(
|
||||
key=API_PM25,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
unique_id_tag="PM25", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
AwairSensorEntityDescription(
|
||||
key=API_PM10,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
unique_id_tag="PM10", # matches legacy format
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""The BlinkStick integration."""
|
||||
@@ -1,87 +0,0 @@
|
||||
"""Support for BlinkStick lights."""
|
||||
|
||||
# mypy: ignore-errors
|
||||
from typing import Any
|
||||
|
||||
# from blinkstick import blinkstick
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_HS_COLOR,
|
||||
PLATFORM_SCHEMA as LIGHT_PLATFORM_SCHEMA,
|
||||
ColorMode,
|
||||
LightEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.util import color as color_util
|
||||
|
||||
CONF_SERIAL = "serial"
|
||||
|
||||
DEFAULT_NAME = "Blinkstick"
|
||||
|
||||
PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SERIAL): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up BlinkStick device specified by serial number."""
|
||||
|
||||
name = config[CONF_NAME]
|
||||
serial = config[CONF_SERIAL]
|
||||
|
||||
stick = blinkstick.find_by_serial(serial)
|
||||
|
||||
add_entities([BlinkStickLight(stick, name)], True)
|
||||
|
||||
|
||||
class BlinkStickLight(LightEntity):
|
||||
"""Representation of a BlinkStick light."""
|
||||
|
||||
_attr_color_mode = ColorMode.HS
|
||||
_attr_supported_color_modes = {ColorMode.HS}
|
||||
|
||||
def __init__(self, stick, name):
|
||||
"""Initialize the light."""
|
||||
self._stick = stick
|
||||
self._attr_name = name
|
||||
|
||||
def update(self) -> None:
|
||||
"""Read back the device state."""
|
||||
rgb_color = self._stick.get_color()
|
||||
hsv = color_util.color_RGB_to_hsv(*rgb_color)
|
||||
self._attr_hs_color = hsv[:2]
|
||||
self._attr_brightness = int(hsv[2])
|
||||
self._attr_is_on = self.brightness is not None and self.brightness > 0
|
||||
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the device on."""
|
||||
if ATTR_HS_COLOR in kwargs:
|
||||
self._attr_hs_color = kwargs[ATTR_HS_COLOR]
|
||||
|
||||
brightness: int = kwargs.get(ATTR_BRIGHTNESS, 255)
|
||||
self._attr_brightness = brightness
|
||||
self._attr_is_on = bool(brightness)
|
||||
|
||||
assert self.hs_color
|
||||
rgb_color = color_util.color_hsv_to_RGB(
|
||||
self.hs_color[0], self.hs_color[1], brightness / 255 * 100
|
||||
)
|
||||
self._stick.set_color(red=rgb_color[0], green=rgb_color[1], blue=rgb_color[2])
|
||||
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the device off."""
|
||||
self._stick.turn_off()
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"domain": "blinksticklight",
|
||||
"name": "BlinkStick",
|
||||
"codeowners": [],
|
||||
"disabled": "This integration is disabled because it uses non-open source code to operate.",
|
||||
"documentation": "https://www.home-assistant.io/integrations/blinksticklight",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["blinkstick"],
|
||||
"quality_scale": "legacy",
|
||||
"requirements": ["BlinkStick==1.2.0"]
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
extend = "../../../pyproject.toml"
|
||||
|
||||
lint.extend-ignore = [
|
||||
"F821"
|
||||
]
|
||||
@@ -13,10 +13,9 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -58,13 +57,13 @@ SENSOR_DESCRIPTIONS: dict[str, SHCSensorEntityDescription] = {
|
||||
HUMIDITY_SENSOR: SHCSensorEntityDescription(
|
||||
key=HUMIDITY_SENSOR,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
value_fn=lambda device: device.humidity,
|
||||
),
|
||||
PURITY_SENSOR: SHCSensorEntityDescription(
|
||||
key=PURITY_SENSOR,
|
||||
translation_key=PURITY_SENSOR,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
value_fn=lambda device: device.purity,
|
||||
),
|
||||
AIR_QUALITY_SENSOR: SHCSensorEntityDescription(
|
||||
@@ -112,7 +111,7 @@ SENSOR_DESCRIPTIONS: dict[str, SHCSensorEntityDescription] = {
|
||||
key=VALVE_TAPPET_SENSOR,
|
||||
translation_key=VALVE_TAPPET_SENSOR,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
value_fn=lambda device: device.position,
|
||||
attributes_fn=lambda device: {
|
||||
"valve_tappet_state": device.valvestate.name,
|
||||
|
||||
@@ -10,12 +10,12 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
PERCENTAGE,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -37,25 +37,25 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="pm10",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="pm2_5",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="pm1",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="humidity",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["bsblan"],
|
||||
"quality_scale": "silver",
|
||||
"requirements": ["python-bsblan==6.1.3"],
|
||||
"requirements": ["python-bsblan==6.1.4"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"name": "bsb-lan*",
|
||||
|
||||
@@ -18,15 +18,13 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
DEGREE,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
REVOLUTIONS_PER_MINUTE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
UnitOfConductivity,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
@@ -34,6 +32,7 @@ from homeassistant.const import (
|
||||
UnitOfMass,
|
||||
UnitOfPower,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
@@ -63,7 +62,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
(BTHomeSensorDeviceClass.BATTERY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.BATTERY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
@@ -96,7 +95,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.CO2}_{Units.CONCENTRATION_PARTS_PER_MILLION}",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Current (Ampere)
|
||||
@@ -182,7 +181,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
(BTHomeSensorDeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Illuminance (lux)
|
||||
@@ -216,7 +215,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
(BTHomeSensorDeviceClass.MOISTURE, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.MOISTURE}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.MOISTURE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Packet Id (-)
|
||||
@@ -234,7 +233,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.PM10}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# PM2.5 (μg/m3)
|
||||
@@ -244,7 +243,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.PM25}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Power (Watt)
|
||||
@@ -357,7 +356,7 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
# Voltage (volt)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""The clementine component."""
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"domain": "clementine",
|
||||
"name": "Clementine Music Player",
|
||||
"codeowners": [],
|
||||
"documentation": "https://www.home-assistant.io/integrations/clementine",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["clementineremote"],
|
||||
"quality_scale": "legacy",
|
||||
"requirements": ["python-clementine-remote==1.0.1"]
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
"""Support for Clementine Music Player as media player."""
|
||||
|
||||
from datetime import timedelta
|
||||
import time
|
||||
from typing import override
|
||||
|
||||
from clementineremote import ClementineRemote
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.media_player import (
|
||||
PLATFORM_SCHEMA as MEDIA_PLAYER_PLATFORM_SCHEMA,
|
||||
MediaPlayerEntity,
|
||||
MediaPlayerEntityFeature,
|
||||
MediaPlayerState,
|
||||
MediaType,
|
||||
)
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST, CONF_NAME, CONF_PORT
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
DEFAULT_NAME = "Clementine Remote"
|
||||
DEFAULT_PORT = 5500
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=5)
|
||||
|
||||
PLATFORM_SCHEMA = MEDIA_PLAYER_PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Optional(CONF_ACCESS_TOKEN): cv.positive_int,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Clementine platform."""
|
||||
|
||||
host = config[CONF_HOST]
|
||||
port = config[CONF_PORT]
|
||||
token = config.get(CONF_ACCESS_TOKEN)
|
||||
|
||||
client = ClementineRemote(host, port, token, reconnect=True)
|
||||
|
||||
add_entities([ClementineDevice(client, config[CONF_NAME])])
|
||||
|
||||
|
||||
class ClementineDevice(MediaPlayerEntity):
|
||||
"""Representation of Clementine Player."""
|
||||
|
||||
_attr_media_content_type = MediaType.MUSIC
|
||||
_attr_supported_features = (
|
||||
MediaPlayerEntityFeature.PAUSE
|
||||
| MediaPlayerEntityFeature.VOLUME_STEP
|
||||
| MediaPlayerEntityFeature.PREVIOUS_TRACK
|
||||
| MediaPlayerEntityFeature.VOLUME_SET
|
||||
| MediaPlayerEntityFeature.NEXT_TRACK
|
||||
| MediaPlayerEntityFeature.SELECT_SOURCE
|
||||
| MediaPlayerEntityFeature.PLAY
|
||||
)
|
||||
_attr_volume_step = 0.04
|
||||
|
||||
def __init__(self, client, name):
|
||||
"""Initialize the Clementine device."""
|
||||
self._client = client
|
||||
self._attr_name = name
|
||||
|
||||
def update(self) -> None:
|
||||
"""Retrieve the latest data from the Clementine Player."""
|
||||
try:
|
||||
client = self._client
|
||||
|
||||
if client.state == "Playing":
|
||||
self._attr_state = MediaPlayerState.PLAYING
|
||||
elif client.state == "Paused":
|
||||
self._attr_state = MediaPlayerState.PAUSED
|
||||
elif client.state == "Disconnected":
|
||||
self._attr_state = MediaPlayerState.OFF
|
||||
else:
|
||||
self._attr_state = MediaPlayerState.PAUSED
|
||||
|
||||
if client.last_update and (time.time() - client.last_update > 40):
|
||||
self._attr_state = MediaPlayerState.OFF
|
||||
|
||||
volume = float(client.volume) if client.volume else 0.0
|
||||
self._attr_volume_level = volume / 100.0
|
||||
if client.active_playlist_id in client.playlists:
|
||||
self._attr_source = client.playlists[client.active_playlist_id]["name"]
|
||||
else:
|
||||
self._attr_source = "Unknown"
|
||||
self._attr_source_list = [s["name"] for s in client.playlists.values()]
|
||||
|
||||
if client.current_track:
|
||||
self._attr_media_title = client.current_track["title"]
|
||||
self._attr_media_artist = client.current_track["track_artist"]
|
||||
self._attr_media_album_name = client.current_track["track_album"]
|
||||
self._attr_media_image_hash = client.current_track["track_id"]
|
||||
else:
|
||||
self._attr_media_image_hash = None
|
||||
|
||||
except Exception:
|
||||
self._attr_state = MediaPlayerState.OFF
|
||||
raise
|
||||
|
||||
@override
|
||||
def select_source(self, source: str) -> None:
|
||||
"""Select input source."""
|
||||
client = self._client
|
||||
sources = [s for s in client.playlists.values() if s["name"] == source]
|
||||
if len(sources) == 1:
|
||||
client.change_song(sources[0]["id"], 0)
|
||||
|
||||
@override
|
||||
async def async_get_media_image(self) -> tuple[bytes | None, str | None]:
|
||||
"""Fetch media image of current playing image."""
|
||||
if self._client.current_track:
|
||||
image = bytes(self._client.current_track["art"])
|
||||
return (image, "image/png")
|
||||
|
||||
return None, None
|
||||
|
||||
@override
|
||||
def mute_volume(self, mute: bool) -> None:
|
||||
"""Send mute command."""
|
||||
self._client.set_volume(0)
|
||||
|
||||
@override
|
||||
def set_volume_level(self, volume: float) -> None:
|
||||
"""Set volume level."""
|
||||
self._client.set_volume(int(100 * volume))
|
||||
|
||||
def media_play_pause(self) -> None:
|
||||
"""Simulate play pause media player."""
|
||||
if self.state == MediaPlayerState.PLAYING:
|
||||
self.media_pause()
|
||||
else:
|
||||
self.media_play()
|
||||
|
||||
@override
|
||||
def media_play(self) -> None:
|
||||
"""Send play command."""
|
||||
self._attr_state = MediaPlayerState.PLAYING
|
||||
self._client.play()
|
||||
|
||||
@override
|
||||
def media_pause(self) -> None:
|
||||
"""Send media pause command to media player."""
|
||||
self._attr_state = MediaPlayerState.PAUSED
|
||||
self._client.pause()
|
||||
|
||||
@override
|
||||
def media_next_track(self) -> None:
|
||||
"""Send next track command."""
|
||||
self._client.next()
|
||||
|
||||
@override
|
||||
def media_previous_track(self) -> None:
|
||||
"""Send the previous track command."""
|
||||
self._client.previous()
|
||||
@@ -13,12 +13,11 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -117,7 +116,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
CompitParameter.BOILER_TEMPERATURE: SensorEntityDescription(
|
||||
key=CompitParameter.BOILER_TEMPERATURE.value,
|
||||
@@ -204,14 +203,14 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
),
|
||||
CompitParameter.CO2_PERCENT: SensorEntityDescription(
|
||||
key=CompitParameter.CO2_PERCENT.value,
|
||||
translation_key="co2_percent",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
CompitParameter.COLLECTOR_POWER: SensorEntityDescription(
|
||||
key=CompitParameter.COLLECTOR_POWER.value,
|
||||
@@ -290,7 +289,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
translation_key="fuel_level",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
CompitParameter.HEATING1_TARGET_TEMPERATURE: SensorEntityDescription(
|
||||
key=CompitParameter.HEATING1_TARGET_TEMPERATURE.value,
|
||||
@@ -333,7 +332,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
CompitParameter.LOWER_SOURCE_TEMPERATURE: SensorEntityDescription(
|
||||
key=CompitParameter.LOWER_SOURCE_TEMPERATURE.value,
|
||||
@@ -401,14 +400,14 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CompitParameter.PM4_LEVEL_MEASURED: SensorEntityDescription(
|
||||
key=CompitParameter.PM4_LEVEL_MEASURED.value,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
device_class=SensorDeviceClass.PM4,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CompitParameter.PM10_LEVEL: SensorEntityDescription(
|
||||
key=CompitParameter.PM10_LEVEL.value,
|
||||
@@ -422,7 +421,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
key=CompitParameter.PM10_MEASURED.value,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CompitParameter.PM25_LEVEL: SensorEntityDescription(
|
||||
key=CompitParameter.PM25_LEVEL.value,
|
||||
@@ -436,7 +435,7 @@ DESCRIPTIONS: dict[CompitParameter, SensorEntityDescription] = {
|
||||
key=CompitParameter.PM25_MEASURED.value,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CompitParameter.PROTECTION_TEMPERATURE: SensorEntityDescription(
|
||||
key=CompitParameter.PROTECTION_TEMPERATURE.value,
|
||||
|
||||
@@ -805,6 +805,10 @@ class DefaultAgent(ConversationEntity):
|
||||
else:
|
||||
num_unmatched_entities += 1
|
||||
|
||||
# Literal text matched is the dominant signal
|
||||
same_text_matched = (maybe_result is not None) and (
|
||||
result.text_chunks_matched == maybe_result.text_chunks_matched
|
||||
)
|
||||
if (
|
||||
(maybe_result is None) # first result
|
||||
or (
|
||||
@@ -813,22 +817,25 @@ class DefaultAgent(ConversationEntity):
|
||||
)
|
||||
or (
|
||||
# More entities matched
|
||||
num_matched_entities > best_num_matched_entities
|
||||
same_text_matched
|
||||
and (num_matched_entities > best_num_matched_entities)
|
||||
)
|
||||
or (
|
||||
# Fewer unmatched entities
|
||||
(num_matched_entities == best_num_matched_entities)
|
||||
same_text_matched
|
||||
and (num_matched_entities == best_num_matched_entities)
|
||||
and (num_unmatched_entities < best_num_unmatched_entities)
|
||||
)
|
||||
or (
|
||||
# Prefer unmatched ranges
|
||||
(num_matched_entities == best_num_matched_entities)
|
||||
same_text_matched
|
||||
and (num_matched_entities == best_num_matched_entities)
|
||||
and (num_unmatched_entities == best_num_unmatched_entities)
|
||||
and (num_unmatched_ranges > best_num_unmatched_ranges)
|
||||
)
|
||||
or (
|
||||
# Prefer match failures with entities
|
||||
(result.text_chunks_matched == maybe_result.text_chunks_matched)
|
||||
same_text_matched
|
||||
and (num_unmatched_entities == best_num_unmatched_entities)
|
||||
and (num_unmatched_ranges == best_num_unmatched_ranges)
|
||||
and (
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/conversation",
|
||||
"integration_type": "entity",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["hassil==3.8.0", "home-assistant-intents==2026.6.1"]
|
||||
"requirements": ["hassil==3.8.0", "home-assistant-intents==2026.6.24"]
|
||||
}
|
||||
|
||||
@@ -35,15 +35,13 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.const import (
|
||||
ATTR_TEMPERATURE,
|
||||
ATTR_VOLTAGE,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
@@ -138,7 +136,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="PPB",
|
||||
old_unique_id_suffix="ppb",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
),
|
||||
DeconzSensorDescription[AirQuality](
|
||||
key="air_quality_formaldehyde",
|
||||
@@ -149,7 +147,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="CH2O",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
DeconzSensorDescription[AirQuality](
|
||||
key="air_quality_co2",
|
||||
@@ -160,7 +158,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="CO2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
),
|
||||
DeconzSensorDescription[AirQuality](
|
||||
key="air_quality_pm2_5",
|
||||
@@ -171,7 +169,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="PM25",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
DeconzSensorDescription[CarbonDioxide](
|
||||
key="carbon_dioxide",
|
||||
@@ -181,7 +179,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
instance_check=CarbonDioxide,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
),
|
||||
DeconzSensorDescription[Consumption](
|
||||
key="consumption",
|
||||
@@ -210,7 +208,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
instance_check=Formaldehyde,
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
),
|
||||
DeconzSensorDescription[GenericStatus](
|
||||
key="status",
|
||||
@@ -227,7 +225,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
instance_check=Humidity,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
DeconzSensorDescription[LightLevel](
|
||||
@@ -248,7 +246,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
instance_check=Moisture,
|
||||
device_class=SensorDeviceClass.MOISTURE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
DeconzSensorDescription[ParticulateMatter](
|
||||
@@ -260,7 +258,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
name_suffix="PM25",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
DeconzSensorDescription[Power](
|
||||
key="power",
|
||||
@@ -310,7 +308,7 @@ ENTITY_DESCRIPTIONS: tuple[DeconzSensorDescription, ...] = (
|
||||
old_unique_id_suffix="battery",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
DeconzSensorDescription[SensorResources](
|
||||
|
||||
@@ -12,11 +12,10 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolume,
|
||||
)
|
||||
@@ -52,7 +51,7 @@ async def async_setup_entry(
|
||||
12,
|
||||
SensorDeviceClass.BATTERY,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
PERCENTAGE,
|
||||
UnitOfRatio.PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_name="Battery",
|
||||
),
|
||||
@@ -63,7 +62,7 @@ async def async_setup_entry(
|
||||
54,
|
||||
SensorDeviceClass.HUMIDITY,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
PERCENTAGE,
|
||||
UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
DemoSensor(
|
||||
"sensor_3",
|
||||
@@ -72,7 +71,7 @@ async def async_setup_entry(
|
||||
54,
|
||||
SensorDeviceClass.CO,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
UnitOfRatio.PARTS_PER_MILLION,
|
||||
),
|
||||
DemoSensor(
|
||||
"sensor_4",
|
||||
@@ -81,7 +80,7 @@ async def async_setup_entry(
|
||||
54,
|
||||
SensorDeviceClass.CO2,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
UnitOfRatio.PARTS_PER_MILLION,
|
||||
),
|
||||
DemoSensor(
|
||||
"battery_4",
|
||||
@@ -90,7 +89,7 @@ async def async_setup_entry(
|
||||
99,
|
||||
SensorDeviceClass.BATTERY,
|
||||
SensorStateClass.MEASUREMENT,
|
||||
PERCENTAGE,
|
||||
UnitOfRatio.PERCENTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
entity_name="Battery",
|
||||
),
|
||||
|
||||
@@ -20,7 +20,7 @@ from homeassistant.data_entry_flow import SectionConfig, section
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from .const import (
|
||||
CONF_ADVANCED_OPTIONS,
|
||||
CONF_ADDITIONAL_OPTIONS,
|
||||
CONF_HOSTNAME,
|
||||
CONF_IPV4,
|
||||
CONF_IPV6,
|
||||
@@ -39,7 +39,7 @@ from .const import (
|
||||
DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_HOSTNAME, default=DEFAULT_HOSTNAME): cv.string,
|
||||
vol.Required(CONF_ADVANCED_OPTIONS): section(
|
||||
vol.Required(CONF_ADDITIONAL_OPTIONS): section(
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_RESOLVER): cv.string,
|
||||
@@ -117,13 +117,13 @@ class DnsIPConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
if user_input:
|
||||
hostname = user_input[CONF_HOSTNAME]
|
||||
name = DEFAULT_NAME if hostname == DEFAULT_HOSTNAME else hostname
|
||||
advanced_options = user_input[CONF_ADVANCED_OPTIONS]
|
||||
resolver = advanced_options.get(CONF_RESOLVER, DEFAULT_RESOLVER)
|
||||
resolver_ipv6 = advanced_options.get(
|
||||
additional_options = user_input[CONF_ADDITIONAL_OPTIONS]
|
||||
resolver = additional_options.get(CONF_RESOLVER, DEFAULT_RESOLVER)
|
||||
resolver_ipv6 = additional_options.get(
|
||||
CONF_RESOLVER_IPV6, DEFAULT_RESOLVER_IPV6
|
||||
)
|
||||
port = advanced_options.get(CONF_PORT, DEFAULT_PORT)
|
||||
port_ipv6 = advanced_options.get(CONF_PORT_IPV6, DEFAULT_PORT)
|
||||
port = additional_options.get(CONF_PORT, DEFAULT_PORT)
|
||||
port_ipv6 = additional_options.get(CONF_PORT_IPV6, DEFAULT_PORT)
|
||||
|
||||
validate = await async_validate_hostname(
|
||||
hostname, resolver, resolver_ipv6, port, port_ipv6
|
||||
|
||||
@@ -12,7 +12,7 @@ CONF_PORT_IPV6 = "port_ipv6"
|
||||
CONF_IPV4 = "ipv4"
|
||||
CONF_IPV6 = "ipv6"
|
||||
CONF_IPV6_V4 = "ipv6_v4"
|
||||
CONF_ADVANCED_OPTIONS = "advanced_options"
|
||||
CONF_ADDITIONAL_OPTIONS = "additional_options"
|
||||
|
||||
DEFAULT_HOSTNAME = "myip.opendns.com"
|
||||
DEFAULT_IPV6 = False
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"hostname": "The hostname for which to perform the DNS query."
|
||||
},
|
||||
"sections": {
|
||||
"advanced_options": {
|
||||
"additional_options": {
|
||||
"data": {
|
||||
"port": "IPv4 port",
|
||||
"port_ipv6": "IPv6 port",
|
||||
@@ -63,16 +63,16 @@
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"port": "[%key:component::dnsip::config::step::user::sections::advanced_options::data::port%]",
|
||||
"port_ipv6": "[%key:component::dnsip::config::step::user::sections::advanced_options::data::port_ipv6%]",
|
||||
"resolver": "[%key:component::dnsip::config::step::user::sections::advanced_options::data::resolver%]",
|
||||
"resolver_ipv6": "[%key:component::dnsip::config::step::user::sections::advanced_options::data::resolver_ipv6%]"
|
||||
"port": "[%key:component::dnsip::config::step::user::sections::additional_options::data::port%]",
|
||||
"port_ipv6": "[%key:component::dnsip::config::step::user::sections::additional_options::data::port_ipv6%]",
|
||||
"resolver": "[%key:component::dnsip::config::step::user::sections::additional_options::data::resolver%]",
|
||||
"resolver_ipv6": "[%key:component::dnsip::config::step::user::sections::additional_options::data::resolver_ipv6%]"
|
||||
},
|
||||
"data_description": {
|
||||
"port": "[%key:component::dnsip::config::step::user::sections::advanced_options::data_description::port%]",
|
||||
"port_ipv6": "[%key:component::dnsip::config::step::user::sections::advanced_options::data_description::port_ipv6%]",
|
||||
"resolver": "[%key:component::dnsip::config::step::user::sections::advanced_options::data_description::resolver%]",
|
||||
"resolver_ipv6": "[%key:component::dnsip::config::step::user::sections::advanced_options::data_description::resolver_ipv6%]"
|
||||
"port": "[%key:component::dnsip::config::step::user::sections::additional_options::data_description::port%]",
|
||||
"port_ipv6": "[%key:component::dnsip::config::step::user::sections::additional_options::data_description::port_ipv6%]",
|
||||
"resolver": "[%key:component::dnsip::config::step::user::sections::additional_options::data_description::resolver%]",
|
||||
"resolver_ipv6": "[%key:component::dnsip::config::step::user::sections::additional_options::data_description::resolver_ipv6%]"
|
||||
},
|
||||
"description": "Optionally change resolvers and ports."
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
"""Support for Dovado router."""
|
||||
|
||||
# mypy: ignore-errors
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
# import dovado
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_PASSWORD,
|
||||
CONF_PORT,
|
||||
CONF_USERNAME,
|
||||
DEVICE_DEFAULT_NAME,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = "dovado"
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_HOST): cv.string,
|
||||
vol.Optional(CONF_PORT): cv.port,
|
||||
}
|
||||
)
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
|
||||
|
||||
|
||||
def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the Dovado component."""
|
||||
|
||||
hass.data[DOMAIN] = DovadoData(
|
||||
dovado.Dovado(
|
||||
config[DOMAIN][CONF_USERNAME],
|
||||
config[DOMAIN][CONF_PASSWORD],
|
||||
config[DOMAIN].get(CONF_HOST),
|
||||
config[DOMAIN].get(CONF_PORT),
|
||||
)
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class DovadoData:
|
||||
"""Maintain a connection to the router."""
|
||||
|
||||
def __init__(self, client):
|
||||
"""Set up a new Dovado connection."""
|
||||
self._client = client
|
||||
self.state = {}
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Name of the router."""
|
||||
return self.state.get("product name", DEVICE_DEFAULT_NAME)
|
||||
|
||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||
def update(self):
|
||||
"""Update device state."""
|
||||
try:
|
||||
self.state = self._client.state or {}
|
||||
if not self.state:
|
||||
return False
|
||||
self.state.update(connected=self.state.get("modem status") == "CONNECTED")
|
||||
except OSError as error:
|
||||
_LOGGER.warning("Could not contact the router: %s", error)
|
||||
return None
|
||||
_LOGGER.debug("Received: %s", self.state)
|
||||
return True
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
"""Dovado client instance."""
|
||||
return self._client
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"domain": "dovado",
|
||||
"name": "Dovado",
|
||||
"codeowners": [],
|
||||
"disabled": "This integration is disabled because it uses non-open source code to operate.",
|
||||
"documentation": "https://www.home-assistant.io/integrations/dovado",
|
||||
"iot_class": "local_polling",
|
||||
"quality_scale": "legacy",
|
||||
"requirements": ["dovado==0.4.1"]
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
"""Support for SMS notifications from the Dovado router."""
|
||||
|
||||
import logging
|
||||
from typing import Any, override
|
||||
|
||||
from homeassistant.components.notify import ATTR_TARGET, BaseNotificationService
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from . import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_service(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> DovadoSMSNotificationService:
|
||||
"""Get the Dovado Router SMS notification service."""
|
||||
return DovadoSMSNotificationService(hass.data[DOMAIN].client)
|
||||
|
||||
|
||||
class DovadoSMSNotificationService(BaseNotificationService):
|
||||
"""Implement the notification service for the Dovado SMS component."""
|
||||
|
||||
def __init__(self, client):
|
||||
"""Initialize the service."""
|
||||
self._client = client
|
||||
|
||||
@override
|
||||
def send_message(self, message: str, **kwargs: Any) -> None:
|
||||
"""Send SMS to the specified target phone number."""
|
||||
if not (target := kwargs.get(ATTR_TARGET)):
|
||||
_LOGGER.error("One target is required")
|
||||
return
|
||||
|
||||
self._client.send_sms(target, message)
|
||||
@@ -1,5 +0,0 @@
|
||||
extend = "../../../pyproject.toml"
|
||||
|
||||
lint.extend-ignore = [
|
||||
"F821"
|
||||
]
|
||||
@@ -1,143 +0,0 @@
|
||||
"""Support for sensors from the Dovado router."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
import re
|
||||
from typing import Any, override
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
)
|
||||
from homeassistant.const import CONF_SENSORS, PERCENTAGE, UnitOfInformation
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from . import DOMAIN
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
|
||||
|
||||
SENSOR_UPLOAD = "upload"
|
||||
SENSOR_DOWNLOAD = "download"
|
||||
SENSOR_SIGNAL = "signal"
|
||||
SENSOR_NETWORK = "network"
|
||||
SENSOR_SMS_UNREAD = "sms"
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class DovadoSensorEntityDescription(SensorEntityDescription):
|
||||
"""Describes Dovado sensor entity."""
|
||||
|
||||
identifier: str
|
||||
|
||||
|
||||
SENSOR_TYPES: tuple[DovadoSensorEntityDescription, ...] = (
|
||||
DovadoSensorEntityDescription(
|
||||
identifier=SENSOR_NETWORK,
|
||||
key="signal strength",
|
||||
name="Network",
|
||||
icon="mdi:access-point-network",
|
||||
),
|
||||
DovadoSensorEntityDescription(
|
||||
identifier=SENSOR_SIGNAL,
|
||||
key="signal strength",
|
||||
name="Signal Strength",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
icon="mdi:signal",
|
||||
),
|
||||
DovadoSensorEntityDescription(
|
||||
identifier=SENSOR_SMS_UNREAD,
|
||||
key="sms unread",
|
||||
name="SMS unread",
|
||||
icon="mdi:message-text-outline",
|
||||
),
|
||||
DovadoSensorEntityDescription(
|
||||
identifier=SENSOR_UPLOAD,
|
||||
key="traffic modem tx",
|
||||
name="Sent",
|
||||
native_unit_of_measurement=UnitOfInformation.GIGABYTES,
|
||||
device_class=SensorDeviceClass.DATA_SIZE,
|
||||
icon="mdi:cloud-upload",
|
||||
),
|
||||
DovadoSensorEntityDescription(
|
||||
identifier=SENSOR_DOWNLOAD,
|
||||
key="traffic modem rx",
|
||||
name="Received",
|
||||
native_unit_of_measurement=UnitOfInformation.GIGABYTES,
|
||||
device_class=SensorDeviceClass.DATA_SIZE,
|
||||
icon="mdi:cloud-download",
|
||||
),
|
||||
)
|
||||
|
||||
SENSOR_KEYS: list[str] = [desc.key for desc in SENSOR_TYPES]
|
||||
|
||||
PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
|
||||
{vol.Required(CONF_SENSORS): vol.All(cv.ensure_list, [vol.In(SENSOR_KEYS)])}
|
||||
)
|
||||
|
||||
|
||||
def setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Dovado sensor platform."""
|
||||
dovado = hass.data[DOMAIN]
|
||||
|
||||
sensors = config[CONF_SENSORS]
|
||||
entities = [
|
||||
DovadoSensor(dovado, description)
|
||||
for description in SENSOR_TYPES
|
||||
if description.key in sensors
|
||||
]
|
||||
add_entities(entities)
|
||||
|
||||
|
||||
class DovadoSensor(SensorEntity):
|
||||
"""Representation of a Dovado sensor."""
|
||||
|
||||
entity_description: DovadoSensorEntityDescription
|
||||
|
||||
def __init__(self, data, description: DovadoSensorEntityDescription) -> None:
|
||||
"""Initialize the sensor."""
|
||||
self.entity_description = description
|
||||
self._data = data
|
||||
|
||||
self._attr_name = f"{data.name} {description.name}"
|
||||
self._attr_native_value = self._compute_state()
|
||||
|
||||
def _compute_state(self):
|
||||
"""Compute the state of the sensor."""
|
||||
state = self._data.state.get(self.entity_description.key)
|
||||
sensor_identifier = self.entity_description.identifier
|
||||
if sensor_identifier == SENSOR_NETWORK:
|
||||
match = re.search(r"\((.+)\)", state)
|
||||
return match.group(1) if match else None
|
||||
if sensor_identifier == SENSOR_SIGNAL:
|
||||
try:
|
||||
return int(state.split()[0])
|
||||
except ValueError:
|
||||
return None
|
||||
if sensor_identifier == SENSOR_SMS_UNREAD:
|
||||
return int(state)
|
||||
if sensor_identifier in [SENSOR_UPLOAD, SENSOR_DOWNLOAD]:
|
||||
return round(float(state) / 1e6, 1)
|
||||
return state
|
||||
|
||||
def update(self) -> None:
|
||||
"""Update sensor values."""
|
||||
self._data.update()
|
||||
self._attr_native_value = self._compute_state()
|
||||
|
||||
@property
|
||||
@override
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes."""
|
||||
return {k: v for k, v in self._data.state.items() if k not in ["date", "time"]}
|
||||
@@ -12,11 +12,10 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
TEMPERATURE,
|
||||
EntityCategory,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolume,
|
||||
UnitOfVolumeFlowRate,
|
||||
@@ -141,7 +140,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=BATTERY,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
suggested_display_precision=0,
|
||||
value_fn=lambda device: device.drop_api.battery(),
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
@@ -158,7 +157,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=INLET_TDS,
|
||||
translation_key=INLET_TDS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
value_fn=lambda device: device.drop_api.inlet_tds(),
|
||||
@@ -166,7 +165,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=OUTLET_TDS,
|
||||
translation_key=OUTLET_TDS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=0,
|
||||
value_fn=lambda device: device.drop_api.outlet_tds(),
|
||||
@@ -174,7 +173,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=CARTRIDGE_1_LIFE,
|
||||
translation_key=CARTRIDGE_1_LIFE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=0,
|
||||
@@ -183,7 +182,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=CARTRIDGE_2_LIFE,
|
||||
translation_key=CARTRIDGE_2_LIFE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=0,
|
||||
@@ -192,7 +191,7 @@ SENSORS: list[DROPSensorEntityDescription] = [
|
||||
DROPSensorEntityDescription(
|
||||
key=CARTRIDGE_3_LIFE,
|
||||
translation_key=CARTRIDGE_3_LIFE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=0,
|
||||
|
||||
@@ -2,9 +2,23 @@
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from duco_connectivity.models import NodeType
|
||||
|
||||
from homeassistant.const import Platform
|
||||
|
||||
DOMAIN = "duco"
|
||||
PLATFORMS = [Platform.FAN, Platform.SELECT, Platform.SENSOR]
|
||||
SCAN_INTERVAL = timedelta(seconds=10)
|
||||
BOX_NODE_ID = 1
|
||||
VENTILATION_CAPABLE_NODE_TYPES: tuple[NodeType, ...] = (
|
||||
NodeType.BOX,
|
||||
NodeType.VLV,
|
||||
NodeType.VLVRH,
|
||||
NodeType.VLVVOC,
|
||||
NodeType.VLVCO2,
|
||||
NodeType.VLVCO2RH,
|
||||
NodeType.EAV,
|
||||
NodeType.EAVRH,
|
||||
NodeType.EAVVOC,
|
||||
NodeType.EAVCO2,
|
||||
)
|
||||
|
||||
@@ -10,7 +10,6 @@ from duco_connectivity import (
|
||||
KnownActionName,
|
||||
Node,
|
||||
NodeListActionItemList,
|
||||
NodeType,
|
||||
VentilationState,
|
||||
)
|
||||
|
||||
@@ -19,7 +18,7 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .const import DOMAIN, VENTILATION_CAPABLE_NODE_TYPES
|
||||
from .coordinator import DucoConfigEntry, DucoCoordinator
|
||||
from .entity import DucoEntity
|
||||
|
||||
@@ -71,7 +70,9 @@ async def async_setup_entry(
|
||||
if node.node_id in known_nodes:
|
||||
continue
|
||||
|
||||
if node.general.node_type is not NodeType.BOX:
|
||||
# Duco advertises SetVentilationState broadly, so keep the select
|
||||
# limited to the box and known valve node families.
|
||||
if node.general.node_type not in VENTILATION_CAPABLE_NODE_TYPES:
|
||||
continue
|
||||
|
||||
options = options_by_node.get(node.node_id)
|
||||
|
||||
@@ -25,7 +25,7 @@ from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import BOX_NODE_ID, DOMAIN
|
||||
from .const import BOX_NODE_ID, DOMAIN, VENTILATION_CAPABLE_NODE_TYPES
|
||||
from .coordinator import DucoConfigEntry, DucoCoordinator
|
||||
from .entity import DucoEntity
|
||||
|
||||
@@ -65,7 +65,7 @@ SENSOR_DESCRIPTIONS: tuple[DucoSensorEntityDescription, ...] = (
|
||||
if node.ventilation and node.ventilation.state != VentilationState.UNKNOWN
|
||||
else None
|
||||
),
|
||||
node_types=(NodeType.BOX,),
|
||||
node_types=VENTILATION_CAPABLE_NODE_TYPES,
|
||||
),
|
||||
DucoSensorEntityDescription(
|
||||
key="target_flow_level",
|
||||
@@ -76,7 +76,7 @@ SENSOR_DESCRIPTIONS: tuple[DucoSensorEntityDescription, ...] = (
|
||||
value_fn=lambda node: (
|
||||
node.ventilation.flow_lvl_tgt if node.ventilation else None
|
||||
),
|
||||
node_types=(NodeType.BOX,),
|
||||
node_types=VENTILATION_CAPABLE_NODE_TYPES,
|
||||
),
|
||||
DucoSensorEntityDescription(
|
||||
key="time_state_end",
|
||||
@@ -89,7 +89,7 @@ SENSOR_DESCRIPTIONS: tuple[DucoSensorEntityDescription, ...] = (
|
||||
if node.ventilation and node.ventilation.time_state_end != 0
|
||||
else None
|
||||
),
|
||||
node_types=(NodeType.BOX,),
|
||||
node_types=VENTILATION_CAPABLE_NODE_TYPES,
|
||||
),
|
||||
DucoSensorEntityDescription(
|
||||
key="co2",
|
||||
|
||||
@@ -11,12 +11,7 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.const import UnitOfDensity, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -42,14 +37,14 @@ SENSOR_TYPES: tuple[EcobeeSensorEntityDescription, ...] = (
|
||||
),
|
||||
EcobeeSensorEntityDescription(
|
||||
key="humidity",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
runtime_key=None,
|
||||
),
|
||||
EcobeeSensorEntityDescription(
|
||||
key="co2PPM",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
runtime_key="actualCO2",
|
||||
@@ -57,7 +52,7 @@ SENSOR_TYPES: tuple[EcobeeSensorEntityDescription, ...] = (
|
||||
EcobeeSensorEntityDescription(
|
||||
key="vocPPM",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
runtime_key="actualVOC",
|
||||
),
|
||||
|
||||
@@ -14,18 +14,17 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
DEGREE,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
UV_INDEX,
|
||||
EntityCategory,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfIrradiance,
|
||||
UnitOfLength,
|
||||
UnitOfPrecipitationDepth,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolumetricFlux,
|
||||
@@ -99,7 +98,7 @@ ECOWITT_SENSORS_MAPPING: Final = {
|
||||
EcoWittSensorTypes.HUMIDITY: SensorEntityDescription(
|
||||
key="HUMIDITY",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
EcoWittSensorTypes.DEGREE: SensorEntityDescription(
|
||||
@@ -122,19 +121,19 @@ ECOWITT_SENSORS_MAPPING: Final = {
|
||||
EcoWittSensorTypes.PM25: SensorEntityDescription(
|
||||
key="PM25",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
EcoWittSensorTypes.PM10: SensorEntityDescription(
|
||||
key="PM10",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
EcoWittSensorTypes.BATTERY_PERCENTAGE: SensorEntityDescription(
|
||||
key="BATTERY_PERCENTAGE",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
@@ -149,7 +148,7 @@ ECOWITT_SENSORS_MAPPING: Final = {
|
||||
EcoWittSensorTypes.CO2_PPM: SensorEntityDescription(
|
||||
key="CO2_PPM",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
EcoWittSensorTypes.LUX: SensorEntityDescription(
|
||||
@@ -263,13 +262,13 @@ ECOWITT_SENSORS_MAPPING: Final = {
|
||||
),
|
||||
EcoWittSensorTypes.PERCENTAGE: SensorEntityDescription(
|
||||
key="PERCENTAGE",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
EcoWittSensorTypes.SOIL_MOISTURE: SensorEntityDescription(
|
||||
key="SOIL_MOISTURE",
|
||||
device_class=SensorDeviceClass.MOISTURE,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
EcoWittSensorTypes.DISTANCE_MM: SensorEntityDescription(
|
||||
@@ -286,13 +285,13 @@ ECOWITT_SENSORS_MAPPING: Final = {
|
||||
EcoWittSensorTypes.PM1: SensorEntityDescription(
|
||||
key="PM1",
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
EcoWittSensorTypes.PM4: SensorEntityDescription(
|
||||
key="PM4",
|
||||
device_class=SensorDeviceClass.PM4,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -9,17 +9,16 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_URL,
|
||||
PERCENTAGE,
|
||||
UnitOfApparentPower,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
UnitOfFrequency,
|
||||
UnitOfPower,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
@@ -158,19 +157,19 @@ SENSORS: dict[str | None, SensorEntityDescription] = {
|
||||
"μg/m³": SensorEntityDescription(
|
||||
key="concentration|microgram_per_cubic_meter",
|
||||
translation_key="concentration",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"ppm": SensorEntityDescription(
|
||||
key="concentration|microgram_parts_per_million",
|
||||
translation_key="concentration",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"%": SensorEntityDescription(
|
||||
key="percent",
|
||||
translation_key="percent",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -65,6 +65,14 @@ async def _get_fixture_collection(envoy: Envoy, serial: str) -> dict[str, Any]:
|
||||
"/ivp/meters/readings",
|
||||
"/ivp/pdm/device_data",
|
||||
"/home",
|
||||
"/inventory.json?deleted=1",
|
||||
"/admin/lib/acb_config",
|
||||
"/ivp/sc/sched",
|
||||
"/admin/lib/network_display",
|
||||
"/admin/lib/wireless_display",
|
||||
"/ivp/ensemble/relay",
|
||||
"/ivp/livedata/status",
|
||||
"/ivp/pdm/energy",
|
||||
]
|
||||
|
||||
for end_point in end_points:
|
||||
@@ -134,16 +142,15 @@ async def async_get_config_entry_diagnostics(
|
||||
"encharge_power": envoy_data.encharge_power,
|
||||
"encharge_aggregate": envoy_data.encharge_aggregate,
|
||||
"enpower": envoy_data.enpower,
|
||||
"acb_power": envoy_data.acb_power,
|
||||
"acb_inventory": envoy_data.acb_inventory,
|
||||
"battery_aggregate": envoy_data.battery_aggregate,
|
||||
"collar": envoy_data.collar,
|
||||
"c6cc": envoy_data.c6cc,
|
||||
"system_consumption": envoy_data.system_consumption,
|
||||
"system_production": envoy_data.system_production,
|
||||
"system_consumption_phases": envoy_data.system_consumption_phases,
|
||||
"system_production_phases": envoy_data.system_production_phases,
|
||||
"ctmeter_production": envoy_data.ctmeter_production,
|
||||
"ctmeter_consumption": envoy_data.ctmeter_consumption,
|
||||
"ctmeter_storage": envoy_data.ctmeter_storage,
|
||||
"ctmeter_production_phases": envoy_data.ctmeter_production_phases,
|
||||
"ctmeter_consumption_phases": envoy_data.ctmeter_consumption_phases,
|
||||
"ctmeter_storage_phases": envoy_data.ctmeter_storage_phases,
|
||||
"ctmeters": envoy_data.ctmeters,
|
||||
"ctmeters_phases": envoy_data.ctmeters_phases,
|
||||
"dry_contact_status": envoy_data.dry_contact_status,
|
||||
|
||||
@@ -8,12 +8,7 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.const import UnitOfPressure, UnitOfRatio, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -26,7 +21,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
key="co2",
|
||||
suggested_display_precision=0,
|
||||
),
|
||||
@@ -40,7 +35,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
key="humidity",
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"mqtt": ["esphome/discover/#"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": [
|
||||
"aioesphomeapi==45.3.1",
|
||||
"aioesphomeapi==45.5.2",
|
||||
"esphome-dashboard-api==1.3.0",
|
||||
"bleak-esphome==3.9.4"
|
||||
],
|
||||
|
||||
@@ -13,12 +13,11 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
Platform,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -39,20 +38,20 @@ MAIN_SENSOR_TYPES: dict[str, SensorEntityDescription] = {
|
||||
"com.fibaro.smokeSensor": SensorEntityDescription(
|
||||
key="com.fibaro.smokeSensor",
|
||||
name="Smoke",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
icon="mdi:fire",
|
||||
),
|
||||
"CO2": SensorEntityDescription(
|
||||
key="CO2",
|
||||
name="CO2",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"com.fibaro.humiditySensor": SensorEntityDescription(
|
||||
key="com.fibaro.humiditySensor",
|
||||
name="Humidity",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -16,12 +16,10 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_TEMPERATURE,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_TOKEN,
|
||||
CONF_USERNAME,
|
||||
PERCENTAGE,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -44,7 +42,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="pm",
|
||||
name=ATTR_PM2_5,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
icon="mdi:cloud",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
@@ -56,25 +54,25 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="hum",
|
||||
name=ATTR_HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
icon="mdi:water-percent",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="co2",
|
||||
name=ATTR_CARBON_DIOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
icon="mdi:molecule-co2",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="voc",
|
||||
name=ATTR_VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_BILLION,
|
||||
icon="mdi:cloud",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="allpollu",
|
||||
name=ATTR_FOOBOT_INDEX,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
icon="mdi:percent",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -126,6 +126,8 @@ class FreeboxRouter:
|
||||
self.raids: dict[int, dict[str, Any]] = {}
|
||||
self.sensors_temperature: dict[str, int] = {}
|
||||
self.sensors_temperature_names: dict[str, str] = {}
|
||||
self.sensors_fan: dict[str, int] = {}
|
||||
self.sensors_fan_names: dict[str, str] = {}
|
||||
self.sensors_connection: dict[str, float] = {}
|
||||
self.call_list: list[dict[str, Any]] = []
|
||||
self.home_granted = True
|
||||
@@ -190,6 +192,12 @@ class FreeboxRouter:
|
||||
self.sensors_temperature[sensor_id] = sensor.get("value")
|
||||
self.sensors_temperature_names[sensor_id] = sensor["name"]
|
||||
|
||||
# Fan speed sensors (rpm). Name and id may vary under Freebox devices.
|
||||
for fan in syst_datas.get("fans", []):
|
||||
fan_id = fan["id"]
|
||||
self.sensors_fan[fan_id] = fan.get("value")
|
||||
self.sensors_fan_names[fan_id] = fan["name"]
|
||||
|
||||
# Connection sensors
|
||||
connection_datas: dict[str, Any] = await self._api.connection.get_status()
|
||||
for sensor_key in CONNECTION_SENSORS_KEYS:
|
||||
@@ -321,7 +329,11 @@ class FreeboxRouter:
|
||||
@property
|
||||
def sensors(self) -> dict[str, Any]:
|
||||
"""Return sensors."""
|
||||
return {**self.sensors_temperature, **self.sensors_connection}
|
||||
return {
|
||||
**self.sensors_temperature,
|
||||
**self.sensors_fan,
|
||||
**self.sensors_connection,
|
||||
}
|
||||
|
||||
@property
|
||||
def call(self) -> Call:
|
||||
|
||||
@@ -11,6 +11,7 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.const import (
|
||||
PERCENTAGE,
|
||||
REVOLUTIONS_PER_MINUTE,
|
||||
EntityCategory,
|
||||
UnitOfDataRate,
|
||||
UnitOfTemperature,
|
||||
@@ -93,6 +94,27 @@ async def async_setup_entry(
|
||||
for sensor_id, sensor_name in router.sensors_temperature_names.items()
|
||||
]
|
||||
|
||||
_LOGGER.debug(
|
||||
"%s - %s - %s fan sensors",
|
||||
router.name,
|
||||
router.mac,
|
||||
len(router.sensors_fan_names),
|
||||
)
|
||||
entities.extend(
|
||||
FreeboxSensor(
|
||||
router,
|
||||
SensorEntityDescription(
|
||||
key=fan_id,
|
||||
name=fan_name,
|
||||
native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
icon="mdi:fan",
|
||||
),
|
||||
)
|
||||
for fan_id, fan_name in router.sensors_fan_names.items()
|
||||
)
|
||||
|
||||
entities.extend(
|
||||
[FreeboxSensor(router, description) for description in CONNECTION_SENSORS]
|
||||
)
|
||||
|
||||
@@ -13,12 +13,7 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
StateType,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolumeFlowRate,
|
||||
)
|
||||
from homeassistant.const import UnitOfRatio, UnitOfTemperature, UnitOfVolumeFlowRate
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -54,14 +49,14 @@ _T2 = FreshrSensorEntityDescription(
|
||||
_CO2 = FreshrSensorEntityDescription(
|
||||
key="co2",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda r: r.co2,
|
||||
)
|
||||
_HUM = FreshrSensorEntityDescription(
|
||||
key="hum",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda r: r.hum,
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ from homeassistant.components.button import (
|
||||
ButtonEntity,
|
||||
ButtonEntityDescription,
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.const import EntityCategory, Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
|
||||
@@ -75,7 +75,7 @@ def repair_issue_cleanup(hass: HomeAssistant, avm_wrapper: AvmWrapper) -> None:
|
||||
if (
|
||||
(
|
||||
entity_button := entity_registry.async_get_entity_id(
|
||||
"button", DOMAIN, f"{avm_wrapper.unique_id}-cleanup"
|
||||
Platform.BUTTON, DOMAIN, f"{avm_wrapper.unique_id}-cleanup"
|
||||
)
|
||||
)
|
||||
and (entity_entry := entity_registry.async_get(entity_button))
|
||||
@@ -102,7 +102,7 @@ def repair_issue_firmware_update(hass: HomeAssistant, avm_wrapper: AvmWrapper) -
|
||||
if (
|
||||
(
|
||||
entity_button := entity_registry.async_get_entity_id(
|
||||
"button", DOMAIN, f"{avm_wrapper.unique_id}-firmware_update"
|
||||
Platform.BUTTON, DOMAIN, f"{avm_wrapper.unique_id}-firmware_update"
|
||||
)
|
||||
)
|
||||
and (entity_entry := entity_registry.async_get(entity_button))
|
||||
|
||||
@@ -7,13 +7,13 @@ from typing import override
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
from homeassistant.components.image import ImageEntity
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.const import EntityCategory, Platform
|
||||
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 .const import DOMAIN
|
||||
from .coordinator import AvmWrapper, FritzConfigEntry
|
||||
from .entity import FritzBoxBaseEntity
|
||||
|
||||
|
||||
@@ -21,5 +21,5 @@
|
||||
"integration_type": "system",
|
||||
"preview_features": { "winter_mode": {} },
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["home-assistant-frontend==20260624.0"]
|
||||
"requirements": ["home-assistant-frontend==20260624.1"]
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
|
||||
from homeassistant.const import UnitOfDensity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -63,7 +63,7 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
|
||||
key=ATTR_C6H6,
|
||||
value=lambda sensors: sensors.c6h6.value if sensors.c6h6 else None,
|
||||
suggested_display_precision=0,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key="c6h6",
|
||||
),
|
||||
@@ -72,7 +72,7 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
|
||||
value=lambda sensors: sensors.co.value if sensors.co else None,
|
||||
suggested_display_precision=0,
|
||||
device_class=SensorDeviceClass.CO,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
GiosSensorEntityDescription(
|
||||
@@ -80,7 +80,7 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
|
||||
value=lambda sensors: sensors.no.value if sensors.no else None,
|
||||
suggested_display_precision=0,
|
||||
device_class=SensorDeviceClass.NITROGEN_MONOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
GiosSensorEntityDescription(
|
||||
@@ -88,7 +88,7 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
|
||||
value=lambda sensors: sensors.no2.value if sensors.no2 else None,
|
||||
suggested_display_precision=0,
|
||||
device_class=SensorDeviceClass.NITROGEN_DIOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
GiosSensorEntityDescription(
|
||||
@@ -104,7 +104,7 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
|
||||
translation_key=ATTR_NOX,
|
||||
value=lambda sensors: sensors.nox.value if sensors.nox else None,
|
||||
suggested_display_precision=0,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
GiosSensorEntityDescription(
|
||||
@@ -112,7 +112,7 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
|
||||
value=lambda sensors: sensors.o3.value if sensors.o3 else None,
|
||||
suggested_display_precision=0,
|
||||
device_class=SensorDeviceClass.OZONE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
GiosSensorEntityDescription(
|
||||
@@ -128,7 +128,7 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
|
||||
value=lambda sensors: sensors.pm10.value if sensors.pm10 else None,
|
||||
suggested_display_precision=0,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
GiosSensorEntityDescription(
|
||||
@@ -144,7 +144,7 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
|
||||
value=lambda sensors: sensors.pm25.value if sensors.pm25 else None,
|
||||
suggested_display_precision=0,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
GiosSensorEntityDescription(
|
||||
@@ -160,7 +160,7 @@ SENSOR_TYPES: tuple[GiosSensorEntityDescription, ...] = (
|
||||
value=lambda sensors: sensors.so2.value if sensors.so2 else None,
|
||||
suggested_display_precision=0,
|
||||
device_class=SensorDeviceClass.SULPHUR_DIOXIDE,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
GiosSensorEntityDescription(
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"integration_type": "service",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["googleapiclient"],
|
||||
"requirements": ["gcal-sync==8.0.0", "oauth2client==4.1.3", "ical==13.2.5"]
|
||||
"requirements": ["gcal-sync==8.0.0", "oauth2client==4.1.3", "ical==13.3.0"]
|
||||
}
|
||||
|
||||
@@ -14,11 +14,7 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigSubentry
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
)
|
||||
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, UnitOfRatio
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -125,7 +121,7 @@ AIR_QUALITY_SENSOR_TYPES: tuple[AirQualitySensorEntityDescription, ...] = (
|
||||
native_unit_of_measurement_fn=lambda x: x.pollutants.co.concentration.units,
|
||||
exists_fn=lambda x: "co" in {p.code for p in x.pollutants},
|
||||
value_fn=lambda x: x.pollutants.co.concentration.value,
|
||||
suggested_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
suggested_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
),
|
||||
AirQualitySensorEntityDescription(
|
||||
key="nh3",
|
||||
|
||||
@@ -19,10 +19,9 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
UnitOfDensity,
|
||||
UnitOfRatio,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -44,13 +43,13 @@ SENSOR_DESCRIPTIONS = {
|
||||
(DeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{DeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(DeviceClass.BATTERY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{DeviceClass.BATTERY}_{Units.PERCENTAGE}",
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(
|
||||
@@ -69,13 +68,13 @@ SENSOR_DESCRIPTIONS = {
|
||||
): SensorEntityDescription(
|
||||
key=f"{DeviceClass.PM25}_{Units.CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
(DeviceClass.CO2, Units.CONCENTRATION_PARTS_PER_MILLION): SensorEntityDescription(
|
||||
key=f"{DeviceClass.CO2}_{Units.CONCENTRATION_PARTS_PER_MILLION}",
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""The greenwave component."""
|
||||
@@ -1,123 +0,0 @@
|
||||
"""Support for Greenwave Reality (TCP Connected) lights."""
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, override
|
||||
|
||||
import greenwavereality as greenwave
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
PLATFORM_SCHEMA as LIGHT_PLATFORM_SCHEMA,
|
||||
ColorMode,
|
||||
LightEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_HOST
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_VERSION = "version"
|
||||
|
||||
PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA.extend(
|
||||
{vol.Required(CONF_HOST): cv.string, vol.Required(CONF_VERSION): cv.positive_int}
|
||||
)
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1)
|
||||
|
||||
|
||||
def setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Greenwave Reality Platform."""
|
||||
host = config.get(CONF_HOST)
|
||||
tokenfilename = hass.config.path(".greenwave")
|
||||
if config.get(CONF_VERSION) == 3:
|
||||
if os.path.exists(tokenfilename):
|
||||
with open(tokenfilename, encoding="utf8") as tokenfile:
|
||||
token = tokenfile.read()
|
||||
else:
|
||||
try:
|
||||
token = greenwave.grab_token(host, "hass", "homeassistant")
|
||||
except PermissionError:
|
||||
_LOGGER.error("The Gateway Is Not In Sync Mode")
|
||||
raise
|
||||
with open(tokenfilename, "w+", encoding="utf8") as tokenfile:
|
||||
tokenfile.write(token)
|
||||
else:
|
||||
token = None
|
||||
bulbs = greenwave.grab_bulbs(host, token)
|
||||
add_entities(
|
||||
GreenwaveLight(device, host, token, GatewayData(host, token))
|
||||
for device in bulbs.values()
|
||||
)
|
||||
|
||||
|
||||
class GreenwaveLight(LightEntity):
|
||||
"""Representation of an Greenwave Reality Light."""
|
||||
|
||||
_attr_color_mode = ColorMode.BRIGHTNESS
|
||||
_attr_supported_color_modes = {ColorMode.BRIGHTNESS}
|
||||
|
||||
def __init__(self, light, host, token, gatewaydata):
|
||||
"""Initialize a Greenwave Reality Light."""
|
||||
self._did = int(light["did"])
|
||||
self._attr_name = light["name"]
|
||||
self._attr_is_on = bool(int(light["state"]))
|
||||
self._attr_brightness = greenwave.hass_brightness(light)
|
||||
self._host = host
|
||||
self._attr_available = greenwave.check_online(light)
|
||||
self._token = token
|
||||
self._gatewaydata = gatewaydata
|
||||
|
||||
@override
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Instruct the light to turn on."""
|
||||
temp_brightness = int((kwargs.get(ATTR_BRIGHTNESS, 255) / 255) * 100)
|
||||
greenwave.set_brightness(self._host, self._did, temp_brightness, self._token)
|
||||
greenwave.turn_on(self._host, self._did, self._token)
|
||||
|
||||
@override
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Instruct the light to turn off."""
|
||||
greenwave.turn_off(self._host, self._did, self._token)
|
||||
|
||||
def update(self) -> None:
|
||||
"""Fetch new state data for this light."""
|
||||
self._gatewaydata.update()
|
||||
bulbs = self._gatewaydata.greenwave
|
||||
|
||||
self._attr_is_on = bool(int(bulbs[self._did]["state"]))
|
||||
self._attr_brightness = greenwave.hass_brightness(bulbs[self._did])
|
||||
self._attr_available = greenwave.check_online(bulbs[self._did])
|
||||
self._attr_name = bulbs[self._did]["name"]
|
||||
|
||||
|
||||
class GatewayData:
|
||||
"""Handle Gateway data and limit updates."""
|
||||
|
||||
def __init__(self, host, token):
|
||||
"""Initialize the data object."""
|
||||
self._host = host
|
||||
self._token = token
|
||||
self._greenwave = greenwave.grab_bulbs(host, token)
|
||||
|
||||
@property
|
||||
def greenwave(self):
|
||||
"""Return Gateway API object."""
|
||||
return self._greenwave
|
||||
|
||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||
def update(self):
|
||||
"""Get the latest data from the gateway."""
|
||||
self._greenwave = greenwave.grab_bulbs(self._host, self._token)
|
||||
return self._greenwave
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"domain": "greenwave",
|
||||
"name": "Greenwave Reality",
|
||||
"codeowners": [],
|
||||
"documentation": "https://www.home-assistant.io/integrations/greenwave",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["greenwavereality"],
|
||||
"quality_scale": "legacy",
|
||||
"requirements": ["greenwavereality==0.5.1"]
|
||||
}
|
||||
@@ -92,7 +92,7 @@ class SupervisorJobs:
|
||||
# We catch all errors to prevent an error in one from stopping the others
|
||||
for match in [job for job in self._jobs.values() if subscription.matches(job)]:
|
||||
try:
|
||||
return subscription.event_callback(match)
|
||||
subscription.event_callback(match)
|
||||
except Exception as err: # noqa: BLE001
|
||||
_LOGGER.error(
|
||||
"Error encountered processing Supervisor Job (%s %s %s) - %s",
|
||||
|
||||
@@ -20,7 +20,7 @@ from .const import (
|
||||
CONF_MIN_STATE_DURATION,
|
||||
CONF_START,
|
||||
PLATFORMS,
|
||||
SECTION_ADVANCED_SETTINGS,
|
||||
SECTION_ADDITIONAL_SETTINGS,
|
||||
)
|
||||
from .coordinator import HistoryStatsUpdateCoordinator
|
||||
from .data import HistoryStats
|
||||
@@ -44,8 +44,8 @@ async def async_setup_entry(
|
||||
min_state_duration: timedelta
|
||||
if duration_dict := entry.options.get(CONF_DURATION):
|
||||
duration = timedelta(**duration_dict)
|
||||
advanced_settings = entry.options.get(SECTION_ADVANCED_SETTINGS, {})
|
||||
if min_state_duration_dict := advanced_settings.get(CONF_MIN_STATE_DURATION):
|
||||
additional_settings = entry.options.get(SECTION_ADDITIONAL_SETTINGS, {})
|
||||
if min_state_duration_dict := additional_settings.get(CONF_MIN_STATE_DURATION):
|
||||
min_state_duration = timedelta(**min_state_duration_dict)
|
||||
else:
|
||||
min_state_duration = timedelta(0)
|
||||
@@ -121,6 +121,13 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry, options=options, minor_version=3
|
||||
)
|
||||
if config_entry.minor_version < 4:
|
||||
# The "advanced_settings" section was renamed to "additional_settings"
|
||||
if (additional := options.pop("advanced_settings", None)) is not None:
|
||||
options[SECTION_ADDITIONAL_SETTINGS] = additional
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry, options=options, minor_version=4
|
||||
)
|
||||
|
||||
_LOGGER.debug(
|
||||
"Migration to version %s.%s successful",
|
||||
|
||||
@@ -44,7 +44,7 @@ from .const import (
|
||||
CONF_TYPE_TIME,
|
||||
DEFAULT_NAME,
|
||||
DOMAIN,
|
||||
SECTION_ADVANCED_SETTINGS,
|
||||
SECTION_ADDITIONAL_SETTINGS,
|
||||
)
|
||||
from .coordinator import HistoryStatsUpdateCoordinator
|
||||
from .data import HistoryStats
|
||||
@@ -149,7 +149,7 @@ def _get_options_schema_with_entity_id(entity_id: str, type: str) -> vol.Schema:
|
||||
mode=SelectSelectorMode.DROPDOWN,
|
||||
),
|
||||
),
|
||||
vol.Optional(SECTION_ADVANCED_SETTINGS): section(
|
||||
vol.Optional(SECTION_ADDITIONAL_SETTINGS): section(
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_MIN_STATE_DURATION): DurationSelector(
|
||||
@@ -189,7 +189,7 @@ OPTIONS_FLOW = {
|
||||
class HistoryStatsConfigFlowHandler(SchemaConfigFlowHandler, domain=DOMAIN):
|
||||
"""Handle a config flow for History stats."""
|
||||
|
||||
MINOR_VERSION = 3
|
||||
MINOR_VERSION = 4
|
||||
|
||||
config_flow = CONFIG_FLOW
|
||||
options_flow = OPTIONS_FLOW
|
||||
@@ -290,8 +290,8 @@ async def ws_start_preview(
|
||||
start = validated_data.get(CONF_START)
|
||||
end = validated_data.get(CONF_END)
|
||||
duration = validated_data.get(CONF_DURATION)
|
||||
advanced_settings = validated_data.get(SECTION_ADVANCED_SETTINGS, {})
|
||||
min_state_duration = advanced_settings.get(CONF_MIN_STATE_DURATION)
|
||||
additional_settings = validated_data.get(SECTION_ADDITIONAL_SETTINGS, {})
|
||||
min_state_duration = additional_settings.get(CONF_MIN_STATE_DURATION)
|
||||
state_class = validated_data.get(CONF_STATE_CLASS)
|
||||
|
||||
history_stats = HistoryStats(
|
||||
|
||||
@@ -18,4 +18,4 @@ CONF_TYPE_KEYS = [CONF_TYPE_TIME, CONF_TYPE_RATIO, CONF_TYPE_COUNT]
|
||||
|
||||
DEFAULT_NAME = "unnamed statistics"
|
||||
|
||||
SECTION_ADVANCED_SETTINGS = "advanced_settings"
|
||||
SECTION_ADDITIONAL_SETTINGS = "additional_settings"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
},
|
||||
"description": "Read the documentation for further details on how to configure the history stats sensor using these options.",
|
||||
"sections": {
|
||||
"advanced_settings": {
|
||||
"additional_settings": {
|
||||
"data": { "min_state_duration": "Minimum state duration" },
|
||||
"data_description": {
|
||||
"min_state_duration": "The minimum state duration to account for the statistics. Default is 0 seconds."
|
||||
@@ -93,14 +93,14 @@
|
||||
},
|
||||
"description": "[%key:component::history_stats::config::step::options::description%]",
|
||||
"sections": {
|
||||
"advanced_settings": {
|
||||
"additional_settings": {
|
||||
"data": {
|
||||
"min_state_duration": "[%key:component::history_stats::config::step::options::sections::advanced_settings::data::min_state_duration%]"
|
||||
"min_state_duration": "[%key:component::history_stats::config::step::options::sections::additional_settings::data::min_state_duration%]"
|
||||
},
|
||||
"data_description": {
|
||||
"min_state_duration": "[%key:component::history_stats::config::step::options::sections::advanced_settings::data_description::min_state_duration%]"
|
||||
"min_state_duration": "[%key:component::history_stats::config::step::options::sections::additional_settings::data_description::min_state_duration%]"
|
||||
},
|
||||
"name": "[%key:component::history_stats::config::step::options::sections::advanced_settings::name%]"
|
||||
"name": "[%key:component::history_stats::config::step::options::sections::additional_settings::name%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfVolume
|
||||
from homeassistant.const import EntityCategory, UnitOfRatio, UnitOfVolume
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util, slugify
|
||||
@@ -67,7 +67,7 @@ BSH_PROGRAM_SENSORS = (
|
||||
),
|
||||
HomeConnectSensorEntityDescription(
|
||||
key=EventKey.BSH_COMMON_OPTION_PROGRAM_PROGRESS,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
translation_key="program_progress",
|
||||
appliance_types=APPLIANCES_WITH_PROGRAMS,
|
||||
),
|
||||
@@ -158,6 +158,7 @@ SENSORS = (
|
||||
HomeConnectSensorEntityDescription(
|
||||
key=StatusKey.BSH_COMMON_BATTERY_LEVEL,
|
||||
device_class=SensorDeviceClass.BATTERY,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
HomeConnectSensorEntityDescription(
|
||||
key=StatusKey.BSH_COMMON_VIDEO_CAMERA_STATE,
|
||||
|
||||
@@ -26,18 +26,17 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
EntityCategory,
|
||||
Platform,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSoundPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
@@ -254,7 +253,7 @@ SIMPLE_SENSOR: dict[str, HomeKitSensorEntityDescription] = {
|
||||
name="Current Humidity",
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
# This sensor is only for humidity characteristics that are not part
|
||||
# of a humidity sensor service.
|
||||
probe=(lambda char: char.service.type != ServicesTypes.HUMIDITY_SENSOR),
|
||||
@@ -270,42 +269,42 @@ SIMPLE_SENSOR: dict[str, HomeKitSensorEntityDescription] = {
|
||||
name="PM2.5 Density",
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CharacteristicsTypes.DENSITY_PM10: HomeKitSensorEntityDescription(
|
||||
key=CharacteristicsTypes.DENSITY_PM10,
|
||||
name="PM10 Density",
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CharacteristicsTypes.DENSITY_OZONE: HomeKitSensorEntityDescription(
|
||||
key=CharacteristicsTypes.DENSITY_OZONE,
|
||||
name="Ozone Density",
|
||||
device_class=SensorDeviceClass.OZONE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CharacteristicsTypes.DENSITY_NO2: HomeKitSensorEntityDescription(
|
||||
key=CharacteristicsTypes.DENSITY_NO2,
|
||||
name="Nitrogen Dioxide Density",
|
||||
device_class=SensorDeviceClass.NITROGEN_DIOXIDE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CharacteristicsTypes.DENSITY_SO2: HomeKitSensorEntityDescription(
|
||||
key=CharacteristicsTypes.DENSITY_SO2,
|
||||
name="Sulphur Dioxide Density",
|
||||
device_class=SensorDeviceClass.SULPHUR_DIOXIDE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CharacteristicsTypes.DENSITY_VOC: HomeKitSensorEntityDescription(
|
||||
key=CharacteristicsTypes.DENSITY_VOC,
|
||||
name="Volatile Organic Compound Density",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
CharacteristicsTypes.THREAD_NODE_CAPABILITIES: HomeKitSensorEntityDescription(
|
||||
key=CharacteristicsTypes.THREAD_NODE_CAPABILITIES,
|
||||
@@ -363,13 +362,13 @@ SIMPLE_SENSOR: dict[str, HomeKitSensorEntityDescription] = {
|
||||
key=CharacteristicsTypes.FILTER_LIFE_LEVEL,
|
||||
name="Filter lifetime",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
CharacteristicsTypes.WATER_LEVEL: HomeKitSensorEntityDescription(
|
||||
key=CharacteristicsTypes.WATER_LEVEL,
|
||||
name="Water level",
|
||||
translation_key="water_level",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
CharacteristicsTypes.VENDOR_EVE_THERMO_VALVE_POSITION: (
|
||||
@@ -379,7 +378,7 @@ SIMPLE_SENSOR: dict[str, HomeKitSensorEntityDescription] = {
|
||||
translation_key="valve_position",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
)
|
||||
),
|
||||
}
|
||||
@@ -409,7 +408,7 @@ class HomeKitHumiditySensor(HomeKitSensor):
|
||||
"""Representation of a Homekit humidity sensor."""
|
||||
|
||||
_attr_device_class = SensorDeviceClass.HUMIDITY
|
||||
_attr_native_unit_of_measurement = PERCENTAGE
|
||||
_attr_native_unit_of_measurement = UnitOfRatio.PERCENTAGE
|
||||
|
||||
@override
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
@@ -481,7 +480,7 @@ class HomeKitCarbonDioxideSensor(HomeKitSensor):
|
||||
"""Representation of a Homekit Carbon Dioxide sensor."""
|
||||
|
||||
_attr_device_class = SensorDeviceClass.CO2
|
||||
_attr_native_unit_of_measurement = CONCENTRATION_PARTS_PER_MILLION
|
||||
_attr_native_unit_of_measurement = UnitOfRatio.PARTS_PER_MILLION
|
||||
|
||||
@override
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
@@ -505,7 +504,7 @@ class HomeKitBatterySensor(HomeKitSensor):
|
||||
"""Representation of a Homekit battery sensor."""
|
||||
|
||||
_attr_device_class = SensorDeviceClass.BATTERY
|
||||
_attr_native_unit_of_measurement = PERCENTAGE
|
||||
_attr_native_unit_of_measurement = UnitOfRatio.PERCENTAGE
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
@override
|
||||
|
||||
@@ -12,11 +12,9 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_NAME,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
DEGREE,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
UnitOfDensity,
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
@@ -24,6 +22,7 @@ from homeassistant.const import (
|
||||
UnitOfPower,
|
||||
UnitOfPrecipitationDepth,
|
||||
UnitOfPressure,
|
||||
UnitOfRatio,
|
||||
UnitOfSpeed,
|
||||
UnitOfTemperature,
|
||||
UnitOfVolume,
|
||||
@@ -57,7 +56,7 @@ HM_STATE_HA_CAST = {
|
||||
SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
|
||||
"HUMIDITY": SensorEntityDescription(
|
||||
key="HUMIDITY",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -129,7 +128,7 @@ SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
|
||||
),
|
||||
"CONCENTRATION": SensorEntityDescription(
|
||||
key="CONCENTRATION",
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||
native_unit_of_measurement=UnitOfRatio.PARTS_PER_MILLION,
|
||||
device_class=SensorDeviceClass.CO2,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
@@ -204,15 +203,15 @@ SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
|
||||
),
|
||||
"VALVE_STATE": SensorEntityDescription(
|
||||
key="VALVE_STATE",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
"CARRIER_SENSE_LEVEL": SensorEntityDescription(
|
||||
key="CARRIER_SENSE_LEVEL",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
"DUTY_CYCLE_LEVEL": SensorEntityDescription(
|
||||
key="DUTY_CYCLE_LEVEL",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
native_unit_of_measurement=UnitOfRatio.PERCENTAGE,
|
||||
),
|
||||
"BRIGHTNESS": SensorEntityDescription(
|
||||
key="BRIGHTNESS",
|
||||
@@ -221,37 +220,37 @@ SENSOR_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_1": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_1",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_2_5": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_2_5",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_10": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_10",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_1_24H_AVERAGE": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_1_24H_AVERAGE",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM1,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_2_5_24H_AVERAGE": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_2_5_24H_AVERAGE",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM25,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"MASS_CONCENTRATION_PM_10_24H_AVERAGE": SensorEntityDescription(
|
||||
key="MASS_CONCENTRATION_PM_10_24H_AVERAGE",
|
||||
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
native_unit_of_measurement=UnitOfDensity.MICROGRAMS_PER_CUBIC_METER,
|
||||
device_class=SensorDeviceClass.PM10,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user