-
Notifications
You must be signed in to change notification settings - Fork 184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Waypoint creation/move/deletion #714
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
"""Program to create and delete waypoint | ||
To run: | ||
python3 examples/waypoint.py --port /dev/ttyUSB0 create 45 test the_desc_2 '2024-12-18T23:05:23' 48.74 7.35 | ||
python examples/waypoint.py delete 45 | ||
""" | ||
|
||
import argparse | ||
import datetime | ||
import sys | ||
import time | ||
|
||
import meshtastic | ||
import meshtastic.serial_interface | ||
|
||
parser = argparse.ArgumentParser( | ||
prog='waypoint', | ||
description='Create and delete Meshtastic waypoint') | ||
parser.add_argument('--port', default=None) | ||
parser.add_argument('--debug', default=False, action='store_true') | ||
|
||
subparsers = parser.add_subparsers(dest='cmd') | ||
parser_delete = subparsers.add_parser('delete', help='Delete a waypoint') | ||
parser_delete.add_argument('id', help="id of the waypoint") | ||
|
||
parser_create = subparsers.add_parser('create', help='Create a new waypoint') | ||
parser_create.add_argument('id', help="id of the waypoint") | ||
parser_create.add_argument('name', help="name of the waypoint") | ||
parser_create.add_argument('description', help="description of the waypoint") | ||
parser_create.add_argument('expire', help="expiration date of the waypoint as interpreted by datetime.fromisoformat") | ||
parser_create.add_argument('latitude', help="latitude of the waypoint") | ||
parser_create.add_argument('longitude', help="longitude of the waypoint") | ||
|
||
args = parser.parse_args() | ||
print(args) | ||
|
||
# By default will try to find a meshtastic device, | ||
# otherwise provide a device path like /dev/ttyUSB0 | ||
if args.debug: | ||
d = sys.stderr | ||
else: | ||
d = None | ||
with meshtastic.serial_interface.SerialInterface(args.port, debugOut=d) as iface: | ||
if args.cmd == 'create': | ||
p = iface.sendWaypoint( | ||
id=int(args.id), | ||
name=args.name, | ||
description=args.description, | ||
expire=int(datetime.datetime.fromisoformat(args.expire).timestamp()), | ||
latitude=float(args.latitude), | ||
longitude=float(args.longitude), | ||
) | ||
else: | ||
p = iface.deleteWaypoint(int(args.id)) | ||
print(p) | ||
|
||
# iface.close() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,9 @@ | |
import collections | ||
import json | ||
import logging | ||
import math | ||
import random | ||
import secrets | ||
import sys | ||
import threading | ||
import time | ||
|
@@ -700,6 +702,98 @@ def onResponseTelemetry(self, p: dict): | |
"No response from node. At least firmware 2.1.22 is required on the destination node." | ||
) | ||
|
||
def sendWaypoint( | ||
self, | ||
name, | ||
description, | ||
expire: int, | ||
id: Optional[int] = None, | ||
latitude: float = 0.0, | ||
longitude: float = 0.0, | ||
destinationId: Union[int, str] = BROADCAST_ADDR, | ||
wantAck: bool = True, | ||
wantResponse: bool = False, | ||
channelIndex: int = 0, | ||
): | ||
""" | ||
Send a waypoint packet to some other node (normally a broadcast) | ||
|
||
Returns the sent packet. The id field will be populated in this packet and | ||
can be used to track future message acks/naks. | ||
""" | ||
w = mesh_pb2.Waypoint() | ||
w.name = name | ||
w.description = description | ||
w.expire = expire | ||
if id is None: | ||
seed = secrets.randbits(32) | ||
w.id = math.floor(seed * math.pow(2, -32) * 1e9) | ||
logging.debug(f"w.id:{w.id}") | ||
else: | ||
w.id = id | ||
if latitude != 0.0: | ||
w.latitude_i = int(latitude * 1e7) | ||
logging.debug(f"w.latitude_i:{w.latitude_i}") | ||
if longitude != 0.0: | ||
w.longitude_i = int(longitude * 1e7) | ||
logging.debug(f"w.longitude_i:{w.longitude_i}") | ||
|
||
if wantResponse: | ||
onResponse = self.onResponseWaypoint | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function doesn't appear to exist. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My bad, I forgot those indeed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These functions are what'd normally be used by the CLI if it supported this stuff, but of course this PR doesn't include that. For now, I think they can just serve as placeholders, so what you have should be fine, I think. |
||
else: | ||
onResponse = None | ||
|
||
d = self.sendData( | ||
w, | ||
destinationId, | ||
portNum=portnums_pb2.PortNum.WAYPOINT_APP, | ||
wantAck=wantAck, | ||
wantResponse=wantResponse, | ||
onResponse=onResponse, | ||
channelIndex=channelIndex, | ||
) | ||
if wantResponse: | ||
self.waitForWaypoint() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't seem to exist either. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see commit 7cc18e9 |
||
return d | ||
|
||
def deleteWaypoint( | ||
self, | ||
id: int, | ||
destinationId: Union[int, str] = BROADCAST_ADDR, | ||
wantAck: bool = True, | ||
wantResponse: bool = False, | ||
channelIndex: int = 0, | ||
): | ||
""" | ||
Send a waypoint deletion packet to some other node (normally a broadcast) | ||
|
||
NB: The id must be the waypoint's id and not the id of the packet creation. | ||
|
||
Returns the sent packet. The id field will be populated in this packet and | ||
can be used to track future message acks/naks. | ||
""" | ||
p = mesh_pb2.Waypoint() | ||
p.id = id | ||
p.expire = 0 | ||
|
||
if wantResponse: | ||
onResponse = self.onResponseWaypoint | ||
else: | ||
onResponse = None | ||
|
||
d = self.sendData( | ||
p, | ||
destinationId, | ||
portNum=portnums_pb2.PortNum.WAYPOINT_APP, | ||
wantAck=wantAck, | ||
wantResponse=wantResponse, | ||
onResponse=onResponse, | ||
channelIndex=channelIndex, | ||
) | ||
if wantResponse: | ||
self.waitForWaypoint() | ||
return d | ||
|
||
def _addResponseHandler( | ||
self, | ||
requestId: int, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the source of this ID generation formula? Looking at the other clients, android seems to just use whatever would be the next packet ID and apple seems to generate a random one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have done similar has in javascript API.
Note that it is not a packet ID but a waypoint ID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. I'm not sure why restricting it to 9 digits is useful, but it's probably fine in any case for this applicaiton.