Skip to content

Commit 98a68e5

Browse files
authored
Merge pull request #6 from SourceLabOrg/spp/voltage
Add support for voltage parameter
2 parents 4f478cf + e7f3488 commit 98a68e5

12 files changed

Lines changed: 76 additions & 21 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
The format is based on [Keep a Changelog](http://keepachangelog.com/)
33
and this project adheres to [Semantic Versioning](http://semver.org/).
44

5-
## 1.1.0 (Unreleased)
5+
## 1.2.0 (06/05/2026)
6+
7+
### Feature Changes
8+
- Add support for optional voltage sensor (v6 parameter). (Issue#5)[https://github.com/SourceLabOrg/HomeAssistant-PVOutputPublisher/issues/5]
9+
10+
## 1.1.0 (05/20/2026)
611

712
### Feature Changes
813
- 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]

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ This integration is installed via [HACS](https://hacs.xyz/).
6262
* **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.
6363
* **Consumption Sensor:** (Optional) Your home's power draw or energy usage sensor.
6464
* **Temperature Sensor:** (Optional) Outside temperature.
65+
* **Voltage Sensor:** (Optional) Tracks grid/inverter operational voltage lines.
6566
* **Update Frequency:** How often to push data to PVOutput (5 to 180 minutes).
6667

6768
### Managing Multiple Systems

‎custom_components/pvoutput_publisher/__init__.py‎

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from .const import (
1414
DOMAIN, CONF_API_KEY, CONF_SYSTEMS, CONF_NAME, CONF_SYSTEM_ID,
1515
CONF_ENTITY_ID, CONF_SECONDARY_ENTITY_ID, CONF_CONSUMPTION_ENTITY_ID,
16-
CONF_TEMPERATURE_ENTITY_ID, CONF_FREQUENCY, PVOUTPUT_API_URL
16+
CONF_TEMPERATURE_ENTITY_ID, CONF_FREQUENCY, PVOUTPUT_API_URL, CONF_VOLTAGE_ENTITY_ID
1717
)
1818

1919
_LOGGER = logging.getLogger(__name__)
@@ -34,11 +34,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
3434
secondary_generation_ent_id = system.get(CONF_SECONDARY_ENTITY_ID)
3535
consumption_ent_id = system.get(CONF_CONSUMPTION_ENTITY_ID)
3636
temperature_ent_id = system.get(CONF_TEMPERATURE_ENTITY_ID)
37+
voltage_ent_id = system.get(CONF_VOLTAGE_ENTITY_ID)
3738
frequency = int(system[CONF_FREQUENCY])
3839
sys_name = system.get(CONF_NAME, system_id)
3940

4041
# We pass loop variables as default arguments to avoid Python closure late-binding bugs
41-
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):
42+
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, volt_id=voltage_ent_id, name=sys_name):
4243
gen_state = hass.states.get(gen_id)
4344
if not gen_state or gen_state.state in ['unknown', 'unavailable']:
4445
return
@@ -64,7 +65,7 @@ async def push_data(now: datetime, sys_id=system_id, gen_id=generation_ent_id, s
6465
has_energy_v1 = False
6566
has_power_v2 = False
6667

67-
# 1A. Primary Generation Data
68+
# Primary Generation Data
6869
if gen_unit in ["wh", "kwh", "mwh"]:
6970
raw_gen = gen_value
7071
if gen_unit == "kwh":
@@ -88,7 +89,7 @@ async def push_data(now: datetime, sys_id=system_id, gen_id=generation_ent_id, s
8889
log_parts.append(f"Gen1 (Power): {raw_gen} {gen_unit} -> v2={int(gen_value)}")
8990
has_power_v2 = True
9091

91-
# 1B. Secondary Generation Data (Optional)
92+
# Secondary Generation Data (Optional)
9293
if sec_id:
9394
sec_state = hass.states.get(sec_id)
9495
if sec_state and sec_state.state not in ['unknown', 'unavailable']:
@@ -127,7 +128,7 @@ async def push_data(now: datetime, sys_id=system_id, gen_id=generation_ent_id, s
127128
except ValueError:
128129
pass
129130

130-
# 2. Add Optional Consumption Data (v3 / v4)
131+
# Add Optional Consumption Data (v3 / v4)
131132
if con_id:
132133
con_state = hass.states.get(con_id)
133134
if con_state and con_state.state not in ['unknown', 'unavailable']:
@@ -151,7 +152,7 @@ async def push_data(now: datetime, sys_id=system_id, gen_id=generation_ent_id, s
151152
except ValueError:
152153
pass
153154

154-
# 3. Add Optional Temperature Data (v5)
155+
# Add Optional Temperature Data (v5)
155156
if temp_id:
156157
temp_state = hass.states.get(temp_id)
157158
if temp_state and temp_state.state not in ['unknown', 'unavailable']:
@@ -170,6 +171,17 @@ async def push_data(now: datetime, sys_id=system_id, gen_id=generation_ent_id, s
170171
except ValueError:
171172
pass
172173

174+
# Add Optional Voltage Data (v6)
175+
if volt_id:
176+
volt_state = hass.states.get(volt_id)
177+
if volt_state and volt_state.state not in ['unknown', 'unavailable']:
178+
try:
179+
volt_value = float(volt_state.state)
180+
log_parts.append(f"Volt: {volt_value:.1f}V -> v6={volt_value:.1f}")
181+
payload += f"&v6={volt_value:.1f}"
182+
except ValueError:
183+
pass
184+
173185
# --- THE HUMAN-READABLE LOG ---
174186
# We use INFO so it shows up without needing to enable debug logging
175187
_LOGGER.info("PVOutput [%s | ID: %s] Preparing to send: %s", name, sys_id, " | ".join(log_parts))

‎custom_components/pvoutput_publisher/config_flow.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .const import (
77
DOMAIN, CONF_API_KEY, CONF_SYSTEMS, CONF_NAME, CONF_SYSTEM_ID,
88
CONF_ENTITY_ID, CONF_SECONDARY_ENTITY_ID, CONF_CONSUMPTION_ENTITY_ID,
9-
CONF_TEMPERATURE_ENTITY_ID, CONF_FREQUENCY, DEFAULT_FREQUENCY
9+
CONF_TEMPERATURE_ENTITY_ID, CONF_FREQUENCY, DEFAULT_FREQUENCY, CONF_VOLTAGE_ENTITY_ID
1010
)
1111

1212
def _get_system_schema(existing_data=None):
@@ -52,6 +52,15 @@ def _get_system_schema(existing_data=None):
5252
selector.EntitySelectorConfig(domain="sensor")
5353
)
5454

55+
if existing_data.get(CONF_VOLTAGE_ENTITY_ID):
56+
schema[vol.Optional(CONF_VOLTAGE_ENTITY_ID, default=existing_data.get(CONF_VOLTAGE_ENTITY_ID))] = selector.EntitySelector(
57+
selector.EntitySelectorConfig(domain="sensor", device_class=["voltage"])
58+
)
59+
else:
60+
schema[vol.Optional(CONF_VOLTAGE_ENTITY_ID)] = selector.EntitySelector(
61+
selector.EntitySelectorConfig(domain="sensor", device_class=["voltage"])
62+
)
63+
5564
schema[vol.Required(CONF_FREQUENCY, default=str(existing_data.get(CONF_FREQUENCY, "5")))] = vol.In(frequency_options)
5665

5766
else:
@@ -69,6 +78,9 @@ def _get_system_schema(existing_data=None):
6978
schema[vol.Optional(CONF_TEMPERATURE_ENTITY_ID)] = selector.EntitySelector(
7079
selector.EntitySelectorConfig(domain="sensor")
7180
)
81+
schema[vol.Optional(CONF_VOLTAGE_ENTITY_ID)] = selector.EntitySelector(
82+
selector.EntitySelectorConfig(domain="sensor", device_class=["voltage"])
83+
)
7284
schema[vol.Required(CONF_FREQUENCY, default="5")] = vol.In(frequency_options)
7385

7486
return vol.Schema(schema)

‎custom_components/pvoutput_publisher/const.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
CONF_CONSUMPTION_ENTITY_ID = "consumption_entity_id"
1010
CONF_TEMPERATURE_ENTITY_ID = "temperature_entity_id"
1111
CONF_FREQUENCY = "frequency"
12+
CONF_VOLTAGE_ENTITY_ID = "voltage_entity_id"
1213

1314
DEFAULT_FREQUENCY = "5"
1415
PVOUTPUT_API_URL = "https://pvoutput.org/service/r2/addstatus.jsp"

‎custom_components/pvoutput_publisher/manifest.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
"iot_class": "cloud_push",
1010
"issue_tracker": "https://github.com/SourceLabOrg/HomeAssistant-PVOutputPublisher/issues",
1111
"requirements": [],
12-
"version": "1.1.0"
12+
"version": "1.2.0"
1313
}

‎custom_components/pvoutput_publisher/translations/de.json‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@
1818
"secondary_entity_id": "Sekundärer Solarsensor (Optional)",
1919
"consumption_entity_id": "Stromverbrauch-Sensor (Optional)",
2020
"temperature_entity_id": "Temperatursensor (Optional)",
21+
"voltage_entity_id": "Spannungssensor (Optional)",
2122
"frequency": "Aktualisierungsintervall"
2223
},
2324
"data_description": {
2425
"name": "Ein benutzerfreundlicher Name für Ihre Übersicht.",
2526
"entity_id": "Der Leistungs- (W) oder Energie- (Wh) Sensor Ihres Wechselrichters.",
2627
"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.",
2728
"consumption_entity_id": "(Optional) Erfasst den Energieverbrauch Ihres Hauses.",
28-
"temperature_entity_id": "(Optional) Erfasst die Außentemperatur."
29+
"temperature_entity_id": "(Optional) Erfasst die Außentemperatur.",
30+
"voltage_entity_id": "(Optional) Erfasst die Betriebsspannung des Netzes/Wechselrichters."
2931
}
3032
},
3133
"systems_manager": {
@@ -66,14 +68,16 @@
6668
"secondary_entity_id": "Sekundärer Solarsensor (Optional)",
6769
"consumption_entity_id": "Stromverbrauch-Sensor (Optional)",
6870
"temperature_entity_id": "Temperatursensor (Optional)",
71+
"voltage_entity_id": "Spannungssensor (Optional)",
6972
"frequency": "Aktualisierungsintervall"
7073
},
7174
"data_description": {
7275
"name": "Ein benutzerfreundlicher Name für Ihre Übersicht.",
7376
"entity_id": "Der Leistungs- (W) oder Energie- (Wh) Sensor Ihres Wechselrichters.",
7477
"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.",
7578
"consumption_entity_id": "(Optional) Erfasst den Energieverbrauch Ihres Hauses.",
76-
"temperature_entity_id": "(Optional) Erfasst die Außentemperatur."
79+
"temperature_entity_id": "(Optional) Erfasst die Außentemperatur.",
80+
"voltage_entity_id": "(Optional) Erfasst die Betriebsspannung des Netzes/Wechselrichters."
7781
}
7882
}
7983
}

