|
|
@ -1,5 +1,6 @@ |
|
|
#fs imports |
|
|
#fs imports |
|
|
from fastapi import FastAPI, HTTPException |
|
|
from fastapi import FastAPI, HTTPException, WebSocket |
|
|
|
|
|
from fastapi.responses import HTMLResponse |
|
|
from uvicorn import run as UR |
|
|
from uvicorn import run as UR |
|
|
from contextlib import asynccontextmanager |
|
|
from contextlib import asynccontextmanager |
|
|
|
|
|
|
|
|
@ -28,13 +29,23 @@ class Servlet: |
|
|
message: List[Message] = [] |
|
|
message: List[Message] = [] |
|
|
msh_state = NOT_CONNECTED |
|
|
msh_state = NOT_CONNECTED |
|
|
|
|
|
|
|
|
|
|
|
ws_clients: List[WebSocket] = [] |
|
|
|
|
|
|
|
|
|
|
|
lstChange = { |
|
|
|
|
|
"channels": time(), |
|
|
|
|
|
"messages": time(), |
|
|
|
|
|
"nodes": time(), |
|
|
|
|
|
"state": time() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
def __init__(self, args): |
|
|
def __init__(self, args): |
|
|
self.app = FastAPI(lifespan=self.lifespan) |
|
|
self.app = FastAPI(lifespan=self.lifespan) |
|
|
self.args = args |
|
|
self.args = args |
|
|
if args.transport == "serial": |
|
|
if args.transport == "serial": |
|
|
self.transport = SerialTransport(port=args.serial_port, baudrate=args.serial_baudrate) |
|
|
self.transport = SerialTransport(port=args.serial_port, baudrate=args.serial_baudrate) |
|
|
self.device = MeshtDevice(self.transport) |
|
|
self.device = MeshtDevice(self.transport) |
|
|
self.buildRoutes() |
|
|
self.buildRoutes() |
|
|
|
|
|
self.buildWS() |
|
|
|
|
|
|
|
|
def run(self): |
|
|
def run(self): |
|
|
UR(self.app, host=self.args.host, port=self.args.port)#, reload = True)#todo |
|
|
UR(self.app, host=self.args.host, port=self.args.port)#, reload = True)#todo |
|
|
@ -46,57 +57,125 @@ class Servlet: |
|
|
yield |
|
|
yield |
|
|
print("server is shutdown now") |
|
|
print("server is shutdown now") |
|
|
|
|
|
|
|
|
|
|
|
async def ws_update(self, data): |
|
|
|
|
|
data.update({"type": WS_TYPE_NEW}) |
|
|
|
|
|
for client in self.ws_clients: |
|
|
|
|
|
try: |
|
|
|
|
|
await client.send_json(data) |
|
|
|
|
|
except: |
|
|
|
|
|
traceback.print_exc() |
|
|
|
|
|
|
|
|
async def meshWorker(self): |
|
|
async def meshWorker(self): |
|
|
run = True |
|
|
run = True |
|
|
while run: |
|
|
while run: |
|
|
try: |
|
|
try: |
|
|
await self.device.start() |
|
|
await self.device.start() |
|
|
self.msh_state = WAIT_CONFIG |
|
|
self.msh_state = WAIT_CONFIG |
|
|
|
|
|
self.lstChange["state"] = time() |
|
|
|
|
|
await self.ws_update({"event": WS_EVENT_STATE, "data": self.msh_state}) |
|
|
init_data = await _wait_for_config_complete(self.device) |
|
|
init_data = await _wait_for_config_complete(self.device) |
|
|
for from_radio in init_data:#todo check dubs |
|
|
for from_radio in init_data:#todo check dubs |
|
|
self.meshCollector(from_radio) |
|
|
await self.meshCollector(from_radio) |
|
|
|
|
|
|
|
|
|
|
|
self.msh_state = AVAILABLE |
|
|
|
|
|
self.lstChange["state"] = time() |
|
|
|
|
|
await self.ws_update({"event": WS_EVENT_STATE, "data": self.msh_state}) |
|
|
|
|
|
await self.ws_update({"event": WS_EVENT_MYID, "data": self.device.my_node_id}) |
|
|
|
|
|
|
|
|
while True: |
|
|
while True: |
|
|
self.msh_state = AVAILABLE |
|
|
|
|
|
self.pulse = time() |
|
|
self.pulse = time() |
|
|
from_radio, _ = await self.device.recv() |
|
|
from_radio, _ = await self.device.recv() |
|
|
self.meshCollector(from_radio) |
|
|
await self.meshCollector(from_radio) |
|
|
|
|
|
|
|
|
except asyncio.exceptions.CancelledError: |
|
|
except asyncio.exceptions.CancelledError: |
|
|
print("Web close") |
|
|
print("Web close") |
|
|
run = False |
|
|
run = False |
|
|
pass |
|
|
pass |
|
|
except: |
|
|
except: |
|
|
self.msh_state = ERR |
|
|
self.msh_state = ERR |
|
|
|
|
|
await self.ws_update({"event": WS_EVENT_STATE, "data": self.msh_state}) |
|
|
|
|
|
self.lstChange["state"] = time() |
|
|
print("Mesh worker is has error, reconnect to mesh device after seconds...") |
|
|
print("Mesh worker is has error, reconnect to mesh device after seconds...") |
|
|
traceback.print_exc() |
|
|
traceback.print_exc() |
|
|
self.msh_state = RECONNECT |
|
|
self.msh_state = RECONNECT |
|
|
|
|
|
await self.ws_update({"event": WS_EVENT_STATE, "data": self.msh_state}) |
|
|
|
|
|
self.lstChange["state"] = time() |
|
|
await asyncio.sleep(1) |
|
|
await asyncio.sleep(1) |
|
|
finally: |
|
|
finally: |
|
|
await self.device.close() |
|
|
await self.device.close() |
|
|
|
|
|
|
|
|
def meshCollector(self, from_radio): |
|
|
async def meshCollector(self, from_radio): |
|
|
try: |
|
|
try: |
|
|
print(from_radio) |
|
|
print(from_radio) |
|
|
if Channel.isThis(from_radio): |
|
|
if Channel.isThis(from_radio): |
|
|
print("Found channel packet") |
|
|
print("Found channel packet") |
|
|
channel = Channel(from_radio) |
|
|
channel = Channel(from_radio) |
|
|
self.channels[channel.index] = channel |
|
|
self.channels[channel.index] = channel |
|
|
|
|
|
await self.ws_update({"type":WS_TYPE_NEW, "event": WS_EVENT_CHANNEL, "data": channel.__dict__}) |
|
|
|
|
|
self.lstChange["channels"] = time() |
|
|
return |
|
|
return |
|
|
|
|
|
|
|
|
if Node.isThis(from_radio): |
|
|
if Node.isThis(from_radio): |
|
|
print("Found node packet") |
|
|
print("Found node packet") |
|
|
node = Node(from_radio) |
|
|
node = Node(from_radio) |
|
|
self.nodes[node.num] = node |
|
|
self.nodes[node.num] = node |
|
|
|
|
|
await self.ws_update({"type":WS_TYPE_NEW, "event": WS_EVENT_NODE, "data": {"id": node.num, "name": str(node)}}) |
|
|
|
|
|
self.lstChange["nodes"] = time() |
|
|
return |
|
|
return |
|
|
|
|
|
|
|
|
if Message.isThis(from_radio): |
|
|
if Message.isThis(from_radio): |
|
|
print("Found message packet") |
|
|
print("Found message packet") |
|
|
self.message.append(Message(from_radio)) |
|
|
msg = Message(from_radio) |
|
|
|
|
|
self.message.append(msg) |
|
|
|
|
|
await self.ws_update({"type":WS_TYPE_NEW, "event": WS_EVENT_MESSAGE, "data": msg.__dict__}) |
|
|
|
|
|
self.lstChange["messages"] = time() |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
except: |
|
|
except: |
|
|
print("cannot parse packet") |
|
|
print("cannot parse packet") |
|
|
traceback.print_exc() |
|
|
traceback.print_exc() |
|
|
|
|
|
|
|
|
|
|
|
def buildWS(self): |
|
|
|
|
|
#from json import dumps, loads |
|
|
|
|
|
from mesh_ws_debug import page |
|
|
|
|
|
|
|
|
|
|
|
@self.app.get("/mesh/wsdebug", response_class=HTMLResponse) |
|
|
|
|
|
async def wsdebug(): |
|
|
|
|
|
return page |
|
|
|
|
|
|
|
|
|
|
|
async def ws_hello(websocket: WebSocket): |
|
|
|
|
|
print("send hello") |
|
|
|
|
|
try: |
|
|
|
|
|
await websocket.send_json({"type":WS_TYPE_INIT, "event": WS_EVENT_MYID, "data": self.device.nid}) |
|
|
|
|
|
#await websocket.send_json({"type":WS_TYPE_INIT, "event": WS_EVENT_MYNODE, "data": self.nodes.get(self.device.nid).__dict__ if self.device.nid in self.nodes else None}) |
|
|
|
|
|
await websocket.send_json({"type":WS_TYPE_INIT, "event": WS_EVENT_CHANNEL, "data": [channel.__dict__ for channel in self.channels.values()]}) |
|
|
|
|
|
await websocket.send_json({"type":WS_TYPE_INIT, "event": WS_EVENT_STATE, "data": self.msh_state}) |
|
|
|
|
|
await websocket.send_json({"type":WS_TYPE_INIT, "event": WS_EVENT_NODE, "data": [{"id": node.num, "name": str(node)} for node in self.nodes.values()]}) |
|
|
|
|
|
await websocket.send_json({"type":WS_TYPE_INIT, "event": WS_EVENT_MESSAGE, "data": [message.__dict__ for message in self.message]}) |
|
|
|
|
|
except: |
|
|
|
|
|
traceback.print_exc() |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
@self.app.websocket("/mesh/ws") |
|
|
|
|
|
async def ws_endpoint(websocket: WebSocket): |
|
|
|
|
|
await websocket.accept() |
|
|
|
|
|
self.ws_clients.append(websocket) |
|
|
|
|
|
#грузим фуру кала |
|
|
|
|
|
try: |
|
|
|
|
|
await ws_hello(websocket) |
|
|
|
|
|
while True: |
|
|
|
|
|
msg = await websocket.receive_json() |
|
|
|
|
|
print(msg) |
|
|
|
|
|
except: |
|
|
|
|
|
traceback.print_exc() |
|
|
|
|
|
pass |
|
|
|
|
|
finally: |
|
|
|
|
|
self.ws_clients.remove(websocket) |
|
|
|
|
|
try: |
|
|
|
|
|
await websocket.close() |
|
|
|
|
|
except: |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
def buildRoutes(self): |
|
|
def buildRoutes(self): |
|
|
route = "/mesh/api" |
|
|
route = "/mesh/api" |
|
|
|
|
|
|
|
|
|