8
8
from homeassistant .config_entries import ConfigEntry
9
9
from homeassistant .const import STATE_OK
10
10
from homeassistant .core import HomeAssistant
11
- from websockets import Subprotocol
12
- import websockets .protocol
11
+ from websockets import Subprotocol , NegotiationError
13
12
import websockets .server
13
+ from websockets .asyncio .server import ServerConnection
14
14
15
15
from .chargepoint import CentralSystemSettings
16
16
from .ocppv16 import ChargePoint as ChargePointv16
21
21
CONF_CSID ,
22
22
CONF_HOST ,
23
23
CONF_PORT ,
24
- CONF_SKIP_SCHEMA_VALIDATION ,
25
24
CONF_SSL ,
26
25
CONF_SSL_CERTFILE_PATH ,
27
26
CONF_SSL_KEYFILE_PATH ,
34
33
DEFAULT_CSID ,
35
34
DEFAULT_HOST ,
36
35
DEFAULT_PORT ,
37
- DEFAULT_SKIP_SCHEMA_VALIDATION ,
38
36
DEFAULT_SSL ,
39
37
DEFAULT_SSL_CERTFILE_PATH ,
40
38
DEFAULT_SSL_KEYFILE_PATH ,
@@ -112,10 +110,11 @@ async def create(hass: HomeAssistant, entry: ConfigEntry):
112
110
"""Create instance and start listening for OCPP connections on given port."""
113
111
self = CentralSystem (hass , entry )
114
112
115
- server = await websockets .server . serve (
113
+ server = await websockets .serve (
116
114
self .on_connect ,
117
115
self .host ,
118
116
self .port ,
117
+ select_subprotocol = self .select_subprotocol ,
119
118
subprotocols = self .subprotocols ,
120
119
ping_interval = None , # ping interval is not used here, because we send pings mamually in ChargePoint.monitor_connection()
121
120
ping_timeout = None ,
@@ -125,27 +124,38 @@ async def create(hass: HomeAssistant, entry: ConfigEntry):
125
124
self ._server = server
126
125
return self
127
126
128
- async def on_connect (self , websocket : websockets .server .WebSocketServerProtocol ):
127
+ def select_subprotocol (
128
+ self , connection : ServerConnection , subprotocols
129
+ ) -> Subprotocol | None :
130
+ """Override default subprotocol selection."""
131
+
132
+ # Server offers at least one subprotocol but client doesn't offer any.
133
+ # Default to None
134
+ if not subprotocols :
135
+ return None
136
+
137
+ # Server and client both offer subprotocols. Look for a shared one.
138
+ proposed_subprotocols = set (subprotocols )
139
+ for subprotocol in proposed_subprotocols :
140
+ if subprotocol in self .subprotocols :
141
+ return subprotocol
142
+
143
+ # No common subprotocol was found.
144
+ raise NegotiationError (
145
+ "invalid subprotocol; expected one of " + ", " .join (self .subprotocols )
146
+ )
147
+
148
+ async def on_connect (self , websocket : ServerConnection ):
129
149
"""Request handler executed for every new OCPP connection."""
130
- if self . config . get ( CONF_SKIP_SCHEMA_VALIDATION , DEFAULT_SKIP_SCHEMA_VALIDATION ) :
131
- _LOGGER .warning ( "Skipping websocket subprotocol validation" )
150
+ if websocket . subprotocol is not None :
151
+ _LOGGER .info ( "Websocket Subprotocol matched: %s" , websocket . subprotocol )
132
152
else :
133
- if websocket .subprotocol is not None :
134
- _LOGGER .info ("Websocket Subprotocol matched: %s" , websocket .subprotocol )
135
- else :
136
- # In the websockets lib if no subprotocols are supported by the
137
- # client and the server, it proceeds without a subprotocol,
138
- # so we have to manually close the connection.
139
- _LOGGER .warning (
140
- "Protocols mismatched | expected Subprotocols: %s,"
141
- " but client supports %s | Closing connection" ,
142
- websocket .available_subprotocols ,
143
- websocket .request_headers .get ("Sec-WebSocket-Protocol" , "" ),
144
- )
145
- return await websocket .close ()
153
+ _LOGGER .info (
154
+ "Websocket Subprotocol not provided by charger: default to ocpp1.6"
155
+ )
146
156
147
- _LOGGER .info (f"Charger websocket path={ websocket .path } " )
148
- cp_id = websocket .path .strip ("/" )
157
+ _LOGGER .info (f"Charger websocket path={ websocket .request . path } " )
158
+ cp_id = websocket .request . path .strip ("/" )
149
159
cp_id = cp_id [cp_id .rfind ("/" ) + 1 :]
150
160
if self .settings .cpid not in self .charge_points :
151
161
_LOGGER .info (f"Charger { cp_id } connected to { self .host } :{ self .port } ." )
0 commit comments