‎custom_components/pvoutput_publisher/translations/en.json‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@
1818
"secondary_entity_id": "Secondary Solar Sensor (Optional)",
1919
"consumption_entity_id": "Consumption Sensor (Optional)",
2020
"temperature_entity_id": "Temperature Sensor (Optional)",
21+
"voltage_entity_id": "Voltage Sensor (Optional)",
2122
"frequency": "Update Frequency"
2223
},
2324
"data_description": {
2425
"name": "A friendly name for your own reference.",
2526
"entity_id": "Your inverter's power (W) or energy (Wh) sensor.",
2627
"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.",
2728
"consumption_entity_id": "(Optional) Tracks your home's energy usage.",
28-
"temperature_entity_id": "(Optional) Tracks outside temperature."
29+
"temperature_entity_id": "(Optional) Tracks outside temperature.",
30+
"voltage_entity_id": "(Optional) Tracks grid/inverter operational voltage lines."
2931
}
3032
},
3133
"systems_manager": {
@@ -66,14 +68,16 @@
6668
"secondary_entity_id": "Secondary Solar Sensor (Optional)",
6769
"consumption_entity_id": "Consumption Sensor (Optional)",
6870
"temperature_entity_id": "Temperature Sensor (Optional)",
71+
"voltage_entity_id": "Voltage Sensor (Optional)",
6972
"frequency": "Update Frequency"
7073
},
7174
"data_description": {
7275
"name": "A friendly name for your own reference.",
7376
"entity_id": "Your inverter's power (W) or energy (Wh) sensor.",
7477
"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.",
7578
"consumption_entity_id": "(Optional) Tracks your home's energy usage.",
76-
"temperature_entity_id": "(Optional) Tracks outside temperature."
79+
"temperature_entity_id": "(Optional) Tracks outside temperature.",
80+
"voltage_entity_id": "(Optional) Tracks grid/inverter operational voltage lines."
7781
}
7882
}
7983
}

