Open luis-castro opened 1 day ago
Hey there @bdraco, @cgarwood, @joostlek, @catsmanac, mind taking a look at this issue as it has been labeled with an integration (enphase_envoy
) you are listed as a code owner for? Thanks!
(message by CodeOwnersMention)
enphase_envoy documentation enphase_envoy source (message by IssueLinks)
When I enabled DEBUG logs, it seems the integration is wrongly trying to use /production.json
instead of the correct API /api/v1/production
and therefore it is unable to decode the output (as expected, becuase the Envoy is returning an error).
If the integration has detected we are running firmware D3.18.10, then it should only make use of the following APIs:
2024-09-17 18:06:14.575 DEBUG (MainThread) [pyenphase.firmware] Request reply in 0.1 sec from http://192.168.1.15/info status 200: text/xml b"<?xml version='1.0' encoding='UTF-8'?>\n<envoy_info>\n <time>1726617974</time>\n <device>\n <sn>[*REDACTED*]</sn>\n <pn>800-00240-r03</pn>\n <software>D3.18.10</software>\n <euaid>4c8675</euaid>\n <seqnum>0</seqnum>\n <apiver>1</apiver>\n </device>\n <package name='backbone'>\n <pn>500-00010-r01</pn>\n <version>02.01.15</version>\n <build>ad8746</build>\n </package>\n <package name='devimg'>\n <pn>500-00004-r01</pn>\n <version>01.02.245</version>\n <build>033b78</build>\n </package>\n <package name='kernel'>\n <pn>500-00003-r01</pn>\n <version>02.04.00</version>\n <build>80e63f</build>\n </package>\n <package name='security'>\n <pn>500-00016-r01</pn>\n <version>02.00.00</version>\n <build>54a6dc</build>\n </package>\n <package name='boot'>\n <pn>590-00015-r01</pn>\n <version>02.00.01</version>\n <build>0b54c5</build>\n </package>\n <package name='geo'>\n <pn>500-00008-r01</pn>\n <version>02.01.22</version>\n <build>702db9</build>\n </package>\n <package name='app'>\n <pn>500-00002-r01</pn>\n <version>03.18.10</version>\n <build>f0855e</build>\n </package>\n <package name='rootfs'>\n <pn>500-00001-r01</pn>\n <version>01.02.00</version>\n <build>807</build>\n </package>\n</envoy_info>\n"
2024-09-17 18:06:14.576 DEBUG (MainThread) [pyenphase.envoy] FW: 3.18.10, Authenticating to Envoy using envoy/installer authentication
2024-09-17 18:06:14.577 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/ivp/meters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:14.705 DEBUG (MainThread) [pyenphase.updaters.meters] Skipping meters endpoint as user does not have access to /ivp/meters: Authentication failed for http://192.168.1.15/ivp/meters with status 401, please check your username/password or token.
2024-09-17 18:06:14.706 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/production.json?details=1 with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:14.933 DEBUG (MainThread) [pyenphase.envoy] Request reply in 0.2 sec from http://192.168.1.15/production.json?details=1 status 200: application/json b' <!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">\n <html>\n <!-- START HEAD CONTENT -->\n <head>\n <!-- include style sheet -->\n <link rel="StyleSheet" type="text/css" href="/include/style.css" />\n <!-- include JS libraries -->\n </head>\n <!-- END HEAD CONTENT -->\n <body>\n <center>\n <img src="/images/emu-small.gif" style="margin:10px" alt="Emu"/>\n <h2>Page Not Found</h2>\n <p>The page you tried to view does not exist\n Try the <a href="/">home</a> page</p>\n </center>\n </body>\n </html>\n'
2024-09-17 18:06:14.934 DEBUG (MainThread) [pyenphase.json] Unable to decode response from Envoy endpoint /production.json?details=1: unexpected character: line 1 column 5 (char 4)
2024-09-17 18:06:14.934 DEBUG (MainThread) [pyenphase.updaters.production] Production endpoint not found at /production.json?details=1: unexpected character: line 1 column 5 (char 4)
2024-09-17 18:06:14.934 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/production with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:15.082 DEBUG (MainThread) [pyenphase.envoy] Request reply in 0.1 sec from http://192.168.1.15/production status 200: application/json b' <h1>System Energy Production</h1>\n <div style="margin-right: auto; margin-left: auto;"><table>\n <tr><td colspan="3">System has been live since\n <div class=good>Fri Sep 01, 2017 02:53 PM GMT+6</div></td></tr>\n <tr><td>Currently</td> <td> 49.0 W</td></tr><tr><td>Today</td> <td> 3.27 kWh</td></tr><tr><td>Past Week</td> <td> 26.9 kWh</td></tr><tr><td>Since Installation</td> <td> 15.0 MWh</td></tr>\n </table><br></div>\n'
2024-09-17 18:06:15.082 DEBUG (MainThread) [pyenphase.json] Unable to decode response from Envoy endpoint /production: unexpected character: line 1 column 7 (char 6)
2024-09-17 18:06:15.082 DEBUG (MainThread) [pyenphase.updaters.production] Production endpoint not found at /production: unexpected character: line 1 column 7 (char 6)
2024-09-17 18:06:15.082 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/api/v1/production with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:15.116 DEBUG (MainThread) [pyenphase.envoy] Request reply in 0.0 sec from http://192.168.1.15/api/v1/production status 200: application/json b'{\n "wattHoursToday": 3272,\n "wattHoursSevenDays": 26896,\n "wattHoursLifetime": 15043584,\n "wattsNow": 49\n}\n'
2024-09-17 18:06:15.116 DEBUG (MainThread) [pyenphase.json] Unable to decode response from Envoy endpoint /production.json?details=1: unexpected character: line 1 column 5 (char 4)
2024-09-17 18:06:15.116 DEBUG (MainThread) [pyenphase.updaters.production] Production endpoint not found at /production.json?details=1: unexpected character: line 1 column 5 (char 4)
2024-09-17 18:06:15.117 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:16.801 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:19.201 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:20.839 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:20.879 DEBUG (MainThread) [pyenphase.updaters.api_v1_production_inverters] Production endpoint not found at /api/v1/production/inverters: Server disconnected without sending a response.
2024-09-17 18:06:20.879 DEBUG (MainThread) [pyenphase.updaters.ensemble] Firmware too old for Ensemble support
Hi @luis-castro, You are correct about the 2 API's it should use. Before I dive into the issue, I've got some question to assist with the troubleshooting.
The integration is constantly losing data from the inverters connected to the Envoy R, showing them as Unavailable.
Does it ever restore from unavailable without restarting Home-Assistant?
This is sometimes solved by restarting homeassist, others I have to delete the integration and add it again.
Looking at the information you provided (also see below) it seems as if the /api/v1/production/inverters is not reliably providing data. If this occurs during normal collection runs, the data will go to unavailable and come back when it works again. If this happens during a Home Assistant restart, the data will be considered as unavailable on the Envoy and not even be collected (some versions don't have this data).
If this happens you don't need to restart Home Assistant completely. If you open settings / devices & services / Enphase Envoy you can use the menu to reload the Envoy Integration. That will restart the communication and retry building all connections. This may work or not, but it avoids the whole restart of Home Assistant. And no, it's not a solution to the issue, just a simpler way to try to get it going again.
As for the debug log details, it shows is the startup sequence during which it determines what is available or not. This is not primary driving by the firmware version, but rather by the responses of the Envoy. This will include some failures depending on the Envoy model and firmware.
It received a successful reply for the /api/vi/production
2024-09-17 18:06:15.116 DEBUG (MainThread) [pyenphase.envoy] Request reply in 0.0 sec from http://192.168.1.15/api/v1/production status 200: application/json b'{\n "wattHoursToday": 3272,\n "wattHoursSevenDays": 26896,\n "wattHoursLifetime": 15043584,\n "wattsNow": 49\n}\n'
and as a result it will use this for production data.
The lines right below it is still part of the inspection and will lead to not trying to use the /production.json endpoint.
2024-09-17 18:06:15.116 DEBUG (MainThread) [pyenphase.json] Unable to decode response from Envoy endpoint /production.json?details=1: unexpected character: line 1 column 5 (char 4)
2024-09-17 18:06:15.116 DEBUG (MainThread) [pyenphase.updaters.production] Production endpoint not found at /production.json?details=1: unexpected character: line 1 column 5 (char 4)
The result is also reflected in the diagnostic file where both end-points are shown used. Raw_data is the data that was collected from the Envoy in the data last collection before the diagnostic report was created.
"raw_data": {
"/api/v1/production": {
"wattHoursToday": 3260,
"wattHoursSevenDays": 26887,
"wattHoursLifetime": 15043572,
"wattsNow": 46
},
"/api/v1/production/inverters": [
{
"serialNumber": "121726021970",
"lastReportDate": 1726616739,
"lastReportWatts": 11,
"maxReportWatts": 218
},
{
"serialNumber": "121726033042",
The next section trying to get the data from the inverters shows some issue though. No data is returned by the Envoy.
2024-09-17 18:06:15.117 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:16.801 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:19.201 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:20.839 DEBUG (MainThread) [pyenphase.envoy] Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
2024-09-17 18:06:20.879 DEBUG (MainThread) [pyenphase.updaters.api_v1_production_inverters] Production endpoint not found at /api/v1/production/inverters: Server disconnected without sending a response.
What can be seen is 4 connection attempts that fail right away and with varying wait time of 1-3 seconds in between. As a result the inverter data will probably not be collected after this restart and it would need another restart/reload on this Envoy in Home Assistant to try again.
The reported error Server disconnected without sending a response
is also reported in the Error log of the original problem report. Although it's not clear if it was for the /api/v1/production/inverters endpoint as well. Based on your description it probably is.
Hi @catsmanac,
Thanks for taking a look at it.
Answering your question: Yes, it has been working for at least a year. It started failing around 2 months ago.
I believe the issue is in the pyenphase library itself. I've been playing around and have the following findings:
curl
to hit the API /api/v1/production/inverters
, it works with no issues:
$ curl -u installer:[REDACTED] --digest http://192.168.1.15/api/v1/production/inverters
[
{
"serialNumber": "121726021970",
"lastReportDate": 1726672636,
"lastReportWatts": 177,
"maxReportWatts": 218
},
{
"serialNumber": "121726033042",
"lastReportDate": 1726672632,
"lastReportWatts": 186,
"maxReportWatts": 195
},
{
"serialNumber": "121726021253",
"lastReportDate": 1726672635,
"lastReportWatts": 85,
"maxReportWatts": 108
},
{
"serialNumber": "121730034753",
"lastReportDate": 1726672634,
"lastReportWatts": 190,
"maxReportWatts": 245
}
]
I can keep this repeating with no issues.
If use the library I noticed that pyenphase/envoy.py
is trying to probe all Updaters, even the ones we know won't work in firmare version 3.
However, even if I comment out the Updaters, it seems the library is not using Digest Authentication when hitting the API /api/v1/production/inverters
.
Here is the modification I applied to envoy,py
:
UPDATERS: list[type["EnvoyUpdater"]] = [
# EnvoyMetersUpdater,
# EnvoyProductionJsonUpdater,
# EnvoyProductionUpdater,
EnvoyApiV1ProductionUpdater,
# EnvoyProductionJsonFallbackUpdater,
EnvoyApiV1ProductionInvertersUpdater,
# EnvoyEnembleUpdater,
# EnvoyTariffUpdater,
# EnvoyGeneratorUpdater,
]
However, when I called envoy.update(), I got this:
DEBUG:pyenphase.envoy:Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_headers.failed exception=RemoteProtocolError('Server disconnected without sending a response.')
DEBUG:httpcore.http11:response_closed.started
DEBUG:httpcore.http11:response_closed.complete
It seems to me the library is not hitting the API with Digest Authentication (but I am not 100% certain of that).
For reference this is the Python script I am using for this test:
import asyncio
from pyenphase import Envoy, EnvoyData
from pprint import pprint
import logging
logging.basicConfig(level=logging.DEBUG)
async def main():
envoy = Envoy("192.168.1.15")
print('Calling envoy.setup()...')
await envoy.setup()
print(f'Envoy: {envoy.host}\nFirmare: {envoy.firmware}\nSerial: {envoy.serial_number}\n')
print('Calling envoy.authenticate()...')
await envoy.authenticate(username="installer")
while True:
print('Calling envoy.update()...')
data: EnvoyData = await envoy.update()
print(f'TodaysEnergy: {data.system_production.watt_hours_today}')
for inverter in data.inverters:
print(f'{inverter} SN: {data.inverters[inverter].serial_number}')
print(f'{inverter} W: {data.inverters[inverter].last_report_watts}')
print('Waiting 10 seconds...')
await asyncio.sleep(10)
if __name__ == "__main__":
print('Calling main...')
asyncio.run(main())
What are your thoughts about this?
It seems I was wrong about the library not using Digest Authentication, however something is not working.
Here is a complete dump of the output. I still don't understand what the problem is:
Calling envoy.authenticate()...
DEBUG:pyenphase.envoy:FW: 3.18.10, Authenticating to Envoy using envoy/installer authentication
Calling envoy.update()...
DEBUG:pyenphase.envoy:Requesting http://192.168.1.15/api/v1/production with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
DEBUG:httpcore.connection:connect_tcp.started host='192.168.1.15' port=80 local_address=None timeout=10.0 socket_options=None
DEBUG:httpcore.connection:connect_tcp.complete return_value=<httpcore._backends.anyio.AnyIOStream object at 0x7fb621921990>
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'OK', [(b'Date', b'Wed, 18 Sep 2024 15:54:33 GMT'), (b'Content-Type', b'application/json'), (b'Content-Length', b'111')])
INFO:httpx:HTTP Request: GET http://192.168.1.15/api/v1/production "HTTP/1.1 200 OK"
DEBUG:httpcore.http11:receive_response_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_body.complete
DEBUG:httpcore.http11:response_closed.started
DEBUG:httpcore.http11:response_closed.complete
DEBUG:pyenphase.envoy:Request reply in 0.0 sec from http://192.168.1.15/api/v1/production status 200: application/json b'{\n "wattHoursToday": 889,\n "wattHoursSevenDays": 27300,\n "wattHoursLifetime": 15044482,\n "wattsNow": 598\n}\n'
DEBUG:pyenphase.envoy:Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_headers.failed exception=RemoteProtocolError('Server disconnected without sending a response.')
DEBUG:httpcore.http11:response_closed.started
DEBUG:httpcore.http11:response_closed.complete
DEBUG:pyenphase.envoy:Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
DEBUG:httpcore.connection:connect_tcp.started host='192.168.1.15' port=80 local_address=None timeout=10.0 socket_options=None
DEBUG:httpcore.connection:connect_tcp.complete return_value=<httpcore._backends.anyio.AnyIOStream object at 0x7fb621974550>
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_headers.complete return_value=(b'HTTP/1.1', 401, b'Unauthorized', [(b'Date', b'Wed, 18 Sep 2024 15:54:34 GMT'), (b'WWW-Authenticate', b'Digest qop="auth", realm="enphaseenergy.com", nonce="1726674874"'), (b'Content-Type', b'application/json'), (b'Content-Length', b'90')])
INFO:httpx:HTTP Request: GET http://192.168.1.15/api/v1/production/inverters "HTTP/1.1 401 Unauthorized"
DEBUG:httpcore.http11:receive_response_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_body.complete
DEBUG:httpcore.http11:response_closed.started
DEBUG:httpcore.http11:response_closed.complete
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_headers.failed exception=RemoteProtocolError('Server disconnected without sending a response.')
DEBUG:httpcore.http11:response_closed.started
DEBUG:httpcore.http11:response_closed.complete
DEBUG:pyenphase.envoy:Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
DEBUG:httpcore.connection:connect_tcp.started host='192.168.1.15' port=80 local_address=None timeout=10.0 socket_options=None
DEBUG:httpcore.connection:connect_tcp.complete return_value=<httpcore._backends.anyio.AnyIOStream object at 0x7fb621974f10>
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_headers.complete return_value=(b'HTTP/1.1', 401, b'Unauthorized', [(b'Date', b'Wed, 18 Sep 2024 15:54:36 GMT'), (b'WWW-Authenticate', b'Digest qop="auth", realm="enphaseenergy.com", nonce="1726674876"'), (b'Content-Type', b'application/json'), (b'Content-Length', b'90')])
INFO:httpx:HTTP Request: GET http://192.168.1.15/api/v1/production/inverters "HTTP/1.1 401 Unauthorized"
DEBUG:httpcore.http11:receive_response_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_body.complete
DEBUG:httpcore.http11:response_closed.started
DEBUG:httpcore.http11:response_closed.complete
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_headers.failed exception=RemoteProtocolError('Server disconnected without sending a response.')
DEBUG:httpcore.http11:response_closed.started
DEBUG:httpcore.http11:response_closed.complete
DEBUG:pyenphase.envoy:Requesting http://192.168.1.15/api/v1/production/inverters with timeout Timeout(connect=10.0, read=45.0, write=10.0, pool=10.0)
DEBUG:httpcore.connection:connect_tcp.started host='192.168.1.15' port=80 local_address=None timeout=10.0 socket_options=None
DEBUG:httpcore.connection:connect_tcp.complete return_value=<httpcore._backends.anyio.AnyIOStream object at 0x7fb621977110>
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_headers.complete return_value=(b'HTTP/1.1', 401, b'Unauthorized', [(b'Date', b'Wed, 18 Sep 2024 15:54:36 GMT'), (b'WWW-Authenticate', b'Digest qop="auth", realm="enphaseenergy.com", nonce="1726674876"'), (b'Content-Type', b'application/json'), (b'Content-Length', b'90')])
INFO:httpx:HTTP Request: GET http://192.168.1.15/api/v1/production/inverters "HTTP/1.1 401 Unauthorized"
DEBUG:httpcore.http11:receive_response_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_body.complete
DEBUG:httpcore.http11:response_closed.started
DEBUG:httpcore.http11:response_closed.complete
DEBUG:httpcore.http11:send_request_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_headers.complete
DEBUG:httpcore.http11:send_request_body.started request=<Request [b'GET']>
DEBUG:httpcore.http11:send_request_body.complete
DEBUG:httpcore.http11:receive_response_headers.started request=<Request [b'GET']>
DEBUG:httpcore.http11:receive_response_headers.failed exception=RemoteProtocolError('Server disconnected without sending a response.')
DEBUG:httpcore.http11:response_closed.started
DEBUG:httpcore.http11:response_closed.complete
DEBUG:pyenphase.updaters.api_v1_production_inverters:Production endpoint not found at /api/v1/production/inverters: Server disconnected without sending a response.
TodaysEnergy: 889
Waiting 10 seconds...
BTW: As this is not a home-assistant issue per se, let me know if I should file an issue with the pyenvoy team.
So your test program shows the issue as well. In the end it's probably a pyenhase library issue, before we move there I want to verify some things. I'm member of the pyenphase team as well, so we can switch when needed.
In your test code can you change start of main to:
from pyenphase import register_updater
from pyenphase.envoy import get_updaters
from pyenphase.updaters.base import EnvoyUpdater
from pyenphase.updaters.production import EnvoyProductionJsonUpdater, EnvoyProductionUpdater, EnvoyProductionJsonFallbackUpdater
logging.basicConfig(level=logging.DEBUG)
async def main():
updaters: list[type[EnvoyUpdater]] = get_updaters()
if EnvoyProductionJsonUpdater in updaters:
_LOGGER.debug("Removing EnvoyProductionJsonUpdater from Pyenphase")
updaters.remove(EnvoyProductionJsonUpdater)
if EnvoyProductionUpdater in updaters:
_LOGGER.debug("Removing EnvoyProductionUpdater from Pyenphase")
updaters.remove(EnvoyProductionUpdater)
if EnvoyProductionJsonFallbackUpdater in updaters:
_LOGGER.debug("Removing EnvoyProductionJsonFallbackUpdater from Pyenphase")
updaters.remove(EnvoyProductionJsonFallbackUpdater)
envoy = Envoy("192.168.1.15")
print('Calling envoy.setup()...')
This will remove the production endpoint updaters and prevent reading the production pages at startup probe to see if that removes the issue or not.
Let it start and run for 2 or 3 cycles and then upload the debug log here.
Done.
BTW: I got an error with _LOGGER.debug
, so I changed it to print
(sorry, I'm new to Python!).
Here is the output: pytest.log
Can try with username='envoy' as well?
Sure, here is the output, but there is no change: output-envoy.log
Anyway, I think "installer" should work as per my tests with curl.
Anyway, I think "installer" should work as per my tests with curl.
Agree
Ok, well not ok yet, on to next step. Let's eliminate the meters and tariff collection. Should only leave info, v1/production and inverters for collection.
Add
from pyenphase.updaters.meters import EnvoyMetersUpdater
from pyenphase.updaters.tariff import EnvoyTariffUpdater
and
if EnvoyMetersUpdater in updaters:
_LOGGER.debug("Removing EnvoyMetersUpdater from Pyenphase")
updaters.remove(EnvoyMetersUpdater)
if EnvoyTariffUpdater in updaters:
_LOGGER.debug("Removing EnvoyTariffUpdater from Pyenphase")
updaters.remove(EnvoyTariffUpdater)
right after the already added sections
Applied the modifications and ran the new test.
See attached log: test-20240918-1925UTC.txt
For reference, this is how the test code looks now:
import asyncio
from pyenphase import Envoy, EnvoyData
from pyenphase import register_updater
from pyenphase.envoy import get_updaters
from pyenphase.updaters.base import EnvoyUpdater
from pyenphase.updaters.production import EnvoyProductionJsonUpdater, EnvoyProductionUpdater, EnvoyProductionJsonFallbackUpdater
from pyenphase.updaters.meters import EnvoyMetersUpdater
from pyenphase.updaters.tariff import EnvoyTariffUpdater
import logging
logging.basicConfig(level=logging.DEBUG)
async def main():
updaters: list[type[EnvoyUpdater]] = get_updaters()
if EnvoyProductionJsonUpdater in updaters:
logging.debug("Removing EnvoyProductionJsonUpdater from Pyenphase")
updaters.remove(EnvoyProductionJsonUpdater)
if EnvoyProductionUpdater in updaters:
logging.debug("Removing EnvoyProductionUpdater from Pyenphase")
updaters.remove(EnvoyProductionUpdater)
if EnvoyProductionJsonFallbackUpdater in updaters:
logging.debug("Removing EnvoyProductionJsonFallbackUpdater from Pyenphase")
updaters.remove(EnvoyProductionJsonFallbackUpdater)
if EnvoyMetersUpdater in updaters:
logging.debug("Removing EnvoyMetersUpdater from Pyenphase")
updaters.remove(EnvoyMetersUpdater)
if EnvoyTariffUpdater in updaters:
logging.debug("Removing EnvoyTariffUpdater from Pyenphase")
updaters.remove(EnvoyTariffUpdater)
envoy = Envoy("192.168.1.15")
logging.debug('Calling envoy.setup()...')
await envoy.setup()
print(f'Envoy: {envoy.host}\nFirmare: {envoy.firmware}\nSerial: {envoy.serial_number}\n')
logging.debug('Calling envoy.authenticate()...')
await envoy.authenticate(username="installer")
while True:
logging.debug('Calling envoy.update()...')
data: EnvoyData = await envoy.update()
print(f'TodaysEnergy: {data.system_production.watt_hours_today}')
for inverter in data.inverters:
print(f'{inverter} SN: {data.inverters[inverter].serial_number}')
print(f'{inverter} W: {data.inverters[inverter].last_report_watts}')
print('Waiting 10 seconds...')
await asyncio.sleep(10)
if __name__ == "__main__":
logging.debug('Calling main...')
asyncio.run(main())
I thought the Envoy was blacklisting my IP, but I ran curl from the same machine I'm running python and it works:
$ curl -u installer:REDACTED --digest http://192.168.1.15/api/v1/production/inverters
[
{
"serialNumber": "121726021970",
"lastReportDate": 1726687061,
"lastReportWatts": 124,
"maxReportWatts": 218
},
...
So behavior is pretty consistent with access denied on the inverters endpoint.
Answering your question: Yes, it has been working for at least a year. It started failing around 2 months ago.
Any idea what version upgrade that was? I.e. if you made any backup of home assistant before upgrades you can see version of the backup in you backup list.
I'll do some search in what all we changed in pyenphase around that time, since like 3 months ago. That will be tomorrow as hours in the day are running out quickly here now.
Unfortunately the earliest backup I keep is from August 24. Back then I was running Home Assistant 2024.8.1 (same version I'm currently running), but I think I applied updates to some add-ons.
I appreciate all your efforts! Let me know if more information or tests are needed.
If you need access to this Envoy, I can arrange that too.
I have reviewed my statistics, the issue I had two months ago was unrelated (sorry about that!)
As you can see in this screenshot, the connectivity became unrealiable since September 6:
Today I upgraded Home Assistant to 2024.9.2 and upgraded Home Assistant OS to version 13.1. The inverters were showing results for a couple of minutes and then they became unavailable again.
The problem
My Envoy Enphase integration is configured with 2 gateways: 1 is running firmware D3.18.10 (Envoy R), and the other is running firmware 7.3.617 (Envoy IQ).
The integration is constantly losing data from the inverters connected to the Envoy R, showing them as Unavailable.
This is sometimes solved by restarting homeassist, others I have to delete the integration and add it again.
What version of Home Assistant Core has the issue?
core-2024.8.1
What was the last working version of Home Assistant Core?
No response
What type of installation are you running?
Home Assistant OS
Integration causing the issue
enphase_envoy
Link to integration documentation on our website
https://www.home-assistant.io/integrations/enphase_envoy
Diagnostics information
config_entry-enphase_envoy-01J815RY1A02ECBF94NKK8NKNV (1).json
Example YAML snippet
No response
Anything in the logs that might be useful for us?
Additional information
No response