diff --git a/.devcontainer/devcontainer-extensions.json b/.devcontainer/devcontainer-extensions.json index 5444bb7..7d01943 100644 --- a/.devcontainer/devcontainer-extensions.json +++ b/.devcontainer/devcontainer-extensions.json @@ -1,6 +1,4 @@ { - "recommendations": [], - "unwantedRecommendations": [ - "ms-python.pylint" - ] + "recommendations": [], + "unwantedRecommendations": ["ms-python.pylint"] } diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 153d8f7..734788b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,11 +7,7 @@ "PYTHONASYNCIODEBUG": "1", "TIBBER_PRICES_DEV": "1" }, - "forwardPorts": [ - 8123, - 3000, - 3001 - ], + "forwardPorts": [8123, 3000, 3001], "portsAttributes": { "8123": { "label": "Home Assistant", @@ -56,9 +52,7 @@ "reportUnusedCoroutine": "none", "reportMissingTypeStubs": "none" }, - "python.analysis.include": [ - "custom_components/tibber_prices" - ], + "python.analysis.include": ["custom_components/tibber_prices"], "python.analysis.exclude": [ "**/.venv/**", "**/venv/**", @@ -74,9 +68,7 @@ ], "python.terminal.activateEnvironment": true, "python.terminal.activateEnvInCurrentTerminal": true, - "python.testing.pytestArgs": [ - "--no-cov" - ], + "python.testing.pytestArgs": ["--no-cov"], "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, @@ -112,15 +104,11 @@ "markdown.validate.fragmentLinks.enabled": "ignore", "json.schemas": [ { - "fileMatch": [ - "homeassistant/components/*/manifest.json" - ], + "fileMatch": ["homeassistant/components/*/manifest.json"], "url": "${containerWorkspaceFolder}/schemas/json/manifest_schema.json" }, { - "fileMatch": [ - "homeassistant/components/*/translations/*.json" - ], + "fileMatch": ["homeassistant/components/*/translations/*.json"], "url": "${containerWorkspaceFolder}/schemas/json/translation_schema.json" } ], diff --git a/.markdownlint.json b/.markdownlint.json index 80715ae..efe7ed5 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,9 +1,9 @@ { - "default": true, - "MD013": false, - "MD033": false, - "MD041": false, - "no-inline-html": false, - "line-length": false, - "first-line-heading": false + "default": true, + "MD013": false, + "MD033": false, + "MD041": false, + "no-inline-html": false, + "line-length": false, + "first-line-heading": false } diff --git a/custom_components/tibber_prices/icons.json b/custom_components/tibber_prices/icons.json index d2756cd..498b32e 100644 --- a/custom_components/tibber_prices/icons.json +++ b/custom_components/tibber_prices/icons.json @@ -1,79 +1,79 @@ { - "services": { - "get_price": { - "service": "mdi:table-search" - }, - "get_chartdata": { - "service": "mdi:chart-bar", - "sections": { - "general": "mdi:identifier", - "selection": "mdi:calendar-range", - "filters": "mdi:filter-variant", - "transformation": "mdi:tune", - "format": "mdi:file-table", - "arrays_of_objects": "mdi:code-json", - "arrays_of_arrays": "mdi:code-brackets" - } - }, - "get_apexcharts_yaml": { - "service": "mdi:chart-line", - "sections": { - "entry_id": "mdi:identifier", - "day": "mdi:calendar-range", - "level_type": "mdi:format-list-bulleted-type", - "resolution": "mdi:timer-sand", - "highlight_best_price": "mdi:battery-charging-low", - "highlight_peak_price": "mdi:battery-alert" - } - }, - "refresh_user_data": { - "service": "mdi:refresh" - }, - "find_cheapest_block": { - "service": "mdi:washing-machine", - "sections": { - "search_range": "mdi:calendar-search", - "time_alternatives": "mdi:clock-time-eight-outline", - "price_filter": "mdi:filter-variant", - "output": "mdi:tune-variant" - } - }, - "find_most_expensive_block": { - "service": "mdi:lightning-bolt-circle", - "sections": { - "search_range": "mdi:calendar-search", - "time_alternatives": "mdi:clock-time-eight-outline", - "price_filter": "mdi:filter-variant", - "output": "mdi:tune-variant" - } - }, - "find_cheapest_hours": { - "service": "mdi:ev-station", - "sections": { - "search_range": "mdi:calendar-search", - "time_alternatives": "mdi:clock-time-eight-outline", - "price_filter": "mdi:filter-variant", - "output": "mdi:tune-variant" - } - }, - "find_most_expensive_hours": { - "service": "mdi:flash-alert", - "sections": { - "search_range": "mdi:calendar-search", - "time_alternatives": "mdi:clock-time-eight-outline", - "price_filter": "mdi:filter-variant", - "output": "mdi:tune-variant" - } - }, - "find_cheapest_schedule": { - "service": "mdi:calendar-check", - "sections": { - "scheduling_options": "mdi:format-list-numbered", - "search_range": "mdi:calendar-search", - "time_alternatives": "mdi:clock-time-eight-outline", - "price_filter": "mdi:filter-variant", - "output": "mdi:tune-variant" - } - } + "services": { + "get_price": { + "service": "mdi:table-search" + }, + "get_chartdata": { + "service": "mdi:chart-bar", + "sections": { + "general": "mdi:identifier", + "selection": "mdi:calendar-range", + "filters": "mdi:filter-variant", + "transformation": "mdi:tune", + "format": "mdi:file-table", + "arrays_of_objects": "mdi:code-json", + "arrays_of_arrays": "mdi:code-brackets" + } + }, + "get_apexcharts_yaml": { + "service": "mdi:chart-line", + "sections": { + "entry_id": "mdi:identifier", + "day": "mdi:calendar-range", + "level_type": "mdi:format-list-bulleted-type", + "resolution": "mdi:timer-sand", + "highlight_best_price": "mdi:battery-charging-low", + "highlight_peak_price": "mdi:battery-alert" + } + }, + "refresh_user_data": { + "service": "mdi:refresh" + }, + "find_cheapest_block": { + "service": "mdi:washing-machine", + "sections": { + "search_range": "mdi:calendar-search", + "time_alternatives": "mdi:clock-time-eight-outline", + "price_filter": "mdi:filter-variant", + "output": "mdi:tune-variant" + } + }, + "find_most_expensive_block": { + "service": "mdi:lightning-bolt-circle", + "sections": { + "search_range": "mdi:calendar-search", + "time_alternatives": "mdi:clock-time-eight-outline", + "price_filter": "mdi:filter-variant", + "output": "mdi:tune-variant" + } + }, + "find_cheapest_hours": { + "service": "mdi:ev-station", + "sections": { + "search_range": "mdi:calendar-search", + "time_alternatives": "mdi:clock-time-eight-outline", + "price_filter": "mdi:filter-variant", + "output": "mdi:tune-variant" + } + }, + "find_most_expensive_hours": { + "service": "mdi:flash-alert", + "sections": { + "search_range": "mdi:calendar-search", + "time_alternatives": "mdi:clock-time-eight-outline", + "price_filter": "mdi:filter-variant", + "output": "mdi:tune-variant" + } + }, + "find_cheapest_schedule": { + "service": "mdi:calendar-check", + "sections": { + "scheduling_options": "mdi:format-list-numbered", + "search_range": "mdi:calendar-search", + "time_alternatives": "mdi:clock-time-eight-outline", + "price_filter": "mdi:filter-variant", + "output": "mdi:tune-variant" + } } + } } diff --git a/custom_components/tibber_prices/manifest.json b/custom_components/tibber_prices/manifest.json index 6d954d8..e8b10ff 100644 --- a/custom_components/tibber_prices/manifest.json +++ b/custom_components/tibber_prices/manifest.json @@ -1,15 +1,11 @@ { "domain": "tibber_prices", "name": "Tibber Price Information & Ratings", - "codeowners": [ - "@jpawlowski" - ], + "codeowners": ["@jpawlowski"], "config_flow": true, "documentation": "https://github.com/jpawlowski/hass.tibber_prices", "iot_class": "cloud_polling", "issue_tracker": "https://github.com/jpawlowski/hass.tibber_prices/issues", - "requirements": [ - "aiofiles>=23.2.1" - ], + "requirements": ["aiofiles>=23.2.1"], "version": "0.30.0" } diff --git a/hacs.json b/hacs.json index 27b11b1..55fc2f7 100644 --- a/hacs.json +++ b/hacs.json @@ -1,5 +1,5 @@ { - "name": "Tibber Price Information & Ratings", - "homeassistant": "2026.4.0", - "hacs": "2.0.5" -} \ No newline at end of file + "name": "Tibber Price Information & Ratings", + "homeassistant": "2026.4.0", + "hacs": "2.0.5" +} diff --git a/schemas/json/translation_schema.json b/schemas/json/translation_schema.json index fba26f9..06d8358 100644 --- a/schemas/json/translation_schema.json +++ b/schemas/json/translation_schema.json @@ -1,372 +1,372 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Home Assistant Translation File Schema", - "description": "Schema for Home Assistant custom integration translation files based on https://developers.home-assistant.io/docs/internationalization/core", - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "Title of the integration (optional, will fallback to integration name if omitted). Only include if not a product brand." + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Home Assistant Translation File Schema", + "description": "Schema for Home Assistant custom integration translation files based on https://developers.home-assistant.io/docs/internationalization/core", + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Title of the integration (optional, will fallback to integration name if omitted). Only include if not a product brand." + }, + "common": { + "type": "object", + "description": "Shared strings that can be referenced using [%key:component::domain::common::key_path%]", + "additionalProperties": true + }, + "config": { + "type": "object", + "description": "Translations for the configuration flow", + "properties": { + "flow_title": { + "type": "string", + "description": "Title shown in list (only rendered if placeholders required), e.g. 'Discovered Device ({host})'" }, - "common": { - "type": "object", - "description": "Shared strings that can be referenced using [%key:component::domain::common::key_path%]", - "additionalProperties": true + "entry_type": { + "type": "string", + "description": "Label explaining what an entry represents (optional, only if default translations are misleading)" }, - "config": { + "initiate_flow": { + "type": "object", + "description": "Menu or button labels for starting flows", + "properties": { + "reconfigure": { + "type": "string", + "description": "Label for reconfigure flow" + }, + "user": { + "type": "string", + "description": "Label for user flow" + } + } + }, + "step": { + "type": "object", + "description": "Translations for each config flow step", + "additionalProperties": { "type": "object", - "description": "Translations for the configuration flow", "properties": { - "flow_title": { - "type": "string", - "description": "Title shown in list (only rendered if placeholders required), e.g. 'Discovered Device ({host})'" - }, - "entry_type": { - "type": "string", - "description": "Label explaining what an entry represents (optional, only if default translations are misleading)" - }, - "initiate_flow": { - "type": "object", - "description": "Menu or button labels for starting flows", - "properties": { - "reconfigure": { - "type": "string", - "description": "Label for reconfigure flow" - }, - "user": { - "type": "string", - "description": "Label for user flow" - } - } - }, - "step": { - "type": "object", - "description": "Translations for each config flow step", - "additionalProperties": { - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "User-visible title of the step (will show integration name if omitted)" - }, - "description": { - "type": "string", - "description": "Markdown description shown with the step (optional)" - }, - "data": { - "type": "object", - "description": "Labels for input fields", - "additionalProperties": { - "type": "string" - } - }, - "data_description": { - "type": "object", - "description": "Descriptions for input fields", - "additionalProperties": { - "type": "string" - } - }, - "sections": { - "type": "object", - "description": "Labels for form sections (only if form has sections)", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Section label" - } - } - } - } - } - } - }, - "error": { - "type": "object", - "description": "Error messages returned by the flow", - "additionalProperties": { - "type": "string" - } - }, - "abort": { - "type": "object", - "description": "Abort messages (supports Markdown)", - "additionalProperties": { - "type": "string" - } - }, - "progress": { - "type": "object", - "description": "Progress messages for async_show_progress (supports Markdown)", - "additionalProperties": { - "type": "string" - } - }, - "create_entry": { - "type": "object", - "description": "Success dialog messages (supports Markdown)", - "properties": { - "default": { - "type": "string", - "description": "Default message if async_create_entry called with description=None" - } - }, - "additionalProperties": { - "type": "string", - "description": "Custom messages for specific description keys" - } - } - } - }, - "options": { - "type": "object", - "description": "Translations for the options flow (same format as config)" - }, - "config_subentries": { - "type": "object", - "description": "Translations for config subentry flows (map of subentry types, each with same format as config)", - "additionalProperties": { - "type": "object" - } - }, - "selector": { - "type": "object", - "description": "Translations for selector options. The key is the translation_key set in SelectSelectorConfig. CRITICAL: Use selector.{translation_key}.options.{value}, NOT selector.select.{translation_key}", - "additionalProperties": { + "title": { + "type": "string", + "description": "User-visible title of the step (will show integration name if omitted)" + }, + "description": { + "type": "string", + "description": "Markdown description shown with the step (optional)" + }, + "data": { "type": "object", - "properties": { - "options": { - "type": "object", - "description": "Option label translations for select selectors. Keys must match the values passed in the options list.", - "additionalProperties": { - "type": "string" - } - }, - "unit_of_measurement": { - "type": "object", - "description": "Unit translations for number selectors", - "additionalProperties": { - "type": "string" - } - } - } - } - }, - "services": { - "type": "object", - "description": "Translations for service actions", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Service action name" - }, - "description": { - "type": "string", - "description": "Service action description" - }, - "fields": { - "type": "object", - "description": "Field translations", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Field name" - }, - "description": { - "type": "string", - "description": "Field description" - } - } - } - }, - "sections": { - "type": "object", - "description": "Collapsible section labels", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Section name" - } - } - } - } - } - } - }, - "entity": { - "type": "object", - "description": "Translations for entities", - "additionalProperties": { - "type": "object", - "description": "Entity domain (sensor, binary_sensor, etc.)", + "description": "Labels for input fields", "additionalProperties": { - "type": "object", - "description": "Entity translation_key", - "properties": { - "name": { - "type": "string", - "description": "Entity name (only for entities with has_entity_name=True)" - }, - "state": { - "type": "object", - "description": "State translations", - "additionalProperties": { - "type": "string" - } - }, - "state_attributes": { - "type": "object", - "description": "Entity state attribute translations", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Attribute name" - }, - "state": { - "type": "object", - "description": "Attribute state translations", - "additionalProperties": { - "type": "string" - } - } - } - } - }, - "unit_of_measurement": { - "type": "string", - "description": "Unit of measurement translation (for sensor/number entities)" - } - } + "type": "string" } - } - }, - "entity_component": { - "type": "object", - "description": "Translations for entity components (if integration provides entities under its domain)", - "additionalProperties": { + }, + "data_description": { "type": "object", - "description": "Device class or '_' for default", - "properties": { - "state": { - "type": "object", - "description": "State translations for this device class", - "additionalProperties": { - "type": "string" - } - }, - "state_attributes": { - "type": "object", - "description": "Attribute name and state translations", - "additionalProperties": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Attribute name" - }, - "state": { - "type": "object", - "description": "Attribute state values", - "additionalProperties": { - "type": "string" - } - } - } - } - } + "description": "Descriptions for input fields", + "additionalProperties": { + "type": "string" } - } - }, - "device": { - "type": "object", - "description": "Translations for device names", - "additionalProperties": { + }, + "sections": { "type": "object", - "properties": { + "description": "Labels for form sections (only if form has sections)", + "additionalProperties": { + "type": "object", + "properties": { "name": { - "type": "string", - "description": "Device name (set device's translation_key to use this)" + "type": "string", + "description": "Section label" } + } } + } } + } }, - "device_automation": { - "type": "object", - "description": "Translations for device automations", - "properties": { - "action_type": { - "type": "object", - "description": "Device action translations", - "additionalProperties": { - "type": "string" - } - }, - "condition_type": { - "type": "object", - "description": "Device condition translations", - "additionalProperties": { - "type": "string" - } - }, - "trigger_type": { - "type": "object", - "description": "Device trigger translations", - "additionalProperties": { - "type": "string" - } - }, - "trigger_subtype": { - "type": "object", - "description": "Device trigger subtype translations (e.g., button names)", - "additionalProperties": { - "type": "string" - } - } - } + "error": { + "type": "object", + "description": "Error messages returned by the flow", + "additionalProperties": { + "type": "string" + } }, - "exceptions": { - "type": "object", - "description": "Translations for HomeAssistantError and subclasses", - "additionalProperties": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Exception message (supports placeholders)" - } - } - } + "abort": { + "type": "object", + "description": "Abort messages (supports Markdown)", + "additionalProperties": { + "type": "string" + } }, - "issues": { - "type": "object", - "description": "Translations for repairs issues", - "additionalProperties": { - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "Issue title" - }, - "description": { - "type": "string", - "description": "Issue description (exactly one of 'description' or 'fix_flow' must be present)" - }, - "fix_flow": { - "type": "object", - "description": "Repair flow translations (same format as config flow, exactly one of 'description' or 'fix_flow' must be present)" - } - } + "progress": { + "type": "object", + "description": "Progress messages for async_show_progress (supports Markdown)", + "additionalProperties": { + "type": "string" + } + }, + "create_entry": { + "type": "object", + "description": "Success dialog messages (supports Markdown)", + "properties": { + "default": { + "type": "string", + "description": "Default message if async_create_entry called with description=None" } + }, + "additionalProperties": { + "type": "string", + "description": "Custom messages for specific description keys" + } } + } + }, + "options": { + "type": "object", + "description": "Translations for the options flow (same format as config)" + }, + "config_subentries": { + "type": "object", + "description": "Translations for config subentry flows (map of subentry types, each with same format as config)", + "additionalProperties": { + "type": "object" + } + }, + "selector": { + "type": "object", + "description": "Translations for selector options. The key is the translation_key set in SelectSelectorConfig. CRITICAL: Use selector.{translation_key}.options.{value}, NOT selector.select.{translation_key}", + "additionalProperties": { + "type": "object", + "properties": { + "options": { + "type": "object", + "description": "Option label translations for select selectors. Keys must match the values passed in the options list.", + "additionalProperties": { + "type": "string" + } + }, + "unit_of_measurement": { + "type": "object", + "description": "Unit translations for number selectors", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "services": { + "type": "object", + "description": "Translations for service actions", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Service action name" + }, + "description": { + "type": "string", + "description": "Service action description" + }, + "fields": { + "type": "object", + "description": "Field translations", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Field name" + }, + "description": { + "type": "string", + "description": "Field description" + } + } + } + }, + "sections": { + "type": "object", + "description": "Collapsible section labels", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Section name" + } + } + } + } + } + } + }, + "entity": { + "type": "object", + "description": "Translations for entities", + "additionalProperties": { + "type": "object", + "description": "Entity domain (sensor, binary_sensor, etc.)", + "additionalProperties": { + "type": "object", + "description": "Entity translation_key", + "properties": { + "name": { + "type": "string", + "description": "Entity name (only for entities with has_entity_name=True)" + }, + "state": { + "type": "object", + "description": "State translations", + "additionalProperties": { + "type": "string" + } + }, + "state_attributes": { + "type": "object", + "description": "Entity state attribute translations", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Attribute name" + }, + "state": { + "type": "object", + "description": "Attribute state translations", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "unit_of_measurement": { + "type": "string", + "description": "Unit of measurement translation (for sensor/number entities)" + } + } + } + } + }, + "entity_component": { + "type": "object", + "description": "Translations for entity components (if integration provides entities under its domain)", + "additionalProperties": { + "type": "object", + "description": "Device class or '_' for default", + "properties": { + "state": { + "type": "object", + "description": "State translations for this device class", + "additionalProperties": { + "type": "string" + } + }, + "state_attributes": { + "type": "object", + "description": "Attribute name and state translations", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Attribute name" + }, + "state": { + "type": "object", + "description": "Attribute state values", + "additionalProperties": { + "type": "string" + } + } + } + } + } + } + } + }, + "device": { + "type": "object", + "description": "Translations for device names", + "additionalProperties": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Device name (set device's translation_key to use this)" + } + } + } + }, + "device_automation": { + "type": "object", + "description": "Translations for device automations", + "properties": { + "action_type": { + "type": "object", + "description": "Device action translations", + "additionalProperties": { + "type": "string" + } + }, + "condition_type": { + "type": "object", + "description": "Device condition translations", + "additionalProperties": { + "type": "string" + } + }, + "trigger_type": { + "type": "object", + "description": "Device trigger translations", + "additionalProperties": { + "type": "string" + } + }, + "trigger_subtype": { + "type": "object", + "description": "Device trigger subtype translations (e.g., button names)", + "additionalProperties": { + "type": "string" + } + } + } + }, + "exceptions": { + "type": "object", + "description": "Translations for HomeAssistantError and subclasses", + "additionalProperties": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Exception message (supports placeholders)" + } + } + } + }, + "issues": { + "type": "object", + "description": "Translations for repairs issues", + "additionalProperties": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Issue title" + }, + "description": { + "type": "string", + "description": "Issue description (exactly one of 'description' or 'fix_flow' must be present)" + }, + "fix_flow": { + "type": "object", + "description": "Repair flow translations (same format as config flow, exactly one of 'description' or 'fix_flow' must be present)" + } + } + } } + } }