Skip to content

Commit

Permalink
Configurable alternative (old) devstatus endpoint for device sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentwolsink committed Dec 11, 2024
1 parent 60aca5c commit 042e65b
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 49 deletions.
5 changes: 5 additions & 0 deletions custom_components/enphase_envoy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
disable_negative_production=options.get("disable_negative_production", False),
disabled_endpoints=disabled_endpoints,
lifetime_production_correction=options.get("lifetime_production_correction", 0),
device_data_endpoint=(
"endpoint_devstatus"
if options.get("devstatus_device_data", False)
else "endpoint_device_data"
),
)
await envoy_reader._sync_store(load=True)

Expand Down
4 changes: 4 additions & 0 deletions custom_components/enphase_envoy/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ async def async_step_user(self, user_input=None):
"enable_pcu_comm_check",
default=self.config_entry.options.get("enable_pcu_comm_check", False),
): bool,
vol.Optional(
"devstatus_device_data",
default=self.config_entry.options.get("devstatus_device_data", False),
): bool,
vol.Optional(
"lifetime_production_correction",
default=self.config_entry.options.get(
Expand Down
2 changes: 1 addition & 1 deletion custom_components/enphase_envoy/envoy_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"url": "https://{}/ivp/pdm/device_data",
"cache": 0,
"installer_required": False,
"optional": False,
"optional": True,
},
"devstatus": {
"url": "https://{}/ivp/peb/devstatus",
Expand Down
25 changes: 17 additions & 8 deletions custom_components/enphase_envoy/envoy_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ def parse_devstatus(data):
"dc_current": "dcCurrentINmA",
"ac_voltage": "acVoltageINmV",
"ac_power": "acPowerINmW",
"gone": "communicating",
}
device_type = {1: "pcu", 12: "nsrb"}

idd = []
for itemtype, content in data.items():
Expand All @@ -96,6 +98,10 @@ def parse_devstatus(data):
_LOGGER.debug(f"Found device status field {field}: {value}")
if dataset[field].endswith(("mA", "mV", "mHz")):
device_data[field] = int(value) / 1000
elif field == "type":
device_data[field] = device_type.get(value, value)
elif field == "gone":
device_data[field] = not value
else:
device_data[field] = value
idd.append(device_data)
Expand Down Expand Up @@ -336,6 +342,7 @@ def required_endpoints(self):
return self._required_endpoints

endpoints = set()
endpoints.add(self.reader.device_data_endpoint)

# Loop through all local attributes, and return unique first required jsonpath attribute.
for attr in dir(self):
Expand Down Expand Up @@ -498,17 +505,17 @@ def relay_info(self):
"serial_num",
)

@envoy_property(required_endpoint="endpoint_device_data")
@envoy_property()
def inverter_device_data(self):
return self._path_to_dict("endpoint_device_data.[?(@.type=='pcu')]", "sn")
return self._path_to_dict(
f"{self.reader.device_data_endpoint}.[?(@.type=='pcu')]", "sn"
)

@envoy_property(required_endpoint="endpoint_device_data")
@envoy_property()
def relay_device_data(self):
return self._path_to_dict("endpoint_device_data.[?(@.type=='nsrb')]", "sn")

@envoy_property(required_endpoint="endpoint_devstatus")
def inverter_device_status(self):
return self._path_to_dict("endpoint_devstatus.[?(@.type==1)]", "sn")
return self._path_to_dict(
f"{self.reader.device_data_endpoint}.[?(@.type=='nsrb')]", "sn"
)

