From fba0d5689a9545b233dccdd3a9b6c81b1d878e57 Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Wed, 20 May 2026 08:19:30 +0900 Subject: [PATCH 1/2] Add support for secondary solar sensor --- CHANGELOG.md | 8 +- README.md | 17 ++-- .../pvoutput_publisher/__init__.py | 63 ++++++++++++--- .../pvoutput_publisher/config_flow.py | 17 +++- custom_components/pvoutput_publisher/const.py | 3 +- .../pvoutput_publisher/translations/de.json | 17 ++-- .../pvoutput_publisher/translations/en.json | 23 +++--- .../pvoutput_publisher/translations/es.json | 17 ++-- .../pvoutput_publisher/translations/ja.json | 19 +++-- .../translations/zh-Hans.json | 77 +++++++++++++++++++ .../translations/zh-Hant.json | 77 +++++++++++++++++++ 11 files changed, 284 insertions(+), 54 deletions(-) create mode 100644 custom_components/pvoutput_publisher/translations/zh-Hans.json create mode 100644 custom_components/pvoutput_publisher/translations/zh-Hant.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ec73cc..579f252 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## 1.1.0 (Unreleased) -### Bugfixes -- Removes `device_class=temperature` restriction when picking your temperature sensor. (Issue#1)[https://github.com/SourceLabOrg/HomeAssistant-PVOutputPublisher/issues/1] - ### Feature Changes - Switched to strict, clock-aligned scheduling to prevent time drift and perfectly sync with PVOutput intervals. (Issue#1)[https://github.com/SourceLabOrg/HomeAssistant-PVOutputPublisher/issues/1] +- Added support for an optional secondary solar sensor to upload Power and Energy data simultaneously for maximum accuracy. +- Add language support for Chinese (Simplified & Traditional) + +### Bugfixes +- Removes `device_class=temperature` restriction when picking your temperature sensor. (Issue#1)[https://github.com/SourceLabOrg/HomeAssistant-PVOutputPublisher/issues/1] ## 1.0.1 (03/23/2026) Setup and submitted to HACs! diff --git a/README.md b/README.md index 8b90a21..dbc0c9d 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,13 @@ Please note that the code and documentation for this project were primarily gene ## Features * **UI Config Flow:** Fully configurable via the Home Assistant UI. No YAML required. * **Multi-System Support:** Publish data for multiple solar arrays or inverters to different PVOutput System IDs using a single API key. +* **Strict Clock Alignment:** Synchronizes uploads to exact wall-clock intervals (e.g., :00, :05, :10) to prevent data drift and match PVOutput's native 5-minute buckets perfectly, even after Home Assistant restarts. * **Smart Data Detection:** Automatically formats the payload based on the units of your selected sensors (Watts vs. Watt-hours, Celsius vs. Fahrenheit). -* **Lifetime Energy Support:** Automatically detects `state_class: total` sensors and flags PVOutput to calculate your daily yield and instantaneous power curves for you. +* **Maximum Accuracy Dual-Sensors:** Support for selecting both Power and Energy sensors simultaneously to plot the most accurate live power curves without relying on backend estimation. +* **Lifetime Energy Support:** Automatically detects `state_class: total` sensors and flags PVOutput to calculate your daily yield for you. * **Comprehensive Metrics:** Supports pushing Generation, Consumption, and Temperature data simultaneously. * **Last Upload Sensor:** Creates a timestamp entity in Home Assistant so you can monitor exactly when the last successful push occurred. -* **Multi-Language Support:** Fully translated into English, Japanese, Spanish, and German. +* **Multi-Language Support:** Fully translated into English, Japanese, Spanish, German, and Chinese (Simplified & Traditional). --- @@ -24,9 +26,9 @@ Please note that the code and documentation for this project were primarily gene PVOutput requires data to be formatted precisely. This integration looks at the `unit_of_measurement` and `state_class` of your selected sensors and automatically handles the conversions: ### Generation & Consumption -* **Power (Watts / kW):** Automatically converted to Watts and sent as `v2` (Generation) or `v4` (Consumption). -* **Daily Energy (Wh / kWh):** Automatically converted to Watt-hours and sent as `v1` (Generation) or `v3` (Consumption). -* **Lifetime Energy:** If your sensor tracks lifetime yield (e.g., `state_class: total_increasing`), the integration sends the `&c1=1` flag. PVOutput will automatically calculate your daily generation and live power curves by comparing the intervals. +* **Single Sensor (Smart Detection):** You can select a single Power (W) or Energy (Wh) sensor. The integration will upload it, and PVOutput will automatically estimate the missing metric. +* **Dual Sensors (Maximum Accuracy):** For the best results, select BOTH a Power and an Energy sensor in the UI configuration. The integration will automatically detect which is which and upload them simultaneously, providing exact live output and daily totals without requiring PVOutput to do any mathematical guessing. +* **Lifetime Energy:** If your sensor tracks lifetime yield (e.g., `state_class: total_increasing`), the integration sends the `&c1=1` flag. ### Temperature * If your Home Assistant sensor uses Fahrenheit (`°F`), it will automatically be converted to Celsius before uploading, as PVOutput strictly requires Celsius for its `v5` parameter. @@ -56,8 +58,9 @@ This integration is installed via [HACS](https://hacs.xyz/). 5. Add your first system by providing: * **System Name:** A friendly name for your reference. * **System ID:** Your PVOutput System ID. - * **Solar Generation Sensor:** Your inverter's power or energy sensor. - * **Power/Energy Consumption Sensor:** (Optional) Your home's power draw or energy usage sensor. + * **Primary Solar Sensor:** Your inverter's power (W) or energy (Wh) sensor. + * **Secondary Solar Sensor:** (Optional) If you selected a Power (W) sensor above, select your Energy (Wh) sensor here, or vice versa, for maximum accuracy. If you only provide the primary sensor, PVOutput will automatically estimate the missing value, which may result in less accurate data. + * **Consumption Sensor:** (Optional) Your home's power draw or energy usage sensor. * **Temperature Sensor:** (Optional) Outside temperature. * **Update Frequency:** How often to push data to PVOutput (5 to 180 minutes). diff --git a/custom_components/pvoutput_publisher/__init__.py b/custom_components/pvoutput_publisher/__init__.py index 7c2edce..aadaa0a 100644 --- a/custom_components/pvoutput_publisher/__init__.py +++ b/custom_components/pvoutput_publisher/__init__.py @@ -1,6 +1,6 @@ import logging import aiohttp -from datetime import datetime, timedelta +from datetime import datetime from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant @@ -12,8 +12,8 @@ from .const import ( DOMAIN, CONF_API_KEY, CONF_SYSTEMS, CONF_NAME, CONF_SYSTEM_ID, - CONF_ENTITY_ID, CONF_CONSUMPTION_ENTITY_ID, CONF_TEMPERATURE_ENTITY_ID, - CONF_FREQUENCY, PVOUTPUT_API_URL + CONF_ENTITY_ID, CONF_SECONDARY_ENTITY_ID, CONF_CONSUMPTION_ENTITY_ID, + CONF_TEMPERATURE_ENTITY_ID, CONF_FREQUENCY, PVOUTPUT_API_URL ) _LOGGER = logging.getLogger(__name__) @@ -31,13 +31,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: for system in systems: system_id = system[CONF_SYSTEM_ID] generation_ent_id = system[CONF_ENTITY_ID] + secondary_generation_ent_id = system.get(CONF_SECONDARY_ENTITY_ID) consumption_ent_id = system.get(CONF_CONSUMPTION_ENTITY_ID) temperature_ent_id = system.get(CONF_TEMPERATURE_ENTITY_ID) frequency = int(system[CONF_FREQUENCY]) sys_name = system.get(CONF_NAME, system_id) # We pass loop variables as default arguments to avoid Python closure late-binding bugs - async def push_data(now: datetime, sys_id=system_id, gen_id=generation_ent_id, con_id=consumption_ent_id, temp_id=temperature_ent_id, name=sys_name): + async def push_data(now: datetime, sys_id=system_id, gen_id=generation_ent_id, sec_id=secondary_generation_ent_id, con_id=consumption_ent_id, temp_id=temperature_ent_id, name=sys_name): gen_state = hass.states.get(gen_id) if not gen_state or gen_state.state in ['unknown', 'unavailable']: return @@ -59,7 +60,11 @@ async def push_data(now: datetime, sys_id=system_id, gen_id=generation_ent_id, c # This list will hold our human-readable log strings log_parts = [] - # 1. Add Generation Data (v1 / v2) + # Flags to prevent overwriting if user selects duplicate sensor types + has_energy_v1 = False + has_power_v2 = False + + # 1A. Primary Generation Data if gen_unit in ["wh", "kwh", "mwh"]: raw_gen = gen_value if gen_unit == "kwh": @@ -67,20 +72,60 @@ async def push_data(now: datetime, sys_id=system_id, gen_id=generation_ent_id, c elif gen_unit == "mwh": gen_value *= 1000000 - # Tell PVOutput to calculate daily yield if this is a lifetime sensor if gen_state_class in ["total", "total_increasing"]: payload += "&c1=1" - log_parts.append(f"Gen (Lifetime): {raw_gen} {gen_unit} -> v1={int(gen_value)}") + log_parts.append(f"Gen1 (Lifetime): {raw_gen} {gen_unit} -> v1={int(gen_value)}") else: - log_parts.append(f"Gen (Daily): {raw_gen} {gen_unit} -> v1={int(gen_value)}") + log_parts.append(f"Gen1 (Daily): {raw_gen} {gen_unit} -> v1={int(gen_value)}") payload += f"&v1={int(gen_value)}" + has_energy_v1 = True else: raw_gen = gen_value if gen_unit in ["kw", "kilowatt", "kilowatts"]: gen_value *= 1000 payload += f"&v2={int(gen_value)}" - log_parts.append(f"Gen (Power): {raw_gen} {gen_unit} -> v2={int(gen_value)}") + log_parts.append(f"Gen1 (Power): {raw_gen} {gen_unit} -> v2={int(gen_value)}") + has_power_v2 = True + + # 1B. Secondary Generation Data (Optional) + if sec_id: + sec_state = hass.states.get(sec_id) + if sec_state and sec_state.state not in ['unknown', 'unavailable']: + try: + sec_value = float(sec_state.state) + sec_unit = sec_state.attributes.get("unit_of_measurement", "").lower() + sec_state_class = sec_state.attributes.get("state_class", "").lower() + raw_sec = sec_value + + if sec_unit in ["wh", "kwh", "mwh"]: + if has_energy_v1: + _LOGGER.warning("PVOutput [%s]: Ignored secondary sensor. You selected two Energy (Wh) sensors.", name) + else: + if sec_unit == "kwh": + sec_value *= 1000 + elif sec_unit == "mwh": + sec_value *= 1000000 + + if sec_state_class in ["total", "total_increasing"]: + payload += "&c1=1" + log_parts.append(f"Gen2 (Lifetime): {raw_sec} {sec_unit} -> v1={int(sec_value)}") + else: + log_parts.append(f"Gen2 (Daily): {raw_sec} {sec_unit} -> v1={int(sec_value)}") + + payload += f"&v1={int(sec_value)}" + has_energy_v1 = True + else: + if has_power_v2: + _LOGGER.warning("PVOutput [%s]: Ignored secondary sensor. You selected two Power (W) sensors.", name) + else: + if sec_unit in ["kw", "kilowatt", "kilowatts"]: + sec_value *= 1000 + payload += f"&v2={int(sec_value)}" + log_parts.append(f"Gen2 (Power): {raw_sec} {sec_unit} -> v2={int(sec_value)}") + has_power_v2 = True + except ValueError: + pass # 2. Add Optional Consumption Data (v3 / v4) if con_id: diff --git a/custom_components/pvoutput_publisher/config_flow.py b/custom_components/pvoutput_publisher/config_flow.py index f66f542..d6a7cee 100644 --- a/custom_components/pvoutput_publisher/config_flow.py +++ b/custom_components/pvoutput_publisher/config_flow.py @@ -5,8 +5,8 @@ from .const import ( DOMAIN, CONF_API_KEY, CONF_SYSTEMS, CONF_NAME, CONF_SYSTEM_ID, - CONF_ENTITY_ID, CONF_CONSUMPTION_ENTITY_ID, CONF_TEMPERATURE_ENTITY_ID, - CONF_FREQUENCY, DEFAULT_FREQUENCY + CONF_ENTITY_ID, CONF_SECONDARY_ENTITY_ID, CONF_CONSUMPTION_ENTITY_ID, + CONF_TEMPERATURE_ENTITY_ID, CONF_FREQUENCY, DEFAULT_FREQUENCY ) def _get_system_schema(existing_data=None): @@ -20,10 +20,20 @@ def _get_system_schema(existing_data=None): if existing_data: schema[vol.Required(CONF_NAME, default=existing_data.get(CONF_NAME, existing_data.get(CONF_SYSTEM_ID)))] = str schema[vol.Required(CONF_SYSTEM_ID, default=existing_data.get(CONF_SYSTEM_ID))] = str + schema[vol.Required(CONF_ENTITY_ID, default=existing_data.get(CONF_ENTITY_ID))] = selector.EntitySelector( selector.EntitySelectorConfig(domain="sensor", device_class=["power", "energy"]) ) + if existing_data.get(CONF_SECONDARY_ENTITY_ID): + schema[vol.Optional(CONF_SECONDARY_ENTITY_ID, default=existing_data.get(CONF_SECONDARY_ENTITY_ID))] = selector.EntitySelector( + selector.EntitySelectorConfig(domain="sensor", device_class=["power", "energy"]) + ) + else: + schema[vol.Optional(CONF_SECONDARY_ENTITY_ID)] = selector.EntitySelector( + selector.EntitySelectorConfig(domain="sensor", device_class=["power", "energy"]) + ) + if existing_data.get(CONF_CONSUMPTION_ENTITY_ID): schema[vol.Optional(CONF_CONSUMPTION_ENTITY_ID, default=existing_data.get(CONF_CONSUMPTION_ENTITY_ID))] = selector.EntitySelector( selector.EntitySelectorConfig(domain="sensor", device_class=["power", "energy"]) @@ -50,6 +60,9 @@ def _get_system_schema(existing_data=None): schema[vol.Required(CONF_ENTITY_ID)] = selector.EntitySelector( selector.EntitySelectorConfig(domain="sensor", device_class=["power", "energy"]) ) + schema[vol.Optional(CONF_SECONDARY_ENTITY_ID)] = selector.EntitySelector( + selector.EntitySelectorConfig(domain="sensor", device_class=["power", "energy"]) + ) schema[vol.Optional(CONF_CONSUMPTION_ENTITY_ID)] = selector.EntitySelector( selector.EntitySelectorConfig(domain="sensor", device_class=["power", "energy"]) ) diff --git a/custom_components/pvoutput_publisher/const.py b/custom_components/pvoutput_publisher/const.py index 2d479f1..51b2dfd 100644 --- a/custom_components/pvoutput_publisher/const.py +++ b/custom_components/pvoutput_publisher/const.py @@ -5,9 +5,10 @@ CONF_NAME = "name" CONF_SYSTEM_ID = "system_id" CONF_ENTITY_ID = "entity_id" +CONF_SECONDARY_ENTITY_ID = "secondary_entity_id" CONF_CONSUMPTION_ENTITY_ID = "consumption_entity_id" CONF_TEMPERATURE_ENTITY_ID = "temperature_entity_id" CONF_FREQUENCY = "frequency" -DEFAULT_FREQUENCY = 5 +DEFAULT_FREQUENCY = "5" PVOUTPUT_API_URL = "https://pvoutput.org/service/r2/addstatus.jsp" diff --git a/custom_components/pvoutput_publisher/translations/de.json b/custom_components/pvoutput_publisher/translations/de.json index 105df7f..763b60d 100644 --- a/custom_components/pvoutput_publisher/translations/de.json +++ b/custom_components/pvoutput_publisher/translations/de.json @@ -10,13 +10,14 @@ }, "add_system": { "title": "System Konfigurieren", - "description": "Wählen Sie die Sensoren für dieses System aus.", + "description": "Wählen Sie die Sensoren für dieses System aus.\n\n**Smarte Erkennung:** Sie können einen einzelnen Leistungs- (W) ODER Energie- (Wh) Sensor auswählen. Die Integration formatiert ihn und PVOutput schätzt den fehlenden Wert.\n\n**Maximale Genauigkeit:** Für die besten Ergebnisse wählen Sie SOWOHL einen Leistungs- als auch einen Energiesensor. Die Integration erkennt automatisch, welcher welcher ist, und lädt beide gleichzeitig hoch.", "data": { "name": "Systemname", "system_id": "System-ID", - "entity_id": "Solarerzeugungs-Sensor", - "consumption_entity_id": "Stromverbrauch-Sensor", - "temperature_entity_id": "Temperatursensor", + "entity_id": "Primärer Solarsensor", + "secondary_entity_id": "Sekundärer Solarsensor (Optional)", + "consumption_entity_id": "Stromverbrauch-Sensor (Optional)", + "temperature_entity_id": "Temperatursensor (Optional)", "frequency": "Aktualisierungsintervall" }, "data_description": { @@ -55,12 +56,14 @@ }, "add_system": { "title": "System Konfigurieren", + "description": "Wählen Sie die Sensoren für dieses System aus.\n\n**Smarte Erkennung:** Sie können einen einzelnen Leistungs- (W) ODER Energie- (Wh) Sensor auswählen. Die Integration formatiert ihn und PVOutput schätzt den fehlenden Wert.\n\n**Maximale Genauigkeit:** Für die besten Ergebnisse wählen Sie SOWOHL einen Leistungs- als auch einen Energiesensor. Die Integration erkennt automatisch, welcher welcher ist, und lädt beide gleichzeitig hoch.", "data": { "name": "Systemname", "system_id": "System-ID", - "entity_id": "Solarerzeugungs-Sensor", - "consumption_entity_id": "Stromverbrauch-Sensor", - "temperature_entity_id": "Temperatursensor", + "entity_id": "Primärer Solarsensor", + "secondary_entity_id": "Sekundärer Solarsensor (Optional)", + "consumption_entity_id": "Stromverbrauch-Sensor (Optional)", + "temperature_entity_id": "Temperatursensor (Optional)", "frequency": "Aktualisierungsintervall" }, "data_description": { diff --git a/custom_components/pvoutput_publisher/translations/en.json b/custom_components/pvoutput_publisher/translations/en.json index 7d89ed5..14c3705 100644 --- a/custom_components/pvoutput_publisher/translations/en.json +++ b/custom_components/pvoutput_publisher/translations/en.json @@ -9,14 +9,15 @@ } }, "add_system": { - "title": "Configure System", - "description": "Select the sensors tracking this system.", + "title": "Configure Solar System", + "description": "Select the sensors for this solar array.\n\n**Smart Detection:** You can select a single Power (W) OR Energy (Wh) sensor. The integration will format it, and PVOutput will estimate the missing metric.\n\n**Maximum Accuracy:** For the best results, select BOTH a Power and an Energy sensor. The integration will automatically detect which is which and upload them simultaneously.", "data": { "name": "System Name", "system_id": "System ID", - "entity_id": "Solar Generation Sensor", - "consumption_entity_id": "Power/Energy Consumption Sensor", - "temperature_entity_id": "Temperature Sensor", + "entity_id": "Primary Solar Sensor", + "secondary_entity_id": "Secondary Solar Sensor (Optional)", + "consumption_entity_id": "Consumption Sensor (Optional)", + "temperature_entity_id": "Temperature Sensor (Optional)", "frequency": "Update Frequency" }, "data_description": { @@ -42,7 +43,7 @@ "step": { "systems_manager": { "title": "Manage PVOutput Publisher", - "description": "Select an action below to update your settings.", + "description": "Select an action below to update your configuration.", "data": { "action": "Action" } @@ -54,13 +55,15 @@ } }, "add_system": { - "title": "Configure System", + "title": "Configure Solar System", + "description": "Select the sensors for this solar array.\n\n**Smart Detection:** You can select a single Power (W) OR Energy (Wh) sensor. The integration will format it, and PVOutput will estimate the missing metric.\n\n**Maximum Accuracy:** For the best results, select BOTH a Power and an Energy sensor. The integration will automatically detect which is which and upload them simultaneously.", "data": { "name": "System Name", "system_id": "System ID", - "entity_id": "Solar Generation Sensor", - "consumption_entity_id": "Power/Energy Consumption Sensor", - "temperature_entity_id": "Temperature Sensor", + "entity_id": "Primary Solar Sensor", + "secondary_entity_id": "Secondary Solar Sensor (Optional)", + "consumption_entity_id": "Consumption Sensor (Optional)", + "temperature_entity_id": "Temperature Sensor (Optional)", "frequency": "Update Frequency" }, "data_description": { diff --git a/custom_components/pvoutput_publisher/translations/es.json b/custom_components/pvoutput_publisher/translations/es.json index 3b6ce51..8aa26aa 100644 --- a/custom_components/pvoutput_publisher/translations/es.json +++ b/custom_components/pvoutput_publisher/translations/es.json @@ -10,13 +10,14 @@ }, "add_system": { "title": "Configurar Sistema", - "description": "Seleccione los sensores para este sistema.", + "description": "Seleccione los sensores para este sistema solar.\n\n**Detección Inteligente:** Puede seleccionar un solo sensor de Potencia (W) O de Energía (Wh). La integración lo formateará y PVOutput estimará la métrica faltante.\n\n**Precisión Máxima:** Para obtener los mejores resultados, seleccione AMBOS sensores: uno de Potencia y uno de Energía. La integración detectará automáticamente cuál es cuál y los subirá simultáneamente.", "data": { "name": "Nombre del Sistema", "system_id": "ID del Sistema", - "entity_id": "Sensor de Generación Solar", - "consumption_entity_id": "Sensor de Consumo Eléctrico", - "temperature_entity_id": "Sensor de Temperatura", + "entity_id": "Sensor Solar Principal", + "secondary_entity_id": "Sensor Solar Secundario (Opcional)", + "consumption_entity_id": "Sensor de Consumo Eléctrico (Opcional)", + "temperature_entity_id": "Sensor de Temperatura (Opcional)", "frequency": "Frecuencia de Actualización" }, "data_description": { @@ -55,12 +56,14 @@ }, "add_system": { "title": "Configurar Sistema", + "description": "Seleccione los sensores para este sistema solar.\n\n**Detección Inteligente:** Puede seleccionar un solo sensor de Potencia (W) O de Energía (Wh). La integración lo formateará y PVOutput estimará la métrica faltante.\n\n**Precisión Máxima:** Para obtener los mejores resultados, seleccione AMBOS sensores: uno de Potencia y uno de Energía. La integración detectará automáticamente cuál es cuál y los subirá simultáneamente.", "data": { "name": "Nombre del Sistema", "system_id": "ID del Sistema", - "entity_id": "Sensor de Generación Solar", - "consumption_entity_id": "Sensor de Consumo Eléctrico", - "temperature_entity_id": "Sensor de Temperatura", + "entity_id": "Sensor Solar Principal", + "secondary_entity_id": "Sensor Solar Secundario (Opcional)", + "consumption_entity_id": "Sensor de Consumo Eléctrico (Opcional)", + "temperature_entity_id": "Sensor de Temperatura (Opcional)", "frequency": "Frecuencia de Actualización" }, "data_description": { diff --git a/custom_components/pvoutput_publisher/translations/ja.json b/custom_components/pvoutput_publisher/translations/ja.json index eef6b4c..1956a16 100644 --- a/custom_components/pvoutput_publisher/translations/ja.json +++ b/custom_components/pvoutput_publisher/translations/ja.json @@ -10,13 +10,14 @@ }, "add_system": { "title": "システムの設定", - "description": "このシステムをトラッキングするセンサーを選択してください。", + "description": "この太陽光発電システム用のセンサーを選択してください。\n\n**スマート検出:** 電力 (W) または 電力量 (Wh) センサーのいずれか1つを選択できます。インテグレーションがフォーマットを自動調整し、不足している指標はPVOutputが推定します。\n\n**最大の精度:** 最高の結果を得るには、電力センサーと電力量センサーの両方を選択してください。インテグレーションが自動的に識別し、同時にアップロードします。", "data": { "name": "システム名", "system_id": "システム ID", - "entity_id": "太陽光発電センサー", - "consumption_entity_id": "電力/エネルギー消費センサー", - "temperature_entity_id": "温度センサー", + "entity_id": "メイン太陽光発電センサー", + "secondary_entity_id": "サブ太陽光発電センサー (オプション)", + "consumption_entity_id": "電力/エネルギー消費センサー (オプション)", + "temperature_entity_id": "温度センサー (オプション)", "frequency": "更新頻度" }, "data_description": { @@ -27,7 +28,7 @@ }, "systems_manager": { "title": "システムの管理", - "description": "以下からアクションを選択してアレイを管理します。", + "description": "以下からアクションを選択してシステムを管理します。", "data": { "action": "アクション" } @@ -55,12 +56,14 @@ }, "add_system": { "title": "システムの設定", + "description": "この太陽光発電システム用のセンサーを選択してください。\n\n**スマート検出:** 電力 (W) または 電力量 (Wh) センサーのいずれか1つを選択できます。インテグレーションがフォーマットを自動調整し、不足している指標はPVOutputが推定します。\n\n**最大の精度:** 最高の結果を得るには、電力センサーと電力量センサーの両方を選択してください。インテグレーションが自動的に識別し、同時にアップロードします。", "data": { "name": "システム名", "system_id": "システム ID", - "entity_id": "太陽光発電センサー", - "consumption_entity_id": "電力/エネルギー消費センサー", - "temperature_entity_id": "温度センサー", + "entity_id": "メイン太陽光発電センサー", + "secondary_entity_id": "サブ太陽光発電センサー (オプション)", + "consumption_entity_id": "電力/エネルギー消費センサー (オプション)", + "temperature_entity_id": "温度センサー (オプション)", "frequency": "更新頻度" }, "data_description": { diff --git a/custom_components/pvoutput_publisher/translations/zh-Hans.json b/custom_components/pvoutput_publisher/translations/zh-Hans.json new file mode 100644 index 0000000..cd36fce --- /dev/null +++ b/custom_components/pvoutput_publisher/translations/zh-Hans.json @@ -0,0 +1,77 @@ +{ + "config": { + "step": { + "user": { + "title": "PVOutput Publisher 设置", + "description": "请输入您的全局 PVOutput API 密钥。", + "data": { + "api_key": "API 密钥" + } + }, + "add_system": { + "title": "设置太阳能系统", + "description": "为此太阳能阵列选择传感器。\n\n**智能检测:** 您可以选择单一的功率 (W) 或电量 (Wh) 传感器。系统将自动格式化,并由 PVOutput 估算缺失的指标。\n\n**最高精确度:** 为了获得最佳结果,请同时选择功率与电量传感器。系统将自动识别并同时上传两者的数据。", + "data": { + "name": "系统名称", + "system_id": "系统 ID", + "entity_id": "主要太阳能传感器", + "secondary_entity_id": "次要太阳能传感器 (选填)", + "consumption_entity_id": "用电消耗传感器 (选填)", + "temperature_entity_id": "温度传感器 (选填)", + "frequency": "更新频率" + }, + "data_description": { + "name": "供您自己参考的自定义名称。", + "consumption_entity_id": "(选填) 追踪您家中的能源使用情况。", + "temperature_entity_id": "(选填) 追踪室外温度。" + } + }, + "systems_manager": { + "title": "管理系统", + "description": "请选择下方的动作来管理您的阵列。", + "data": { + "action": "动作" + } + } + }, + "error": {}, + "abort": { + "already_configured": "此集成已经设置完成。" + } + }, + "options": { + "step": { + "systems_manager": { + "title": "管理 PVOutput Publisher", + "description": "请选择下方的动作来更新您的设置。", + "data": { + "action": "动作" + } + }, + "edit_api": { + "title": "编辑 API 密钥", + "data": { + "api_key": "API 密钥" + } + }, + "add_system": { + "title": "设置太阳能系统", + "description": "为此太阳能阵列选择传感器。\n\n**智能检测:** 您可以选择单一的功率 (W) 或电量 (Wh) 传感器。系统将自动格式化,并由 PVOutput 估算缺失的指标。\n\n**最高精确度:** 为了获得最佳结果,请同时选择功率与电量传感器。系统将自动识别并同时上传两者的数据。", + "data": { + "name": "系统名称", + "system_id": "系统 ID", + "entity_id": "主要太阳能传感器", + "secondary_entity_id": "次要太阳能传感器 (选填)", + "consumption_entity_id": "用电消耗传感器 (选填)", + "temperature_entity_id": "温度传感器 (选填)", + "frequency": "更新频率" + }, + "data_description": { + "name": "供您自己参考的自定义名称。", + "consumption_entity_id": "(选填) 追踪您家中的能源使用情况。", + "temperature_entity_id": "(选填) 追踪室外温度。" + } + } + } + } +} diff --git a/custom_components/pvoutput_publisher/translations/zh-Hant.json b/custom_components/pvoutput_publisher/translations/zh-Hant.json new file mode 100644 index 0000000..d955369 --- /dev/null +++ b/custom_components/pvoutput_publisher/translations/zh-Hant.json @@ -0,0 +1,77 @@ +{ + "config": { + "step": { + "user": { + "title": "PVOutput Publisher 設定", + "description": "請輸入您的全局 PVOutput API 金鑰。", + "data": { + "api_key": "API 金鑰" + } + }, + "add_system": { + "title": "設定太陽能系統", + "description": "為此太陽能陣列選擇感測器。\n\n**智慧偵測:** 您可以選擇單一的功率 (W) 或電量 (Wh) 感測器。系統將自動格式化,並由 PVOutput 估算缺失的指標。\n\n**最高精確度:** 為了獲得最佳結果,請同時選擇功率與電量感測器。系統將自動識別並同時上傳兩者的數據。", + "data": { + "name": "系統名稱", + "system_id": "系統 ID", + "entity_id": "主要太陽能感測器", + "secondary_entity_id": "次要太陽能感測器 (選填)", + "consumption_entity_id": "用電消耗感測器 (選填)", + "temperature_entity_id": "溫度感測器 (選填)", + "frequency": "更新頻率" + }, + "data_description": { + "name": "供您自己參考的自訂名稱。", + "consumption_entity_id": "(選填) 追蹤您家中的能源使用情況。", + "temperature_entity_id": "(選填) 追蹤室外溫度。" + } + }, + "systems_manager": { + "title": "管理系統", + "description": "請選擇下方的動作來管理您的陣列。", + "data": { + "action": "動作" + } + } + }, + "error": {}, + "abort": { + "already_configured": "此整合已經設定完成。" + } + }, + "options": { + "step": { + "systems_manager": { + "title": "管理 PVOutput Publisher", + "description": "請選擇下方的動作來更新您的設定。", + "data": { + "action": "動作" + } + }, + "edit_api": { + "title": "編輯 API 金鑰", + "data": { + "api_key": "API 金鑰" + } + }, + "add_system": { + "title": "設定太陽能系統", + "description": "為此太陽能陣列選擇感測器。\n\n**智慧偵測:** 您可以選擇單一的功率 (W) 或電量 (Wh) 感測器。系統將自動格式化,並由 PVOutput 估算缺失的指標。\n\n**最高精確度:** 為了獲得最佳結果,請同時選擇功率與電量感測器。系統將自動識別並同時上傳兩者的數據。", + "data": { + "name": "系統名稱", + "system_id": "系統 ID", + "entity_id": "主要太陽能感測器", + "secondary_entity_id": "次要太陽能感測器 (選填)", + "consumption_entity_id": "用電消耗感測器 (選填)", + "temperature_entity_id": "溫度感測器 (選填)", + "frequency": "更新頻率" + }, + "data_description": { + "name": "供您自己參考的自訂名稱。", + "consumption_entity_id": "(選填) 追蹤您家中的能源使用情況。", + "temperature_entity_id": "(選填) 追蹤室外溫度。" + } + } + } + } +} From 6a26d747627132d0228bd75ba9c0f3da922d2faa Mon Sep 17 00:00:00 2001 From: Stephen Powis Date: Wed, 20 May 2026 08:46:28 +0900 Subject: [PATCH 2/2] Add better inline help --- custom_components/pvoutput_publisher/translations/de.json | 4 ++++ custom_components/pvoutput_publisher/translations/en.json | 4 ++++ custom_components/pvoutput_publisher/translations/es.json | 4 ++++ custom_components/pvoutput_publisher/translations/ja.json | 4 ++++ .../pvoutput_publisher/translations/zh-Hans.json | 4 ++++ .../pvoutput_publisher/translations/zh-Hant.json | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/custom_components/pvoutput_publisher/translations/de.json b/custom_components/pvoutput_publisher/translations/de.json index 763b60d..d2eb750 100644 --- a/custom_components/pvoutput_publisher/translations/de.json +++ b/custom_components/pvoutput_publisher/translations/de.json @@ -22,6 +22,8 @@ }, "data_description": { "name": "Ein benutzerfreundlicher Name für Ihre Übersicht.", + "entity_id": "Der Leistungs- (W) oder Energie- (Wh) Sensor Ihres Wechselrichters.", + "secondary_entity_id": "Wenn Sie oben einen Leistungs- (W) Sensor ausgewählt haben, wählen Sie hier Ihren Energie- (Wh) Sensor (oder umgekehrt) für maximale Genauigkeit. Wenn leer gelassen, schätzt PVOutput den fehlenden Wert automatisch.", "consumption_entity_id": "(Optional) Erfasst den Energieverbrauch Ihres Hauses.", "temperature_entity_id": "(Optional) Erfasst die Außentemperatur." } @@ -68,6 +70,8 @@ }, "data_description": { "name": "Ein benutzerfreundlicher Name für Ihre Übersicht.", + "entity_id": "Der Leistungs- (W) oder Energie- (Wh) Sensor Ihres Wechselrichters.", + "secondary_entity_id": "Wenn Sie oben einen Leistungs- (W) Sensor ausgewählt haben, wählen Sie hier Ihren Energie- (Wh) Sensor (oder umgekehrt) für maximale Genauigkeit. Wenn leer gelassen, schätzt PVOutput den fehlenden Wert automatisch.", "consumption_entity_id": "(Optional) Erfasst den Energieverbrauch Ihres Hauses.", "temperature_entity_id": "(Optional) Erfasst die Außentemperatur." } diff --git a/custom_components/pvoutput_publisher/translations/en.json b/custom_components/pvoutput_publisher/translations/en.json index 14c3705..496b20e 100644 --- a/custom_components/pvoutput_publisher/translations/en.json +++ b/custom_components/pvoutput_publisher/translations/en.json @@ -22,6 +22,8 @@ }, "data_description": { "name": "A friendly name for your own reference.", + "entity_id": "Your inverter's power (W) or energy (Wh) sensor.", + "secondary_entity_id": "If you selected a Power (W) sensor above, select your Energy (Wh) sensor here (or vice versa) for maximum accuracy. If left blank, PVOutput will automatically estimate the missing value.", "consumption_entity_id": "(Optional) Tracks your home's energy usage.", "temperature_entity_id": "(Optional) Tracks outside temperature." } @@ -68,6 +70,8 @@ }, "data_description": { "name": "A friendly name for your own reference.", + "entity_id": "Your inverter's power (W) or energy (Wh) sensor.", + "secondary_entity_id": "If you selected a Power (W) sensor above, select your Energy (Wh) sensor here (or vice versa) for maximum accuracy. If left blank, PVOutput will automatically estimate the missing value.", "consumption_entity_id": "(Optional) Tracks your home's energy usage.", "temperature_entity_id": "(Optional) Tracks outside temperature." } diff --git a/custom_components/pvoutput_publisher/translations/es.json b/custom_components/pvoutput_publisher/translations/es.json index 8aa26aa..3a48679 100644 --- a/custom_components/pvoutput_publisher/translations/es.json +++ b/custom_components/pvoutput_publisher/translations/es.json @@ -22,6 +22,8 @@ }, "data_description": { "name": "Un nombre descriptivo para su propia referencia.", + "entity_id": "El sensor de potencia (W) o energía (Wh) de su inversor.", + "secondary_entity_id": "Si seleccionó un sensor de Potencia (W) arriba, seleccione aquí su sensor de Energía (Wh) (o viceversa) para obtener la máxima precisión. Si se deja en blanco, PVOutput estimará automáticamente el valor faltante.", "consumption_entity_id": "(Opcional) Registra el uso de energía de su hogar.", "temperature_entity_id": "(Opcional) Registra la temperatura exterior." } @@ -68,6 +70,8 @@ }, "data_description": { "name": "Un nombre descriptivo para su propia referencia.", + "entity_id": "El sensor de potencia (W) o energía (Wh) de su inversor.", + "secondary_entity_id": "Si seleccionó un sensor de Potencia (W) arriba, seleccione aquí su sensor de Energía (Wh) (o viceversa) para obtener la máxima precisión. Si se deja en blanco, PVOutput estimará automáticamente el valor faltante.", "consumption_entity_id": "(Opcional) Registra el uso de energía de su hogar.", "temperature_entity_id": "(Opcional) Registra la temperatura exterior." } diff --git a/custom_components/pvoutput_publisher/translations/ja.json b/custom_components/pvoutput_publisher/translations/ja.json index 1956a16..f96c67d 100644 --- a/custom_components/pvoutput_publisher/translations/ja.json +++ b/custom_components/pvoutput_publisher/translations/ja.json @@ -22,6 +22,8 @@ }, "data_description": { "name": "管理用のわかりやすい名前。", + "entity_id": "パワーコンディショナの電力 (W) または電力量 (Wh) センサー。", + "secondary_entity_id": "最大の精度を得るために、上で電力 (W) センサーを選択した場合は、ここで電力量 (Wh) センサーを選択してください(その逆も同様です)。空白の場合、PVOutputは不足している値を自動的に推定します。", "consumption_entity_id": "(オプション) 自宅のエネルギー使用量を記録します。", "temperature_entity_id": "(オプション) 外気温を記録します。" } @@ -68,6 +70,8 @@ }, "data_description": { "name": "管理用のわかりやすい名前。", + "entity_id": "パワーコンディショナの電力 (W) または電力量 (Wh) センサー。", + "secondary_entity_id": "最大の精度を得るために、上で電力 (W) センサーを選択した場合は、ここで電力量 (Wh) センサーを選択してください(その逆も同様です)。空白の場合、PVOutputは不足している値を自動的に推定します。", "consumption_entity_id": "(オプション) 自宅のエネルギー使用量を記録します。", "temperature_entity_id": "(オプション) 外気温を記録します。" } diff --git a/custom_components/pvoutput_publisher/translations/zh-Hans.json b/custom_components/pvoutput_publisher/translations/zh-Hans.json index cd36fce..13ba773 100644 --- a/custom_components/pvoutput_publisher/translations/zh-Hans.json +++ b/custom_components/pvoutput_publisher/translations/zh-Hans.json @@ -22,6 +22,8 @@ }, "data_description": { "name": "供您自己参考的自定义名称。", + "entity_id": "您逆变器的功率 (W) 或电量 (Wh) 传感器。", + "secondary_entity_id": "如果您在上方选择了功率 (W) 传感器,请在此处选择电量 (Wh) 传感器(反之亦然)以达到最高精确度。如果留空,PVOutput 将自动估算缺失的值。", "consumption_entity_id": "(选填) 追踪您家中的能源使用情况。", "temperature_entity_id": "(选填) 追踪室外温度。" } @@ -68,6 +70,8 @@ }, "data_description": { "name": "供您自己参考的自定义名称。", + "entity_id": "您逆变器的功率 (W) 或电量 (Wh) 传感器。", + "secondary_entity_id": "如果您在上方选择了功率 (W) 传感器,请在此处选择电量 (Wh) 传感器(反之亦然)以达到最高精确度。如果留空,PVOutput 将自动估算缺失的值。", "consumption_entity_id": "(选填) 追踪您家中的能源使用情况。", "temperature_entity_id": "(选填) 追踪室外温度。" } diff --git a/custom_components/pvoutput_publisher/translations/zh-Hant.json b/custom_components/pvoutput_publisher/translations/zh-Hant.json index d955369..ec6e97c 100644 --- a/custom_components/pvoutput_publisher/translations/zh-Hant.json +++ b/custom_components/pvoutput_publisher/translations/zh-Hant.json @@ -22,6 +22,8 @@ }, "data_description": { "name": "供您自己參考的自訂名稱。", + "entity_id": "您逆變器的功率 (W) 或電量 (Wh) 感測器。", + "secondary_entity_id": "如果您在上方選擇了功率 (W) 感測器,請在此處選擇電量 (Wh) 感測器(反之亦然)以達到最高精確度。如果留空,PVOutput 將自動估算缺失的值。", "consumption_entity_id": "(選填) 追蹤您家中的能源使用情況。", "temperature_entity_id": "(選填) 追蹤室外溫度。" } @@ -68,6 +70,8 @@ }, "data_description": { "name": "供您自己參考的自訂名稱。", + "entity_id": "您逆變器的功率 (W) 或電量 (Wh) 感測器。", + "secondary_entity_id": "如果您在上方選擇了功率 (W) 感測器,請在此處選擇電量 (Wh) 感測器(反之亦然)以達到最高精確度。如果留空,PVOutput 將自動估算缺失的值。", "consumption_entity_id": "(選填) 追蹤您家中的能源使用情況。", "temperature_entity_id": "(選填) 追蹤室外溫度。" }