Skip to content

Localapi feature support#128

Open
jtooley307 wants to merge 23 commits intokrbaker:mainfrom
jtooley307:localapi-migration
Open

Localapi feature support#128
jtooley307 wants to merge 23 commits intokrbaker:mainfrom
jtooley307:localapi-migration

Conversation

@jtooley307
Copy link

feat: add LocalAPI support with automatic fallback

Adds support for LocalAPI (Varserver FCGI) on PVS firmware build >= 61840 while maintaining full backwards compatibility with legacy CGI endpoints.

Changes

  • Automatic API detection - queries firmware version and selects appropriate API
  • LocalAPI for newer firmware - uses authenticated /vars endpoint with session management and caching
  • Direct LAN access - works via standard LAN IP, no proxy or special network setup required
  • Legacy CGI fallback - older firmware continues using existing endpoints
  • Auto-fetch credentials - serial suffix automatically retrieved from PVS (no manual configuration)
  • Performance improvements - caching mechanism stores variable paths for faster queries

Testing

Tested with firmware build 61845:

  • Auto-detection working
  • Authentication successful
  • Device discovery (20 devices: 1 PVS, 2 meters, 17 inverters)
  • Data quality verified

Files Modified

  • sunpower.py - LocalAPI implementation (~460 lines added)
  • init.py - Updated to pass None for serial suffix (auto-fetch from PVS)
  • config_flow.py - Improved logging and error handling for setup diagnostics
  • README.md - Updated documentation (LocalAPI details, polling guidance, troubleshooting)

BREAKING CHANGE: None - full backwards compatibility maintained

- Implement session-based authentication with auto-detected serial suffix
- Add firmware version validation (requires build >= 61840)
- Replace device list queries with variable match queries
- Add data translation layer for backward compatibility
- Fix blocking I/O calls for async compliance
- Add missing sensors: leg power, grid/home energy
- Maintain 100% backward compatibility with existing installations

Tested on PVS6 firmware 2025.09.04.61845 with 20 devices (1 PVS, 2 meters, 17 inverters).
All legacy sensors maintained, new sensors added, no breaking changes.
…, add input validation, improve error messages, implement session refresh
…fallback

- Implement automatic firmware detection and API selection
- Add LocalAPI authentication and session management
- Maintain full backwards compatibility with legacy CGI endpoints
- Add host validation and improved error handling
- Implement caching mechanism for improved performance
- Serial suffix is now auto-fetched directly in sunpower.py
- No need for constant since it's not passed through config
- Remove host validation (regex) - not in upstream
- Remove firmware detection logging - happens automatically in SunPowerMonitor
- Remove InvalidHost exception - not needed
- Match upstream implementation exactly
- Remove references to removed validation features
- Update debugging section for automatic API detection
- Clarify that API selection is transparent
- Remove reference to test file not in PR
- Link to pypvs LocalAPI documentation
- Reference pypvs project for technical details
- Explain that cache stores variable paths, not values
- Note that cache resets on Home Assistant restart
- Emphasize data is always fresh
- Explain API detection occurs at HA startup/reload
- Note that remote firmware upgrades require HA restart to detect
- Clarify automatic LocalAPI switch after restart
- Add clear navigation to settings location
- Document defaults and minimums for both intervals
- Include LocalAPI polling guidance from official docs
- Differentiate between LocalAPI and Legacy CGI recommendations
- Add note that LocalAPI works via standard LAN IP
- No proxy or special network setup required
- Add code comment explaining camelCase to snake_case conversion
- Document in README that LocalAPI field names are converted to match legacy format
- Ensures reviewers understand why manual mapping is necessary
@jgrant216
Copy link

@jtooley307 , I cloned your repo / branch and overwrote the typical HACS integration with it. I got this error on startup. My PVS6 is on build 61845.

