gsd 4 months ago
parent
commit
8b446f9a4c
  1. 8
      botExtensions/PingPong.py
  2. 8
      botExtensions/SignalTest.py
  3. 108
      botManager.py
  4. 12
      logger.py
  5. 2
      mesht_device.py
  6. 54
      service.py
  7. 10
      todo

8
botExtensions/PingPong.py

@ -0,0 +1,8 @@
class BotExtension:
def __init__(self, bm):
self.bm = bm
self.name = "Base ping pong"
self.trigger = ['ping', 'p']
def __call__(self, msg, text):
return "P0N9"

8
botExtensions/SignalTest.py

@ -0,0 +1,8 @@
class BotExtension:
def __init__(self, bm):
self.bm = bm
self.name = "Signal check"
self.trigger = ['signal', 's']
def __call__(self, msg, text):
return f"snr: {msg.packet.get('rx_snr', 'unk')} dB\nrssi: {msg.packet.get('rx_rssi', 'unk')} dB\nhops: {msg.packet.get('hop_start', 0) - msg.packet.get('hop_limit', 0)}"

108
botManager.py

@ -0,0 +1,108 @@
from mesht_models import PUB_CH
from mesht_device import PORTNUMS
import sys, os
from logger import logger
class MeshtasticMessage:
def __init__(self, from_radio, myId):
self.myId = myId
self.packet = from_radio.get("packet", {})
self.decoded = self.packet.get("decoded", {})
if not self.decoded:
return
def getFrom(self):
return self.packet["from"]
def getTo(self):
return self.packet["to"]
def isDm(self):
return self.packet["to"] == self.myId
def isPublic(self):
return self.packet["to"] == PUB_CH
def getText(self):
try:
return self.decoded["payload"].decode()
except:
return ""
def __str__(self):
return f"[{self.getFrom()}] -> [{self.getTo()}] [{'PUB' if self.isPublic() else 'DM'}] > {self.getText()}"
class BotManager:
prefix = "/?"
def __init__(self, core):
#delaem workdir esli ne delali
os.chdir(os.path.dirname(os.path.abspath(__file__)))
self.coreService = core
self.exts = {}
self.extensionLoader(["botExtensions"])
def extensionLoader(self, search_paths = []):
if type(search_paths) == str:
search_paths = [search_paths]
for path in search_paths:
logger.info(f"Try found extensions in {path}")
if not os.path.exists(path) or not os.path.isdir(path):
logger.info(f"Directory is not exists or not directory, skip")
continue
sys.path.insert(0, path)
for extension in os.listdir(path):
extension, ext = os.path.splitext(extension)
if ext != ".py":
continue
logger.info(f"Found ext: {extension}")
self.exts[f"{path}/{extension}"] = __import__(extension).BotExtension(self)
sys.path.pop(0)
logger.info(f"Found {self.exts.keys().__len__()} extension")
async def handleMessage(self, from_radio):
if not self.isTextMessage(from_radio):
return
if not self.isToMe(from_radio):
return
msg = MeshtasticMessage(from_radio, self.coreService.device.my_node_id_dec)
logger.info(msg)
if msg.isPublic() and msg.getText().startswith(self.prefix):
await self.processMessage(msg, msg.getText()[len(self.prefix):])#remove prefix
elif msg.isDm():
await self.processMessage(msg, msg.getText())
else:
#nichego ne delaem
pass
async def processMessage(self, msg: MeshtasticMessage, msgText: str):
if not msgText:
return
for path, ext in self.exts.items():
if msgText.split()[0].lower() in ext.trigger:
response = ext(msg, msgText)
return await self.reply(msg, response)
async def reply(self, msg: MeshtasticMessage, text: str):
if msg.isDm():
return await self.coreService.device.sendMsgToDM(text, msg.getFrom())
elif msg.isPublic():
return await self.coreService.device.sendMsgToChannel(text)
else:
return
def isTextMessage(self, from_radio):
return from_radio and from_radio.get("packet", {}).get("decoded", {}).get("portnum", 0) == 1
def isToMe(self, from_radio):
return self.coreService.device.my_node_id_dec == from_radio.get("packet", {}).get("to", 0) or from_radio.get("packet", {}).get("to", 0) == PUB_CH

12
logger.py