‎custom_components/pvoutput_publisher/translations/es.json‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@
1818
"secondary_entity_id": "Sensor Solar Secundario (Opcional)",
1919
"consumption_entity_id": "Sensor de Consumo Eléctrico (Opcional)",
2020
"temperature_entity_id": "Sensor de Temperatura (Opcional)",
21+
"voltage_entity_id": "Sensor de Voltaje (Opcional)",
2122
"frequency": "Frecuencia de Actualización"
2223
},
2324
"data_description": {
2425
"name": "Un nombre descriptivo para su propia referencia.",
2526
"entity_id": "El sensor de potencia (W) o energía (Wh) de su inversor.",
2627
"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.",
2728
"consumption_entity_id": "(Opcional) Registra el uso de energía de su hogar.",
28-
"temperature_entity_id": "(Opcional) Registra la temperatura exterior."
29+
"temperature_entity_id": "(Opcional) Registra la temperatura exterior.",
30+
"voltage_entity_id": "(Opcional) Registra el voltaje operativo de la red o del inversor."
2931
}
3032
},
3133
"systems_manager": {
@@ -66,14 +68,16 @@
6668
"secondary_entity_id": "Sensor Solar Secundario (Opcional)",
6769
"consumption_entity_id": "Sensor de Consumo Eléctrico (Opcional)",
6870
"temperature_entity_id": "Sensor de Temperatura (Opcional)",
71+
"voltage_entity_id": "Sensor de Voltaje (Opcional)",
6972
"frequency": "Frecuencia de Actualización"
7073
},
7174
"data_description": {
7275
"name": "Un nombre descriptivo para su propia referencia.",
7376
"entity_id": "El sensor de potencia (W) o energía (Wh) de su inversor.",
7477
"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.",
7578
"consumption_entity_id": "(Opcional) Registra el uso de energía de su hogar.",
76-
"temperature_entity_id": "(Opcional) Registra la temperatura exterior."
79+
"temperature_entity_id": "(Opcional) Registra la temperatura exterior.",
80+
"voltage_entity_id": "(Opcional) Registra el voltaje operativo de la red o del inversor."
7781
}
7882
}
7983
}

