From 834722ba66881c425b54fa8fc3e78b9d4001410d Mon Sep 17 00:00:00 2001 From: Keith Baker Date: Fri, 19 Apr 2024 09:59:29 -0400 Subject: [PATCH 1/3] add reconfgiuration support --- custom_components/sunpower/config_flow.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/custom_components/sunpower/config_flow.py b/custom_components/sunpower/config_flow.py index 1540712..816be33 100644 --- a/custom_components/sunpower/config_flow.py +++ b/custom_components/sunpower/config_flow.py @@ -92,6 +92,25 @@ async def async_step_import(self, user_input): return await self.async_step_user(user_input) + async def async_step_reconfigure(self, user_input): + """Add reconfigure step to allow to reconfigure a config entry.""" + errors = {} + try: + info = await validate_input(self.hass, user_input) + await self.async_set_unique_id(user_input[SUNPOWER_HOST]) + return self.async_create_entry(title=info["title"], data=user_input) + except CannotConnect: + errors["base"] = "cannot_connect" + except Exception: # pylint: disable=broad-except + _LOGGER.exception("Unexpected exception") + errors["base"] = "unknown" + + return self.async_show_form( + step_id="reconfigure", + data_schema=DATA_SCHEMA, + errors=errors, + ) + class CannotConnect(exceptions.HomeAssistantError): """Error to indicate we cannot connect.""" From 764c4eb83e30d66213bbcddd7f19bd0bc4ad6b31 Mon Sep 17 00:00:00 2001 From: Keith Baker Date: Fri, 19 Apr 2024 10:54:46 -0400 Subject: [PATCH 2/3] reuse existing config flows? --- custom_components/sunpower/config_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/sunpower/config_flow.py b/custom_components/sunpower/config_flow.py index 816be33..2a1e565 100644 --- a/custom_components/sunpower/config_flow.py +++ b/custom_components/sunpower/config_flow.py @@ -106,7 +106,7 @@ async def async_step_reconfigure(self, user_input): errors["base"] = "unknown" return self.async_show_form( - step_id="reconfigure", + step_id="user", data_schema=DATA_SCHEMA, errors=errors, ) From d7df1f23ac1c024d9ac4559a9c53c53e0c401f19 Mon Sep 17 00:00:00 2001 From: Keith Baker Date: Mon, 20 May 2024 14:07:10 -0400 Subject: [PATCH 3/3] Enable ESS Autodetection Enable reconfigure of polling times Add Virtual production meter Update README and strings --- README.md | 38 +++++---- custom_components/sunpower/__init__.py | 54 ++++++++---- custom_components/sunpower/binary_sensor.py | 12 +-- custom_components/sunpower/config_flow.py | 85 +++++++++++++------ custom_components/sunpower/const.py | 4 +- custom_components/sunpower/manifest.json | 2 +- custom_components/sunpower/sensor.py | 12 +-- custom_components/sunpower/strings.json | 24 ++++-- .../sunpower/translations/en.json | 30 ++++--- hacs.json | 2 +- 10 files changed, 173 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 85f4ea9..b1042c7 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,6 @@ Notes: * This network interface has a DHCP server running on it. If you plug it straight into your home network it will make probably other systems stop working as they will DHCP to the wrong address. - * If you have a battery you can enable collecting that data with 'use-ess' - * Be careful changing the refresh intervals for ESS or PVS. The PVS takes a very long time to return data, I've found 120s is really the lowest safe rate. ESS I'm less sure about though I've seen it as low as 10s in other places (I have seen home assistant grind to a hault with too many state change entries) @@ -75,21 +73,14 @@ When selected during installation, entities added for each device will have the descriptor added onto the front of their name. This adds 'sunpower' 'sunvault' and 'pvs' to entities making them even more distinct but *very* long. -## Enable virtual production meter +## Energy storage system -This adds an additional virtual device which sums up the current production and lifetime production -for all microinverters and then averages the volts and frequency across all readings. -This is useful for people who don't have a production meter installed but the data is not as -accurate. +This will now auto-detect and the option to enable/disable has been +removed (This addition thanks to [@CanisUrsa](https://github.com/CanisUrsa)) -![Virtual Meter Output](virtual_meter.png) - -## Use energy storage system - -If you have a SunVault system along side your solar you can select this option to -include data from the energy storage system. (This addition thanks to [@CanisUrsa](https://github.com/CanisUrsa)) +## Options (available from 'configure' once integration is setup) -## Solar data update interval (seconds) +### Solar data update interval (seconds) This sets how fast the integration will try to get updated solar info from the PVS. The lowest "safe" rate looks like about 120 seconds. I am concerned some PVSs may fail @@ -97,7 +88,7 @@ to work properly over time and I'm guessing it might be request or error logging their memory. I am running with 300 seconds right now as I went through a heck of a time with a PVS that began to fail pushing to Sunpower's cloud. -## Energy storage update interval (seconds) +### Energy storage update interval (seconds) Should evenly divide into Solar data update interval or be an even multiple of it (this is due to the currently silly way polling is handled through one timer). The original author of the ESS addon @@ -173,6 +164,23 @@ You should see one of these for every panel you have, they are listed by serial | `MPPT Amps` | Amps | [MPPT][mppt] optimized panel amperage. This is the actual amperage the panel is driven by inverter to develop currently. | | `MPPT KW` | KW | [MPPT][mppt] optimized panel output in kw. This is the actual power the panel developing currently. | +## Virtual production meter + +![Virtual Meter Output](virtual_meter.png) +This data is a sum of all inverter data to make some things like the energy dashboard easier to +use for people who might be missing the production CT. +Note: this data is less accurate than a production CT. + +| Entity | Units | Description | +| ---------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `State` | String | If any inverter has an error this will be an error, in low light expect errors | +| `Frequency` | Hz | Average Observed AC Frequency across all inverters. | +| `Lifetime Power` | kwh | Lifetime produced across all inverters | +| `Power` | kw | Current power sum from all inverters | +| `Voltage` | Volts | Average voltage across all inverters | +| `Temperature` | F | Average temperature across all inverters | +| `Amps` | Amps | Total amperage produced by all inverters | + ### HUB+ This is the data from the HUB+. diff --git a/custom_components/sunpower/__init__.py b/custom_components/sunpower/__init__.py index 9397746..b19bfd4 100644 --- a/custom_components/sunpower/__init__.py +++ b/custom_components/sunpower/__init__.py @@ -28,13 +28,11 @@ PVS_DEVICE_TYPE, SETUP_TIMEOUT_MIN, SUNPOWER_COORDINATOR, - SUNPOWER_ESS, SUNPOWER_HOST, SUNPOWER_OBJECT, SUNPOWER_UPDATE_INTERVAL, SUNVAULT_DEVICE_TYPE, SUNVAULT_UPDATE_INTERVAL, - VIRTUAL_PRODUCTION, ) from .sunpower import ( ConnectionException, @@ -98,14 +96,13 @@ def create_vmeter(data): return data -def convert_sunpower_data(sunpower_data, virtual_production): +def convert_sunpower_data(sunpower_data): """Convert PVS data into indexable format data[device_type][serial]""" data = {} for device in sunpower_data["devices"]: data.setdefault(device["DEVICE_TYPE"], {})[device["SERIAL"]] = device - if virtual_production: - create_vmeter(data) + create_vmeter(data) return data @@ -263,10 +260,8 @@ def convert_ess_data(ess_data, data): def sunpower_fetch( sunpower_monitor, - use_ess, sunpower_update_invertal, sunvault_update_invertal, - virtual_production, ): """Basic data fetch routine to get and reformat sunpower data to a dict of device type and serial #""" @@ -277,6 +272,8 @@ def sunpower_fetch( sunpower_data = PREVIOUS_PVS_SAMPLE ess_data = PREVIOUS_ESS_SAMPLE + use_ess = False + data = None try: if (time.time() - PREVIOUS_PVS_SAMPLE_TIME) >= (sunpower_update_invertal - 1): @@ -284,17 +281,23 @@ def sunpower_fetch( sunpower_data = sunpower_monitor.device_list() PREVIOUS_PVS_SAMPLE = sunpower_data _LOGGER.debug("got PVS data %s", sunpower_data) + except (ParseException, ConnectionException) as error: + raise UpdateFailed from error + + data = convert_sunpower_data(sunpower_data) + if ESS_DEVICE_TYPE in data: # Look for an ESS in PVS data + use_ess = True + try: if use_ess and (time.time() - PREVIOUS_ESS_SAMPLE_TIME) >= (sunvault_update_invertal - 1): PREVIOUS_ESS_SAMPLE_TIME = time.time() ess_data = sunpower_monitor.energy_storage_system_status() - PREVIOUS_ESS_SAMPLE = sunpower_data + PREVIOUS_ESS_SAMPLE = ess_data _LOGGER.debug("got ESS data %s", ess_data) - except ConnectionException as error: + except (ParseException, ConnectionException) as error: raise UpdateFailed from error try: - data = convert_sunpower_data(sunpower_data, virtual_production) if use_ess: convert_ess_data( ess_data, @@ -325,17 +328,16 @@ async def async_setup(hass: HomeAssistant, config: dict): async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): """Set up sunpower from a config entry.""" + _LOGGER.debug(f"Setting up {entry.entry_id}, Options {entry.options}, Config {entry.data}") entry_id = entry.entry_id hass.data[DOMAIN].setdefault(entry_id, {}) sunpower_monitor = SunPowerMonitor(entry.data[SUNPOWER_HOST]) - use_ess = entry.data.get(SUNPOWER_ESS, False) - virtual_production = entry.data.get(VIRTUAL_PRODUCTION, True) - sunpower_update_invertal = entry.data.get( + sunpower_update_invertal = entry.options.get( SUNPOWER_UPDATE_INTERVAL, DEFAULT_SUNPOWER_UPDATE_INTERVAL, ) - sunvault_update_invertal = entry.data.get( + sunvault_update_invertal = entry.options.get( SUNVAULT_UPDATE_INTERVAL, DEFAULT_SUNVAULT_UPDATE_INTERVAL, ) @@ -346,20 +348,23 @@ async def async_update_data(): return await hass.async_add_executor_job( sunpower_fetch, sunpower_monitor, - use_ess, sunpower_update_invertal, sunvault_update_invertal, - virtual_production, ) # This could be better, taking the shortest time interval as the coordinator update is fine # if the long interval is an even multiple of the short or *much* smaller coordinator_interval = ( sunvault_update_invertal - if sunvault_update_invertal < sunpower_update_invertal and use_ess + if sunvault_update_invertal < sunpower_update_invertal else sunpower_update_invertal ) + _LOGGER.debug( + f"Intervals: Sunpower {sunpower_update_invertal} Sunvault {sunvault_update_invertal}", + ) + _LOGGER.debug(f"Coordinator update interval set to {coordinator_interval}") + coordinator = DataUpdateCoordinator( hass, _LOGGER, @@ -387,9 +392,24 @@ async def async_update_data(): hass.config_entries.async_forward_entry_setup(entry, component), ) + entry.async_on_unload(entry.add_update_listener(update_listener)) + return True +async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Update listener.""" + _LOGGER.debug( + "Updating: %s with data=%s and options=%s", + entry.entry_id, + entry.data, + entry.options, + ) + _LOGGER.debug("Update listener called, reloading") + await hass.config_entries.async_reload(entry.entry_id) + _LOGGER.debug("Update listener done reloading") + + async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unload a config entry.""" unload_ok = all( diff --git a/custom_components/sunpower/binary_sensor.py b/custom_components/sunpower/binary_sensor.py index 06b7f25..1f11b49 100644 --- a/custom_components/sunpower/binary_sensor.py +++ b/custom_components/sunpower/binary_sensor.py @@ -6,11 +6,11 @@ from .const import ( DOMAIN, + ESS_DEVICE_TYPE, PVS_DEVICE_TYPE, SUNPOWER_BINARY_SENSORS, SUNPOWER_COORDINATOR, SUNPOWER_DESCRIPTIVE_NAMES, - SUNPOWER_ESS, SUNPOWER_PRODUCT_NAMES, SUNVAULT_BINARY_SENSORS, ) @@ -32,13 +32,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities): if SUNPOWER_PRODUCT_NAMES in config_entry.data: do_product_names = config_entry.data[SUNPOWER_PRODUCT_NAMES] - do_ess = False - if SUNPOWER_ESS in config_entry.data: - do_ess = config_entry.data[SUNPOWER_ESS] - coordinator = sunpower_state[SUNPOWER_COORDINATOR] sunpower_data = coordinator.data + do_ess = False + if ESS_DEVICE_TYPE in sunpower_data: + do_ess = True + else: + _LOGGER.debug("Found No ESS Data") + if PVS_DEVICE_TYPE not in sunpower_data: _LOGGER.error("Cannot find PVS Entry") else: diff --git a/custom_components/sunpower/config_flow.py b/custom_components/sunpower/config_flow.py index 2a1e565..ea08c0b 100644 --- a/custom_components/sunpower/config_flow.py +++ b/custom_components/sunpower/config_flow.py @@ -14,13 +14,13 @@ DEFAULT_SUNPOWER_UPDATE_INTERVAL, DEFAULT_SUNVAULT_UPDATE_INTERVAL, DOMAIN, + MIN_SUNPOWER_UPDATE_INTERVAL, + MIN_SUNVAULT_UPDATE_INTERVAL, SUNPOWER_DESCRIPTIVE_NAMES, - SUNPOWER_ESS, SUNPOWER_HOST, SUNPOWER_PRODUCT_NAMES, SUNPOWER_UPDATE_INTERVAL, SUNVAULT_UPDATE_INTERVAL, - VIRTUAL_PRODUCTION, ) from .sunpower import ( ConnectionException, @@ -32,12 +32,8 @@ DATA_SCHEMA = vol.Schema( { vol.Required(CONF_HOST): str, - vol.Required(SUNPOWER_DESCRIPTIVE_NAMES, default=False): bool, + vol.Required(SUNPOWER_DESCRIPTIVE_NAMES, default=True): bool, vol.Required(SUNPOWER_PRODUCT_NAMES, default=False): bool, - vol.Required(SUNPOWER_ESS, default=False): bool, - vol.Required(VIRTUAL_PRODUCTION, default=True): bool, - vol.Required(SUNPOWER_UPDATE_INTERVAL, default=DEFAULT_SUNPOWER_UPDATE_INTERVAL): int, - vol.Required(SUNVAULT_UPDATE_INTERVAL, default=DEFAULT_SUNVAULT_UPDATE_INTERVAL): int, }, ) @@ -48,11 +44,11 @@ async def validate_input(hass: core.HomeAssistant, data): Data has the keys from DATA_SCHEMA with values provided by the user. """ - spm = SunPowerMonitor(data["host"]) - name = "PVS {}".format(data["host"]) + spm = SunPowerMonitor(data[SUNPOWER_HOST]) + name = "PVS {}".format(data[SUNPOWER_HOST]) try: response = await hass.async_add_executor_job(spm.network_status) - _LOGGER.debug("Got from %s %s", data["host"], response) + _LOGGER.debug("Got from %s %s", data[SUNPOWER_HOST], response) except ConnectionException as error: raise CannotConnect from error @@ -65,9 +61,18 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL - async def async_step_user(self, user_input=None): + @staticmethod + @core.callback + def async_get_options_flow( + config_entry: config_entries.ConfigEntry, + ) -> config_entries.OptionsFlow: + """Create the options flow.""" + return OptionsFlowHandler(config_entry) + + async def async_step_user(self, user_input: dict[str, any] | None = None): """Handle the initial step.""" errors = {} + _LOGGER.debug(f"User Setup input {user_input}") if user_input is not None: try: info = await validate_input(self.hass, user_input) @@ -85,29 +90,55 @@ async def async_step_user(self, user_input=None): errors=errors, ) - async def async_step_import(self, user_input): + async def async_step_import(self, user_input: dict[str, any] | None = None): """Handle import.""" - await self.async_set_unique_id(user_input["host"]) + await self.async_set_unique_id(user_input[SUNPOWER_HOST]) self._abort_if_unique_id_configured() - return await self.async_step_user(user_input) - async def async_step_reconfigure(self, user_input): - """Add reconfigure step to allow to reconfigure a config entry.""" + +class OptionsFlowHandler(config_entries.OptionsFlow): + def __init__(self, config_entry: config_entries.ConfigEntry) -> None: + """Initialize options flow.""" + self.config_entry = config_entry + + async def async_step_init( + self, + user_input: dict[str, any] | None = None, + ) -> config_entries.FlowResult: + """Manage the options.""" + _LOGGER.debug(f"Options input {user_input} {self.config_entry}") + options = dict(self.config_entry.options) + errors = {} - try: - info = await validate_input(self.hass, user_input) - await self.async_set_unique_id(user_input[SUNPOWER_HOST]) - return self.async_create_entry(title=info["title"], data=user_input) - except CannotConnect: - errors["base"] = "cannot_connect" - except Exception: # pylint: disable=broad-except - _LOGGER.exception("Unexpected exception") - errors["base"] = "unknown" + + if user_input is not None: + if user_input[SUNPOWER_UPDATE_INTERVAL] < MIN_SUNPOWER_UPDATE_INTERVAL: + errors[SUNPOWER_UPDATE_INTERVAL] = "MIN_INTERVAL" + if user_input[SUNVAULT_UPDATE_INTERVAL] < MIN_SUNVAULT_UPDATE_INTERVAL: + errors[SUNPOWER_UPDATE_INTERVAL] = "MIN_INTERVAL" + if len(errors) == 0: + options[SUNPOWER_UPDATE_INTERVAL] = user_input[SUNPOWER_UPDATE_INTERVAL] + options[SUNVAULT_UPDATE_INTERVAL] = user_input[SUNVAULT_UPDATE_INTERVAL] + return self.async_create_entry(title="", data=user_input) + + current_sunpower_interval = options.get( + SUNPOWER_UPDATE_INTERVAL, + DEFAULT_SUNPOWER_UPDATE_INTERVAL, + ) + current_sunvault_interval = options.get( + SUNVAULT_UPDATE_INTERVAL, + DEFAULT_SUNVAULT_UPDATE_INTERVAL, + ) return self.async_show_form( - step_id="user", - data_schema=DATA_SCHEMA, + step_id="init", + data_schema=vol.Schema( + { + vol.Required(SUNPOWER_UPDATE_INTERVAL, default=current_sunpower_interval): int, + vol.Required(SUNVAULT_UPDATE_INTERVAL, default=current_sunvault_interval): int, + }, + ), errors=errors, ) diff --git a/custom_components/sunpower/const.py b/custom_components/sunpower/const.py index be64d35..0f82ef1 100644 --- a/custom_components/sunpower/const.py +++ b/custom_components/sunpower/const.py @@ -23,12 +23,13 @@ SUNPOWER_DESCRIPTIVE_NAMES = "use_descriptive_names" SUNPOWER_PRODUCT_NAMES = "use_product_names" -SUNPOWER_ESS = "use_ess" SUNPOWER_OBJECT = "sunpower" SUNPOWER_HOST = "host" SUNPOWER_COORDINATOR = "coordinator" DEFAULT_SUNPOWER_UPDATE_INTERVAL = 120 DEFAULT_SUNVAULT_UPDATE_INTERVAL = 60 +MIN_SUNPOWER_UPDATE_INTERVAL = 60 +MIN_SUNVAULT_UPDATE_INTERVAL = 20 SUNPOWER_UPDATE_INTERVAL = "PVS_UPDATE_INTERVAL" SUNVAULT_UPDATE_INTERVAL = "ESS_UPDATE_INTERVAL" SETUP_TIMEOUT_MIN = 5 @@ -40,7 +41,6 @@ ESS_DEVICE_TYPE = "Energy Storage System" HUBPLUS_DEVICE_TYPE = "HUB+" SUNVAULT_DEVICE_TYPE = "SunVault" -VIRTUAL_PRODUCTION = "VIRTUAL_PRODUCTION" WORKING_STATE = "working" diff --git a/custom_components/sunpower/manifest.json b/custom_components/sunpower/manifest.json index ad7282e..72bc5da 100644 --- a/custom_components/sunpower/manifest.json +++ b/custom_components/sunpower/manifest.json @@ -10,6 +10,6 @@ "issue_tracker": "https://github.com/krbaker/hass-sunpower/issues", "requirements": ["requests"], "ssdp": [], - "version": "2024.4.2", + "version": "2024.5.1", "zeroconf": [] } diff --git a/custom_components/sunpower/sensor.py b/custom_components/sunpower/sensor.py index d59d20f..a7308ec 100644 --- a/custom_components/sunpower/sensor.py +++ b/custom_components/sunpower/sensor.py @@ -9,10 +9,10 @@ from .const import ( DOMAIN, + ESS_DEVICE_TYPE, PVS_DEVICE_TYPE, SUNPOWER_COORDINATOR, SUNPOWER_DESCRIPTIVE_NAMES, - SUNPOWER_ESS, SUNPOWER_PRODUCT_NAMES, SUNPOWER_SENSORS, SUNVAULT_SENSORS, @@ -35,13 +35,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities): if SUNPOWER_PRODUCT_NAMES in config_entry.data: do_product_names = config_entry.data[SUNPOWER_PRODUCT_NAMES] - do_ess = False - if SUNPOWER_ESS in config_entry.data: - do_ess = config_entry.data[SUNPOWER_ESS] - coordinator = sunpower_state[SUNPOWER_COORDINATOR] sunpower_data = coordinator.data + do_ess = False + if ESS_DEVICE_TYPE in sunpower_data: + do_ess = True + else: + _LOGGER.debug("Found No ESS Data") + if PVS_DEVICE_TYPE not in sunpower_data: _LOGGER.error("Cannot find PVS Entry") else: diff --git a/custom_components/sunpower/strings.json b/custom_components/sunpower/strings.json index 570bb06..c57b419 100644 --- a/custom_components/sunpower/strings.json +++ b/custom_components/sunpower/strings.json @@ -5,14 +5,10 @@ "user": { "data": { "host": "Host", - "use_descriptive_names": "Use descriptive entity names", - "use_product_names": "Use products in entity names", - "VIRTUAL_PRODUCTION": "Enable virtual production meter", - "use_ess": "Use energy storage system", - "PVS_UPDATE_INTERVAL": "Solar data update interval", - "ESS_UPDATE_INTERCAL": "Energy storage update interval" + "use_descriptive_names": "Use descriptive entity names (recommended)", + "use_product_names": "Use products in entity names (not recommended)" }, - "description": "If 'Use descriptive entity names' is selected, device names\nwill be prepended on all entity names." + "description": "Hostname or IP of PVS (usually 172.27.153.1)" } }, "error": { @@ -22,5 +18,19 @@ "abort": { "already_configured": "Already Configured" } + }, + "options": { + "step": { + "init": { + "data": { + "PVS_UPDATE_INTERVAL": "Solar data update interval (not less than 60)", + "ESS_UPDATE_INTERVAL": "Energy storage update interval (not less than 20)" + }, + "description": "Update intervals to change the polling rate, reminder: the PVS is slow" + } + }, + "error": { + "MIN_INTERVAL": "Interval too small" + } } } diff --git a/custom_components/sunpower/translations/en.json b/custom_components/sunpower/translations/en.json index 6877bce..0eb6620 100644 --- a/custom_components/sunpower/translations/en.json +++ b/custom_components/sunpower/translations/en.json @@ -9,17 +9,27 @@ }, "step": { "user": { - "data": { - "host": "Host", - "use_descriptive_names": "Use descriptive entity names", - "use_product_names": "Use products in entity names", - "VIRTUAL_PRODUCTION": "Enable virtual production meter", - "use_ess": "Use energy storage system", - "PVS_UPDATE_INTERVAL": "Solar data update interval", - "ESS_UPDATE_INTERCAL": "Energy storage update interval" - }, - "description": "If 'Use descriptive entity names' is selected, device names\nwill be prepended on all entity names." + "data": { + "host": "Host", + "use_descriptive_names": "Use descriptive entity names (recommended)", + "use_product_names": "Use products in entity names (not recommended)" + }, + "description": "Hostname or IP of PVS (usually 172.27.153.1)" + } + } + }, + "options":{ + "step": { + "init": { + "data": { + "PVS_UPDATE_INTERVAL": "Solar data update interval (not less than 60)", + "ESS_UPDATE_INTERVAL": "Energy storage update interval (not less than 20)" + }, + "description": "Update intervals to change the polling rate, note: the PVS is slow" } + }, + "error": { + "MIN_INTERVAL": "Interval too small" } }, "title": "SunPower" diff --git a/hacs.json b/hacs.json index dab78de..3ed84fb 100644 --- a/hacs.json +++ b/hacs.json @@ -1,7 +1,7 @@ { "name": "SunPower", "domains": ["binary_sensor", "sensor"], - "homeassistant": "2021.9.0", + "homeassistant": "2024.1.0", "iot_class": ["Local Poll"], "render_readme": true }