2025-10-04 22:23:06.043 ERROR (MainThread) [custom_components.sunpower] Unexpected error fetching SunPower PVS data
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 392, in _async_refresh
    self.data = await self._async_update_data()
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 293, in _async_update_data
    return await self.update_method()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/sunpower/__init__.py", line 347, in async_update_data
    return await hass.async_add_executor_job(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<4 lines>...
    )
    ^
  File "/usr/local/lib/python3.13/concurrent/futures/thread.py", line 59, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/sunpower/__init__.py", line 286, in sunpower_fetch
    data = convert_sunpower_data(sunpower_data)
  File "/config/custom_components/sunpower/__init__.py", line 101, in convert_sunpower_data
    for device in sunpower_data["devices"]:
                  ~~~~~~~~~~~~~^^^^^^^^^^^

@jtooley307
Copy link
Author

jtooley307 commented Oct 7, 2025

Add some logging after line 284.

if not sunpower_data or "devices" not in sunpower_data: _LOGGER.error("Invalid PVS data structure: %s", sunpower_data) raise UpdateFailed("PVS returned invalid data structure - missing 'devices' key")

Check the log to see if it auto detected the new firmware version too. You could use curl to get a session token, and then use it to get the device list.

@jtooley307
Copy link
Author

jtooley307 commented Oct 7, 2025

try this, update your IP. I will also put a little more debugging and checks in the initialization code

