diff --git a/README.md b/README.md index b4f2a52..8d48ebd 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ Home Assistant SunPower Integration using the local installer ethernet interface. +Original Integration is [https://github.com/krbaker/hass-sunpower](https://github.com/krbaker/hass-sunpower) + +* If this is a fork, please add what's different here and fix up the badges below + [![GitHub Release][releases-shield]][releases] [![GitHub Activity][commits-shield]][commits] [![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge)](https://github.com/custom-components/hacs) @@ -21,6 +25,14 @@ YMMV, any damage to your system is your responsibility (see also: [LICENSE](LICE ## Component to integrate with [sunpower][sunpower-us] PVS 5/6 monitors +Notes: + +* For PVS < 5 you can try [jcronq](https://github.com/jcronq/)'s fork +[https://github.com/jcronq/hass-sunpower](https://github.com/jcronq/hass-sunpower) +* The Original ESS fork by [CanisUrsa](https://github.com/CanisUrsa/) is + here + [https://github.com/CanisUrsa/hass-sunpower](https://github.com/CanisUrsa/hass-sunpower) + **This component will set up the following platforms.** | Platform | Description | diff --git a/custom_components/sunpower/__init__.py b/custom_components/sunpower/__init__.py index 4b3627c..4c6a325 100644 --- a/custom_components/sunpower/__init__.py +++ b/custom_components/sunpower/__init__.py @@ -23,6 +23,8 @@ DOMAIN, ESS_DEVICE_TYPE, HUBPLUS_DEVICE_TYPE, + INVERTER_DEVICE_TYPE, + METER_DEVICE_TYPE, PVS_DEVICE_TYPE, SETUP_TIMEOUT_MIN, SUNPOWER_COORDINATOR, @@ -51,17 +53,63 @@ PREVIOUS_ESS_SAMPLE = {} +def create_vmeter(data): + # Create a virtual 'METER' that uses the sum of inverters + kwh = 0.0 + kw = 0.0 + amps = 0.0 + freq = [] + volts = [] + state = "working" + for _serial, inverter in data.get(INVERTER_DEVICE_TYPE, {}).items(): + if "STATE" in inverter and inverter["STATE"] != "working": + state = inverter["STATE"] + kwh += float(inverter.get("ltea_3phsum_kwh", "0")) + kw += float(inverter.get("p_mppt1_kw", "0")) + amps += float(inverter.get("i_3phsum_a", "0")) + if "freq_hz" in inverter: + freq.append(float(inverter["freq_hz"])) + if "vln_3phavg_v" in inverter: + volts.append(float(inverter["vln_3phavg_v"])) + + freq_avg = sum(freq) / len(freq) + volts_avg = sum(volts) / len(volts) + + pvs_serial = next(iter(data[PVS_DEVICE_TYPE])) # only one PVS + vmeter_serial = f"{pvs_serial}pv" + data.setdefault(METER_DEVICE_TYPE, {})[vmeter_serial] = { + "SERIAL": vmeter_serial, + "TYPE": "PVS-METER-P", + "STATE": state, + "MODEL": "Virtual", + "DESCR": f"Power Meter {vmeter_serial}", + "DEVICE_TYPE": "Power Meter", + "interface": "virtual", + "SWVER": "1.0", + "HWVER": "Virtual", + "origin": "virtual", + "net_ltea_3phsum_kwh": kwh, + "p_3phsum_kw": kw, + "freq_hz": freq_avg, + "i_a": amps, + "v12_v": volts_avg, + } + return data + + def convert_sunpower_data(sunpower_data): """Convert PVS data into indexable format data[device_type][serial]""" data = {} for device in sunpower_data["devices"]: data.setdefault(device["DEVICE_TYPE"], {})[device["SERIAL"]] = device + + create_vmeter(data) + return data -def convert_ess_data(ess_data, pvs_serial): +def convert_ess_data(ess_data, data): """Do all the gymnastics to Integrate ESS data from its unique data source into the PVS data""" - data = {} sunvault_amperages = [] sunvault_voltages = [] sunvault_temperatures = [] @@ -177,6 +225,7 @@ def convert_ess_data(ess_data, pvs_serial): if True: # Generate a usable serial number for this virtual device, use PVS serial as base # since we must be talking through one and it has a serial + pvs_serial = next(iter(data[PVS_DEVICE_TYPE])) # only one PVS sunvault_serial = f"sunvault_{pvs_serial}" data[SUNVAULT_DEVICE_TYPE] = {sunvault_serial: {}} data[SUNVAULT_DEVICE_TYPE][sunvault_serial]["sunvault_amperage"] = sum( @@ -238,9 +287,11 @@ def sunpower_fetch(sunpower_monitor, use_ess, sunpower_update_invertal, sunvault try: data = convert_sunpower_data(sunpower_data) - pvs_serial = next(iter(data[PVS_DEVICE_TYPE])) # only one PVS if use_ess: - data.update(convert_ess_data(ess_data, pvs_serial)) + convert_ess_data( + ess_data, + data, + ) # ess converter appends to items in existing PVS structure return data except ParseException as error: raise UpdateFailed from error diff --git a/custom_components/sunpower/sensor.py b/custom_components/sunpower/sensor.py index 4cd62c4..9283074 100644 --- a/custom_components/sunpower/sensor.py +++ b/custom_components/sunpower/sensor.py @@ -170,12 +170,9 @@ def native_value(self): if self._my_device_class == SensorDeviceClass.POWER_FACTOR: try: value = float( - self.coordinator.data[self._device_type][self.base_unique_id].get( - self._field, - None, - ), + self.coordinator.data[self._device_type][self.base_unique_id][self._field], ) return value * 100.0 - except ValueError: + except (ValueError, KeyError): pass # sometimes this value might be something like 'unavailable' return self.coordinator.data[self._device_type][self.base_unique_id].get(self._field, None)