From bae799079e3051bd655684a50faab5fad1408160 Mon Sep 17 00:00:00 2001 From: Keith Baker Date: Sun, 3 Oct 2021 15:25:26 -0400 Subject: [PATCH 1/3] Add fields needed for energy dashboard - found missing subclass of sensor and binary sensor which might have impacted other things --- custom_components/sunpower/binary_sensor.py | 7 +- custom_components/sunpower/const.py | 143 +++++++++++++++----- custom_components/sunpower/sensor.py | 77 ++++++++--- 3 files changed, 177 insertions(+), 50 deletions(-) diff --git a/custom_components/sunpower/binary_sensor.py b/custom_components/sunpower/binary_sensor.py index bb795d9..8628fb7 100644 --- a/custom_components/sunpower/binary_sensor.py +++ b/custom_components/sunpower/binary_sensor.py @@ -2,6 +2,7 @@ import logging from homeassistant.const import DEVICE_CLASS_POWER +from homeassistant.components.binary_sensor import BinarySensorEntity from .const import ( DOMAIN, @@ -52,7 +53,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_entities(entities, True) -class SunPowerPVSState(SunPowerPVSEntity): +class SunPowerPVSState(SunPowerPVSEntity, BinarySensorEntity): """Representation of SunPower PVS Working State""" def __init__(self, coordinator, pvs_info, do_descriptive_names): @@ -88,7 +89,7 @@ def is_on(self): return self.state == WORKING_STATE -class SunPowerMeterState(SunPowerMeterEntity): +class SunPowerMeterState(SunPowerMeterEntity, BinarySensorEntity): """Representation of SunPower Meter Working State""" def __init__(self, coordinator, meter_info, pvs_info, do_descriptive_names): @@ -124,7 +125,7 @@ def is_on(self): return self.state == WORKING_STATE -class SunPowerInverterState(SunPowerInverterEntity): +class SunPowerInverterState(SunPowerInverterEntity, BinarySensorEntity): """Representation of SunPower Inverter Working State""" def __init__(self, coordinator, inverter_info, pvs_info, do_descriptive_names): diff --git a/custom_components/sunpower/const.py b/custom_components/sunpower/const.py index 46b94f3..f4d4446 100644 --- a/custom_components/sunpower/const.py +++ b/custom_components/sunpower/const.py @@ -8,9 +8,20 @@ POWER_VOLT_AMPERE, PERCENTAGE, ELECTRIC_POTENTIAL_VOLT, + ELECTRIC_CURRENT_AMPERE, TEMP_CELSIUS, + DEVICE_CLASS_ENERGY, + DEVICE_CLASS_POWER, + DEVICE_CLASS_VOLTAGE, + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_POWER_FACTOR ) +from homeassistant.components.sensor import ( + STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING +) DOMAIN = "sunpower" @@ -34,26 +45,41 @@ WORKING_STATE = "working" METER_SENSORS = { - "METER_FREQUENCY": ["freq_hz", "Frequency", FREQUENCY_HERTZ, "mdi:flash"], + "METER_FREQUENCY": ["freq_hz", "Frequency", FREQUENCY_HERTZ, "mdi:flash", + None, STATE_CLASS_MEASUREMENT], "METER_NET_KWH": [ "net_ltea_3phsum_kwh", "Lifetime Power", ENERGY_KILO_WATT_HOUR, "mdi:flash", + DEVICE_CLASS_ENERGY, STATE_CLASS_TOTAL_INCREASING, ], - "METER_KW": ["p_3phsum_kw", "Power", POWER_KILO_WATT, "mdi:flash"], - "METER_VAR": ["q_3phsum_kvar", "KVA Reactive", POWER_VOLT_AMPERE, "mdi:flash"], - "METER_VA": ["s_3phsum_kva", "KVA Apparent", POWER_VOLT_AMPERE, "mdi:flash"], - "METER_POWER_FACTOR": ["tot_pf_rto", "Power Factor", PERCENTAGE, "mdi:flash"], - "METER_L1_A": ["i1_a", "Leg 1 Amps", POWER_VOLT_AMPERE, "mdi:flash"], - "METER_L2_A": ["i2_a", "Leg 2 Amps", POWER_VOLT_AMPERE, "mdi:flash"], - "METER_L1_KW": ["p1_kw", "Leg 1 KW", POWER_KILO_WATT, "mdi:flash"], - "METER_L2_KW": ["p2_kw", "Leg 2 KW", POWER_KILO_WATT, "mdi:flash"], - "METER_L1_V": ["v1n_v", "Leg 1 Volts", ELECTRIC_POTENTIAL_VOLT, "mdi:flash"], - "METER_L2_V": ["v2n_v", "Leg 2 Volts", ELECTRIC_POTENTIAL_VOLT, "mdi:flash"], - "METER_L12_V": ["v12_v", "Supply Volts", ELECTRIC_POTENTIAL_VOLT, "mdi:flash"], - "METER_TO_GRID": ["neg_ltea_3phsum_kwh", "KWH To Grid", ENERGY_KILO_WATT_HOUR, "mdi:flash"], - "METER_TO_HOME": ["pos_ltea_3phsum_kwh", "KWH To Home", ENERGY_KILO_WATT_HOUR, "mdi:flash"] + "METER_KW": ["p_3phsum_kw", "Power", POWER_KILO_WATT, "mdi:flash", + DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT], + "METER_VAR": ["q_3phsum_kvar", "KVA Reactive", POWER_VOLT_AMPERE, "mdi:flash", + None, STATE_CLASS_MEASUREMENT], + "METER_VA": ["s_3phsum_kva", "KVA Apparent", POWER_VOLT_AMPERE, "mdi:flash", + None, STATE_CLASS_MEASUREMENT], + "METER_POWER_FACTOR": ["tot_pf_rto", "Power Factor", PERCENTAGE, "mdi:flash", + DEVICE_CLASS_POWER_FACTOR, STATE_CLASS_MEASUREMENT], + "METER_L1_A": ["i1_a", "Leg 1 Amps", ELECTRIC_CURRENT_AMPERE, "mdi:flash", + DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT], + "METER_L2_A": ["i2_a", "Leg 2 Amps", ELECTRIC_CURRENT_AMPERE, "mdi:flash", + DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT], + "METER_L1_KW": ["p1_kw", "Leg 1 KW", POWER_KILO_WATT, "mdi:flash", + DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT], + "METER_L2_KW": ["p2_kw", "Leg 2 KW", POWER_KILO_WATT, "mdi:flash", + DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT], + "METER_L1_V": ["v1n_v", "Leg 1 Volts", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", + DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT], + "METER_L2_V": ["v2n_v", "Leg 2 Volts", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", + DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT], + "METER_L12_V": ["v12_v", "Supply Volts", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", + DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT], + "METER_TO_GRID": ["neg_ltea_3phsum_kwh", "KWH To Grid", ENERGY_KILO_WATT_HOUR, "mdi:flash", + DEVICE_CLASS_ENERGY, STATE_CLASS_TOTAL_INCREASING], + "METER_TO_HOME": ["pos_ltea_3phsum_kwh", "KWH To Home", ENERGY_KILO_WATT_HOUR, "mdi:flash", + DEVICE_CLASS_ENERGY, STATE_CLASS_TOTAL_INCREASING] } INVERTER_SENSORS = { @@ -62,51 +88,106 @@ "Lifetime Power", ENERGY_KILO_WATT_HOUR, "mdi:flash", + DEVICE_CLASS_ENERGY, + STATE_CLASS_TOTAL_INCREASING ], - "INVERTER_KW": ["p_3phsum_kw", "Power", POWER_KILO_WATT, "mdi:flash"], - "INVERTER_VOLTS": ["vln_3phavg_v", "Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash"], - "INVERTER_AMPS": ["i_3phsum_a", "Amps", POWER_VOLT_AMPERE, "mdi:flash"], - "INVERTER_MPPT_KW": ["p_mpptsum_kw", "MPPT KW", POWER_KILO_WATT, "mdi:flash"], - "INVERTER_MPPT1_KW": ["p_mppt1_kw", "MPPT KW", POWER_KILO_WATT, "mdi:flash"], - "INVERTER_MPPT_V": ["v_mppt1_v", "MPPT Volts", ELECTRIC_POTENTIAL_VOLT, "mdi:flash"], - "INVERTER_MPPT_A": ["i_mppt1_a", "MPPT Amps", POWER_VOLT_AMPERE, "mdi:flash"], + "INVERTER_KW": ["p_3phsum_kw", "Power", POWER_KILO_WATT, "mdi:flash", + DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT], + "INVERTER_VOLTS": ["vln_3phavg_v", "Voltage", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", + DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT], + "INVERTER_AMPS": ["i_3phsum_a", "Amps", ELECTRIC_CURRENT_AMPERE, "mdi:flash", + DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT], + "INVERTER_MPPT_KW": ["p_mpptsum_kw", "MPPT KW", POWER_KILO_WATT, "mdi:flash", + DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT], + "INVERTER_MPPT1_KW": ["p_mppt1_kw", "MPPT KW", POWER_KILO_WATT, "mdi:flash", + DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT], + "INVERTER_MPPT_V": ["v_mppt1_v", "MPPT Volts", ELECTRIC_POTENTIAL_VOLT, "mdi:flash", + DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT], + "INVERTER_MPPT_A": ["i_mppt1_a", "MPPT Amps", POWER_VOLT_AMPERE, "mdi:flash", + DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT], "INVERTER_TEMPERATURE": [ "t_htsnk_degc", "Temperature", TEMP_CELSIUS, "mdi:thermometer", + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT ], - "INVERTER_FREQUENCY": ["freq_hz", "Frequency", FREQUENCY_HERTZ, "mdi:flash"], + "INVERTER_FREQUENCY": ["freq_hz", "Frequency", FREQUENCY_HERTZ, "mdi:flash", + None, STATE_CLASS_MEASUREMENT], } PVS_SENSORS = { - "PVS_LOAD": ["dl_cpu_load", "System Load", "", "mdi:gauge"], - "PVS_ERROR_COUNT": ["dl_err_count", "Error Count", "", "mdi:alert-circle"], + "PVS_LOAD": [ + "dl_cpu_load", + "System Load", + "", + "mdi:gauge", + None, + STATE_CLASS_MEASUREMENT + ], + "PVS_ERROR_COUNT": [ + "dl_err_count", + "Error Count", + "", + "mdi:alert-circle", + None, + STATE_CLASS_TOTAL_INCREASING + ], "PVS_COMMUNICATION_ERRORS": [ "dl_comm_err", "Communication Errors", "", "mdi:network-off", - ], + None, + STATE_CLASS_TOTAL_INCREASING + ], "PVS_SKIPPED_SCANS": [ "dl_skipped_scans", "Skipped Scans", "", "mdi:network-strength-off-outline", - ], - "PVS_SCAN_TIME": ["dl_scan_time", "Scan Time", TIME_SECONDS, "mdi:timer-outline"], + None, + STATE_CLASS_TOTAL_INCREASING + ], + "PVS_SCAN_TIME": [ + "dl_scan_time", + "Scan Time", + TIME_SECONDS, + "mdi:timer-outline", + None, + STATE_CLASS_MEASUREMENT + ], "PVS_UNTRANSMITTED": [ "dl_untransmitted", "Untransmitted Data", "", "mdi:radio-tower", - ], - "PVS_UPTIME": ["dl_uptime", "Uptime", TIME_SECONDS, "mdi:timer-outline"], - "PVS_MEMORY_USED": ["dl_mem_used", "Memory Used", DATA_KILOBYTES, "mdi:memory"], + None, + STATE_CLASS_MEASUREMENT + ], + "PVS_UPTIME": [ + "dl_uptime", + "Uptime", + TIME_SECONDS, + "mdi:timer-outline", + None, + STATE_CLASS_TOTAL_INCREASING + ], + "PVS_MEMORY_USED": [ + "dl_mem_used", + "Memory Used", + DATA_KILOBYTES, + "mdi:memory", + None, + STATE_CLASS_MEASUREMENT + ], "PVS_FLASH_AVAILABLE": [ "dl_flash_avail", "Flash Available", DATA_KILOBYTES, "mdi:memory", - ], + None, + STATE_CLASS_MEASUREMENT + ], } diff --git a/custom_components/sunpower/sensor.py b/custom_components/sunpower/sensor.py index 4f7b625..c6500f9 100644 --- a/custom_components/sunpower/sensor.py +++ b/custom_components/sunpower/sensor.py @@ -1,7 +1,7 @@ """Support for Sunpower sensors.""" import logging -# from homeassistant.const import TIME_SECONDS, DATA_BYTES +from homeassistant.components.sensor import SensorEntity from .const import ( DOMAIN, @@ -16,6 +16,7 @@ ) from .entity import SunPowerPVSEntity, SunPowerMeterEntity, SunPowerInverterEntity + _LOGGER = logging.getLogger(__name__) @@ -47,9 +48,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): title, PVS_SENSORS[sensor][2], PVS_SENSORS[sensor][3], + PVS_SENSORS[sensor][4], + PVS_SENSORS[sensor][5], ) try: - spb.state + spb.native_value entities.append(spb) except KeyError: pass @@ -71,9 +74,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): title, METER_SENSORS[sensor][2], METER_SENSORS[sensor][3], + METER_SENSORS[sensor][4], + METER_SENSORS[sensor][5], ) try: - smb.state + smb.native_value entities.append(smb) except KeyError: pass @@ -95,9 +100,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): title, INVERTER_SENSORS[sensor][2], INVERTER_SENSORS[sensor][3], + INVERTER_SENSORS[sensor][4], + INVERTER_SENSORS[sensor][5] ) try: - sib.state + sib.native_value entities.append(sib) except KeyError: pass @@ -105,22 +112,34 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_entities(entities, True) -class SunPowerPVSBasic(SunPowerPVSEntity): +class SunPowerPVSBasic(SunPowerPVSEntity, SensorEntity): """Representation of SunPower PVS Stat""" - def __init__(self, coordinator, pvs_info, field, title, unit, icon): + def __init__(self, coordinator, pvs_info, field, title, unit, icon, device_class, state_class): """Initialize the sensor.""" super().__init__(coordinator, pvs_info) self._title = title self._field = field self._unit = unit self._icon = icon + self._my_device_class = device_class + self._my_state_class = state_class @property - def unit_of_measurement(self): + def native_unit_of_measurement(self): """Return the unit of measurement.""" return self._unit + @property + def device_class(self): + """Return device class.""" + return self._my_device_class + + @property + def state_class(self): + """Return state class.""" + return self._my_state_class + @property def icon(self): """Icon to use in the frontend, if any.""" @@ -137,27 +156,40 @@ def unique_id(self): return f"{self.base_unique_id}_pvs_{self._field}" @property - def state(self): + def native_value(self): """Get the current value""" return self.coordinator.data[PVS_DEVICE_TYPE][self.base_unique_id][self._field] -class SunPowerMeterBasic(SunPowerMeterEntity): +class SunPowerMeterBasic(SunPowerMeterEntity, SensorEntity): """Representation of SunPower Meter Stat""" - def __init__(self, coordinator, meter_info, pvs_info, field, title, unit, icon): + def __init__(self, coordinator, meter_info, pvs_info, field, title, unit, icon, + device_class, state_class): """Initialize the sensor.""" super().__init__(coordinator, meter_info, pvs_info) self._title = title self._field = field self._unit = unit self._icon = icon + self._my_device_class = device_class + self._my_state_class = state_class @property - def unit_of_measurement(self): + def native_unit_of_measurement(self): """Return the unit of measurement.""" return self._unit + @property + def device_class(self): + """Return device class.""" + return self._my_device_class + + @property + def state_class(self): + """Return state class.""" + return self._my_state_class + @property def icon(self): """Icon to use in the frontend, if any.""" @@ -174,27 +206,40 @@ def unique_id(self): return f"{self.base_unique_id}_pvs_{self._field}" @property - def state(self): + def native_value(self): """Get the current value""" return self.coordinator.data[METER_DEVICE_TYPE][self.base_unique_id][self._field] -class SunPowerInverterBasic(SunPowerInverterEntity): +class SunPowerInverterBasic(SunPowerInverterEntity, SensorEntity): """Representation of SunPower Meter Stat""" - def __init__(self, coordinator, inverter_info, pvs_info, field, title, unit, icon): + def __init__(self, coordinator, inverter_info, pvs_info, field, title, unit, icon, + device_class, state_class): """Initialize the sensor.""" super().__init__(coordinator, inverter_info, pvs_info) self._title = title self._field = field self._unit = unit self._icon = icon + self._my_device_class = device_class + self._my_state_class = state_class @property - def unit_of_measurement(self): + def native_unit_of_measurement(self): """Return the unit of measurement.""" return self._unit + @property + def device_class(self): + """Return device class.""" + return self._my_device_class + + @property + def state_class(self): + """Return state class.""" + return self._my_state_class + @property def icon(self): """Icon to use in the frontend, if any.""" @@ -211,6 +256,6 @@ def unique_id(self): return f"{self.base_unique_id}_pvs_{self._field}" @property - def state(self): + def native_value(self): """Get the current value""" return self.coordinator.data[INVERTER_DEVICE_TYPE][self.base_unique_id][self._field] From 7798e790066a4006e1dc577038bfe08f47af9d9c Mon Sep 17 00:00:00 2001 From: Keith Baker Date: Sun, 3 Oct 2021 15:40:41 -0400 Subject: [PATCH 2/3] existing installations that didnt reinstall seem to run into this data missing --- custom_components/sunpower/binary_sensor.py | 2 ++ custom_components/sunpower/sensor.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/custom_components/sunpower/binary_sensor.py b/custom_components/sunpower/binary_sensor.py index 8628fb7..587df8b 100644 --- a/custom_components/sunpower/binary_sensor.py +++ b/custom_components/sunpower/binary_sensor.py @@ -26,6 +26,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): sunpower_state = hass.data[DOMAIN][config_entry.entry_id] _LOGGER.debug("Sunpower_state: %s", sunpower_state) + if not SUNPOWER_DESCRIPTIVE_NAMES in config_entry.data: + config_entry.data[SUNPOWER_DESCRIPTIVE_NAMES] = False do_descriptive_names = config_entry.data[SUNPOWER_DESCRIPTIVE_NAMES] coordinator = sunpower_state[SUNPOWER_COORDINATOR] diff --git a/custom_components/sunpower/sensor.py b/custom_components/sunpower/sensor.py index c6500f9..69f629e 100644 --- a/custom_components/sunpower/sensor.py +++ b/custom_components/sunpower/sensor.py @@ -25,6 +25,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): sunpower_state = hass.data[DOMAIN][config_entry.entry_id] _LOGGER.debug("Sunpower_state: %s", sunpower_state) + if not SUNPOWER_DESCRIPTIVE_NAMES in config_entry.data: + config_entry.data[SUNPOWER_DESCRIPTIVE_NAMES] = False do_descriptive_names = config_entry.data[SUNPOWER_DESCRIPTIVE_NAMES] coordinator = sunpower_state[SUNPOWER_COORDINATOR] From 273ab20be84bb962ea4510f6b8634fa4115dfefd Mon Sep 17 00:00:00 2001 From: Keith Baker Date: Sun, 3 Oct 2021 15:43:08 -0400 Subject: [PATCH 3/3] add changes to make this a new release --- custom_components/sunpower/manifest.json | 2 +- hacs.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/sunpower/manifest.json b/custom_components/sunpower/manifest.json index 0578dc5..c7660f1 100644 --- a/custom_components/sunpower/manifest.json +++ b/custom_components/sunpower/manifest.json @@ -1,5 +1,5 @@ { - "version": "0.0.10", + "version": "0.0.11", "domain": "sunpower", "name": "sunpower", "config_flow": true, diff --git a/hacs.json b/hacs.json index 9d5aefb..18120db 100644 --- a/hacs.json +++ b/hacs.json @@ -2,7 +2,7 @@ "name": "SunPower", "country": "US", "domains": ["binary_sensor", "sensor"], - "homeassistant": "2021.8.0", + "homeassistant": "2021.9.0", "iot_class": ["Local Poll"], "render_readme": true }