`PVS_IP="192.168.x.x"

SERIAL_SUFFIX=$(curl -s "http://$PVS_IP/cgi-bin/dl_cgi/supervisor/info" |
python3 -c "import sys, json; print(json.load(sys.stdin)['supervisor']['SERIAL'][-5:])")

echo "Serial suffix: $SERIAL_SUFFIX"

SESSION=$(curl -s "http://$PVS_IP/auth?login"
-H "Authorization: basic $(echo -n "ssm_owner:$SERIAL_SUFFIX" | base64)"
| python3 -c "import sys, json; print(json.load(sys.stdin)['session'])")

echo "Session token: $SESSION"

echo ""
echo "Fetching meter data..."
curl -s "http://$PVS_IP/vars?match=meter&fmt=obj"
-H "Cookie: session=$SESSION" | python3 -m json.tool | head -30``

- Test /auth endpoint instead of /api/v1/eliteapi/session
- PVS6 Build 61845 uses original LocalAPI paths, not newer API paths
- Add error handling for invalid device data structure
- Prevents false positive LocalAPI detection on systems without it
@jgrant216
Copy link

I updated your latest code and my panels are showing up again! 🥇 Thanks @jtooley307

That script worked for me.

Fetching meter data...
{
    "/sys/devices/meter/0/ctSclFctr": "50",
    "/sys/devices/meter/0/freqHz": "60.014000",
... snip ...
    "/sys/devices/meter/1/redacted": "0.688285",

@jtooley307
Copy link
Author

you can get your configuration details with this command in the HA terminal

cat /config/.storage/core.config_entries | jq '.data.entries[] | select(.domain == "sunpower")'

Adds defensive checks in create_vmeter() and convert_ess_data() to handle
cases where the PVS device is temporarily missing from the API response.
This prevents the integration from crashing when the PVS is offline or
during network issues.

The fix logs a warning and skips virtual device creation when PVS is
missing, allowing the integration to continue operating with available
devices. Normal operation resumes when PVS data becomes available again.

Fixes issue where integration would error out after working for a while
with 'KeyError: PVS' in the logs.
@jgrant216
Copy link

I had the KeyError: 'PVS' and restart resolved.

I noticed your latest commit about it so I've fetched it and recycled again. Reconnected without issue.

@heathseals
Copy link

Tried this as a drop-in replacement and it just worked. 💯

- Add validation for empty PVS_DEVICE_TYPE in create_vmeter() and sensor setup
- Add device type existence checks in convert_ess_data() for BATTERY, ESS, and HUBPLUS
- Add serial number validation before accessing device data in ESS conversion loops
- Standardize use of 'serial' variable throughout ESS data processing
- Log warnings when expected devices are missing instead of crashing

Fixes KeyError: 'PVS' that occurred when PVS device data was unavailable
- Add validation in sensor.native_value to check device type and serial exist
- Add validation in binary_sensor.state to check device type and serial exist
- Return None gracefully when device data is unavailable
- Add unit tests to verify defensive checks work correctly

Fixes KeyError: 'Power Meter' that occurred when virtual meter wasn't created
- Log all device types found in API response
- Log sample devices when PVS type is missing
- Helps diagnose why PVS device is not found
BUG FIXES:
- Fix 400 Bad Request errors from LocalAPI /vars endpoint
- Remove unsupported 'cache' parameter from _fetch_meters(), _fetch_inverters(), _fetch_sysinfo()
- LocalAPI only supports 'match' parameter, not 'cache'

DEFENSIVE CHECKS:
- Add validation for missing/empty PVS device data in create_vmeter()
- Add validation for missing device types (BATTERY, ESS, HUBPLUS) in convert_ess_data()
- Add serial number validation before accessing device data in ESS conversion loops
- Add device type/serial existence checks in sensor.native_value property
- Add device type/serial existence checks in binary_sensor.state property
- Return None gracefully when device data is unavailable instead of crashing

DIAGNOSTIC IMPROVEMENTS:
- Add comprehensive logging for device types found in API responses
- Add detailed error messages with URL and params for connection failures
- Log device counts by type and sample devices when PVS is missing
- Add traceback logging for inverter fetch failures to aid debugging

DOCUMENTATION:
- Update README with recent bug fixes section
- Document LocalAPI cache parameter fix
- Document defensive checks and improved resilience

Resolves:
- KeyError: 'PVS' (1,216+ occurrences)
- KeyError: 'Power Meter' (404 occurrences)
- 400 Client Error: Bad Request for /vars endpoint (209 occurrences)
- Failed to fetch inverters/meters errors
Update comments and documentation to accurately reflect that:
- LocalAPI does support the cache parameter
- We removed it for simplicity and reliability, not because it's unsupported
- Performance benefit is negligible at 120-second polling intervals
- Avoiding cache state management improves integration stability
@jgrant216
Copy link

I had lost connection at around 8a today with many KeyError: 'Power Meter' in the logs.. I restarted around 4p.

I just pulled the latest and applied it. Will report back.

@jtooley307
Copy link
Author

I finally had the Key Error show up in my system yesterday. So I had a chance to debug it with some more defensive code. I updated the PR earlier today with those. Hopefully it resolves it for you and me

This commit enhances the robustness of the LocalAPI implementation by adding
comprehensive error handling and ensuring critical devices are always available.

Key improvements:

1. Guaranteed PVS device presence
   - PVS device is now always added to device list, even if sysinfo fetch fails
   - Uses sensible defaults (host-based serial, 'PVS' model) as fallback
   - Prevents 'PVS device not found' crashes in downstream code

2. Enhanced error handling in _vars() method
   - Added explicit 400 Bad Request detection with debug logging
   - Logs response body for troubleshooting LocalAPI parameter issues
   - Added HTTPError handling before generic RequestException
   - Provides clear error messages about endpoint support

3. Graceful degradation for device fetches
   - Meters: Logs warning if fetch fails, continues with empty dict
   - Inverters: Logs error + debug traceback if fetch fails, continues
   - Integration continues operating with whatever data is available
   - No crashes when individual device types are unavailable

4. Improved logging
   - Moved logging/traceback imports to top of file (cleaner code)
   - Changed missing inverters from ERROR to WARNING (normal for some configs)
   - Added informative messages explaining inverters may be aggregated
   - Added summary logging showing counts of devices fetched
   - Changed traceback from ERROR to DEBUG level

5. Code quality improvements
   - Removed inline imports, moved to top-level
   - Consistent error handling patterns throughout
   - Clear comments explaining behavior
   - Maintains full backwards compatibility

These changes make the integration resilient to:
- Temporary PVS connection issues
- Incomplete LocalAPI implementations
- Network timeouts and intermittent failures
- Systems where inverters aren't exposed via LocalAPI

Tested with PVS firmware build 61845 returning 1 PVS, 2 meters, 17 inverters.
@jgrant216
Copy link

Was stable the last two days. I pulled 5db3733 and applied it now.

@sphen13
Copy link

sphen13 commented Oct 14, 2025

i just updated my code to your latest commit - fyi it has been working solid since your last bugfix / oct 8th

@julio8a
Copy link

julio8a commented Oct 14, 2025

Will this get merged and published? I don't know how to apply it like @jgrant216 and @sphen13. Is there doc somewhere or can anyone give me some quick steps on how to apply this in HA?

@sphen13
Copy link

sphen13 commented Oct 14, 2025

Will this get merged and published? I don't know how to apply it like @jgrant216 and @sphen13. Is there doc somewhere or can anyone give me some quick steps on how to apply this in HA?

i presume it will once the bugs are ironed out - this is open source and you are at the whim of the overwhelming generosity of the developers taking their free time.

you can try to download this: https://github.com/jtooley307/hass-sunpower/archive/refs/heads/localapi-migration.zip

unzip, then take the entire sunpower folder from within custom_components and drop it into your HA config folder under custom_components. reboot HA.

BUT you prob dont want to do anything if you are on older firmware as it may break your setup. he did code it to allow for fallback but i have not tested.

@julio8a
Copy link

julio8a commented Oct 14, 2025

I am on 61845

Address code review feedback from schneideradam:
- Replace 'if key not in dict' checks with 'if not dict.get(key)'
- This provides cleaner error handling and better stack traces
- Applied consistently to all PVS_DEVICE_TYPE and INVERTER_DEVICE_TYPE checks

Changes:
- create_vmeter(): Use data.get(PVS_DEVICE_TYPE) instead of checking membership
- convert_sunpower_data(): Use data.get() for both PVS and inverter checks
- convert_ess_data(): Use data.get(PVS_DEVICE_TYPE) for SunVault creation

This makes the code more Pythonic and allows KeyError to surface naturally
if there are unexpected access patterns, while still handling expected
missing keys gracefully.
@jgrant216
Copy link

jgrant216 commented Oct 18, 2025

Day 5, still gathering data. Several warnings/errors in the logs, which I expect is just your proactive logging of them even though the plugin resolves. Here's what those are in case you're interested...

Warning 670 times since October 15

No inverter devices found - this is normal for some PVS configurations

Error 67 times since October 15

Failed to fetch inverters: Bad Request (400) - LocalAPI endpoint may not support these parameters. URL: http://172.27.153.1/vars, params: {'match': 'inverter', 'fmt': 'obj'}

Error 2 times since this morning, October 17

Unexpected exception during read

I have not yet pulled the updates from @schneideradam.

@jgrant216
Copy link

jgrant216 commented Oct 18, 2025

Will this get merged and published? I don't know how to apply it like @jgrant216 and @sphen13. Is there doc somewhere or can anyone give me some quick steps on how to apply this in HA?

@julio8a , here is what I did to get this update without messing with my original.

  1. Install a terminal HACS integration.
  2. Open terminal
  3. cd /tmp
  4. git clone https://github.com/jtooley307/hass-sunpower/
  5. cd hass-sunpower
  6. cp -R sunpower /config/custom_components
  7. Restart HA

Number 6 will overwrite the default code with the cloned repo code.

To update if more commits are made to their repo...

  1. cd /tmp/haas-sunpower
  2. git pull
  3. cp -R sunpower /config/custom_components
  4. Restart HA

Hope this helps.

@jtooley307
Copy link
Author

I moved over to https://github.com/smcneece/ha-esunpower without any issues. I will put any any fixes or enhancements into his repo.

@sphen13
Copy link

sphen13 commented Oct 20, 2025

I moved over to https://github.com/smcneece/ha-esunpower without any issues. I will put any any fixes or enhancements into his repo.

welp i guess that makes up my mind! thanks!

@jgrant216
Copy link

I moved over to https://github.com/smcneece/ha-esunpower without any issues. I will put any any fixes or enhancements into his repo.

@jtooley307 fork stopped working for me, even after restarts. Since they have moved over to the smcneece fork, I have as well. The update was smooth and my history was retained.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants