mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-07-28 17:46:49 +00:00
Compare commits
No commits in common. "91147bd79c4245c9d7c61d1c620e240fdc330fb3" and "9efa7809d02ea274727f49acff88df765d7fc83a" have entirely different histories.
91147bd79c
...
9efa7809d0
21 changed files with 595 additions and 892 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "jpawlowski/hass.tibber_prices",
|
"name": "jpawlowski/hass.tibber_prices",
|
||||||
"image": "mcr.microsoft.com/devcontainers/base:debian",
|
"image": "mcr.microsoft.com/devcontainers/python:3.14",
|
||||||
"postCreateCommand": "bash .devcontainer/setup-git.sh && scripts/setup/setup",
|
"postCreateCommand": "bash .devcontainer/setup-git.sh && scripts/setup/setup",
|
||||||
"postStartCommand": "scripts/motd",
|
"postStartCommand": "scripts/motd",
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
|
|
@ -63,7 +63,9 @@
|
||||||
"**/node_modules/**"
|
"**/node_modules/**"
|
||||||
],
|
],
|
||||||
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
|
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
|
||||||
"python.analysis.extraPaths": ["${workspaceFolder}/.venv/lib/python3.14/site-packages"],
|
"python.analysis.extraPaths": [
|
||||||
|
"${workspaceFolder}/.venv/lib/python3.14/site-packages"
|
||||||
|
],
|
||||||
"python.terminal.activateEnvironment": true,
|
"python.terminal.activateEnvironment": true,
|
||||||
"python.terminal.activateEnvInCurrentTerminal": true,
|
"python.terminal.activateEnvInCurrentTerminal": true,
|
||||||
"python.testing.pytestArgs": ["--no-cov"],
|
"python.testing.pytestArgs": ["--no-cov"],
|
||||||
|
|
@ -140,8 +142,6 @@
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers-extra/features/apt-packages:1": {
|
"ghcr.io/devcontainers-extra/features/apt-packages:1": {
|
||||||
"packages": [
|
"packages": [
|
||||||
"autoconf",
|
|
||||||
"automake",
|
|
||||||
"bat",
|
"bat",
|
||||||
"eza",
|
"eza",
|
||||||
"fd-find",
|
"fd-find",
|
||||||
|
|
@ -154,12 +154,9 @@
|
||||||
"jo",
|
"jo",
|
||||||
"jq",
|
"jq",
|
||||||
"libpcap-dev",
|
"libpcap-dev",
|
||||||
"libssl-dev",
|
|
||||||
"libtool",
|
|
||||||
"libturbojpeg0",
|
"libturbojpeg0",
|
||||||
"miller",
|
"miller",
|
||||||
"moreutils",
|
"moreutils",
|
||||||
"pipx",
|
|
||||||
"ripgrep",
|
"ripgrep",
|
||||||
"shellcheck",
|
"shellcheck",
|
||||||
"shfmt",
|
"shfmt",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
# top-most EditorConfig file
|
# top-most EditorConfig file
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
# Default settings - AI-friendly baseline
|
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
|
|
@ -10,71 +9,12 @@ trim_trailing_whitespace = true
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
# Python - Home Assistant & Ruff defaults (120 chars)
|
|
||||||
[*.py]
|
[*.py]
|
||||||
|
# Python style aligns with Black
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
max_line_length = 120
|
|
||||||
|
|
||||||
# YAML - Home Assistant configs, GitHub workflows
|
|
||||||
[*.{yaml,yml}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# JSON - manifest.json, translations, etc.
|
|
||||||
[*.json]
|
[*.json]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
# Markdown - READMEs, docs (preserve AI formatting)
|
|
||||||
[*.md]
|
[*.md]
|
||||||
indent_size = 2
|
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
max_line_length = off
|
|
||||||
|
|
||||||
# TOML - pyproject.toml, Python packaging
|
|
||||||
[*.toml]
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
# Shell scripts - setup scripts, CI/CD
|
|
||||||
[*.{sh,bash}]
|
|
||||||
indent_size = 4
|
|
||||||
end_of_line = lf
|
|
||||||
|
|
||||||
# JavaScript/TypeScript - Frontend panel development
|
|
||||||
[*.{js,ts,jsx,tsx,mjs,cjs}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# CSS/SCSS - Frontend styling
|
|
||||||
[*.{css,scss,sass}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# HTML - Lovelace cards, frontend templates
|
|
||||||
[*.html]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# XML - Android Auto integration, etc.
|
|
||||||
[*.xml]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# Jinja2 templates - Home Assistant templates
|
|
||||||
[*.jinja,*.jinja2,*.j2]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# Makefiles require tabs
|
|
||||||
[Makefile]
|
|
||||||
indent_style = tab
|
|
||||||
|
|
||||||
# GitHub-specific files
|
|
||||||
[.github/workflows/*.{yml,yaml}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[.github/dependabot.{yml,yaml}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# Docker files
|
|
||||||
[Dockerfile*]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.dockerignore]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[docker-compose*.{yml,yaml}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
|
||||||
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
github: [jpawlowski]
|
github: [ jpawlowski ]
|
||||||
buy_me_a_coffee: jpawlowski
|
buy_me_a_coffee: jpawlowski
|
||||||
|
|
|
||||||
18
.github/ISSUE_TEMPLATE/bug.yml
vendored
18
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
|
@ -3,30 +3,30 @@ name: "Bug report"
|
||||||
description: "Report a bug with the custom integration"
|
description: "Report a bug with the custom integration"
|
||||||
labels: ["bug"]
|
labels: ["bug"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: Before you open a new issue, search through the existing issues to see if others have had the same problem.
|
value: Before you open a new issue, search through the existing issues to see if others have had the same problem.
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: "Home Assistant version"
|
label: "Home Assistant version"
|
||||||
description: "The version of Home Assistant you are using"
|
description: "The version of Home Assistant you are using"
|
||||||
placeholder: "2025.1.0"
|
placeholder: "2025.1.0"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: "Integration version"
|
label: "Integration version"
|
||||||
description: "The version of this custom integration you are using"
|
description: "The version of this custom integration you are using"
|
||||||
placeholder: "1.0.0"
|
placeholder: "1.0.0"
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: "System Health details"
|
label: "System Health details"
|
||||||
description: "Paste the data from the System Health card in Home Assistant (https://www.home-assistant.io/more-info/system-health#github-issues)"
|
description: "Paste the data from the System Health card in Home Assistant (https://www.home-assistant.io/more-info/system-health#github-issues)"
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
label: Checklist
|
label: Checklist
|
||||||
options:
|
options:
|
||||||
|
|
@ -38,13 +38,13 @@ body:
|
||||||
required: true
|
required: true
|
||||||
- label: This issue is not a duplicate issue of any [previous issues](https://github.com/jpawlowski/hass.tibber_prices/issues?q=is%3Aissue+label%3A%22Bug%22+)..
|
- label: This issue is not a duplicate issue of any [previous issues](https://github.com/jpawlowski/hass.tibber_prices/issues?q=is%3Aissue+label%3A%22Bug%22+)..
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: "Describe the issue"
|
label: "Describe the issue"
|
||||||
description: "A clear and concise description of what the issue is."
|
description: "A clear and concise description of what the issue is."
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Reproduction steps
|
label: Reproduction steps
|
||||||
description: "Without steps to reproduce, it will be hard to fix. It is very important that you fill out this part. Issues without it will be closed."
|
description: "Without steps to reproduce, it will be hard to fix. It is very important that you fill out this part. Issues without it will be closed."
|
||||||
|
|
@ -55,7 +55,7 @@ body:
|
||||||
...
|
...
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: "Debug logs"
|
label: "Debug logs"
|
||||||
description: "To enable debug logs check this https://www.home-assistant.io/integrations/logger/, this **needs** to include _everything_ from startup of Home Assistant to the point where you encounter the issue."
|
description: "To enable debug logs check this https://www.home-assistant.io/integrations/logger/, this **needs** to include _everything_ from startup of Home Assistant to the point where you encounter the issue."
|
||||||
|
|
@ -63,7 +63,7 @@ body:
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: "Diagnostics dump"
|
label: "Diagnostics dump"
|
||||||
description: "Drag the diagnostics dump file here. (see https://www.home-assistant.io/integrations/diagnostics/ for info)"
|
description: "Drag the diagnostics dump file here. (see https://www.home-assistant.io/integrations/diagnostics/ for info)"
|
||||||
|
|
|
||||||
12
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
12
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
|
|
@ -3,10 +3,10 @@ name: "Feature request"
|
||||||
description: "Suggest an idea for this custom integration"
|
description: "Suggest an idea for this custom integration"
|
||||||
labels: ["Feature request"]
|
labels: ["Feature request"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: Before you open a new feature request, search through the existing feature requests to see if others have had the same idea.
|
value: Before you open a new feature request, search through the existing feature requests to see if others have had the same idea.
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
label: Checklist
|
label: Checklist
|
||||||
options:
|
options:
|
||||||
|
|
@ -17,7 +17,7 @@ body:
|
||||||
- label: This issue is not a duplicate feature request of [previous feature requests](https://github.com/jpawlowski/hass.tibber_prices/issues?q=is%3Aissue+label%3A%22Feature+Request%22+).
|
- label: This issue is not a duplicate feature request of [previous feature requests](https://github.com/jpawlowski/hass.tibber_prices/issues?q=is%3Aissue+label%3A%22Feature+Request%22+).
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: "Is your feature request related to a problem? Please describe."
|
label: "Is your feature request related to a problem? Please describe."
|
||||||
description: "A clear and concise description of what the problem is."
|
description: "A clear and concise description of what the problem is."
|
||||||
|
|
@ -25,21 +25,21 @@ body:
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: "Describe the solution you'd like"
|
label: "Describe the solution you'd like"
|
||||||
description: "A clear and concise description of what you want to happen."
|
description: "A clear and concise description of what you want to happen."
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: "Describe alternatives you've considered"
|
label: "Describe alternatives you've considered"
|
||||||
description: "A clear and concise description of any alternative solutions or features you've considered."
|
description: "A clear and concise description of any alternative solutions or features you've considered."
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: "Additional context"
|
label: "Additional context"
|
||||||
description: "Add any other context or screenshots about the feature request here."
|
description: "Add any other context or screenshots about the feature request here."
|
||||||
|
|
|
||||||
2
.github/workflows/auto-tag.yml
vendored
2
.github/workflows/auto-tag.yml
vendored
|
|
@ -5,7 +5,7 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- "custom_components/tibber_prices/manifest.json"
|
- 'custom_components/tibber_prices/manifest.json'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
|
||||||
10
.github/workflows/docusaurus.yml
vendored
10
.github/workflows/docusaurus.yml
vendored
|
|
@ -4,10 +4,10 @@ on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
paths:
|
paths:
|
||||||
- "docs/**"
|
- 'docs/**'
|
||||||
- ".github/workflows/docusaurus.yml"
|
- '.github/workflows/docusaurus.yml'
|
||||||
tags:
|
tags:
|
||||||
- "v*.*.*"
|
- 'v*.*.*'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
# Concurrency control: cancel in-progress deployments
|
# Concurrency control: cancel in-progress deployments
|
||||||
|
|
@ -47,7 +47,7 @@ jobs:
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: "npm"
|
cache: 'npm'
|
||||||
cache-dependency-path: |
|
cache-dependency-path: |
|
||||||
docs/user/package-lock.json
|
docs/user/package-lock.json
|
||||||
docs/developer/package-lock.json
|
docs/developer/package-lock.json
|
||||||
|
|
@ -56,7 +56,7 @@ jobs:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v6
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: "3.14"
|
python-version: '3.14'
|
||||||
|
|
||||||
- name: Verify sensor reference is up-to-date
|
- name: Verify sensor reference is up-to-date
|
||||||
run: python3 scripts/docs/generate-sensor-reference --check
|
run: python3 scripts/docs/generate-sensor-reference --check
|
||||||
|
|
|
||||||
8
.github/workflows/lint.yml
vendored
8
.github/workflows/lint.yml
vendored
|
|
@ -5,14 +5,14 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- "main"
|
- "main"
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "docs/**"
|
- 'docs/**'
|
||||||
- ".github/workflows/docusaurus.yml"
|
- '.github/workflows/docusaurus.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- "main"
|
- "main"
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "docs/**"
|
- 'docs/**'
|
||||||
- ".github/workflows/docusaurus.yml"
|
- '.github/workflows/docusaurus.yml'
|
||||||
|
|
||||||
permissions: {}
|
permissions: {}
|
||||||
|
|
||||||
|
|
|
||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
|
|
@ -3,11 +3,11 @@ name: Generate Release Notes
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "v*.*.*" # Triggers on version tags like v1.0.0, v2.1.3, etc.
|
- 'v*.*.*' # Triggers on version tags like v1.0.0, v2.1.3, etc.
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
tag:
|
tag:
|
||||||
description: "Tag version to release (e.g., v0.3.0)"
|
description: 'Tag version to release (e.g., v0.3.0)'
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
|
|
||||||
8
.github/workflows/validate.yml
vendored
8
.github/workflows/validate.yml
vendored
|
|
@ -8,14 +8,14 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "docs/**"
|
- 'docs/**'
|
||||||
- ".github/workflows/docusaurus.yml"
|
- '.github/workflows/docusaurus.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "docs/**"
|
- 'docs/**'
|
||||||
- ".github/workflows/docusaurus.yml"
|
- '.github/workflows/docusaurus.yml'
|
||||||
|
|
||||||
permissions: {}
|
permissions: {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,9 @@
|
||||||
{
|
{
|
||||||
"default": true,
|
"default": true,
|
||||||
"MD004": false,
|
|
||||||
"MD013": false,
|
"MD013": false,
|
||||||
"MD036": false,
|
"MD033": false,
|
||||||
"MD041": false,
|
"MD041": false,
|
||||||
"no-trailing-punctuation": false,
|
"no-inline-html": false,
|
||||||
"no-inline-html": {
|
"line-length": false,
|
||||||
"allowed_elements": ["br", "details", "summary", "img", "a", "kbd"]
|
"first-line-heading": false
|
||||||
},
|
|
||||||
"code-block-style": {
|
|
||||||
"style": "fenced"
|
|
||||||
},
|
|
||||||
"emphasis-style": {
|
|
||||||
"style": "underscore"
|
|
||||||
},
|
|
||||||
"strong-style": {
|
|
||||||
"style": "asterisk"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,6 @@ __pycache__/
|
||||||
env/
|
env/
|
||||||
venv/
|
venv/
|
||||||
|
|
||||||
# Ignore local HA dev instance config (not production code)
|
# Ignore compiled YAML or generated docs
|
||||||
config/
|
*.yaml
|
||||||
|
*.yml
|
||||||
# Ignore YAML schemas (structural files with specific formatting conventions)
|
|
||||||
schemas/yaml/
|
|
||||||
|
|
||||||
# Ignore Docusaurus documentation sites – they have their own toolchain
|
|
||||||
# and Prettier reformats <details> blocks inside lists in a way that breaks MDX
|
|
||||||
docs/
|
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
# Prettier configuration for Home Assistant Custom Component Development
|
|
||||||
# Aligned with .editorconfig and .markdownlint.json
|
|
||||||
|
|
||||||
printWidth: 120
|
|
||||||
tabWidth: 2
|
|
||||||
useTabs: false
|
|
||||||
semi: true
|
|
||||||
singleQuote: false
|
|
||||||
quoteProps: "as-needed"
|
|
||||||
trailingComma: "es5"
|
|
||||||
bracketSpacing: true
|
|
||||||
arrowParens: "always"
|
|
||||||
proseWrap: "preserve"
|
|
||||||
endOfLine: "lf"
|
|
||||||
|
|
||||||
# File-specific overrides
|
|
||||||
overrides:
|
|
||||||
# Markdown - preserve formatting, avoid conflicts with markdownlint
|
|
||||||
- files: "*.md"
|
|
||||||
options:
|
|
||||||
proseWrap: "preserve"
|
|
||||||
printWidth: 120
|
|
||||||
trailingComma: "none"
|
|
||||||
|
|
||||||
# JSON - Home Assistant manifest, translations
|
|
||||||
- files: "*.json"
|
|
||||||
options:
|
|
||||||
tabWidth: 2
|
|
||||||
trailingComma: "none"
|
|
||||||
|
|
||||||
# JSONC - VS Code settings, devcontainer config
|
|
||||||
- files: "*.jsonc"
|
|
||||||
options:
|
|
||||||
tabWidth: 2
|
|
||||||
trailingComma: "none"
|
|
||||||
|
|
||||||
# YAML would go here, but it's in .prettierignore (handled by redhat.vscode-yaml)
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
{
|
{
|
||||||
"domain": "tibber_prices",
|
"domain": "tibber_prices",
|
||||||
"name": "Tibber Price Information & Ratings",
|
"name": "Tibber Price Information & Ratings",
|
||||||
"codeowners": ["@jpawlowski"],
|
"codeowners": [
|
||||||
|
"@jpawlowski"
|
||||||
|
],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://github.com/jpawlowski/hass.tibber_prices",
|
"documentation": "https://github.com/jpawlowski/hass.tibber_prices",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"issue_tracker": "https://github.com/jpawlowski/hass.tibber_prices/issues",
|
"issue_tracker": "https://github.com/jpawlowski/hass.tibber_prices/issues",
|
||||||
"requirements": ["aiofiles>=23.2.1"],
|
"requirements": [
|
||||||
|
"aiofiles>=23.2.1"
|
||||||
|
],
|
||||||
"version": "0.31.0b1"
|
"version": "0.31.0b1"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
318
pyproject.toml
318
pyproject.toml
|
|
@ -1,9 +1,6 @@
|
||||||
# Custom Component pyproject.toml based on Home Assistant Core
|
[build-system]
|
||||||
# https://github.com/home-assistant/core/blob/dev/pyproject.toml
|
requires = ["setuptools==82.0.1"]
|
||||||
#
|
build-backend = "setuptools.build_meta"
|
||||||
# Sections not included (HA Core specific):
|
|
||||||
# - [build-system] - Not published to PyPI (installed via HACS)
|
|
||||||
# - [tool.pylint.*] - Optional additional linting (Ruff is sufficient)
|
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tibber_prices"
|
name = "tibber_prices"
|
||||||
|
|
@ -16,276 +13,73 @@ packages = ["custom_components.tibber_prices"]
|
||||||
[tool.pyright]
|
[tool.pyright]
|
||||||
include = ["custom_components/tibber_prices"]
|
include = ["custom_components/tibber_prices"]
|
||||||
exclude = [
|
exclude = [
|
||||||
"**/.*",
|
|
||||||
"**/__pycache__",
|
|
||||||
"**/config",
|
|
||||||
"**/docs",
|
|
||||||
"**/node_modules",
|
"**/node_modules",
|
||||||
|
"**/__pycache__",
|
||||||
|
"**/.git",
|
||||||
|
"**/.github",
|
||||||
|
"**/docs",
|
||||||
"**/venv",
|
"**/venv",
|
||||||
|
"**/.venv",
|
||||||
]
|
]
|
||||||
venvPath = "."
|
venvPath = "."
|
||||||
venv = ".venv"
|
venv = ".venv"
|
||||||
typeCheckingMode = "basic"
|
typeCheckingMode = "basic"
|
||||||
reportUnusedImport = "none"
|
|
||||||
reportUnusedVariable = "none"
|
[tool.ruff]
|
||||||
reportUnusedCoroutine = "none"
|
# Based on https://github.com/home-assistant/core/blob/dev/pyproject.toml
|
||||||
reportMissingTypeStubs = "none"
|
target-version = "py314"
|
||||||
|
line-length = 120
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["ALL"]
|
||||||
|
ignore = [
|
||||||
|
# "ANN101", # Missing type annotation for `self` in method
|
||||||
|
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
|
||||||
|
"D203", # no-blank-line-before-class (incompatible with formatter)
|
||||||
|
"D212", # multi-line-summary-first-line (incompatible with formatter)
|
||||||
|
"COM812", # incompatible with formatter
|
||||||
|
"ISC001", # incompatible with formatter
|
||||||
|
"UP037", # quoted annotations; needed for TYPE_CHECKING forward references
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"tests/*" = [
|
||||||
|
"S101", # assert is fine in tests
|
||||||
|
"PLR2004", # Magic values are fine in tests
|
||||||
|
]
|
||||||
|
"scripts/*" = [
|
||||||
|
"T201", # print() is the correct output method for CLI scripts
|
||||||
|
"INP001", # scripts/ is not a Python package (no __init__.py)
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.lint.flake8-pytest-style]
|
||||||
|
fixture-parentheses = false
|
||||||
|
|
||||||
|
[tool.ruff.lint.pyupgrade]
|
||||||
|
keep-runtime-typing = true
|
||||||
|
|
||||||
|
[tool.ruff.lint.mccabe]
|
||||||
|
max-complexity = 25
|
||||||
|
|
||||||
|
[tool.ruff.lint.isort]
|
||||||
|
force-single-line = false
|
||||||
|
known-first-party = ["custom_components", "homeassistant"]
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
testpaths = ["tests"]
|
testpaths = ["tests"]
|
||||||
norecursedirs = [".git", "testing_config"]
|
python_files = ["test_*.py"]
|
||||||
log_format = "%(asctime)s.%(msecs)03d %(levelname)-8s %(threadName)s %(name)s:%(filename)s:%(lineno)s %(message)s"
|
python_classes = ["Test*"]
|
||||||
log_date_format = "%Y-%m-%d %H:%M:%S"
|
python_functions = ["test_*"]
|
||||||
asyncio_debug = true
|
|
||||||
asyncio_mode = "auto"
|
|
||||||
asyncio_default_fixture_loop_scope = "function"
|
asyncio_default_fixture_loop_scope = "function"
|
||||||
addopts = "-ra -q --strict-markers"
|
addopts = "-ra -q --strict-markers"
|
||||||
markers = [
|
markers = [
|
||||||
"unit: Unit tests (fast, no external dependencies)",
|
"unit: Unit tests (fast, no external dependencies)",
|
||||||
"integration: Integration tests (may use coordinator/time service)",
|
"integration: Integration tests (may use coordinator/time service)",
|
||||||
]
|
]
|
||||||
filterwarnings = [
|
|
||||||
# Treat warnings as errors to catch issues early
|
|
||||||
"error",
|
|
||||||
# Ignore specific warnings from third-party libraries as needed
|
|
||||||
# "ignore:.*custom_components.* is using deprecated.*:DeprecationWarning",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.coverage.run]
|
|
||||||
source = ["custom_components/tibber_prices"]
|
|
||||||
omit = ["tests/*"]
|
|
||||||
|
|
||||||
[tool.coverage.report]
|
|
||||||
exclude_lines = [
|
|
||||||
"pragma: no cover",
|
|
||||||
"def __repr__",
|
|
||||||
"raise AssertionError",
|
|
||||||
"raise NotImplementedError",
|
|
||||||
"if TYPE_CHECKING:",
|
|
||||||
"@overload",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.ruff]
|
|
||||||
# Based on https://github.com/home-assistant/core/blob/dev/pyproject.toml
|
|
||||||
required-version = ">=0.15.1"
|
|
||||||
target-version = "py314"
|
|
||||||
line-length = 120
|
|
||||||
|
|
||||||
[tool.ruff.lint]
|
|
||||||
select = [
|
|
||||||
"A001", # Variable {name} is shadowing a Python builtin
|
|
||||||
"ASYNC", # flake8-async
|
|
||||||
"B002", # Python does not support the unary prefix increment
|
|
||||||
"B005", # Using .strip() with multi-character strings is misleading
|
|
||||||
"B007", # Loop control variable {name} not used within loop body
|
|
||||||
"B009", # Do not call getattr with a constant attribute value. It is not any safer than normal property access.
|
|
||||||
"B014", # Exception handler with duplicate exception
|
|
||||||
"B015", # Pointless comparison. Did you mean to assign a value? Otherwise, prepend assert or remove it.
|
|
||||||
"B017", # pytest.raises(BaseException) should be considered evil
|
|
||||||
"B018", # Found useless attribute access. Either assign it to a variable or remove it.
|
|
||||||
"B023", # Function definition does not bind loop variable {name}
|
|
||||||
"B024", # `{name}` is an abstract base class, but it has no abstract methods or properties
|
|
||||||
"B025", # try-except* block with duplicate exception {name}
|
|
||||||
"B026", # Star-arg unpacking after a keyword argument is strongly discouraged
|
|
||||||
"B032", # Possible unintentional type annotation (using :). Did you mean to assign (using =)?
|
|
||||||
"B035", # Dictionary comprehension uses static key
|
|
||||||
"B904", # Use raise from to specify exception cause
|
|
||||||
"B905", # zip() without an explicit strict= parameter
|
|
||||||
"BLE",
|
|
||||||
"C", # complexity
|
|
||||||
"COM818", # Trailing comma on bare tuple prohibited
|
|
||||||
"D", # docstrings
|
|
||||||
"DTZ003", # Use datetime.now(tz=) instead of datetime.utcnow()
|
|
||||||
"DTZ004", # Use datetime.fromtimestamp(ts, tz=) instead of datetime.utcfromtimestamp(ts)
|
|
||||||
"E", # pycodestyle
|
|
||||||
"F", # pyflakes/autoflake
|
|
||||||
"F541", # f-string without any placeholders
|
|
||||||
"FLY", # flynt
|
|
||||||
"FURB", # refurb
|
|
||||||
"G", # flake8-logging-format
|
|
||||||
"I", # isort
|
|
||||||
"INP", # flake8-no-pep420
|
|
||||||
"ISC", # flake8-implicit-str-concat
|
|
||||||
"ICN001", # import concentions; {name} should be imported as {asname}
|
|
||||||
"LOG", # flake8-logging
|
|
||||||
"N804", # First argument of a class method should be named cls
|
|
||||||
"N805", # First argument of a method should be named self
|
|
||||||
"N815", # Variable {name} in class scope should not be mixedCase
|
|
||||||
"PERF", # Perflint
|
|
||||||
"PGH", # pygrep-hooks
|
|
||||||
"PIE", # flake8-pie
|
|
||||||
"PL", # pylint
|
|
||||||
"PT", # flake8-pytest-style
|
|
||||||
"PTH", # flake8-pathlib
|
|
||||||
"PYI", # flake8-pyi
|
|
||||||
"RET", # flake8-return
|
|
||||||
"RSE", # flake8-raise
|
|
||||||
"RUF005", # Consider iterable unpacking instead of concatenation
|
|
||||||
"RUF006", # Store a reference to the return value of asyncio.create_task
|
|
||||||
"RUF007", # Prefer itertools.pairwise() over zip() when iterating over successive pairs
|
|
||||||
"RUF008", # Do not use mutable default values for dataclass attributes
|
|
||||||
"RUF010", # Use explicit conversion flag
|
|
||||||
"RUF013", # PEP 484 prohibits implicit Optional
|
|
||||||
"RUF016", # Slice in indexed access to type {value_type} uses type {index_type} instead of an integer
|
|
||||||
"RUF017", # Avoid quadratic list summation
|
|
||||||
"RUF018", # Avoid assignment expressions in assert statements
|
|
||||||
"RUF019", # Unnecessary key check before dictionary access
|
|
||||||
"RUF020", # {never_like} | T is equivalent to T
|
|
||||||
"RUF021", # Parenthesize a and b expressions when chaining and and or together, to make the precedence clear
|
|
||||||
"RUF022", # Sort __all__
|
|
||||||
"RUF023", # Sort __slots__
|
|
||||||
"RUF024", # Do not pass mutable objects as values to dict.fromkeys
|
|
||||||
"RUF026", # default_factory is a positional-only argument to defaultdict
|
|
||||||
"RUF030", # print() call in assert statement is likely unintentional
|
|
||||||
"RUF032", # Decimal() called with float literal argument
|
|
||||||
"RUF033", # __post_init__ method with argument defaults
|
|
||||||
"RUF034", # Useless if-else condition
|
|
||||||
"RUF059", # unused-unpacked-variable
|
|
||||||
"RUF100", # Unused `noqa` directive
|
|
||||||
"RUF101", # noqa directives that use redirected rule codes
|
|
||||||
"RUF200", # Failed to parse pyproject.toml: {message}
|
|
||||||
"S102", # Use of exec detected
|
|
||||||
"S103", # bad-file-permissions
|
|
||||||
"S108", # hardcoded-temp-file
|
|
||||||
"S306", # suspicious-mktemp-usage
|
|
||||||
"S307", # suspicious-eval-usage
|
|
||||||
"S313", # suspicious-xmlc-element-tree-usage
|
|
||||||
"S314", # suspicious-xml-element-tree-usage
|
|
||||||
"S315", # suspicious-xml-expat-reader-usage
|
|
||||||
"S316", # suspicious-xml-expat-builder-usage
|
|
||||||
"S317", # suspicious-xml-sax-usage
|
|
||||||
"S318", # suspicious-xml-mini-dom-usage
|
|
||||||
"S319", # suspicious-xml-pull-dom-usage
|
|
||||||
"S601", # paramiko-call
|
|
||||||
"S602", # subprocess-popen-with-shell-equals-true
|
|
||||||
"S604", # call-with-shell-equals-true
|
|
||||||
"S608", # hardcoded-sql-expression
|
|
||||||
"S609", # unix-command-wildcard-injection
|
|
||||||
"SIM", # flake8-simplify
|
|
||||||
"SLF", # flake8-self
|
|
||||||
"SLOT", # flake8-slots
|
|
||||||
"T100", # Trace found: {name} used
|
|
||||||
"T20", # flake8-print
|
|
||||||
"TC", # flake8-type-checking
|
|
||||||
"TID", # Tidy imports
|
|
||||||
"TRY", # tryceratops
|
|
||||||
"UP", # pyupgrade
|
|
||||||
"UP031", # Use format specifiers instead of percent format
|
|
||||||
"UP032", # Use f-string instead of `format` call
|
|
||||||
"W", # pycodestyle
|
|
||||||
]
|
|
||||||
|
|
||||||
ignore = [
|
|
||||||
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
|
|
||||||
"ASYNC109", # Async function definition with a `timeout` parameter Use `asyncio.timeout` instead
|
|
||||||
"ASYNC110", # Use `asyncio.Event` instead of awaiting `asyncio.sleep` in a `while` loop
|
|
||||||
"ASYNC240", # Use an async function for entering the file system
|
|
||||||
"D202", # No blank lines allowed after function docstring
|
|
||||||
"D203", # 1 blank line required before class docstring
|
|
||||||
"D213", # Multi-line docstring summary should start at the second line
|
|
||||||
"D406", # Section name should end with a newline
|
|
||||||
"D407", # Section name underlining
|
|
||||||
"D417", # Missing argument descriptions in docstring - to allow documenting only non-obvious parameters
|
|
||||||
"E501", # line too long
|
|
||||||
|
|
||||||
"PLC1901", # {existing} can be simplified to {replacement} as an empty string is falsey; too many false positives
|
|
||||||
"PLR0911", # Too many return statements ({returns} > {max_returns})
|
|
||||||
"PLR0912", # Too many branches ({branches} > {max_branches})
|
|
||||||
"PLR0913", # Too many arguments to function call ({c_args} > {max_args})
|
|
||||||
"PLR0915", # Too many statements ({statements} > {max_statements})
|
|
||||||
"PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable
|
|
||||||
"PLW0108", # Unnecessary lambda wrapping a function call; can often be replaced by the function itself
|
|
||||||
"PLW1641", # __eq__ without __hash__
|
|
||||||
"PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target
|
|
||||||
"PT011", # pytest.raises({exception}) is too broad, set the `match` parameter or use a more specific exception
|
|
||||||
"PT018", # Assertion should be broken down into multiple parts
|
|
||||||
"RUF001", # String contains ambiguous unicode character.
|
|
||||||
"RUF002", # Docstring contains ambiguous unicode character.
|
|
||||||
"RUF003", # Comment contains ambiguous unicode character.
|
|
||||||
"RUF015", # Prefer next(...) over single element slice
|
|
||||||
"SIM102", # Use a single if statement instead of nested if statements
|
|
||||||
"SIM103", # Return the condition {condition} directly
|
|
||||||
"SIM108", # Use ternary operator {contents} instead of if-else-block
|
|
||||||
"SIM115", # Use context handler for opening files
|
|
||||||
|
|
||||||
# Moving imports into type-checking blocks can mess with pytest.patch()
|
|
||||||
"TC001", # Move application import {} into a type-checking block
|
|
||||||
"TC002", # Move third-party import {} into a type-checking block
|
|
||||||
"TC003", # Move standard library import {} into a type-checking block
|
|
||||||
# Quotes for typing.cast generally not necessary, only for performance critical paths
|
|
||||||
"TC006", # Add quotes to type expression in typing.cast()
|
|
||||||
|
|
||||||
"TRY003", # Avoid specifying long messages outside the exception class
|
|
||||||
"TRY400", # Use `logging.exception` instead of `logging.error`
|
|
||||||
|
|
||||||
"UP046", # Non PEP 695 generic class
|
|
||||||
"UP047", # Non PEP 696 generic function
|
|
||||||
"UP049", # Avoid private type parameter names
|
|
||||||
|
|
||||||
# May conflict with the formatter, https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
|
|
||||||
"W191",
|
|
||||||
"E111",
|
|
||||||
"E114",
|
|
||||||
"E117",
|
|
||||||
"D203",
|
|
||||||
"D206",
|
|
||||||
"D212",
|
|
||||||
"D300",
|
|
||||||
"Q",
|
|
||||||
"COM812",
|
|
||||||
"COM819",
|
|
||||||
"ISC001",
|
|
||||||
|
|
||||||
# Disabled because ruff does not understand type of __all__ generated by a function
|
|
||||||
"PLE0605",
|
|
||||||
|
|
||||||
"FURB116",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.ruff.lint.flake8-import-conventions.extend-aliases]
|
|
||||||
# Commonly used Home Assistant imports
|
|
||||||
voluptuous = "vol"
|
|
||||||
"homeassistant.helpers.config_validation" = "cv"
|
|
||||||
"homeassistant.helpers.device_registry" = "dr"
|
|
||||||
"homeassistant.helpers.entity_registry" = "er"
|
|
||||||
"homeassistant.util.dt" = "dt_util"
|
|
||||||
|
|
||||||
[tool.ruff.lint.flake8-pytest-style]
|
|
||||||
fixture-parentheses = false
|
|
||||||
mark-parentheses = false
|
|
||||||
|
|
||||||
[tool.ruff.lint.flake8-tidy-imports.banned-api]
|
|
||||||
"async_timeout".msg = "use asyncio.timeout instead"
|
|
||||||
"pytz".msg = "use zoneinfo instead"
|
|
||||||
"tests".msg = "You should not import tests"
|
|
||||||
|
|
||||||
[tool.ruff.lint.isort]
|
|
||||||
force-sort-within-sections = true
|
|
||||||
known-first-party = ["custom_components", "homeassistant"]
|
|
||||||
combine-as-imports = true
|
|
||||||
split-on-trailing-comma = false
|
|
||||||
|
|
||||||
[tool.ruff.lint.per-file-ignores]
|
|
||||||
"script/*" = [
|
|
||||||
"T20", # print() allowed in scripts
|
|
||||||
"INP001", # Implicit namespace package (scripts are not a package)
|
|
||||||
]
|
|
||||||
"tests/*" = [
|
|
||||||
"S101", # assert is fine in tests
|
|
||||||
"PLR2004", # Magic values are fine in tests
|
|
||||||
"D", # Docstrings not required in tests
|
|
||||||
"PTH", # Use pathlib - temporary exemption for tests
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.ruff.lint.mccabe]
|
|
||||||
max-complexity = 25
|
|
||||||
|
|
||||||
[tool.ruff.lint.pydocstyle]
|
|
||||||
convention = "google"
|
|
||||||
property-decorators = ["propcache.api.cached_property"]
|
|
||||||
|
|
||||||
[tool.ruff.lint.pyupgrade]
|
|
||||||
keep-runtime-typing = true
|
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
test = ["pytest-homeassistant-custom-component>=0.13.323"]
|
test = [
|
||||||
|
"pytest>=9.0.3",
|
||||||
|
"pytest-asyncio>=1.3.0",
|
||||||
|
"pytest-homeassistant-custom-component>=0.13.323",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,15 @@
|
||||||
"description": "The integration type.\nhttps://developers.home-assistant.io/docs/creating_integration_manifest/#integration-type",
|
"description": "The integration type.\nhttps://developers.home-assistant.io/docs/creating_integration_manifest/#integration-type",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "hub",
|
"default": "hub",
|
||||||
"enum": ["device", "entity", "hardware", "helper", "hub", "service", "system"]
|
"enum": [
|
||||||
|
"device",
|
||||||
|
"entity",
|
||||||
|
"hardware",
|
||||||
|
"helper",
|
||||||
|
"hub",
|
||||||
|
"service",
|
||||||
|
"system"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"config_flow": {
|
"config_flow": {
|
||||||
"description": "Whether the integration is configurable from the UI.\nhttps://developers.home-assistant.io/docs/creating_integration_manifest/#config-flow",
|
"description": "Whether the integration is configurable from the UI.\nhttps://developers.home-assistant.io/docs/creating_integration_manifest/#config-flow",
|
||||||
|
|
@ -367,7 +375,14 @@
|
||||||
"iot_class": {
|
"iot_class": {
|
||||||
"description": "The IoT class of the integration, describing how the integration connects to the device or service.\nhttps://developers.home-assistant.io/docs/creating_integration_manifest/#iot-class",
|
"description": "The IoT class of the integration, describing how the integration connects to the device or service.\nhttps://developers.home-assistant.io/docs/creating_integration_manifest/#iot-class",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["assumed_state", "cloud_polling", "cloud_push", "local_polling", "local_push", "calculated"]
|
"enum": [
|
||||||
|
"assumed_state",
|
||||||
|
"cloud_polling",
|
||||||
|
"cloud_push",
|
||||||
|
"local_polling",
|
||||||
|
"local_push",
|
||||||
|
"calculated"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"single_config_entry": {
|
"single_config_entry": {
|
||||||
"description": "Whether the integration only supports a single config entry.\nhttps://developers.home-assistant.io/docs/creating_integration_manifest/#single-config-entry-only",
|
"description": "Whether the integration only supports a single config entry.\nhttps://developers.home-assistant.io/docs/creating_integration_manifest/#single-config-entry-only",
|
||||||
|
|
@ -380,7 +395,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": ["domain", "name", "codeowners", "documentation", "issue_tracker", "version"],
|
"required": [
|
||||||
|
"domain",
|
||||||
|
"name",
|
||||||
|
"codeowners",
|
||||||
|
"documentation",
|
||||||
|
"issue_tracker",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue