Skip to content

Conversation

@phoenix-blue
Copy link

Proposed change

Improve the Zeversolar integration so that night-time/offline states no longer raise errors or notifications. Adds a dedicated status sensor, preserves the last known energy value, suppresses retry spam from the underlying library, and lets the configuration flow finish successfully even when the inverter is offline.

Type of change

  • Bugfix (non-breaking change which fixes an issue)
  • Dependency upgrade
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

  • This PR fixes or closes issue: n/a
  • This PR is related to issue: n/a
  • Link to documentation pull request: n/a
  • Link to developer documentation pull request: n/a
  • Link to frontend pull request: n/a

Checklist

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.
  • Any generated code has been carefully reviewed for correctness and compliance with project standards.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.

To help with the load of incoming pull requests:

Copilot AI review requested due to automatic review settings October 27, 2025 22:17
Copy link

@home-assistant home-assistant bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @phoenix-blue

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

@home-assistant
Copy link

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@home-assistant
Copy link

Hey there @kvanzuijlen, mind taking a look at this pull request as it has been labeled with an integration (zeversolar) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of zeversolar can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign zeversolar Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component) on the pull request.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves the Zeversolar integration's handling of offline states (typically occurring at night when solar inverters are inactive). The changes prevent error notifications and allow configuration to succeed even when the inverter is offline by treating offline states as normal operating conditions rather than errors.

Key changes:

  • Modified the coordinator to return None instead of raising exceptions when offline, treating disconnection as expected behavior
  • Added a dedicated status sensor to explicitly show online/offline state
  • Implemented preservation of the last known energy value when the inverter goes offline

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
homeassistant/components/zeversolar/__init__.py Commented out initial refresh to allow setup when inverter is offline
homeassistant/components/zeversolar/config_flow.py Removed validation checks to permit configuration during offline periods
homeassistant/components/zeversolar/coordinator.py Changed return type to allow None, added offline handling logic, and suppressed retry library logs
homeassistant/components/zeversolar/entity.py Added fallback device info creation using host when serial number unavailable
homeassistant/components/zeversolar/icons.json Updated icons for sensors and added state-based icons for status sensor
homeassistant/components/zeversolar/sensor.py Added status sensor, modified sensors to handle None data, implemented last-known-value preservation, and overrode availability
homeassistant/components/zeversolar/strings.json Added translations for new status sensor and power sensor

entity_category=EntityCategory.DIAGNOSTIC,
device_class=SensorDeviceClass.POWER,
value_fn=lambda data: data.pac,
value_fn=lambda data: data.pac if data else 0,
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lambda should check for None explicitly rather than using truthiness. An empty ZeverSolarData object (if it exists) would evaluate to falsy but is semantically different from None. Use data is not None for clarity and correctness.

Copilot uses AI. Check for mistakes.
state_class=SensorStateClass.TOTAL_INCREASING,
device_class=SensorDeviceClass.ENERGY,
value_fn=lambda data: data.energy_today,
value_fn=lambda data: data.energy_today if data else None,
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lambda should check for None explicitly rather than using truthiness. Use data is not None to avoid potential issues if an empty ZeverSolarData object could exist.

Copilot uses AI. Check for mistakes.
key="status",
translation_key="status",
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda data: "online" if data else "offline",
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lambda should check for None explicitly rather than using truthiness. Use data is not None for clarity and to avoid edge cases with empty objects.

Suggested change
value_fn=lambda data: "online" if data else "offline",
value_fn=lambda data: "online" if data is not None else "offline",

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +20
# Suppress noisy retry logs from zeversolar library during offline periods
logging.getLogger("retry.api").setLevel(logging.ERROR)
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting the log level globally for 'retry.api' at module import time affects all integrations using this logger. Consider setting this within the coordinator's __init__ method or using a more targeted approach to avoid side effects on other code.

Copilot uses AI. Check for mistakes.

# Skip initial refresh to allow setup even when inverter is offline
# The coordinator will handle offline status gracefully during normal updates
# await coordinator.async_config_entry_first_refresh()
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented-out code should be removed. If skipping the initial refresh is intentional, remove the line entirely rather than commenting it out.

Suggested change
# await coordinator.async_config_entry_first_refresh()

Copilot uses AI. Check for mistakes.
)
# Use current data or last known data for device info
device_data = coordinator.data or coordinator.last_known_data
host = coordinator.config_entry.data.get("host", "unknown")
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the CONF_HOST constant from homeassistant.const instead of the string literal 'host' for consistency with the rest of the codebase.

Copilot uses AI. Check for mistakes.
)
# Skip validation - allow configuration even when inverter is offline
# This enables setup during night time when inverter is naturally offline
_LOGGER.info("Configuring Zeversolar integration for host: %s (no validation)", user_input[CONF_HOST])
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using info level for standard configuration flow messages is unnecessarily verbose. Consider using debug level instead, as this is normal operation and not something that needs to appear in standard logs.

Suggested change
_LOGGER.info("Configuring Zeversolar integration for host: %s (no validation)", user_input[CONF_HOST])
_LOGGER.debug("Configuring Zeversolar integration for host: %s (no validation)", user_input[CONF_HOST])

Copilot uses AI. Check for mistakes.
Comment on lines +120 to +122
# Always show all sensors as available to prevent "unavailable" status
# The status sensor will show online/offline state instead
return True
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overriding available to always return True breaks Home Assistant's entity availability semantics. Entities should be marked unavailable when they cannot provide meaningful data. Consider removing this override and using the coordinator's availability instead, or at minimum exclude the status sensor from this override since it can always provide meaningful state.

Suggested change
# Always show all sensors as available to prevent "unavailable" status
# The status sensor will show online/offline state instead
return True
# The status sensor can always provide a meaningful state ("online"/"offline")
if self.entity_description.key == "status":
return True
return self.coordinator.available

Copilot uses AI. Check for mistakes.
@phoenix-blue phoenix-blue marked this pull request as ready for review October 27, 2025 23:41
Copy link
Contributor

@epenet epenet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely NOT OK to be able to setup an integration when the device is offline.
Config flow changes definitely need to come out.

For the rest, it feels like a hack that goes at least partially against Home Assistant best practises.
Maybe "Energy today" makes sense to display last know data, but it doesn't make any sense for a "Power" sensor to show last data.

Comment on lines -40 to -44
errors = {}

client = zeversolar.ZeverSolarClient(host=user_input[CONF_HOST])
try:
data = await self.hass.async_add_executor_job(client.get_data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a really bad idea.

You should definitly make sure that the client is available before attempting to connect.

_LOGGER = logging.getLogger(__name__)

# Suppress noisy retry logs from zeversolar library during offline periods
logging.getLogger("retry.api").setLevel(logging.ERROR)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change should be changed in the library - it shouldn't be done in Home Assistant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like changes to strings.json are unrelated to the other changes in the PR.
Please create a separate PR for the string changes.

@home-assistant home-assistant bot marked this pull request as draft October 28, 2025 14:32
@phoenix-blue
Copy link
Author

The main intention of this change is to avoid unnecessary log pollution in Home Assistant when the inverter is offline, which currently happens without this adjustment.
If this approach is not aligned with Home Assistant best practices, we’re fine with reverting it.

@phoenix-blue phoenix-blue deleted the zeversolar-offline-improvements-sparse branch October 28, 2025 16:46
@github-actions github-actions bot locked and limited conversation to collaborators Oct 29, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants