diff --git a/custom_components/enphase_envoy/envoy_reader.py b/custom_components/enphase_envoy/envoy_reader.py index ed4ae31..06b20ec 100644 --- a/custom_components/enphase_envoy/envoy_reader.py +++ b/custom_components/enphase_envoy/envoy_reader.py @@ -437,6 +437,12 @@ def grid_status(self): if grid_status != None: return grid_status == "closed" + @envoy_property(required_endpoint="endpoint_production_inverters") + def inverter_production(self): + return self._path_to_dict( + "endpoint_production_inverters.[?(@.devType==1)]", "serialNumber" + ) + pcu_availability_value = "endpoint_pcu_comm_check" @envoy_property(required_endpoint="endpoint_inventory") @@ -595,11 +601,6 @@ def __new__(cls, reader, **kw): f"endpoint_production_json.production[?(@.type=='eim')].lines[{i}].whToday", ) - # When we're using the endpoint_production_report primarily, then the following - # endpoint can be used way less frequently - reader.uri_registry["endpoint_production_json"]["cache_time"] = 50 - reader.uri_registry["endpoint_production_inverters"]["cache_time"] = 290 - return EnvoyMetered.__new__(cls) diff --git a/custom_components/enphase_envoy/sensor.py b/custom_components/enphase_envoy/sensor.py index 206781f..888f835 100644 --- a/custom_components/enphase_envoy/sensor.py +++ b/custom_components/enphase_envoy/sensor.py @@ -45,11 +45,9 @@ async def async_setup_entry( entities = [] _LOGGER.debug("Setting up Sensors") for sensor_description in SENSORS: - _LOGGER.debug(f"Evaluating Sensor {sensor_description}") if not options.get(ENABLE_ADDITIONAL_METRICS, False): if sensor_description.key in ADDITIONAL_METRICS: continue - _LOGGER.debug(f"Picking how to handle Sensor {sensor_description}") if sensor_description.key == "inverter_pcu_communication_level": if coordinator.data.get("pcu_availability"): for serial_number in coordinator.data["inverter_device_data"]: @@ -84,6 +82,23 @@ async def async_setup_entry( ) ) + elif sensor_description.key == "inverter_data_watts": + if coordinator.data.get("inverter_production"): + for inverter in coordinator.data["inverter_production"].keys(): + 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_data_"): _LOGGER.debug(f"Inverter Data Sensor {sensor_description}") if coordinator.data.get("inverter_device_data"): @@ -378,21 +393,30 @@ class EnvoyInverterEntity(EnvoyDeviceEntity): @property def native_value(self): """Return the state of the sensor.""" - if self.entity_description.key.startswith("inverter_data_"): - _LOGGER.debug(f"Getting Key {self.entity_description.key}") + if self.entity_description.key == "inverter_data_watts": + if self.coordinator.data.get("inverter_production"): + return ( + self.coordinator.data.get("inverter_production") + .get(self._device_serial_number) + .get("lastReportWatts") + ) + elif self.entity_description.key.startswith("inverter_data_"): if self.coordinator.data.get("inverter_device_data"): - device_data = self.coordinator.data.get("inverter_device_data") - _LOGGER.debug(f"Found Data, getting {self._device_serial_number}") - serial = device_data.get(self._device_serial_number) - _LOGGER.debug( - f"Found Serial {serial}, getting {self.entity_description.key[14:]}" + value = ( + self.coordinator.data.get("inverter_device_data") + .get(self._device_serial_number) + .get(self.entity_description.key[14:]) ) - value = serial.get(self.entity_description.key[14:]) if self.entity_description.key.endswith("last_reading"): return datetime.datetime.fromtimestamp( int(value), tz=datetime.timezone.utc ) - if serial.get("gone", True) and not self.entity_description.retain: + if ( + self.coordinator.data.get("inverter_device_data") + .get(self._device_serial_number) + .get("gone") + and not self.entity_description.retain + ): return None return value elif self.entity_description.key.startswith("inverter_info_"): @@ -408,7 +432,19 @@ def native_value(self): @property def extra_state_attributes(self): """Return the state attributes.""" - if self.entity_description.key.startswith("inverter_info_"): + if self.entity_description.key == "inverter_data_watts": + if self.coordinator.data.get("inverter_production"): + value = ( + self.coordinator.data.get("inverter_production") + .get(self._device_serial_number) + .get("lastReportDate") + ) + return { + "last_reported": datetime.datetime.fromtimestamp( + int(value), tz=datetime.timezone.utc + ) + } + elif self.entity_description.key.startswith("inverter_info_"): if self.coordinator.data.get("inverter_info"): value = ( self.coordinator.data.get("inverter_info") @@ -422,9 +458,11 @@ def extra_state_attributes(self): } elif self.entity_description.key.startswith("inverter_data_"): if self.coordinator.data.get("inverter_device_data"): - device_data = self.coordinator.data.get("inverter_device_data") - serial = device_data.get(self._device_serial_number) - value = serial.get("last_reading") + value = ( + self.coordinator.data.get("inverter_device_data") + .get(self._device_serial_number) + .get("last_reading") + ) return { "last_reported": datetime.datetime.fromtimestamp( int(value), tz=datetime.timezone.utc