@envoy_property(required_endpoint="endpoint_ensemble_inventory")
def batteries(self):
Expand Down Expand Up @@ -679,6 +686,7 @@ def __init__(
disable_negative_production=False,
disabled_endpoints=[],
lifetime_production_correction=0,
device_data_endpoint="endpoint_device_data",
):
"""Init the EnvoyReader."""
self.host = host.lower()
Expand All @@ -703,6 +711,7 @@ def __init__(
self.required_endpoints = set() # in case we would need it..
self.disabled_endpoints = disabled_endpoints
self.lifetime_production_correction = lifetime_production_correction
self.device_data_endpoint = device_data_endpoint

self.uri_registry = {}
for key, endpoint in ENVOY_ENDPOINTS.items():
Expand Down
86 changes: 46 additions & 40 deletions custom_components/enphase_envoy/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,24 +100,27 @@ async def async_setup_entry(
)

elif sensor_description.key.startswith("inverter_data_"):
_LOGGER.debug(f"Inverter Data Sensor {sensor_description}")
if coordinator.data.get("inverter_device_data"):
_LOGGER.debug(f"Inverter Data Sensor DATA {sensor_description}")
for inverter in coordinator.data["inverter_device_data"].keys():
_LOGGER.debug(f"Inverter Data Sensor DATA {inverter}")
device_name = f"Inverter {inverter}"
serial_number = inverter
entities.append(
EnvoyInverterEntity(
description=sensor_description,
name=f"{device_name} {sensor_description.name}",
device_name=device_name,
device_serial_number=serial_number,
serial_number=None,
coordinator=coordinator,
parent_device=config_entry.unique_id,
if (
coordinator.data["inverter_device_data"][inverter].get(
sensor_description.key[14:]
)
is not None
):
device_name = f"Inverter {inverter}"
serial_number = inverter
entities.append(
EnvoyInverterEntity(
description=sensor_description,
name=f"{device_name} {sensor_description.name}",
device_name=device_name,
device_serial_number=serial_number,
serial_number=None,
coordinator=coordinator,
parent_device=config_entry.unique_id,
)
)
)

elif sensor_description.key.startswith("inverter_info_"):
if coordinator.data.get("inverter_info"):
Expand All @@ -137,35 +140,38 @@ async def async_setup_entry(
)

elif sensor_description.key.startswith("relay_data_"):
_LOGGER.debug(f"Relay Data Sensor {sensor_description}")
if coordinator.data.get("relay_device_data"):
_LOGGER.debug(f"Relay Data Sensor DATA {sensor_description}")
for relay in coordinator.data["relay_device_data"].keys():
_LOGGER.debug(f"Relay Data Sensor DATA {relay}")
device_name = f"Relay {relay}"
serial_number = relay

if sensor_description.key.endswith(("l1", "l2", "l3")):
line = sensor_description.key[-2:].replace("l", "line")
line_connected = (
coordinator.data.get("relay_info", {})
.get(relay, {})
.get(f"{line}-connected")
if (
coordinator.data["relay_device_data"][relay].get(
sensor_description.key[11:]
)
if line_connected is False:
continue

entities.append(
EnvoyRelayEntity(
description=sensor_description,
name=f"{device_name} {sensor_description.name}",
device_name=device_name,
device_serial_number=serial_number,
serial_number=None,
coordinator=coordinator,
parent_device=config_entry.unique_id,
is not None
):
device_name = f"Relay {relay}"
serial_number = relay

if sensor_description.key.endswith(("l1", "l2", "l3")):
line = sensor_description.key[-2:].replace("l", "line")
line_connected = (
coordinator.data.get("relay_info", {})
.get(relay, {})
.get(f"{line}-connected")
)
if line_connected is False:
continue

entities.append(
EnvoyRelayEntity(
description=sensor_description,
name=f"{device_name} {sensor_description.name}",
device_name=device_name,
device_serial_number=serial_number,
serial_number=None,
coordinator=coordinator,
parent_device=config_entry.unique_id,
)
)
)

elif sensor_description.key.startswith("relay_info_"):
if coordinator.data.get("relay_info"):
Expand Down
1 change: 1 addition & 0 deletions custom_components/enphase_envoy/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"enable_additional_metrics": "[Metered only] Enable additional metrics like total amps, frequency, apparent and reactive power and power factor.",
"disable_installer_account_use": "Do not collect data that requires installer or DIY enphase account",
"enable_pcu_comm_check": "Enable powerline communication level sensors (slow)",
"devstatus_device_data": "Use alternative endpoint 'devstatus' (installer account only) for device sensors",
"lifetime_production_correction": "Correction of lifetime production value (Wh)",
"disabled_endpoints": "[Advanced] Disabled Envoy endpoints"
},
Expand Down
1 change: 1 addition & 0 deletions custom_components/enphase_envoy/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"enable_additional_metrics": "[Envoy-S Metered] Enable additional metrics like total amps, frequency, apparent and reactive power and power factor.",
"disable_installer_account_use": "Do not collect data that requires installer or DIY enphase account",
"enable_pcu_comm_check": "Enable powerline communication level sensors (slow)",
"devstatus_device_data": "Use alternative endpoint 'devstatus' (installer account only) for device sensors",
"lifetime_production_correction": "Correction of lifetime production value (Wh)",
"disabled_endpoints": "[Advanced] Disabled Envoy endpoints"
},
Expand Down
1 change: 1 addition & 0 deletions custom_components/enphase_envoy/translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"enable_additional_metrics": "[Envoy-S Metered] Extra metrics inschakelen, zoals total amps, frequency, apparent en reactive power en power factor.",
"disable_installer_account_use": "Haal geen data op die een installateur of DHZ enphase account vereisen",
"enable_pcu_comm_check": "Powerline communication level sensors inschakelen (langzaam)",
"devstatus_device_data": "Gebruik alternatief endpoint 'devstatus' (alleen installer account) voor apparaat sensoren",
"lifetime_production_correction": "Correctie van lifetime production waarde (Wh)",
"disabled_endpoints": "[Geavanceerd] Uitgeschakelde Envoy endpoints"
},
Expand Down

0 comments on commit 042e65b

Please sign in to comment.