Skip to content

Commit f15552a

Browse files
Merge pull request #34 from mattjgalloway/pv_divert_updates
PV diverter updates
2 parents 6b1efd1 + ca87803 commit f15552a

File tree

6 files changed

+250
-85
lines changed

6 files changed

+250
-85
lines changed

custom_components/mixergy/__init__.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .const import ATTR_CHARGE, SERVICE_SET_CHARGE, ATTR_TEMPERATURE, SERVICE_SET_TARGET_TEMPERATURE
2+
from datetime import timedelta
23
import logging
34
import asyncio
45
import voluptuous as vol
@@ -11,13 +12,18 @@
1112
from .tank import Tank
1213
from typing import Any, Final, final
1314
import homeassistant.helpers.config_validation as cv
15+
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
1416

1517
CHARGE_SERVICE_SCHEMA: Final = make_entity_service_schema(
1618
{vol.Optional("target_percentage"): cv.positive_int}
1719
)
1820

1921
DOMAIN = "mixergy"
20-
PLATFORMS = ["sensor"]
22+
PLATFORMS = [
23+
"sensor",
24+
"switch",
25+
"number",
26+
]
2127
_LOGGER = logging.getLogger(__name__)
2228

2329
async def async_setup(hass: HomeAssistant, config):
@@ -38,7 +44,18 @@ async def async_setup_entry(hass: HomeAssistant, entry:ConfigEntry) -> bool:
3844

3945
tank = Tank(hass, entry.data[CONF_USERNAME],entry.data[CONF_PASSWORD],entry.data["serial_number"])
4046

41-
hass.data[DOMAIN][entry.entry_id] = tank
47+
async def async_update_data():
48+
_LOGGER.info("Fetching data from Mixergy...")
49+
await tank.fetch_data()
50+
51+
# Create a coordinator to fetch data from the Mixergy API.
52+
coordinator = DataUpdateCoordinator(hass, _LOGGER, name="Mixergy", update_method = async_update_data, update_interval = timedelta(seconds=30))
53+
await coordinator.async_config_entry_first_refresh()
54+
55+
hass.data[DOMAIN][entry.entry_id] = {
56+
"tank": tank,
57+
"coordinator": coordinator,
58+
}
4259

4360
_register_services(hass)
4461

@@ -73,7 +90,7 @@ async def mixergy_set_charge(call):
7390

7491
tasks = [
7592
tank.set_target_charge(charge)
76-
for tank in hass.data[DOMAIN].values()
93+
for tank in [d["tank"] for d in hass.data[DOMAIN].values()]
7794
if isinstance(tank, Tank)
7895
]
7996

@@ -89,7 +106,7 @@ async def mixergy_set_target_temperature(call):
89106

90107
tasks = [
91108
tank.set_target_temperature(temperature)
92-
for tank in hass.data[DOMAIN].values()
109+
for tank in [d["tank"] for d in hass.data[DOMAIN].values()]
93110
if isinstance(tank, Tank)
94111
]
95112

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from .const import DOMAIN
2+
from .tank import Tank
3+
from homeassistant.helpers.update_coordinator import CoordinatorEntity
4+
5+
class MixergyEntityBase(CoordinatorEntity):
6+
7+
should_poll = True
8+
9+
def __init__(self, coordinator, tank:Tank):
10+
super().__init__(coordinator)
11+
self._tank = tank
12+
13+
@property
14+
def device_info(self):
15+
return {
16+
"identifiers": {(DOMAIN, self._tank.serial_number)},
17+
"manufacturer": "Mixergy Ltd",
18+
"name": "Mixergy Tank",
19+
"suggested_area": "garage",
20+
"model": self._tank.modelCode,
21+
"sw_version": self._tank.firmwareVersion
22+
}
23+
24+
@property
25+
def available(self) -> bool:
26+
return self._tank.online
27+
28+
async def async_added_to_hass(self):
29+
self._tank.register_callback(self.async_write_ha_state)
30+
31+
async def async_will_remove_from_hass(self):
32+
self._tank.remove_callback(self.async_write_ha_state)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import logging
2+
from homeassistant.components.number import NumberEntity
3+
from .const import DOMAIN
4+
from .tank import Tank
5+
from .mixergy_entity import MixergyEntityBase
6+
7+
_LOGGER = logging.getLogger(__name__)
8+
9+
async def async_setup_entry(hass, config_entry, async_add_entities):
10+
_LOGGER.info("Setting up entry based on user config")
11+
12+
entry = hass.data[DOMAIN][config_entry.entry_id]
13+
tank = entry["tank"]
14+
coordinator = entry["coordinator"]
15+
16+
new_entities = []
17+
18+
new_entities.append(PVChargeLimitSensor(coordinator, tank))
19+
20+
async_add_entities(new_entities)
21+
22+
class NumberEntityBase(MixergyEntityBase, NumberEntity):
23+
24+
def __init__(self, coordinator, tank:Tank):
25+
super().__init__(coordinator, tank)
26+
27+
class PVChargeLimitSensor(NumberEntityBase):
28+
29+
native_max_value = 100
30+
native_min_value = 0
31+
native_step = 10
32+
33+
def __init__(self, coordinator, tank:Tank):
34+
super().__init__( coordinator, tank)
35+
36+
@property
37+
def unique_id(self):
38+
return f"mixergy_{self._tank.tank_id}_pv_charge_limit"
39+
40+
@property
41+
def state(self):
42+
return self._tank.pv_charge_limit
43+
44+
@property
45+
def available(self):
46+
return super().available and self._tank.has_pv_diverter
47+
48+
async def async_set_native_value(self, value: float):
49+
await self._tank.set_pv_charge_limit(int(value))
50+
51+
@property
52+
def icon(self):
53+
return "mdi:lightning-bolt"
54+
55+
@property
56+
def name(self):
57+
return f"PV Charge Limit"

