|
5 | 5 | import collections |
6 | 6 | import json |
7 | 7 | import logging |
| 8 | +import math |
8 | 9 | import random |
| 10 | +import secrets |
9 | 11 | import sys |
10 | 12 | import threading |
11 | 13 | import time |
@@ -737,6 +739,113 @@ def onResponseTelemetry(self, p: dict): |
737 | 739 | "No response from node. At least firmware 2.1.22 is required on the destination node." |
738 | 740 | ) |
739 | 741 |
|
| 742 | + def onResponseWaypoint(self, p: dict): |
| 743 | + """on response for waypoint""" |
| 744 | + if p["decoded"]["portnum"] == "WAYPOINT_APP": |
| 745 | + self._acknowledgment.receivedWaypoint = True |
| 746 | + w = mesh_pb2.Waypoint() |
| 747 | + w.ParseFromString(p["decoded"]["payload"]) |
| 748 | + print(f"Waypoint received: {w}") |
| 749 | + elif p["decoded"]["portnum"] == "ROUTING_APP": |
| 750 | + if p["decoded"]["routing"]["errorReason"] == "NO_RESPONSE": |
| 751 | + our_exit( |
| 752 | + "No response from node. At least firmware 2.1.22 is required on the destination node." |
| 753 | + ) |
| 754 | + |
| 755 | + def sendWaypoint( |
| 756 | + self, |
| 757 | + name, |
| 758 | + description, |
| 759 | + expire: int, |
| 760 | + waypoint_id: Optional[int] = None, |
| 761 | + latitude: float = 0.0, |
| 762 | + longitude: float = 0.0, |
| 763 | + destinationId: Union[int, str] = BROADCAST_ADDR, |
| 764 | + wantAck: bool = True, |
| 765 | + wantResponse: bool = False, |
| 766 | + channelIndex: int = 0, |
| 767 | + ): # pylint: disable=R0913 |
| 768 | + """ |
| 769 | + Send a waypoint packet to some other node (normally a broadcast) |
| 770 | +
|
| 771 | + Returns the sent packet. The id field will be populated in this packet and |
| 772 | + can be used to track future message acks/naks. |
| 773 | + """ |
| 774 | + w = mesh_pb2.Waypoint() |
| 775 | + w.name = name |
| 776 | + w.description = description |
| 777 | + w.expire = expire |
| 778 | + if waypoint_id is None: |
| 779 | + # Generate a waypoint's id, NOT a packet ID. |
| 780 | + # same algorithm as https://github.com/meshtastic/js/blob/715e35d2374276a43ffa93c628e3710875d43907/src/meshDevice.ts#L791 |
| 781 | + seed = secrets.randbits(32) |
| 782 | + w.id = math.floor(seed * math.pow(2, -32) * 1e9) |
| 783 | + logging.debug(f"w.id:{w.id}") |
| 784 | + else: |
| 785 | + w.id = waypoint_id |
| 786 | + if latitude != 0.0: |
| 787 | + w.latitude_i = int(latitude * 1e7) |
| 788 | + logging.debug(f"w.latitude_i:{w.latitude_i}") |
| 789 | + if longitude != 0.0: |
| 790 | + w.longitude_i = int(longitude * 1e7) |
| 791 | + logging.debug(f"w.longitude_i:{w.longitude_i}") |
| 792 | + |
| 793 | + if wantResponse: |
| 794 | + onResponse = self.onResponseWaypoint |
| 795 | + else: |
| 796 | + onResponse = None |
| 797 | + |
| 798 | + d = self.sendData( |
| 799 | + w, |
| 800 | + destinationId, |
| 801 | + portNum=portnums_pb2.PortNum.WAYPOINT_APP, |
| 802 | + wantAck=wantAck, |
| 803 | + wantResponse=wantResponse, |
| 804 | + onResponse=onResponse, |
| 805 | + channelIndex=channelIndex, |
| 806 | + ) |
| 807 | + if wantResponse: |
| 808 | + self.waitForWaypoint() |
| 809 | + return d |
| 810 | + |
| 811 | + def deleteWaypoint( |
| 812 | + self, |
| 813 | + waypoint_id: int, |
| 814 | + destinationId: Union[int, str] = BROADCAST_ADDR, |
| 815 | + wantAck: bool = True, |
| 816 | + wantResponse: bool = False, |
| 817 | + channelIndex: int = 0, |
| 818 | + ): |
| 819 | + """ |
| 820 | + Send a waypoint deletion packet to some other node (normally a broadcast) |
| 821 | +
|
| 822 | + NB: The id must be the waypoint's id and not the id of the packet creation. |
| 823 | + |
| 824 | + Returns the sent packet. The id field will be populated in this packet and |
| 825 | + can be used to track future message acks/naks. |
| 826 | + """ |
| 827 | + p = mesh_pb2.Waypoint() |
| 828 | + p.id = waypoint_id |
| 829 | + p.expire = 0 |
| 830 | + |
| 831 | + if wantResponse: |
| 832 | + onResponse = self.onResponseWaypoint |
| 833 | + else: |
| 834 | + onResponse = None |
| 835 | + |
| 836 | + d = self.sendData( |
| 837 | + p, |
| 838 | + destinationId, |
| 839 | + portNum=portnums_pb2.PortNum.WAYPOINT_APP, |
| 840 | + wantAck=wantAck, |
| 841 | + wantResponse=wantResponse, |
| 842 | + onResponse=onResponse, |
| 843 | + channelIndex=channelIndex, |
| 844 | + ) |
| 845 | + if wantResponse: |
| 846 | + self.waitForWaypoint() |
| 847 | + return d |
| 848 | + |
740 | 849 | def _addResponseHandler( |
741 | 850 | self, |
742 | 851 | requestId: int, |
@@ -861,6 +970,12 @@ def waitForPosition(self): |
861 | 970 | if not success: |
862 | 971 | raise MeshInterface.MeshInterfaceError("Timed out waiting for position") |
863 | 972 |
|
| 973 | + def waitForWaypoint(self): |
| 974 | + """Wait for waypoint""" |
| 975 | + success = self._timeout.waitForWaypoint(self._acknowledgment) |
| 976 | + if not success: |
| 977 | + raise MeshInterface.MeshInterfaceError("Timed out waiting for waypoint") |
| 978 | + |
864 | 979 | def getMyNodeInfo(self) -> Optional[Dict]: |
865 | 980 | """Get info about my node.""" |
866 | 981 | if self.myInfo is None or self.nodesByNum is None: |
|
0 commit comments