diff --git a/middleware/communication/__init__.py b/middleware/communication/__init__.py index 3df9e93..2597930 100644 --- a/middleware/communication/__init__.py +++ b/middleware/communication/__init__.py @@ -6,7 +6,7 @@ from typing import Any import socketio import json - +import websockets class StatusManager(Enum): ESTABLISHED = 1 # to indicate - connection is established between two parties @@ -16,10 +16,13 @@ class StatusManager(Enum): class ESP32Manager(): """Manages all the communication related to the ESP32. """ - # status maintainers -- to use in other modules + # status maintainer -- to use in other modules conn_status = StatusManager.TERMINATED + # websockets to use in another modules.. + cam_ws = None + data_ws = None # Get the helpers.. - from .esp32 import camera_client, collision_dist_fetcher, _connection_establisher, _connection_terminater # make the + from .esp32 import camera_client, collision_dist_fetcher, connection_establisher, _connection_terminater # make the def __init__(self, esp32IP: str, cam_port: int = 81, data_port: int = 82): # set it to the assigned IP address to ESP32 when connected to WiFi. @@ -35,9 +38,6 @@ def __init__(self, esp32IP: str, cam_port: int = 81, data_port: int = 82): self.cam_task = None self.data_task = None - self.cam_ws = None - self.data_ws = None - self.task = None self.router = APIRouter() @@ -48,20 +48,18 @@ async def read_root(): @self.router.get("/connection/{function:str}") async def connections_handler(function: str): if function == 'establish': - if self.cam_ws is None and self.data_ws is None: + if ESP32Manager.cam_ws is None and ESP32Manager.data_ws is None: task = asyncio.create_task( - self._connection_establisher()) + self.connection_establisher()) success = await task - ESP32Manager.conn_status = StatusManager.ESTABLISHED return {"message": "Connection to ESP32 established."} if success else {"message": "Failure in ESP32 connection establishment. Please check log."} else: return {"message": "Connections already established."} elif function == 'terminate': - if self.cam_ws is not None and self.data_ws is not None: + if ESP32Manager.cam_ws is not None and ESP32Manager.data_ws is not None: task = asyncio.create_task( self._connection_terminater()) success = await task - ESP32Manager.conn_status = StatusManager.TERMINATED return {"message": "ES32 connections terminated successfully.."} if success else {"message": "Failure in termination of ESP32 connections. Please check log."} else: return {"message": "Connections already terminated."} @@ -72,7 +70,7 @@ async def connections_handler(function: str): async def camera_feed_handler(function: str): if function == 'start': # check connection status.. - if self.cam_ws is None: + if ESP32Manager.cam_ws is None: return {'error': 'No connection established with ESP32. Please establish first.'} # when connection already established.. if self.cam_task is None: @@ -101,7 +99,7 @@ async def camera_feed_handler(function: str): async def collision_dist_handler(function: str): if function == 'start': # check connection status.. - if self.data_ws is None: + if ESP32Manager.data_ws is None: return {'error': 'No connection established with ESP32. Please establish first.'} # when connection already established.. if self.data_task is None: @@ -168,6 +166,10 @@ def __init__(self): self.collision_task = None self.camera_task = None + # to hold of speed and interval + self.speed=150 + self.interval=52 + @self.router.get('/web') def sayhello(): return 'Hello Web app' @@ -242,6 +244,53 @@ async def handle_camera_feed(sid, request): else: await self.sio.send(json.dumps({'error': 'collsion_feed - sent invalid request'})) + @self.sio.on('navigations') + async def handle_navigations(sid, request): + print(f"client-{sid} on navigations: {request}.") + from main import esp32_mngr + + if request == 'start': + await self.sio.send(json.dumps({'info': 'Server ready to take navigations.'})) + print("status: connection establishment: ", esp32_mngr.conn_status) + print("status: websocket status: ", ESP32Manager.data_ws) + elif request == 'stop': + await self.sio.send(json.dumps({'info': 'Server stopps to take navigations.'})) + + @self.sio.on('direction') + async def handle_direction(sid, request): + print(f"client-{sid} on direction: {request}.") + from main import esp32_mngr + print("status: connection establishment") + try: + if esp32_mngr.conn_status == StatusManager.ESTABLISHED: + if ESP32Manager.data_ws is not None: + print("Setup ready to send..") + control={ + 's':self.speed, + 'd':str(request), + 'i':self.interval + } + await ESP32Manager.data_ws.send(str(control)) + else: + print("couldn't send data to ESP32") + # handle connection close.. + except websockets.exceptions.ConnectionClosedError as e: + print("Oops..!! Connection closed. Auto-Reconnecting... Please wait..") + # try reconnecting.. first terminate explicitly ( to avoid multiple connection instances ) + task = asyncio.create_task(esp32_mngr._connection_terminater()) + success = await task + if success: + print("Connection cleaned up.!! Establishing fresh connection, please wait..!!") + task = asyncio.create_task(esp32_mngr.connection_establisher()) + success = await task + if success: + print("Connection re-established..!!") + else: + print("auto-reconnect failed. Please try manually.") + # to handle other exceptions.. + except Exception as e: + print("[EXCEPTION] exception occured: ", e) + # @self.sio.on("broadcast") # async def broadcast(sid, msg): # print(f"broadcast {msg}") diff --git a/middleware/communication/esp32.py b/middleware/communication/esp32.py index e57a098..e852195 100644 --- a/middleware/communication/esp32.py +++ b/middleware/communication/esp32.py @@ -8,10 +8,12 @@ # The below functions will become data members of ESP32Manager in __init__.py -async def _connection_establisher(self) -> bool: +async def connection_establisher(self) -> bool: + from . import ESP32Manager, StatusManager try: - self.cam_ws = await websockets.connect(self.camera_ws_url) - self.data_ws = await websockets.connect(self.data_txrx_url) + ESP32Manager.cam_ws = await websockets.connect(self.camera_ws_url) + ESP32Manager.data_ws = await websockets.connect(self.data_txrx_url) + ESP32Manager.conn_status = StatusManager.ESTABLISHED return True except Exception as e: logging.error( @@ -22,12 +24,14 @@ async def _connection_establisher(self) -> bool: async def _connection_terminater(self) -> bool: + from . import ESP32Manager, StatusManager try: # Close the connection - await self.cam_ws.close() - await self.data_ws.close() + await ESP32Manager.cam_ws.close() + await ESP32Manager.data_ws.close() + ESP32Manager.conn_status = StatusManager.TERMINATED # Empty the connection holders - self.cam_ws, self.data_ws = None, None + ESP32Manager.cam_ws, ESP32Manager.data_ws = None, None return True except Exception as e: logging.error( @@ -38,9 +42,10 @@ async def _connection_terminater(self) -> bool: async def camera_client(self, to_web: bool = False, ws: WebSocket = None, ) -> bool: + from . import ESP32Manager try: while True: - msg = await self.cam_ws.recv() + msg = await ESP32Manager.cam_ws.recv() # even try with msg.data npimg = np.array(bytearray(msg), dtype=np.uint8) img = cv2.imdecode(npimg, -1) @@ -65,10 +70,11 @@ async def camera_client(self, to_web: bool = False, ws: WebSocket = None, ) -> b async def collision_dist_fetcher(self, to_web: bool = False, ws: WebSocket = None, ) -> bool: counter=0 + from . import ESP32Manager try: print("------------------ Collision data fetcher ------------------------------") while True: - dist = int(await self.data_ws.recv()) + dist = int(await ESP32Manager.data_ws.recv()) print(f"Received message: {dist}") # if need send to web-client.. @@ -92,3 +98,4 @@ async def collision_dist_fetcher(self, to_web: bool = False, ws: WebSocket = Non print("[EXCEPTION] data fetching failed. Error: ", e) logging.error("Collision data fetching interrupted. Error: ", e) return False + diff --git a/middleware/main.py b/middleware/main.py index e14cc17..d95e94e 100644 --- a/middleware/main.py +++ b/middleware/main.py @@ -4,7 +4,7 @@ import uvicorn app = FastAPI() -esp32_mngr = ESP32Manager(esp32IP='192.168.184.165') +esp32_mngr = ESP32Manager(esp32IP='192.168.147.165') conn_mngr = ConnectionManager() web = WebManager() app.mount('/bar', web.socket_app) # mounting the socketio app to fastapi @@ -13,5 +13,5 @@ app.include_router(web.router) -# if __name__ == "__main__": -# uvicorn.run(app, host="127.0.0.2", port=8500) +if __name__ == "__main__": + uvicorn.run(app, host="127.0.0.2", port=8500) diff --git a/web/templates/manualMode.htm b/web/templates/manualMode.htm index e5eb840..19f0b92 100644 --- a/web/templates/manualMode.htm +++ b/web/templates/manualMode.htm @@ -189,7 +189,7 @@

Manual Mode

/********************************************* SOCKETIO Connection ******************************************************* */ - const socket = io.connect('http://127.0.0.1:8000/',{path:'/bar/foo', autoReconnect:true}); // url of the python server, later use namespace/room specific to mode + const socket = io.connect('http://127.0.0.2:8500/',{path:'/bar/foo', autoReconnect:true}); // url of the python server, later use namespace/room specific to mode // --------------------------------------------- general socketio handlers -------------------------------------------- socket.on('connect', function(){ @@ -292,14 +292,14 @@

Manual Mode

function listen_navigations(element){ if(in_navigation_mode && element.id in keymap) console.log(element.id); - // socket.emit('direction', keymap[key]) + socket.emit('direction', keymap[element.id]) } document.addEventListener('keydown', (event)=>{ // only when in navigation mode.. if(in_navigation_mode && event.code in keymap){ // capture only the arrow key presses.. console.log(event.code); - // socket.emit('direction', keymap[key]) + socket.emit('direction', keymap[event.code]) } })