Skip to content

v2.4.12

Choose a tag to compare

@AndrewTapp AndrewTapp released this 12 Mar 10:57
· 72 commits to main since this release
a34a528

v2.4.12 - SolarEdge Optimizers – Changes Summary

This document summarizes changes made to the integration, including recent work on constants, status handling, aggregation, debug logging, CodeFactor-related fixes, documentation, and resource cleanup.


1. Constants and configuration

  • Centralized constants in const.py: Cache TTLs (PANELS_CACHE_TTL_ONE, PANELS_CACHE_TTL_LEGACY, LIFETIME_ENERGY_CACHE_TTL, TEMPERATURE_CACHE_TTL), light-check intervals (LIGHT_CHECK_DESIRED_INTERVAL_FRESH, LIGHT_CHECK_DESIRED_INTERVAL_STALE), API URLs, OAuth client ID, locale-dependent measurement keys (MEASUREMENT_KEYS), and API source labels (OBTAINED_FROM_ONE, OBTAINED_FROM_LEGACY).
  • Module docstring in const.py documents each constant and shared helpers.
  • Status helpers in const.py: is_status_active(status), status_display_value(raw), status_icon(display_value) for consistent handling of blank, Active, Inactive, and other statuses across the integration.

2. Status handling

  • Blank (empty) status is treated as active everywhere: aggregation, sorting, display, and icons.
  • Display: Blank → shown as "blank" with active icon; "Active" / "Inactive" in proper case; any other value shown as-is with unknown (help-circle) icon.
  • Icons: check-circle for Active/blank, alert-circle for Inactive, help-circle for unknown.
  • Child counts (Optimizer count, String count, Inverter count) count only active devices (status blank or "Active").
  • Duplicate resolution (suffixes a, b, c…): active (including blank) items are ordered first, then others.

3. Aggregation behaviour

  • Aggregated values (power, current average, voltage average, lifetime energy) at string, inverter, and site level include data from all devices (any status) that have recent measurements. Averages use the count of devices that contributed data; totals sum all contributing devices.
  • Child counts (Optimizer count per string, String count per inverter, Inverter count per site) count only active devices (status blank or "Active") and are always integers.
  • Coordinator uses optimizer_count / string_count / inverter_count for average divisors and active_optimizers / active_strings / active_inverters for child_count sensors.

4. Debug logging

  • Cache messages now include TTL where relevant:
    • SolarEdge One: Panels, lifetime energy, and temperature cache hit/miss logs include TTL (e.g. "Panels cache miss (TTL=%s)", "Using cached panels (age=%s, TTL=%s)").
    • Legacy: Panels and lifetime energy cache messages include TTL and consistent "(legacy)" prefix.
  • Coordinator: _log_update_cycle_debug logs interval_kind ("fresh" or "stale") and splits the long format string across lines so it stays within line-length limits.
  • Temperature (One API): Added cache-miss debug before fetching when the temperature cache is expired.
  • All debug calls remain guarded with _LOGGER.isEnabledFor(logging.DEBUG).

5. CodeFactor-related fixes

  • config_flow.py: Replaced except Exception: with except Exception as e: in the user step and reauth step; log messages now include the exception (e.g. _LOGGER.exception("Unexpected exception: %s", e)).
  • coordinator.py: Long debug format string in _log_update_cycle_debug split across two lines with implicit string concatenation.
  • solaredgeoptimizers.py:
    • requestSystemData: Long URL split into base + params + url.
    • requestItemHistory: Long chartData URL split into base + q + url; long dict comprehension rewritten as a multi-line dict comprehension.
  • Custom exception: SolarEdgeAPIError in exceptions.py is used for API/processing errors instead of generic Exception where appropriate.
  • Legacy client: Replaced assert with explicit ValueError where parameter validation is required; replaced generic raise Exception(...) with raise SolarEdgeAPIError(...).

6. File descriptor and resource cleanup

  • config_flow.py – validate_input: API client is closed in a finally block after credential validation so temporary sessions are released.
  • config_flow.py – async_remove_entry: When the integration is removed, the coordinator is popped from hass.data and the API client is closed (if present) before calling remove_entities_and_devices_for_entry, so file descriptors are released even if unload did not run or did not close the API.
  • init.py: On setup failure (before the coordinator is stored), the temporary API instance is closed in a finally block.
  • api_dual.py: close() closes both One and Legacy clients with explicit logging; exceptions from one client do not prevent closing the other.
  • Legacy client: close() docstring clarifies that Session.close() releases file descriptors and thread-local session is cleared.

7. Documentation updates

  • README.md: Temperature refresh described as using the temperature cache expiry (30 minutes, TEMPERATURE_CACHE_TTL). Inactive devices section updated: aggregation uses all devices (any status) with recent data; child counts use only active devices.
  • info.md: Inactive devices / aggregation paragraph updated to match (aggregation = all devices; child counts = active only).
  • docs/Wiki-Home.md:
    • Aggregation behaviour (Section 9) rewritten: aggregation values from all devices with recent data; child counts from active only; note on inactive devices contributing to aggregates when they have data.
    • Temperature references updated from "15 min" to "30 min" / TEMPERATURE_CACHE_TTL (data flow note, Section 7 table, Section 12 caching).
    • Removal cleanup: async_remove_entry now documented as closing the API client (releasing file descriptors) when the coordinator is still in hass.data, then calling the shared helper. Config flow table row updated similarly.
  • coordinator.py module docstring: Polling interval described as coordinator tick every 5 minutes; minimum interval between full refreshes set to 5 minutes (LIGHT_CHECK_MIN_INTERVAL). Data aggregation summary updated: power/current/voltage/lifetime from all devices with recent data; child counts from active only.

8. Timing and cache constants (reference)

Constant Value Purpose
UPDATE_DELAY 5 min Coordinator tick interval
LIGHT_CHECK_MIN_INTERVAL 5 min Min time between a light-check-triggered full refresh and the next
LIGHT_CHECK_DESIRED_INTERVAL_FRESH 5 min Desired light-check interval when data is fresh
LIGHT_CHECK_DESIRED_INTERVAL_STALE 30 min Desired light-check interval when data is stale or missing
PANELS_CACHE_TTL_ONE 2 h Layout cache (SolarEdge One)
PANELS_CACHE_TTL_LEGACY 1 h Layout cache (legacy API)
LIFETIME_ENERGY_CACHE_TTL 1 h Lifetime energy cache
TEMPERATURE_CACHE_TTL 30 min Optimizer temperatures cache (One API only)

9. File structure (relevant files)

  • const.py – Constants, status helpers, resolve_duplicate_indices, display-name parsers.
  • exceptions.pySolarEdgeAPIError.
  • config_flow.py – Validation (dual API), API close after validation and on entry removal.
  • __init__.py – Setup with API cleanup on failure; remove_entities_and_devices_for_entry.
  • coordinator.py – Adaptive polling, aggregation (all statuses for values, active only for child counts), device registration.
  • solaredgeoptimizers.py – Legacy API; SolarEdgeAPIError; cache TTLs from const.
  • solaredge_one_api.py – One API; cache TTLs and status check from const.
  • api_dual.py – Dual API; OBTAINED_FROM_* from const; robust close().

This summary reflects the state of the integration after the documented changes. For installation and user-facing features, see the main README and Wiki-Home.

What's Changed

New Contributors

Full Changelog: 2.4.11...2.4.12