Skip to content

Commit

Permalink
cloud support
Browse files Browse the repository at this point in the history
  • Loading branch information
marq24 committed Jun 30, 2024
1 parent 467b59a commit ae35467
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 62 deletions.
66 changes: 48 additions & 18 deletions custom_components/goecharger_api2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from homeassistant.components.number import NumberDeviceClass
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.const import CONF_HOST, CONF_TYPE, CONF_ID, CONF_SCAN_INTERVAL
from homeassistant.const import CONF_HOST, CONF_TYPE, CONF_ID, CONF_SCAN_INTERVAL, CONF_MODE, CONF_TOKEN
from homeassistant.core import Config, Event, SupportsResponse
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
Expand All @@ -19,6 +19,8 @@
from custom_components.goecharger_api2.pygoecharger_ha import GoeChargerApiV2Bridge, TRANSLATIONS
from custom_components.goecharger_api2.pygoecharger_ha.keys import Tag
from .const import (
LAN,
WAN,
NAME,
DOMAIN,
MANUFACTURER,
Expand Down Expand Up @@ -161,9 +163,20 @@ class GoeChargerDataUpdateCoordinator(DataUpdateCoordinator):
def __init__(self, hass: HomeAssistant, config_entry):
lang = hass.config.language.lower()
self.name = config_entry.title
self.bridge = GoeChargerApiV2Bridge(host=config_entry.options.get(CONF_HOST, config_entry.data.get(CONF_HOST)),
web_session=async_get_clientsession(hass),
lang=lang)
if CONF_MODE in config_entry.data and config_entry.data.get(CONF_MODE) == WAN:
self.mode = WAN
self.bridge = GoeChargerApiV2Bridge(host=None,
serial=config_entry.options.get(CONF_ID, config_entry.data.get(CONF_ID)),
token=config_entry.options.get(CONF_TOKEN, config_entry.data.get(CONF_TOKEN)),
web_session=async_get_clientsession(hass),
lang=lang)
else:
self.mode = LAN
self.bridge = GoeChargerApiV2Bridge(host=config_entry.options.get(CONF_HOST, config_entry.data.get(CONF_HOST)),
serial=None,
token=None,
web_session=async_get_clientsession(hass),
lang=lang)

global SCAN_INTERVAL
SCAN_INTERVAL = timedelta(seconds=config_entry.options.get(CONF_SCAN_INTERVAL,
Expand Down Expand Up @@ -234,19 +247,32 @@ async def async_write_key(self, key: str, value, entity: Entity = None) -> dict:

async def read_versions(self):
await self.bridge.read_versions()
self._device_info_dict = {
"identifiers": {
("DOMAIN", DOMAIN),
("SERIAL", self._serial),
("IP", self._config_entry.options.get(CONF_HOST, self._config_entry.data.get(CONF_HOST))),
},
"manufacturer": MANUFACTURER,
"suggested_area": "Garage",
"name": NAME,
"model": self._config_entry.data.get(CONF_TYPE),
"sw_version": self.bridge._versions[Tag.FWV.key]
# hw_version
}
if self.mode == LAN:
self._device_info_dict = {
"identifiers": {(
DOMAIN,
self._config_entry.data.get(CONF_HOST),
self._config_entry.title)},
"manufacturer": MANUFACTURER,
"suggested_area": "Garage",
"name": self._config_entry.title,
"model": self._config_entry.data.get(CONF_TYPE),
"sw_version": self.bridge._versions[Tag.FWV.key]
# hw_version
}
else:
self._device_info_dict = {
"identifiers": {(
DOMAIN,
self._config_entry.data.get(CONF_TOKEN),
self._config_entry.title)},
"manufacturer": MANUFACTURER,
"suggested_area": "Garage",
"name": self._config_entry.title,
"model": self._config_entry.data.get(CONF_TYPE),
"sw_version": self.bridge._versions[Tag.FWV.key]
# hw_version
}

# fetching the available cards that are enabled
self.available_cards_idx = []
Expand Down Expand Up @@ -295,7 +321,11 @@ def __init__(self, coordinator: GoeChargerDataUpdateCoordinator, description: En

self.entity_description = description
self.coordinator = coordinator
self.entity_id = f"{DOMAIN}.goe_{self.coordinator._serial}_{self._attr_translation_key}"

if self.coordinator.mode == WAN:
self.entity_id = f"{DOMAIN}.goe_wan_{self.coordinator._serial}_{self._attr_translation_key}"
else:
self.entity_id = f"{DOMAIN}.goe_{self.coordinator._serial}_{self._attr_translation_key}"

def _name_internal(self, device_class_name: str | None,
platform_translations: dict[str, Any], ) -> str | UndefinedType | None:
Expand Down
141 changes: 124 additions & 17 deletions custom_components/goecharger_api2/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import logging
from typing import Final

import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_ID, CONF_HOST, CONF_MODEL, CONF_TYPE, CONF_SCAN_INTERVAL
from homeassistant.const import CONF_ID, CONF_HOST, CONF_MODEL, CONF_TYPE, CONF_SCAN_INTERVAL, CONF_TOKEN, CONF_MODE
from homeassistant.core import callback
from homeassistant.helpers import selector
from homeassistant.helpers.aiohttp_client import async_create_clientsession

from custom_components.goecharger_api2.pygoecharger_ha import GoeChargerApiV2Bridge
from custom_components.goecharger_api2.pygoecharger_ha.keys import Tag
from .const import (
DOMAIN, CONF_11KWLIMIT
DOMAIN, CONF_11KWLIMIT, LAN, WAN
)

_LOGGER: logging.Logger = logging.getLogger(__package__)

SETUP_SYS_TYPE: Final = "stype"
SYSTEM_TYPES: Final = [LAN, WAN]


class GoeChargerApiV2FlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Config flow for goecharger_api2."""
Expand All @@ -29,6 +34,38 @@ def __init__(self):
self._serial = ""

async def async_step_user(self, user_input=None):
self._errors = {}
if user_input is not None:
self._selected_system = user_input

if self._selected_system.get(SETUP_SYS_TYPE) == WAN:
return await self.async_step_user_wan()
else:
# return await self.async_step_mode()
return await self.async_step_user_lan()
else:
user_input = {}
user_input[SETUP_SYS_TYPE] = LAN

return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(SETUP_SYS_TYPE, default=user_input.get(SETUP_SYS_TYPE, LAN)):
selector.SelectSelector(
selector.SelectSelectorConfig(
options=SYSTEM_TYPES,
mode=selector.SelectSelectorMode.DROPDOWN,
translation_key=SETUP_SYS_TYPE,
)
)
}
),
last_step=False,
errors=self._errors,
)

async def async_step_user_lan(self, user_input=None):
"""Handle a flow initialized by the user."""
self._errors = {}

Expand All @@ -37,23 +74,24 @@ async def async_step_user(self, user_input=None):
# return self.async_abort(reason="single_instance_allowed")

if user_input is not None:
valid = await self._test_host(host=user_input[CONF_HOST])
valid = await self._test_host(host=user_input[CONF_HOST], serial=None, token=None)
if valid:
user_input[CONF_MODE] = LAN
user_input[CONF_MODEL] = self._model.split(' ')[0]
user_input[CONF_TYPE] = f"{self._type} [{self._model}]"
user_input[CONF_TYPE] = f"{self._type} [{self._model}] Local"
user_input[CONF_ID] = self._serial
user_input[CONF_SCAN_INTERVAL] = max(5, user_input[CONF_SCAN_INTERVAL])
title = f"go-eCharger API v2 [{self._serial}]"
title = f"go-eCharger API v2 [{self._serial}] Local"
return self.async_create_entry(title=title, data=user_input)
else:
self._errors["base"] = "auth"
self._errors["base"] = "auth_lan"
else:
user_input = {}
user_input[CONF_HOST] = ""
user_input[CONF_SCAN_INTERVAL] = 5

return self.async_show_form(
step_id="user",
step_id="user_lan",
data_schema=vol.Schema({
vol.Required(CONF_HOST, default=user_input.get(CONF_HOST)): str,
vol.Required(CONF_SCAN_INTERVAL, default=user_input.get(CONF_SCAN_INTERVAL)): int,
Expand All @@ -62,15 +100,53 @@ async def async_step_user(self, user_input=None):
errors=self._errors
)

async def _test_host(self, host):
async def async_step_user_wan(self, user_input=None):
"""Handle a flow initialized by the user."""
self._errors = {}

# Uncomment the next 2 lines if only a single instance of the integration is allowed:
# if self._async_current_entries():
# return self.async_abort(reason="single_instance_allowed")

if user_input is not None:
valid = await self._test_host(host=None, serial=user_input[CONF_ID], token=user_input[CONF_TOKEN])
if valid:
user_input[CONF_MODE] = WAN
user_input[CONF_MODEL] = self._model.split(' ')[0]
user_input[CONF_TYPE] = f"{self._type} [{self._model}] Cloud"
user_input[CONF_ID] = self._serial
user_input[CONF_SCAN_INTERVAL] = max(30, user_input[CONF_SCAN_INTERVAL])
title = f"go-eCharger API v2 [{self._serial}] Cloud"
return self.async_create_entry(title=title, data=user_input)
else:
self._errors["base"] = "auth_wan"
else:
user_input = {}
user_input[CONF_ID] = "YOUR-SERIAL-HERE"
user_input[CONF_TOKEN] = "YOUR-API-KEY-HERE"
user_input[CONF_SCAN_INTERVAL] = 60

return self.async_show_form(
step_id="user_wan",
data_schema=vol.Schema({
vol.Required(CONF_ID, default=user_input.get(CONF_ID)): str,
vol.Required(CONF_TOKEN, default=user_input.get(CONF_TOKEN)): str,
vol.Required(CONF_SCAN_INTERVAL, default=user_input.get(CONF_SCAN_INTERVAL)): int,
}),
last_step=True,
errors=self._errors
)

async def _test_host(self, host, serial, token):
try:
session = async_create_clientsession(self.hass)
client = GoeChargerApiV2Bridge(host=host, web_session=session, lang=self.hass.config.language.lower())
client = GoeChargerApiV2Bridge(host=host, serial=serial, token=token, web_session=session,
lang=self.hass.config.language.lower())

ret = await client.read_system()
if ret is not None and len(ret) > 0:
await client.read_versions()
#self._oem = ret[Tag.OEM.key]
# self._oem = ret[Tag.OEM.key]
self._type = str(ret[Tag.TYP.key]).replace('_', ' ')
self._model = f"{ret[Tag.VAR.key]} kW"
self._serial = ret[Tag.SSE.key]
Expand Down Expand Up @@ -98,29 +174,60 @@ def __init__(self, config_entry):

async def async_step_init(self, user_input=None): # pylint: disable=unused-argument
"""Manage the options."""
return await self.async_step_user()
if self.options.get(CONF_MODE, None) == WAN:
return await self.async_step_user_wan()
else:
return await self.async_step_user_lan()

async def async_step_user(self, user_input=None):
async def async_step_user_lan(self, user_input=None):
"""Handle a flow initialized by the user."""
interval = 5
step_type = "user_lan"
if user_input is not None:
user_input[CONF_SCAN_INTERVAL] = max(interval, user_input[CONF_SCAN_INTERVAL])
self.options.update(user_input)
return await self._update_options()

# is this the 11kW or the 22kW Version?
if int(self.options.get(CONF_MODEL)) == 11:
return self.async_show_form(
step_id=step_type,
data_schema=vol.Schema({
vol.Required(CONF_SCAN_INTERVAL, default=self.options.get(CONF_SCAN_INTERVAL, interval)): int
})
)
else:
return self.async_show_form(
step_id=step_type,
data_schema=vol.Schema({
vol.Required(CONF_11KWLIMIT, default=self.options.get(CONF_11KWLIMIT, False)): bool,
vol.Required(CONF_SCAN_INTERVAL, default=self.options.get(CONF_SCAN_INTERVAL, interval)): int
})
)

async def async_step_user_wan(self, user_input=None):
"""Handle a flow initialized by the user."""
interval = 30
step_type = "user_wan"
if user_input is not None:
user_input[CONF_SCAN_INTERVAL] = max(5, user_input[CONF_SCAN_INTERVAL])
user_input[CONF_SCAN_INTERVAL] = max(interval, user_input[CONF_SCAN_INTERVAL])
self.options.update(user_input)
return await self._update_options()

# is this the 11kW or the 22kW Version?
if int(self.options.get(CONF_MODEL)) == 11:
return self.async_show_form(
step_id="user",
step_id=step_type,
data_schema=vol.Schema({
vol.Required(CONF_SCAN_INTERVAL, default=self.options.get(CONF_SCAN_INTERVAL, 5)): int
vol.Required(CONF_SCAN_INTERVAL, default=self.options.get(CONF_SCAN_INTERVAL, interval)): int
})
)
else:
return self.async_show_form(
step_id="user",
step_id=step_type,
data_schema=vol.Schema({
vol.Required(CONF_11KWLIMIT, default=self.options.get(CONF_11KWLIMIT, False)): bool,
vol.Required(CONF_SCAN_INTERVAL, default=self.options.get(CONF_SCAN_INTERVAL, 5)): int
vol.Required(CONF_SCAN_INTERVAL, default=self.options.get(CONF_SCAN_INTERVAL, interval)): int
})
)

Expand Down
3 changes: 3 additions & 0 deletions custom_components/goecharger_api2/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
SERVICE_SET_PV_DATA: Final = "set_pv_data"
SERVICE_STOP_CHARGING: Final = "stop_charging"
CONF_11KWLIMIT: Final = "limit_to_11kw"
WAN: Final = "wan"
LAN: Final = "lan"

@dataclass
class ExtBinarySensorEntityDescription(BinarySensorEntityDescription):
Expand Down Expand Up @@ -1646,6 +1648,7 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
native_unit_of_measurement=UnitOfPower.WATT,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.POWER,
suggested_display_precision=2,
entity_registry_enabled_default=True
),
# wh
Expand Down
2 changes: 1 addition & 1 deletion custom_components/goecharger_api2/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
"iot_class": "local_polling",
"issue_tracker": "https://github.com/marq24/ha-goecharger-api2/issues",
"requirements": [],
"version": "2024.6.3"
"version": "2024.6.4"
}
Loading

0 comments on commit ae35467

Please sign in to comment.