@@ -98,6 +98,7 @@ typedef struct {
9898static wifi_radio_error_t wifi_status = WIFI_RADIO_ERROR_NONE ;
9999
100100static mdns_server_obj_t mdns ;
101+ static uint32_t web_api_port = 80 ;
101102
102103static socketpool_socketpool_obj_t pool ;
103104static socketpool_socket_obj_t listening ;
@@ -189,6 +190,9 @@ void supervisor_web_workflow_status(void) {
189190 }
190191
191192 mp_printf (& mp_plat_print , "%s" , _our_ip_encoded );
193+ if (web_api_port != 80 ) {
194+ mp_printf (& mp_plat_print , ":%d" , web_api_port );
195+ }
192196 // TODO: Use these unicode to show signal strength: ▂▄▆█
193197 }
194198 } else {
@@ -199,11 +203,6 @@ void supervisor_web_workflow_status(void) {
199203void supervisor_start_web_workflow (void ) {
200204 #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI
201205
202- if (common_hal_wifi_radio_get_enabled (& common_hal_wifi_radio_obj ) &&
203- wifi_radio_get_ipv4_address (& common_hal_wifi_radio_obj ) != 0 ) {
204- // Already started.
205- return ;
206- }
207206
208207 char ssid [33 ];
209208 char password [64 ];
@@ -218,15 +217,20 @@ void supervisor_start_web_workflow(void) {
218217 password_len <= 0 || (size_t )password_len >= sizeof (password )) {
219218 return ;
220219 }
221- common_hal_wifi_init (false);
222- common_hal_wifi_radio_set_enabled (& common_hal_wifi_radio_obj , true);
220+ if (!common_hal_wifi_radio_get_enabled (& common_hal_wifi_radio_obj )) {
221+ common_hal_wifi_init (false);
222+ common_hal_wifi_radio_set_enabled (& common_hal_wifi_radio_obj , true);
223+ }
223224
224225 // TODO: Do our own scan so that we can find the channel we want before calling connect.
225226 // Otherwise, connect will do a full slow scan to pick the best AP.
226227
227228 // NUL terminate the strings because dotenv doesn't.
228229 ssid [ssid_len ] = '\0' ;
229230 password [password_len ] = '\0' ;
231+ // We can all connect again because it will return early if we're already connected to the
232+ // network. If we are connected to a different network, then it will disconnect before
233+ // attempting to connect to the given network.
230234 wifi_status = common_hal_wifi_radio_connect (
231235 & common_hal_wifi_radio_obj , (uint8_t * )ssid , ssid_len , (uint8_t * )password , password_len ,
232236 0 , 0.1 , NULL , 0 );
@@ -236,21 +240,46 @@ void supervisor_start_web_workflow(void) {
236240 return ;
237241 }
238242
239- mdns_server_construct (& mdns , true);
240- common_hal_mdns_server_set_instance_name (& mdns , MICROPY_HW_BOARD_NAME );
241- common_hal_mdns_server_advertise_service (& mdns , "_circuitpython" , "_tcp" , 80 );
243+ char port_encoded [6 ];
244+ size_t port_len = 0 ;
245+ size_t new_port = web_api_port ;
246+ #if CIRCUITPY_DOTENV
247+ port_len = dotenv_get_key ("/.env" , "CIRCUITPY_WEB_API_PORT" , port_encoded , sizeof (port_encoded ) - 1 );
248+ #endif
249+ if (0 < port_len && port_len < sizeof (port_encoded )) {
250+ new_port = strtoul (port_encoded , NULL , 10 );
251+ }
252+
253+ bool first_start = mdns .base .type != & mdns_server_type ;
254+ bool port_changed = new_port != web_api_port ;
242255
243- pool .base .type = & socketpool_socketpool_type ;
244- common_hal_socketpool_socketpool_construct (& pool , & common_hal_wifi_radio_obj );
256+ if (first_start ) {
257+ ESP_LOGI (TAG , "Starting web workflow" );
258+ mdns_server_construct (& mdns , true);
259+ mdns .base .type = & mdns_server_type ;
260+ common_hal_mdns_server_set_instance_name (& mdns , MICROPY_HW_BOARD_NAME );
261+ pool .base .type = & socketpool_socketpool_type ;
262+ common_hal_socketpool_socketpool_construct (& pool , & common_hal_wifi_radio_obj );
245263
246- ESP_LOGI (TAG , "Starting web workflow" );
247- listening .base .type = & socketpool_socket_type ;
248- socketpool_socket (& pool , SOCKETPOOL_AF_INET , SOCKETPOOL_SOCK_STREAM , & listening );
249- common_hal_socketpool_socket_settimeout (& listening , 0 );
250- // Bind to any ip.
251- // TODO: Make this port .env configurable.
252- common_hal_socketpool_socket_bind (& listening , "" , 0 , 80 );
253- common_hal_socketpool_socket_listen (& listening , 1 );
264+ listening .base .type = & socketpool_socket_type ;
265+ active .base .type = & socketpool_socket_type ;
266+ active .num = -1 ;
267+ active .connected = false;
268+
269+ websocket_init ();
270+ }
271+ if (port_changed ) {
272+ common_hal_socketpool_socket_close (& listening );
273+ }
274+ if (first_start || port_changed ) {
275+ web_api_port = new_port ;
276+ common_hal_mdns_server_advertise_service (& mdns , "_circuitpython" , "_tcp" , web_api_port );
277+ socketpool_socket (& pool , SOCKETPOOL_AF_INET , SOCKETPOOL_SOCK_STREAM , & listening );
278+ common_hal_socketpool_socket_settimeout (& listening , 0 );
279+ // Bind to any ip.
280+ common_hal_socketpool_socket_bind (& listening , "" , 0 , web_api_port );
281+ common_hal_socketpool_socket_listen (& listening , 1 );
282+ }
254283
255284 mp_int_t api_password_len = dotenv_get_key ("/.env" , "CIRCUITPY_WEB_API_PASSWORD" , _api_password + 1 , sizeof (_api_password ) - 2 );
256285 if (api_password_len > 0 ) {
@@ -259,12 +288,6 @@ void supervisor_start_web_workflow(void) {
259288 _base64_in_place (_api_password , api_password_len + 1 , sizeof (_api_password ));
260289 }
261290
262- active .base .type = & socketpool_socket_type ;
263- active .num = -1 ;
264- active .connected = false;
265-
266- websocket_init ();
267-
268291 // TODO:
269292 // GET /cp/serial.txt
270293 // - Most recent 1k of serial output.
@@ -529,7 +552,13 @@ static void _reply_redirect(socketpool_socket_obj_t *socket, _request *request,
529552 _send_str (socket , "http" );
530553 }
531554
532- _send_strs (socket , "://" , hostname , ".local" , path , "\r\n" , NULL );
555+ _send_strs (socket , "://" , hostname , ".local" , NULL );
556+ if (web_api_port != 80 ) {
557+ char encoded_port [6 ];
558+ snprintf (encoded_port , sizeof (encoded_port ), "%d" , web_api_port );
559+ _send_strs (socket , ":" , encoded_port , NULL );
560+ }
561+ _send_strs (socket , path , "\r\n" , NULL );
533562 _cors_header (socket , request );
534563 _send_str (socket , "\r\n" );
535564}
@@ -647,7 +676,7 @@ static void _reply_with_devices_json(socketpool_socket_obj_t *socket, _request *
647676 }
648677 const char * hostname = common_hal_mdns_remoteservice_get_hostname (& found_devices [i ]);
649678 const char * instance_name = common_hal_mdns_remoteservice_get_instance_name (& found_devices [i ]);
650- char port_encoded [4 ];
679+ char port_encoded [6 ];
651680 int port = common_hal_mdns_remoteservice_get_port (& found_devices [i ]);
652681 snprintf (port_encoded , sizeof (port_encoded ), "%d" , port );
653682 char ip_encoded [4 * 4 ];
@@ -675,6 +704,8 @@ static void _reply_with_version_json(socketpool_socket_obj_t *socket, _request *
675704 char encoded_creation_id [11 ]; // 2 ** 32 is 10 decimal digits plus one for \0
676705 snprintf (encoded_creation_id , sizeof (encoded_creation_id ), "%u" , CIRCUITPY_CREATION_ID );
677706 const char * hostname = common_hal_mdns_server_get_hostname (& mdns );
707+ char encoded_port [6 ];
708+ snprintf (encoded_port , sizeof (encoded_port ), "%d" , web_api_port );
678709 _send_chunks (socket ,
679710 "{\"web_api_version\": 1, " ,
680711 "\"version\": \"" , MICROPY_GIT_TAG , "\", " ,
@@ -685,7 +716,7 @@ static void _reply_with_version_json(socketpool_socket_obj_t *socket, _request *
685716 "\"creator_id\": " , encoded_creator_id , ", " ,
686717 "\"creation_id\": " , encoded_creation_id , ", " ,
687718 "\"hostname\": \"" , hostname , "\", " ,
688- "\"port\": 80 , " ,
719+ "\"port\": " , encoded_port , " , " ,
689720 "\"ip\": \"" , _our_ip_encoded ,
690721 "\"}" , NULL );
691722 // Empty chunk signals the end of the response.
@@ -1173,7 +1204,9 @@ static void _process_request(socketpool_socket_obj_t *socket, _request *request)
11731204 request -> authenticated = memcmp (request -> header_value , prefix , strlen (prefix )) == 0 &&
11741205 strcmp (_api_password , request -> header_value + strlen (prefix )) == 0 ;
11751206 } else if (strcmp (request -> header_key , "Host" ) == 0 ) {
1176- request -> redirect = strcmp (request -> header_value , "circuitpython.local" ) == 0 ;
1207+ // Do a prefix check so that port is ignored.
1208+ const char * cp_local = "circuitpython.local" ;
1209+ request -> redirect = memcmp (request -> header_value , cp_local , strlen (cp_local )) == 0 ;
11771210 } else if (strcmp (request -> header_key , "Content-Length" ) == 0 ) {
11781211 request -> content_length = strtoul (request -> header_value , NULL , 10 );
11791212 } else if (strcmp (request -> header_key , "Expect" ) == 0 ) {
0 commit comments