Skip to content

Commit a7723c7

Browse files
authored
Add 2.13.0 files
1 parent 229a2ae commit a7723c7

File tree

5 files changed

+114
-12
lines changed

5 files changed

+114
-12
lines changed

custom_components/apsystems_ecu_reader/__init__.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
from homeassistant.helpers import device_registry as dr
88
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
99

10-
from .const import DOMAIN, ECU_MODEL_MAP, DEFAULT_SCAN_INTERVAL, DEFAULT_PORT_RETRIES, SETUP_DELAY_SECONDS, DEFAULT_CACHE_REBOOT
10+
from .const import (
11+
DOMAIN,
12+
ECU_MODEL_MAP,
13+
DEFAULT_SCAN_INTERVAL,
14+
DEFAULT_PORT_RETRIES,
15+
SETUP_DELAY_SECONDS,
16+
DEFAULT_CACHE_REBOOT,
17+
)
1118
from .ecu_api import APsystemsSocket, APsystemsInvalidData
1219
from .gui_helpers import (
1320
set_inverter_state,
@@ -28,7 +35,7 @@ class ECUREADER:
2835
def __init__(
2936
self, ipaddr: str, wifi_ssid: str, wifi_password: str, show_graphs: bool
3037
) -> None:
31-
38+
3239
self.ipaddr = ipaddr
3340
self.wifi_ssid = wifi_ssid
3441
self.wifi_password = wifi_password
@@ -49,9 +56,14 @@ async def set_inverter_state(self, inverter_id, state) -> bool:
4956
"""Set the on/off state of an inverter. 1=on, 2=off"""
5057
return await set_inverter_state(self.ipaddr, inverter_id, state)
5158

52-
async def set_zero_export(self, state):
59+
async def set_zero_export(self, state, power_limit):
5360
"""Set the bridge state for zero export. 0=closed, 1=open"""
54-
return await set_zero_export(self.ipaddr, state)
61+
return await set_zero_export(self.ipaddr, state, power_limit)
62+
63+
# called from number.py
64+
async def set_power_limit(self, power_limit):
65+
"""Set the power limit for zero export"""
66+
return await set_zero_export(self.ipaddr, 1, power_limit)
5567

5668
# called from button.py
5769
async def reboot_ecu(self):
@@ -128,7 +140,9 @@ async def async_setup_entry(hass, config):
128140
if len(hass.data[DOMAIN]) > 1:
129141
await asyncio.sleep(SETUP_DELAY_SECONDS)
130142

131-
interval = timedelta(seconds=config.data.get("scan_interval", DEFAULT_SCAN_INTERVAL))
143+
interval = timedelta(
144+
seconds=config.data.get("scan_interval", DEFAULT_SCAN_INTERVAL)
145+
)
132146
ecu = ECUREADER(
133147
config.data["ecu_host"],
134148
config.data.get("wifi_ssid", "ECU-local"),

custom_components/apsystems_ecu_reader/gui_helpers.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,13 @@ async def set_inverter_state(ipaddr, inverter_id, state) -> bool:
6161
return False
6262

6363

64-
async def set_zero_export(ipaddr, state):
64+
async def set_zero_export(ipaddr, state, power_limit=0):
6565
"""Set the bridge state for zero export. 0=closed, 1=open"""
66-
action = {"meter_func": "1" if state else "0", "this_func": "1", "power_limit": "0"}
66+
action = {
67+
"meter_func": "1" if state else "0",
68+
"this_func": "1",
69+
"power_limit": str(power_limit),
70+
}
6771
headers = {"X-Requested-With": "XMLHttpRequest", "Connection": "keep-alive"}
6872
url = f"http://{ipaddr}/index.php/meter/set_meter_display_funcs"
6973

custom_components/apsystems_ecu_reader/manifest.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
"config_flow": true,
66
"dependencies": [],
77
"documentation": "https://github.com/haedwin/homeassistant-apsystems_ecu_reader",
8+
"homeassistant": "2022.2.0",
89
"integration_type": "hub",
910
"iot_class": "local_polling",
1011
"issue_tracker": "https://github.com/haedwin/homeassistant-apsystems_ecu_reader/issues",
1112
"loggers": ["custom_components.apsystems_ecu_reader"],
12-
"version": "2.12.1"
13+
"requirements": [],
14+
"version": "2.13.0"
1315
}

custom_components/apsystems_ecu_reader/number.py

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,28 @@
55
from homeassistant.helpers.entity import EntityCategory
66

77

8-
from .const import DOMAIN, INVERTER_MODEL_MAP
8+
from .const import DOMAIN, INVERTER_MODEL_MAP, ECU_MODEL_MAP
99

1010

1111
async def async_setup_entry(hass, config_entry, async_add_entities):
1212
"""Set up the number platform."""
1313
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
1414
ecu = hass.data[DOMAIN][config_entry.entry_id]["ecu"]
1515

16-
# Only compatible with ECU-C and ECU-R-Pro
16+
entities = []
17+
18+
# ECU Power Limit Number - only compatible with ECU-C
19+
if ecu.ecu.ecu_id.startswith("215"):
20+
entities.append(ECUPowerLimitNumber(coordinator, ecu))
21+
22+
# Inverter Max Power Numbers - only compatible with ECU-C and ECU-R-Pro
1723
if ecu.ecu.ecu_id.startswith(("215", "2162")):
18-
entities = []
1924
for inverter_id, inverter_data in coordinator.data.get("inverters", {}).items():
2025
entities.append(
2126
InverterMaxPwrNumber(coordinator, ecu, inverter_id, inverter_data)
2227
)
28+
29+
if entities:
2330
async_add_entities(entities, True)
2431

2532

@@ -67,6 +74,70 @@ async def async_set_native_value(self, value: float):
6774
self._attr_native_value = value
6875
self.async_write_ha_state()
6976

77+
def set_native_value(self, value: float):
78+
"""Set the value synchronously (required by NumberEntity)."""
79+
# This is called by Home Assistant framework, but we use async version
80+
self._attr_native_value = value
81+
82+
async def async_added_to_hass(self):
83+
"""Handle entity which value will be restored."""
84+
await super().async_added_to_hass()
85+
if (last_state := await self.async_get_last_state()) is not None:
86+
self._attr_native_value = float(last_state.state)
87+
88+
89+
class ECUPowerLimitNumber(CoordinatorEntity, RestoreNumber):
90+
"""Representation of an ECU Power Limit Number entity."""
91+
92+
def __init__(self, coordinator, ecu):
93+
"""Initialize the number entity."""
94+
super().__init__(coordinator)
95+
self._ecu = ecu
96+
self._attr_name = f"ECU {ecu.ecu.ecu_id} Power Limit"
97+
self._attr_unique_id = f"{ecu.ecu.ecu_id}_power_limit"
98+
self._attr_native_min_value = 0
99+
self._attr_native_max_value = 3
100+
self._attr_native_step = 0.1
101+
self._attr_native_value = 0
102+
self._attr_device_class = "power"
103+
self._attr_native_unit_of_measurement = "kW"
104+
self._attr_mode = "slider"
105+
106+
@property
107+
def device_info(self):
108+
"""Return the device info."""
109+
return {
110+
"identifiers": {
111+
(DOMAIN, f"ecu_{self._ecu.ecu.ecu_id}"),
112+
},
113+
"name": f"ECU {self._ecu.ecu.ecu_id}",
114+
"manufacturer": "APsystems",
115+
"model": ECU_MODEL_MAP.get(self._ecu.ecu.ecu_id[:4], "Unknown Model"),
116+
}
117+
118+
@property
119+
def entity_category(self):
120+
"""Return the category of the entity."""
121+
return EntityCategory.CONFIG
122+
123+
@property
124+
def suggested_display_precision(self):
125+
"""Return the suggested number of decimal places for display."""
126+
return 1
127+
128+
async def async_set_native_value(self, value: float):
129+
"""Update the current value."""
130+
# Convert from kW to watts for the ECU API
131+
power_limit_watts = int(value * 1000)
132+
await self._ecu.set_power_limit(power_limit_watts)
133+
self._attr_native_value = value
134+
self.async_write_ha_state()
135+
136+
def set_native_value(self, value: float):
137+
"""Set the value synchronously (required by NumberEntity)."""
138+
# This is called by Home Assistant framework, but we use async version
139+
self._attr_native_value = value
140+
70141
async def async_added_to_hass(self):
71142
"""Handle entity which value will be restored."""
72143
await super().async_added_to_hass()

custom_components/apsystems_ecu_reader/switch.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,18 @@ def __init__(self, coordinator, ecu):
175175
async def async_turn_on(self, **kwargs):
176176
"""Turn on zero export."""
177177
try:
178-
await self._ecu.set_zero_export(1)
178+
# Get the current power limit from the number entity
179+
power_limit_entity_id = f"number.ecu_{self._ecu.ecu.ecu_id}_power_limit"
180+
power_limit_state = self.hass.states.get(power_limit_entity_id)
181+
power_limit = 0
182+
if power_limit_state and power_limit_state.state not in (
183+
"unknown",
184+
"unavailable",
185+
):
186+
# Convert from kW display value to watts
187+
power_limit = int(float(power_limit_state.state) * 1000)
188+
189+
await self._ecu.set_zero_export(1, power_limit)
179190
self._state = True
180191
self.async_write_ha_state()
181192
except (ConnectionError, TimeoutError) as e:

0 commit comments

Comments
 (0)