Skip to content

Commit 488c3bf

Browse files
committed
feat: Added sensor for providing total exports provided by Home Mini - This is not available for all meters (30 minutes dev time)
1 parent 1e3a98a commit 488c3bf

File tree

4 files changed

+149
-1
lines changed

4 files changed

+149
-1
lines changed

_docs/entities/electricity.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,27 @@ The total consumption reported by the meter for all time. This will try and upda
474474
| `is_export` | `boolean` | Determines if the meter exports energy rather than imports |
475475
| `is_smart_meter` | `boolean` | Determines if the meter is considered smart by Octopus Energy |
476476

477+
### Current Total Export
478+
479+
`sensor.octopus_energy_electricity_{{METER_SERIAL_NUMBER}}_{{MPAN_NUMBER}}_current_total_export`
480+
481+
!!! warning
482+
This will only be available if you have specified you have an [Octopus Home Mini](../setup/account.md#home-mini). Do not set unless you have one.
483+
484+
!!! info
485+
Not all meters provide this information. In these scenarios, this sensor will report zero.
486+
487+
!!! note
488+
This is [disabled by default](../faq.md#there-are-entities-that-are-disabled-why-are-they-disabled-and-how-do-i-enable-them).
489+
490+
The total export reported by the meter for all time. This will try and update every minute for Home Mini.
491+
492+
| Attribute | Type | Description |
493+
|-----------|------|-------------|
494+
| `mpan` | `string` | The mpan for the associated meter |
495+
| `serial_number` | `string` | The serial for the associated meter |
496+
| `is_smart_meter` | `boolean` | Determines if the meter is considered smart by Octopus Energy |
497+
477498
### Current Accumulative Cost
478499

479500
`sensor.octopus_energy_electricity_{{METER_SERIAL_NUMBER}}_{{MPAN_NUMBER}}_current_accumulative_cost`

custom_components/octopus_energy/api_client/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
consumption
114114
consumptionDelta
115115
demand
116+
export
116117
}}
117118
}}'''
118119

@@ -1133,6 +1134,7 @@ async def async_get_smart_meter_consumption(self, device_id: str, period_from: d
11331134
if (response_body is not None and "data" in response_body and "smartMeterTelemetry" in response_body["data"] and response_body["data"]["smartMeterTelemetry"] is not None and len(response_body["data"]["smartMeterTelemetry"]) > 0):
11341135
return list(map(lambda mp: {
11351136
"total_consumption": float(mp["consumption"]) / 1000 if "consumption" in mp and mp["consumption"] is not None else None,
1137+
"total_export": float(mp["export"]) / 1000 if "export" in mp and mp["export"] is not None else None,
11361138
"consumption": float(mp["consumptionDelta"]) / 1000 if "consumptionDelta" in mp and mp["consumptionDelta"] is not None else 0,
11371139
"demand": float(mp["demand"]) if "demand" in mp and mp["demand"] is not None else None,
11381140
"start": parse_datetime(mp["readAt"]),
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import logging
2+
3+
from homeassistant.const import (
4+
STATE_UNAVAILABLE,
5+
STATE_UNKNOWN,
6+
)
7+
from homeassistant.core import HomeAssistant, callback
8+
9+
from homeassistant.helpers.update_coordinator import (
10+
CoordinatorEntity,
11+
)
12+
13+
from homeassistant.components.sensor import (
14+
RestoreSensor,
15+
SensorDeviceClass,
16+
SensorStateClass,
17+
)
18+
from homeassistant.const import (
19+
UnitOfEnergy
20+
)
21+
22+
from homeassistant.util.dt import (now)
23+
24+
from ..coordinators.current_consumption import CurrentConsumptionCoordinatorResult
25+
from .base import (OctopusEnergyElectricitySensor)
26+
from ..utils.attributes import dict_to_typed_dict
27+
28+
_LOGGER = logging.getLogger(__name__)
29+
30+
class OctopusEnergyCurrentTotalElectricityExport(CoordinatorEntity, OctopusEnergyElectricitySensor, RestoreSensor):
31+
"""Sensor for displaying the current total electricity export."""
32+
33+
def __init__(self, hass: HomeAssistant, coordinator, meter, point):
34+
"""Init sensor."""
35+
CoordinatorEntity.__init__(self, coordinator)
36+
37+
self._state = None
38+
self._last_reset = None
39+
40+
OctopusEnergyElectricitySensor.__init__(self, hass, meter, point)
41+
42+
@property
43+
def entity_registry_enabled_default(self) -> bool:
44+
"""Return if the entity should be enabled when first added.
45+
46+
This only applies when fist added to the entity registry.
47+
"""
48+
return False
49+
50+
@property
51+
def unique_id(self):
52+
"""The id of the sensor."""
53+
return f"octopus_energy_electricity_{self._serial_number}_{self._mpan}_current_total_export"
54+
55+
@property
56+
def name(self):
57+
"""Name of the sensor."""
58+
return f"Current Total Export Electricity ({self._serial_number}/{self._mpan})"
59+
60+
@property
61+
def device_class(self):
62+
"""The type of sensor"""
63+
return SensorDeviceClass.ENERGY
64+
65+
@property
66+
def state_class(self):
67+
"""The state class of sensor"""
68+
return SensorStateClass.TOTAL_INCREASING
69+
70+
@property
71+
def native_unit_of_measurement(self):
72+
"""The unit of measurement of sensor"""
73+
return UnitOfEnergy.KILO_WATT_HOUR
74+
75+
@property
76+
def icon(self):
77+
"""Icon of the sensor."""
78+
return "mdi:lightning-bolt"
79+
80+
@property
81+
def extra_state_attributes(self):
82+
"""Attributes of the sensor."""
83+
return self._attributes
84+
85+
@property
86+
def native_value(self):
87+
return self._state
88+
89+
@callback
90+
def _handle_coordinator_update(self) -> None:
91+
"""Retrieve the current days accumulative export"""
92+
current = now()
93+
consumption_result: CurrentConsumptionCoordinatorResult = self.coordinator.data if self.coordinator is not None and self.coordinator.data is not None else None
94+
consumption_data = consumption_result.data if consumption_result is not None else None
95+
96+
if (consumption_data is not None and len(consumption_data) > 0):
97+
_LOGGER.debug(f"Calculated total electricity export for '{self._mpan}/{self._serial_number}'...")
98+
99+
if consumption_data[-1]["total_export"] is not None:
100+
self._state = consumption_data[-1]["total_export"] if consumption_data[-1]["total_export"] is not None and consumption_data[-1]["total_export"] != 0 else None
101+
self._last_reset = current
102+
103+
self._attributes = {
104+
"mpan": self._mpan,
105+
"serial_number": self._serial_number,
106+
"is_smart_meter": self._is_smart_meter,
107+
}
108+
109+
self._attributes = dict_to_typed_dict(self._attributes)
110+
super()._handle_coordinator_update()
111+
112+
async def async_added_to_hass(self):
113+
"""Call when entity about to be added to hass."""
114+
# If not None, we got an initial value.
115+
await super().async_added_to_hass()
116+
state = await self.async_get_last_state()
117+
last_sensor_state = await self.async_get_last_sensor_data()
118+
119+
if state is not None and last_sensor_state is not None and self._state is None:
120+
self._state = None if state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN) else last_sensor_state.native_value
121+
self._attributes = dict_to_typed_dict(state.attributes)
122+
123+
_LOGGER.debug(f'Restored state: {self._state}')

custom_components/octopus_energy/sensor.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datetime import timedelta
2-
from custom_components.octopus_energy.diagnostics_entities.heat_pump_data_last_retrieved import OctopusEnergyHeatPumpDataLastRetrieved
32
import voluptuous as vol
43
import logging
54

@@ -22,6 +21,8 @@
2221
from .electricity.previous_accumulative_cost_override import OctopusEnergyPreviousAccumulativeElectricityCostOverride
2322
from .electricity.rates_previous_consumption_override import OctopusEnergyElectricityPreviousConsumptionOverrideRates
2423
from .electricity.current_total_consumption import OctopusEnergyCurrentTotalElectricityConsumption
24+
from .diagnostics_entities.heat_pump_data_last_retrieved import OctopusEnergyHeatPumpDataLastRetrieved
25+
from .electricity.current_total_export import OctopusEnergyCurrentTotalElectricityExport
2526
from .gas.current_rate import OctopusEnergyGasCurrentRate
2627
from .gas.next_rate import OctopusEnergyGasNextRate
2728
from .gas.previous_rate import OctopusEnergyGasPreviousRate
@@ -425,6 +426,7 @@ async def async_setup_default_sensors(hass: HomeAssistant, config, async_add_ent
425426
entities.append(OctopusEnergyCurrentAccumulativeElectricityCost(hass, consumption_coordinator, electricity_rate_coordinator, electricity_standing_charges_coordinator, meter, point))
426427
entities.append(OctopusEnergyCurrentElectricityIntervalAccumulativeConsumption(hass, consumption_coordinator, saving_session_coordinator, meter, point))
427428
entities.append(OctopusEnergyCurrentConsumptionDataLastRetrieved(hass, consumption_coordinator, True, meter, point))
429+
entities.append(OctopusEnergyCurrentTotalElectricityExport(hass, consumption_coordinator, meter, point))
428430

429431
if home_pro_client is None:
430432
entities.append(OctopusEnergyCurrentElectricityDemand(hass, consumption_coordinator, meter, point))

0 commit comments

Comments
 (0)