@ -0,0 +1,12 @@
class logger:
@staticmethod
def info(t):
print("[INFO]", t)
@staticmethod
def error(t):
print("[ERROR]", t)
@staticmethod
def debug(t):
print("[DEBUG]", t)

2
mesht_device.py

@ -201,6 +201,7 @@ class MeshtDevice:
self.lora_config = None
# Track local node number from MyNodeInfo
self.my_node_id = "00000000"
self.my_node_id_dec = 0
self.nid = None
async def start(self):
@ -261,6 +262,7 @@ class MeshtDevice:
return
self.nid = mi.get("my_node_num", 0)
self.my_node_id_dec = int(self.nid)
self.my_node_id = f"{self.nid & 0xFFFFFFFF:08x}"
def _maybe_store_channel(self, from_radio):

54
service.py

@ -5,19 +5,9 @@ import sys
import asyncio
from time import time
from typing import List, Dict
import copy
class logger:
@staticmethod
def info(t):
print("[INFO]", t)
@staticmethod
def error(t):
print("[ERROR]", t)
@staticmethod
def debug(t):
print("[DEBUG]", t)
from logger import logger
#mesh
from mesht_device import MeshtDevice
@ -32,6 +22,9 @@ from contextlib import asynccontextmanager
#mongo
from pymongo import AsyncMongoClient
#other
from botManager import BotManager
def isInt(any):
try:
int(any)
@ -73,7 +66,7 @@ class MeshListener(MeshArgsParse):
self.meshState = AVAILABLE
while True:
from_radio, _ = await self.device.recv()
logger.debug(from_radio)
#logger.debug(from_radio)
await queue.put(from_radio)
except asyncio.exceptions.CancelledError:
logger.info("Kill mesh device")
@ -119,7 +112,7 @@ class MongoDriver(MeshArgsParse):
self.dbStore = self.dbClient[self.args.mongo_db]
#self.dbCollection = self.dbStore.from_radio
async def dbSaveRadio(self, from_radio):
async def dbSaveRadio(self, new_from_radio):
'''try:
anyJson = from_radio["packet"]
except:
@ -128,6 +121,7 @@ class MongoDriver(MeshArgsParse):
#logger.debug(from_radio)
#logger.debug(len(list(from_radio.keys())))
from_radio = copy.deepcopy(new_from_radio)
for k, v in from_radio.items():
if type(v) != dict:
v = {"data": v, "ts": time()}
@ -149,7 +143,7 @@ class MongoDriver(MeshArgsParse):
await self.dbStore[k].insert_one(v)
async def dbQueueListener(self, queue: asyncio.Queue):
'''async def dbQueueListener(self, queue: asyncio.Queue):
logger.info("Start db queue listener")
run = True
while run:
@ -163,7 +157,7 @@ class MongoDriver(MeshArgsParse):
logger.info("Kill db listener")
run = False
except:
traceback.print_exc()
traceback.print_exc()'''
class MeshCenter(MeshListener, MeshApi, MongoDriver, MeshArgsParse):
queue: asyncio.Queue = asyncio.Queue()
@ -174,15 +168,37 @@ class MeshCenter(MeshListener, MeshApi, MongoDriver, MeshArgsParse):
MeshApi.__init__(self, args)
MongoDriver.__init__(self, args)
self.buildBackgroundTasks()
self.bot = BotManager(self)
async def queueHandler(self):
logger.info("Start queue handler")
run = True
while run:
try:
from_radio = await self.queue.get()
if from_radio:
yield from_radio
except asyncio.exceptions.CancelledError:
run = False
except:
traceback.print_exc()
def buildBackgroundTasks(self):
#input queue
async def mL():
await self.meshWorker(self.queue)
self.tasks.append(mL)
async def dbL():
await self.dbQueueListener(self.queue)
self.tasks.append(dbL)
#output
async def handlerTask():
async for from_radio in self.queueHandler():
#logger.debug(from_radio)
asyncio.create_task(self.dbSaveRadio(from_radio))
asyncio.create_task(self.bot.handleMessage(from_radio))
self.tasks.append(handlerTask)
if __name__ == "__main__":
parser = argparse.ArgumentParser()

10
todo

@ -0,0 +1,10 @@
Viewing Collection: node_info
график изменения количество snr и хопов относително времени
график по пакетам от клиентов и также снр ссри
топ по количеству сранья протобафами
мб можно развлечься с триангуляцией
hop_start == hop_limit - директы
Loading…
Cancel
Save