custom_components/mixergy/sensor.py

Lines changed: 15 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,21 @@
11
import logging
22
from datetime import timedelta
33
from homeassistant.const import UnitOfPower, UnitOfTemperature, PERCENTAGE, STATE_OFF
4-
from homeassistant.components.sensor import SensorEntity
5-
from homeassistant.components.sensor import SensorDeviceClass
4+
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
65
from homeassistant.components.integration.sensor import IntegrationSensor
7-
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
8-
from homeassistant.components.binary_sensor import BinarySensorEntity
6+
from homeassistant.components.binary_sensor import BinarySensorDeviceClass, BinarySensorEntity
97
from .const import DOMAIN
108
from .tank import Tank
11-
from homeassistant.helpers.update_coordinator import (
12-
CoordinatorEntity,
13-
DataUpdateCoordinator,
14-
)
9+
from .mixergy_entity import MixergyEntityBase
1510

1611
_LOGGER = logging.getLogger(__name__)
1712

1813
async def async_setup_entry(hass, config_entry, async_add_entities):
1914
_LOGGER.info("Setting up entry based on user config")
2015

21-
tank = hass.data[DOMAIN][config_entry.entry_id]
22-
23-
async def async_update_data():
24-
_LOGGER.info("Fetching data from Mixergy...")
25-
await tank.fetch_data()
26-
27-
# Create a coordinator to fetch data from the Mixergy API.
28-
coordinator = DataUpdateCoordinator(hass, _LOGGER, name="sensor", update_method = async_update_data, update_interval = timedelta(seconds=30))
29-
30-
await coordinator.async_config_entry_first_refresh()
16+
entry = hass.data[DOMAIN][config_entry.entry_id]
17+
tank = entry["tank"]
18+
coordinator = entry["coordinator"]
3119

3220
new_entities = []
3321

@@ -48,66 +36,18 @@ async def async_update_data():
4836
new_entities.append(PVEnergySensor(tank))
4937
new_entities.append(ClampPowerSensor(coordinator, tank))
5038
new_entities.append(IsChargingSensor(coordinator, tank))
51-
52-
async_add_entities(new_entities)
5339

54-
class SensorBase(CoordinatorEntity,SensorEntity):
40+
async_add_entities(new_entities)
5541

56-
should_poll = True
42+
class SensorBase(MixergyEntityBase, SensorEntity):
5743

5844
def __init__(self, coordinator, tank:Tank):
59-
super().__init__(coordinator)
60-
self._tank = tank
61-
62-
@property
63-
def device_info(self):
64-
return {
65-
"identifiers": {(DOMAIN, self._tank.serial_number)},
66-
"manufacturer":"Mixergy Ltd",
67-
"name":"Mixergy Tank",
68-
"suggested_area":"garage",
69-
"model":self._tank.modelCode,
70-
"sw_version":self._tank.firmwareVersion
71-
}
72-
73-
@property
74-
def available(self) -> bool:
75-
return self._tank.online
76-
77-
async def async_added_to_hass(self):
78-
self._tank.register_callback(self.async_write_ha_state)
79-
80-
async def async_will_remove_from_hass(self):
81-
self._tank.remove_callback(self.async_write_ha_state)
82-
83-
class BinarySensorBase(CoordinatorEntity,BinarySensorEntity):
45+
super().__init__(coordinator, tank)
8446

