forked from iarv/meshtastic-bridge
update
This commit is contained in:
24
.github/workflows/main.yaml
vendored
Normal file
24
.github/workflows/main.yaml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build, push
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout master
|
||||
uses: actions/checkout@main
|
||||
|
||||
- name: Build container
|
||||
run: docker build --tag gwhittington/meshtastic-bridge:latest
|
||||
|
||||
- name: Log in to Container Registry with short-lived credentials
|
||||
run: docker login --username=gwhittington --password "${{secrets.DOCKER_HUB}}"
|
||||
|
||||
- name: Push image to Container Registry
|
||||
run: docker push gwhittington/meshtastic-bridge:latest
|
||||
|
||||
- name: Logout from Container Registry
|
||||
run: docker logout
|
||||
124
main.py
124
main.py
@@ -7,105 +7,61 @@ import time
|
||||
from meshtastic import portnums_pb2, mesh_pb2
|
||||
from meshtastic.__init__ import LOCAL_ADDR, BROADCAST_NUM, BROADCAST_ADDR
|
||||
import os
|
||||
|
||||
from plugins import plugins
|
||||
from pubsub import pub
|
||||
import yaml
|
||||
from yaml.loader import SafeLoader
|
||||
|
||||
local_interface = None
|
||||
remote_interface = None
|
||||
bridge_logger = logging.getLogger(name="meshtastic.bridge")
|
||||
logger = logging.getLogger(name="meshtastic.bridge")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
BRIDGE_LOG = os.environ['BRIDGE_LOG'] if 'BRIDGE_LOG' in os.environ else 'INFO'
|
||||
NODE_LOG = os.environ['NODE_LOG'] if 'NODE_LOG' in os.environ else 'INFO'
|
||||
with open("config.yaml") as f:
|
||||
bridge_config = yaml.load(f, Loader=SafeLoader)
|
||||
|
||||
if BRIDGE_LOG == 'DEBUG':
|
||||
bridge_logger.setLevel(logging.DEBUG)
|
||||
elif BRIDGE_LOG == 'INFO':
|
||||
bridge_logger.setLevel(logging.INFO)
|
||||
devices = {}
|
||||
|
||||
if NODE_LOG == 'DEBUG':
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
elif NODE_LOG == 'INFO':
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
for device in bridge_config["devices"]:
|
||||
if "serial" in device:
|
||||
devices[device["name"]] = meshtastic.serial_interface.SerialInterface(
|
||||
devPath=device["serial"]
|
||||
)
|
||||
elif "tcp" in device:
|
||||
devices[device["name"]] = meshtastic.tcp_interface.TCPInterface(
|
||||
hostname=device["tcp"]
|
||||
)
|
||||
else:
|
||||
devices[device["name"]] = meshtastic.serial_interface.SerialInterface()
|
||||
|
||||
local_node_addr = os.environ['LOCAL_NODE_ADDR'] if 'LOCAL_NODE_ADDR' in os.environ else None
|
||||
remote_node_addr = os.environ['REMOTE_NODE_ADDR']
|
||||
|
||||
if local_node_addr and '/' in local_node_addr:
|
||||
bridge_logger.debug(f"Connecting to local node via serial port: {local_node_addr} ...")
|
||||
local_interface = meshtastic.serial_interface.SerialInterface(devPath=local_node_addr)
|
||||
elif local_node_addr:
|
||||
bridge_logger.debug(f"Connecting to local node via TCP: {local_node_addr} ...")
|
||||
local_interface = meshtastic.tcp_interface.TCPInterface(hostname=local_node_addr)
|
||||
else:
|
||||
bridge_logger.debug(f"Connecting to local node via serial port ...")
|
||||
local_interface = meshtastic.serial_interface.SerialInterface()
|
||||
def onReceive(packet, interface): # called when a packet arrives
|
||||
for pipeline in bridge_config["pipelines"]:
|
||||
|
||||
bridge_logger.info(f"Connected to local node")
|
||||
pipeline_packet = packet
|
||||
|
||||
bridge_logger.debug(f"Connecting to remote node via TCP: {remote_node_addr} ...")
|
||||
remote_interface = meshtastic.tcp_interface.TCPInterface(hostname=remote_node_addr)
|
||||
bridge_logger.info(f"Connected to remote node")
|
||||
ourNode = local_interface.getNode('^local')
|
||||
for key, config in pipeline.items():
|
||||
|
||||
SUPPORTED_MESSAGES = [
|
||||
'POSITION_APP',
|
||||
'TEXT_MESSAGE_APP'
|
||||
]
|
||||
if not pipeline_packet:
|
||||
continue
|
||||
|
||||
SUPPORTED_BRIDGE_DISTANCE_KM = int(os.environ['BRIDGE_DISTANCE_KM']) if 'BRIDGE_DISTANCE_KM' in os.environ else 0
|
||||
CHANNEL_INDEX = 0
|
||||
NODE_PROXY = {BROADCAST_ADDR: BROADCAST_ADDR}
|
||||
if key not in plugins:
|
||||
logger.error(f"No such plugin: {key}. Skipping")
|
||||
continue
|
||||
|
||||
def onReceive(packet, interface): # called when a packet arrives
|
||||
p = plugins[key]
|
||||
p.configure(devices, config)
|
||||
|
||||
bridge_logger.debug(f"Packet received: {packet}")
|
||||
pipeline_packet = p.do_action(pipeline_packet)
|
||||
|
||||
if packet['decoded']['portnum'] not in SUPPORTED_MESSAGES:
|
||||
bridge_logger.debug(f"Dropping {packet['decoded']['portnum']}")
|
||||
return
|
||||
|
||||
message_source_position = None
|
||||
current_local_position = None
|
||||
def onConnection(
|
||||
interface, topic=pub.AUTO_TOPIC
|
||||
): # called when we (re)connect to the radio
|
||||
nodeInfo = interface.getMyNodeInfo()
|
||||
|
||||
if 'position' in packet['decoded']:
|
||||
logger.info(
|
||||
f"Connected to node: userId={nodeInfo['user']['id']} hwModel={nodeInfo['user']['hwModel']}"
|
||||
)
|
||||
|
||||
if 'latitude' in packet['decoded']['position'] and 'longitude' in packet['decoded']['position']:
|
||||
message_source_position = (packet['decoded']['position']['latitude'], packet['decoded']['position']['longitude'])
|
||||
|
||||
nodeInfo = local_interface.getMyNodeInfo()
|
||||
current_local_position = (nodeInfo['position']['latitude'], nodeInfo['position']['longitude'])
|
||||
|
||||
if message_source_position and current_local_position:
|
||||
|
||||
distance_km = haversine(message_source_position, current_local_position)
|
||||
|
||||
# message originates from too far a distance
|
||||
if SUPPORTED_BRIDGE_DISTANCE_KM > 0 and distance_km > SUPPORTED_BRIDGE_DISTANCE_KM:
|
||||
bridge_logger.debug(f"Packet from too far: {distance_km} > {SUPPORTED_BRIDGE_DISTANCE_KM}")
|
||||
return
|
||||
|
||||
if 'to' in packet:
|
||||
# Broadcast messages or specific
|
||||
if packet['to'] in NODE_PROXY:
|
||||
destinationId = NODE_PROXY[packet['to']]
|
||||
else:
|
||||
destinationId = packet['to']
|
||||
|
||||
channelIndex = CHANNEL_INDEX
|
||||
|
||||
meshPacket = mesh_pb2.MeshPacket()
|
||||
meshPacket.channel = channelIndex
|
||||
meshPacket.decoded.payload = packet['decoded']['payload']
|
||||
meshPacket.decoded.portnum = packet['decoded']['portnum']
|
||||
meshPacket.decoded.want_response = False
|
||||
meshPacket.id = remote_interface._generatePacketId()
|
||||
|
||||
if destinationId == BROADCAST_ADDR or destinationId in remote_interface.nodes:
|
||||
bridge_logger.debug(f"Sending packet {meshPacket.id} to TCP server")
|
||||
remote_interface._sendPacket(meshPacket=meshPacket, destinationId=destinationId)
|
||||
|
||||
def onConnection(interface, topic=pub.AUTO_TOPIC): # called when we (re)connect to the radio
|
||||
print("Connected.")
|
||||
|
||||
pub.subscribe(onReceive, "meshtastic.receive")
|
||||
pub.subscribe(onConnection, "meshtastic.connection.established")
|
||||
@@ -113,5 +69,5 @@ pub.subscribe(onConnection, "meshtastic.connection.established")
|
||||
while True:
|
||||
time.sleep(1000)
|
||||
|
||||
local_interface.close()
|
||||
remote_interface.close()
|
||||
for device, instance in devices.items():
|
||||
instance.close()
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
haversine
|
||||
meshtastic
|
||||
requests
|
||||
pyyaml
|
||||
|
||||
Reference in New Issue
Block a user