diff --git a/custom_components/andersen_ev/sensor.py b/custom_components/andersen_ev/sensor.py index 901300a..dbf2fec 100644 --- a/custom_components/andersen_ev/sensor.py +++ b/custom_components/andersen_ev/sensor.py @@ -82,6 +82,9 @@ async def async_setup_entry( ) # Live status sensors + # sysGridPower/sysSolarPower are declared KILO_WATT; chargeStatus.gridPower + # below is declared WATT for the same physical quantity but only reports + # during a charge session. Unit verified via live load test (~2.9 kW kettle). entities.append( AndersenEvLiveSensor( coordinator, @@ -95,6 +98,94 @@ async def async_setup_entry( "mdi:transmission-tower", ) ) + # --- Solar live sensors ------------------------------------------------- + # sysSolarPower/sysSolarEnergyDelta/sysChargePower are already fetched in + # the GraphQL query (konnect/const.py) but were never exposed as entities. + # They live in deviceStatus, not chargeStatus, so they report continuously + # - not just during a charge session - making this a whole-house solar + # monitor for free. + entities.append( + AndersenEvLiveSensor( + coordinator, + device, + "sys_solar_power", + "System Solar Power", + "sysSolarPower", + SensorDeviceClass.POWER, + SensorStateClass.MEASUREMENT, + UnitOfPower.KILO_WATT, + "mdi:solar-power", + ) + ) + entities.append( + AndersenEvLiveSensor( + coordinator, + device, + "sys_charge_power", + "System Charge Power", + "sysChargePower", + SensorDeviceClass.POWER, + SensorStateClass.MEASUREMENT, + UnitOfPower.KILO_WATT, + "mdi:ev-station", + ) + ) + entities.append( + AndersenEvLiveSensor( + coordinator, + device, + "sys_solar_energy_delta", + "System Solar Energy Delta", + "sysSolarEnergyDelta", + SensorDeviceClass.ENERGY, + SensorStateClass.TOTAL, + UnitOfEnergy.KILO_WATT_HOUR, + "mdi:solar-power", + ) + ) + # --- CT clamp diagnostics ------------------------------------------------ + # Raw CT readings and configuration - not for the Energy dashboard. These + # exist to diagnose mis-clamped or mis-configured CTs, a common cause of + # solar generation reading suspiciously low. + entities.append( + AndersenEvLiveSensor( + coordinator, + device, + "sys_solar_ct", + "Solar CT", + "sysSolarCT", + None, + None, + None, + "mdi:gauge", + ) + ) + entities.append( + AndersenEvLiveSensor( + coordinator, + device, + "sys_grid_ct", + "Grid CT", + "sysGridCT", + None, + None, + None, + "mdi:gauge", + ) + ) + entities.append( + AndersenEvLiveSensor( + coordinator, + device, + "cfg_ct_config", + "CT Configuration", + "cfgCTConfig", + None, + None, + None, + "mdi:cog-outline", + ) + ) entities.append( AndersenEvLiveSensor( coordinator, diff --git a/custom_components/andersen_ev/tests/test_sensor.py b/custom_components/andersen_ev/tests/test_sensor.py index 7cdcf7a..2a2bdf7 100644 --- a/custom_components/andersen_ev/tests/test_sensor.py +++ b/custom_components/andersen_ev/tests/test_sensor.py @@ -60,12 +60,12 @@ async def test_creates_all_sensor_types_per_device(self): await async_setup_entry(MagicMock(), entry, async_add_entities) entities = async_add_entities.call_args.args[0] - assert len(entities) == 44 + assert len(entities) == 56 assert sum(isinstance(e, AndersenEvEnergySensor) for e in entities) == 8 assert sum(isinstance(e, AndersenEvCostSensor) for e in entities) == 8 assert sum(isinstance(e, AndersenEvConnectorSensor) for e in entities) == 2 assert sum(isinstance(e, AndersenEvChargeStatusSensor) for e in entities) == 16 - assert sum(isinstance(e, AndersenEvLiveSensor) for e in entities) == 10 + assert sum(isinstance(e, AndersenEvLiveSensor) for e in entities) == 22 @pytest.mark.asyncio async def test_no_devices_creates_no_entities(self):