Skip to content

Commit

Permalink
⚗️ #2 Could able to send directions to ESP32
Browse files Browse the repository at this point in the history
  • Loading branch information
Balaji-Ganesh committed Jun 18, 2023
1 parent 2bb2e50 commit 2ee7b4a
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 27 deletions.
75 changes: 62 additions & 13 deletions middleware/communication/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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()

Expand All @@ -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."}
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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}")
Expand Down
23 changes: 15 additions & 8 deletions middleware/communication/esp32.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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)
Expand All @@ -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..
Expand All @@ -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

6 changes: 3 additions & 3 deletions middleware/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
6 changes: 3 additions & 3 deletions web/templates/manualMode.htm
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ <h1>Manual Mode</h1>

/********************************************* 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(){
Expand Down Expand Up @@ -292,14 +292,14 @@ <h1>Manual Mode</h1>
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])
}
})
</script>
Expand Down

0 comments on commit 2ee7b4a

Please sign in to comment.