The only reason I am going to have a go at trying to contribute to this discussion is that it forces me to learn stuff. Apparently it is good to learn new stuffâŚ
Log error messages usually tell you useful stuff, and I can see that
- this is a message from the hassio_supervisor
- the âerrorâ is for information only (not critical)
- it is about the supervisor.api.proxy
- trying to process an API call from Home Assistant WebSocket
- getting a WebSocket message that is of an unsupported type
First up, this is not critical. It happens, the WebSocket connection from Node-RED (WebSocket nodes) back to Home Assistant has closed, due to âsomethingâ. After the supervisor closes the connection, it re-opens it and we carry on.
I am going to have a stab at this, and hopefully someone else who understands this stuff will correct me here, but:
Home Assistant exposes services to the world via a public API. This you get at using the normal UI front end address.
When HA is being run in fully supervised mode, what is going on is that the HA supervisor runs on the machine in a docker-container. The supervisor manages the docker-containers, and runs up another one for Home Assistant. Then, if you have the Node-RED as an addon, the supervisor runs up yet another docker-container for Node-RED.
Now, docker containers canât talk to each other. They exist as âvirtualâ devices, unlike physical devices on a network. The Home Assistant running in one container is desperate to share services over an API, but has to use a proxy to manage this between different docker-containers. The supervisor, which has control of all the containers including its own, sets up and runs a proxy that bridges API calls from one container to another.
The Proxy can manage WebSocket connections, and thus Node-RED (WebSocket nodes server) connects a WebSocket to the supervisor proxy and through this to HA and the special internal API point that HA provides for proxy connections from the HA container to other addon (containers).
The Proxy is written into the supervisor code. This being all âopen sourceâ you can find and read the code for yourself!
https://github.com/home-assistant/supervisor/blob/13783f0d4a58146c510f05b651ee4830e3f26c31/supervisor/api/proxy.py#L175C5-L196C1
async def _proxy_message(
self,
read_task: asyncio.Task,
target: web.WebSocketResponse | ClientWebSocketResponse,
) -> None:
"""Proxy a message from client to server or vice versa."""
if read_task.exception():
raise read_task.exception()
msg: WSMessage = read_task.result()
if msg.type == WSMsgType.TEXT:
return await target.send_str(msg.data)
if msg.type == WSMsgType.BINARY:
return await target.send_bytes(msg.data)
if msg.type == WSMsgType.CLOSE:
_LOGGER.debug("Received close message from WebSocket.")
return await target.close()
raise TypeError(
f"Cannot proxy websocket message of unsupported type: {msg.type}"
)
Proxy a message from client to server, or vice versa (ie from the NR WebSocket node server to the proxy, and from the proxy to HA WebSocket API, and then back from HA WebSocket API to the proxy, and from the proxy to the NR WebSocket node server).
So, as far as HA supervisor Proxy code is concerned, WebSocket message type can be text, binary, or close. Everything else throws an error - which is the one you are seeing.
Note. Close has just been added to the code in a recent PR to reduce the number of messages being seen when the client/server to the Proxy sends a âclose connectionâ message.
So, looking at another reference I found
https://docs.aiohttp.org/en/stable/websocket_utilities.html#aiohttp.WSMsgType
we get to see the WebSocket close messages, and also the WSMsgType
- CONTINUATION (user will never get the message with this type)
- TEXT
- BINARY
- PING
- PONG
- CLOSE
- CLOSE FRAME
- ERROR
Since the HA supervisor code deals with TEXT and BINARY, and now CLOSE, we have to assume that the unsupported type is one of
PING, PONG, CLOSE FRAME, ERROR
After a lot of digging I found the code for aiohttp websocket, including the IntEnum list.
https://docs.aiohttp.org/en/stable/_modules/aiohttp/http_websocket.html
class WSMsgType(IntEnum):
# websocket spec types
CONTINUATION = 0x0
TEXT = 0x1
BINARY = 0x2
PING = 0x9
PONG = 0xA
CLOSE = 0x8
# aiohttp specific types
CLOSING = 0x100
CLOSED = 0x101
ERROR = 0x102
text = TEXT
binary = BINARY
ping = PING
pong = PONG
close = CLOSE
closing = CLOSING
closed = CLOSED
error = ERROR
And there it is! Type 257 is âCLOSEDâ.
So the âerrorâ message in the logs is actually the proxy saying that the WebSocket is closed.
You have a server that is attempting to use the WebSocket, but it has closed. The attempted call probably re-opens the WebSocket, but in the mean time the HA Supervisor Proxy gets a message of type CLOSED and, not knowing what to do with it, throws an error.
Conclusion:
You have more than one Addon using the Proxy - Node-RED and VSCode. Since both open WebSocket connections with the proxy, perhaps one (VSCode) is closing the connection (timeout?) or erroring the proxy (forced close) and then in the mean time the Node-RED WebSocket nodes server is also using the Proxy, makes a legitimate call (or receives back a return from HA) and the WebSocket is CLOSED so the Proxy gets that message, which it cannot process.
I hope this has been useful to you.
I certainly learnt a great deal today.
Corrections and contributions anyone?