85-
should_poll = True
47+
class BinarySensorBase(MixergyEntityBase, BinarySensorEntity):
8648

8749
def __init__(self, coordinator, tank:Tank):
88-
super().__init__(coordinator)
89-
self._tank = tank
90-
91-
@property
92-
def device_info(self):
93-
return {
94-
"identifiers": {(DOMAIN, self._tank.serial_number)},
95-
"manufacturer":"Mixergy Ltd",
96-
"name":"Mixergy Tank",
97-
"suggested_area":"garage",
98-
"model":self._tank.modelCode,
99-
"sw_version":self._tank.firmwareVersion
100-
}
101-
102-
@property
103-
def available(self) -> bool:
104-
return self._tank.online
105-
106-
async def async_added_to_hass(self):
107-
self._tank.register_callback(self.async_write_ha_state)
108-
109-
async def async_will_remove_from_hass(self):
110-
self._tank.remove_callback(self.async_write_ha_state)
50+
super().__init__(coordinator, tank)
11151

11252
class ChargeSensor(SensorBase):
11353

@@ -133,7 +73,7 @@ def icon(self):
13373
@property
13474
def name(self):
13575
return f"Current Charge"
136-
76+
13777
class TargetChargeSensor(SensorBase):
13878

13979
def __init__(self, coordinator, tank:Tank):
@@ -205,7 +145,7 @@ def unit_of_measurement(self):
205145
@property
206146
def name(self):
207147
return f"Coldest Water Temperature"
208-
148+
209149
class TargetTemperatureSensor(SensorBase):
210150

211151
device_class = SensorDeviceClass.TEMPERATURE
@@ -335,7 +275,7 @@ def icon(self):
335275
@property
336276
def name(self):
337277
return f"Low Hot Water"
338-
278+
339279
class IsChargingSensor(BinarySensorBase):
340280

341281
def __init__(self, coordinator, tank:Tank):
@@ -461,7 +401,7 @@ def state(self):
461401

462402
@property
463403
def unit_of_measurement(self):
464-
return POWER_WATT
404+
return UnitOfPower.WATT
465405

466406
@property
467407
def name(self):
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import logging
2+
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity
3+
from .const import DOMAIN
4+
from .tank import Tank
5+
from .mixergy_entity import MixergyEntityBase
6+
7+
_LOGGER = logging.getLogger(__name__)
8+
9+
async def async_setup_entry(hass, config_entry, async_add_entities):
10+
_LOGGER.info("Setting up entry based on user config")
11+
12+
entry = hass.data[DOMAIN][config_entry.entry_id]
13+
tank = entry["tank"]
14+
coordinator = entry["coordinator"]
15+
16+
new_entities = []
17+
18+
new_entities.append(PVDivertSwitch(coordinator, tank))
19+
20+
async_add_entities(new_entities)
21+
22+
class SwitchEntityBase(MixergyEntityBase, SwitchEntity):
23+
24+
device_class = SwitchDeviceClass.SWITCH
25+
26+
def __init__(self, coordinator, tank:Tank):
27+
super().__init__(coordinator, tank)
28+
29+
class PVDivertSwitch(SwitchEntityBase):
30+
31+
def __init__(self, coordinator, tank:Tank):
32+
super().__init__(coordinator, tank)
33+
34+
@property
35+
def unique_id(self):
36+
return f"mixergy_{self._tank.tank_id}_pv_divert_enabled"
37+
38+
@property
39+
def name(self):
40+
return f"PV Divert Enabled"
41+
42+
@property
43+
def available(self):
44+
return super().available and self._tank.has_pv_diverter
45+
46+
@property
47+
def is_on(self):
48+
return self._tank.divert_exported_enabled
49+
50+
async def async_turn_on(self, **kwargs):
51+
await self._tank.set_divert_exported_enabled(True)
52+
53+
async def async_turn_off(self, **kwargs):
54+
await self._tank.set_divert_exported_enabled(False)

0 commit comments

Comments
 (0)