‎custom_components/pvoutput_publisher/translations/ja.json‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@
1818
"secondary_entity_id": "サブ太陽光発電センサー (オプション)",
1919
"consumption_entity_id": "電力/エネルギー消費センサー (オプション)",
2020
"temperature_entity_id": "温度センサー (オプション)",
21+
"voltage_entity_id": "電圧センサー (オプション)",
2122
"frequency": "更新頻度"
2223
},
2324
"data_description": {
2425
"name": "管理用のわかりやすい名前。",
2526
"entity_id": "パワーコンディショナの電力 (W) または電力量 (Wh) センサー。",
2627
"secondary_entity_id": "最大の精度を得るために、上で電力 (W) センサーを選択した場合は、ここで電力量 (Wh) センサーを選択してください(その逆も同様です)。空白の場合、PVOutputは不足している値を自動的に推定します。",
2728
"consumption_entity_id": "(オプション) 自宅のエネルギー使用量を記録します。",
28-
"temperature_entity_id": "(オプション) 外気温を記録します。"
29+
"temperature_entity_id": "(オプション) 外気温を記録します。",
30+
"voltage_entity_id": "(オプション) グリッドまたはパワーコンディショナの動作電圧を記録します。"
2931
}
3032
},
3133
"systems_manager": {
@@ -66,14 +68,16 @@
6668
"secondary_entity_id": "サブ太陽光発電センサー (オプション)",
6769
"consumption_entity_id": "電力/エネルギー消費センサー (オプション)",
6870
"temperature_entity_id": "温度センサー (オプション)",
71+
"voltage_entity_id": "電圧センサー (オプション)",
6972
"frequency": "更新頻度"
7073
},
7174
"data_description": {
7275
"name": "管理用のわかりやすい名前。",
7376
"entity_id": "パワーコンディショナの電力 (W) または電力量 (Wh) センサー。",
7477
"secondary_entity_id": "最大の精度を得るために、上で電力 (W) センサーを選択した場合は、ここで電力量 (Wh) センサーを選択してください(その逆も同様です)。空白の場合、PVOutputは不足している値を自動的に推定します。",
7578
"consumption_entity_id": "(オプション) 自宅のエネルギー使用量を記録します。",
76-
"temperature_entity_id": "(オプション) 外気温を記録します。"
79+
"temperature_entity_id": "(オプション) 外気温を記録します。",
80+
"voltage_entity_id": "(オプション) グリッドまたはパワーコンディショナの動作電圧を記録します。"
7781
}
7882
}
7983
}

0 commit comments

Comments
 (0)