Skip to content

Commit 9284a84

Browse files
committed
feat(waypoint): Waypoint creation/deletion
Add methods to send (create or move), delete waypoint. Add an example script to create, move, delete waypoint.
1 parent 7c89e23 commit 9284a84

2 files changed

Lines changed: 150 additions & 0 deletions

File tree

examples/waypoint.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Program to create and delete waypoint
2+
To run:
3+
python3 examples/waypoint.py --port /dev/ttyUSB0 create 45 test the_desc_2 '2024-12-18T23:05:23' 48.74 7.35
4+
python examples/waypoint.py delete 45
5+
"""
6+
7+
import argparse
8+
import datetime
9+
import sys
10+
import time
11+
12+
import meshtastic
13+
import meshtastic.serial_interface
14+
15+
parser = argparse.ArgumentParser(
16+
prog='waypoint',
17+
description='Create and delete Meshtastic waypoint')
18+
parser.add_argument('--port', default=None)
19+
parser.add_argument('--debug', default=False, action='store_true')
20+
21+
subparsers = parser.add_subparsers(dest='cmd')
22+
parser_delete = subparsers.add_parser('delete', help='Delete a waypoint')
23+
parser_delete.add_argument('id', help="id of the waypoint")
24+
25+
parser_create = subparsers.add_parser('create', help='Create a new waypoint')
26+
parser_create.add_argument('id', help="id of the waypoint")
27+
parser_create.add_argument('name', help="name of the waypoint")
28+
parser_create.add_argument('description', help="description of the waypoint")
29+
parser_create.add_argument('expire', help="expiration date of the waypoint as interpreted by datetime.fromisoformat")
30+
parser_create.add_argument('latitude', help="latitude of the waypoint")
31+
parser_create.add_argument('longitude', help="longitude of the waypoint")
32+
33+
args = parser.parse_args()
34+
print(args)
35+
36+
# By default will try to find a meshtastic device,
37+
# otherwise provide a device path like /dev/ttyUSB0
38+
if args.debug:
39+
d = sys.stderr
40+
else:
41+
d = None
42+
with meshtastic.serial_interface.SerialInterface(args.port, debugOut=d) as iface:
43+
if args.cmd == 'create':
44+
p = iface.sendWaypoint(
45+
id=int(args.id),
46+
name=args.name,
47+
description=args.description,
48+
expire=int(datetime.datetime.fromisoformat(args.expire).timestamp()),
49+
latitude=float(args.latitude),
50+
longitude=float(args.longitude),
51+
)
52+
else:
53+
p = iface.deleteWaypoint(int(args.id))
54+
print(p)
55+
56+
# iface.close()

meshtastic/mesh_interface.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import collections
66
import json
77
import logging
8+
import math
89
import random
10+
import secrets
911
import sys
1012
import threading
1113
import time
@@ -700,6 +702,98 @@ def onResponseTelemetry(self, p: dict):
700702
"No response from node. At least firmware 2.1.22 is required on the destination node."
701703
)
702704

705+
def sendWaypoint(
706+
self,
707+
name,
708+
description,
709+
expire: int,
710+
id: Optional[int] = None,
711+
latitude: float = 0.0,
712+
longitude: float = 0.0,
713+
destinationId: Union[int, str] = BROADCAST_ADDR,
714+
wantAck: bool = True,
715+
wantResponse: bool = False,
716+
channelIndex: int = 0,
717+
):
718+
"""
719+
Send a waypoint packet to some other node (normally a broadcast)
720+
721+
Returns the sent packet. The id field will be populated in this packet and
722+
can be used to track future message acks/naks.
723+
"""
724+
w = mesh_pb2.Waypoint()
725+
w.name = name
726+
w.description = description
727+
w.expire = expire
728+
if id is None:
729+
seed = secrets.randbits(32)
730+
w.id = math.floor(seed * math.pow(2, -32) * 1e9)
731+
logging.debug(f"w.id:{w.id}")
732+
else:
733+
w.id = id
734+
if latitude != 0.0:
735+
w.latitude_i = int(latitude * 1e7)
736+
logging.debug(f"w.latitude_i:{w.latitude_i}")
737+
if longitude != 0.0:
738+
w.longitude_i = int(longitude * 1e7)
739+
logging.debug(f"w.longitude_i:{w.longitude_i}")
740+
741+
if wantResponse:
742+
onResponse = self.onResponseWaypoint
743+
else:
744+
onResponse = None
745+
746+
d = self.sendData(
747+
w,
748+
destinationId,
749+
portNum=portnums_pb2.PortNum.WAYPOINT_APP,
750+
wantAck=wantAck,
751+
wantResponse=wantResponse,
752+
onResponse=onResponse,
753+
channelIndex=channelIndex,
754+
)
755+
if wantResponse:
756+
self.waitForWaypoint()
757+
return d
758+
759+
def deleteWaypoint(
760+
self,
761+
id: int,
762+
destinationId: Union[int, str] = BROADCAST_ADDR,
763+
wantAck: bool = True,
764+
wantResponse: bool = False,
765+
channelIndex: int = 0,
766+
):
767+
"""
768+
Send a waypoint deletion packet to some other node (normally a broadcast)
769+
770+
NB: The id must be the waypoint's id and not the id of the packet creation.
771+
772+
Returns the sent packet. The id field will be populated in this packet and
773+
can be used to track future message acks/naks.
774+
"""
775+
p = mesh_pb2.Waypoint()
776+
p.id = id
777+
p.expire = 0
778+
779+
if wantResponse:
780+
onResponse = self.onResponseWaypoint
781+
else:
782+
onResponse = None
783+
784+
d = self.sendData(
785+
p,
786+
destinationId,
787+
portNum=portnums_pb2.PortNum.WAYPOINT_APP,
788+
wantAck=wantAck,
789+
wantResponse=wantResponse,
790+
onResponse=onResponse,
791+
channelIndex=channelIndex,
792+
)
793+
if wantResponse:
794+
self.waitForWaypoint()
795+
return d
796+
703797
def _addResponseHandler(
704798
self,
705799
requestId: int,

0 commit comments

Comments
 (0)