Skip to content

Commit e924afd

Browse files
authored
Merge branch 'master' into channel-hash-info
2 parents a17cfe9 + 87682c1 commit e924afd

File tree

8 files changed

+57
-40
lines changed

8 files changed

+57
-40
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ examples/__pycache__
1717
meshtastic.spec
1818
.hypothesis/
1919
coverage.xml
20-
.ipynb_checkpoints
20+
.ipynb_checkpoints
21+
.cursor/

examples/waypoint.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
parser_create.add_argument('id', help="id of the waypoint")
2626
parser_create.add_argument('name', help="name of the waypoint")
2727
parser_create.add_argument('description', help="description of the waypoint")
28+
parser_create.add_argument('icon', help="icon of the waypoint")
2829
parser_create.add_argument('expire', help="expiration date of the waypoint as interpreted by datetime.fromisoformat")
2930
parser_create.add_argument('latitude', help="latitude of the waypoint")
3031
parser_create.add_argument('longitude', help="longitude of the waypoint")
@@ -44,6 +45,7 @@
4445
waypoint_id=int(args.id),
4546
name=args.name,
4647
description=args.description,
48+
icon=args.icon,
4749
expire=int(datetime.datetime.fromisoformat(args.expire).timestamp()),
4850
latitude=float(args.latitude),
4951
longitude=float(args.longitude),

meshtastic/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,8 @@ def setPref(config, comp_name, raw_val) -> bool:
277277
else:
278278
print(f"Adding '{raw_val}' to the {pref.name} list")
279279
cur_vals = [x for x in getattr(config_values, pref.name) if x not in [0, "", b""]]
280-
cur_vals.append(val)
280+
if val not in cur_vals:
281+
cur_vals.append(val)
281282
getattr(config_values, pref.name)[:] = cur_vals
282283
return True
283284

meshtastic/mesh_interface.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ def sendWaypoint(
830830
self,
831831
name,
832832
description,
833+
icon,
833834
expire: int,
834835
waypoint_id: Optional[int] = None,
835836
latitude: float = 0.0,
@@ -848,6 +849,7 @@ def sendWaypoint(
848849
w = mesh_pb2.Waypoint()
849850
w.name = name
850851
w.description = description
852+
w.icon = icon
851853
w.expire = expire
852854
if waypoint_id is None:
853855
# Generate a waypoint's id, NOT a packet ID.

meshtastic/node.py

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
stripnl,
1818
message_to_json,
1919
generate_channel_hash,
20+
to_node_num,
2021
)
2122

2223
logger = logging.getLogger(__name__)
@@ -715,11 +716,7 @@ def factoryReset(self, full: bool = False):
715716
def removeNode(self, nodeId: Union[int, str]):
716717
"""Tell the node to remove a specific node by ID"""
717718
self.ensureSessionKey()
718-
if isinstance(nodeId, str):
719-
if nodeId.startswith("!"):
720-
nodeId = int(nodeId[1:], 16)
721-
else:
722-
nodeId = int(nodeId)
719+
nodeId = to_node_num(nodeId)
723720

724721
p = admin_pb2.AdminMessage()
725722
p.remove_by_nodenum = nodeId
@@ -733,11 +730,7 @@ def removeNode(self, nodeId: Union[int, str]):
733730
def setFavorite(self, nodeId: Union[int, str]):
734731
"""Tell the node to set the specified node ID to be favorited on the NodeDB on the device"""
735732
self.ensureSessionKey()
736-
if isinstance(nodeId, str):
737-
if nodeId.startswith("!"):
738-
nodeId = int(nodeId[1:], 16)
739-
else:
740-
nodeId = int(nodeId)
733+
nodeId = to_node_num(nodeId)
741734

742735
p = admin_pb2.AdminMessage()
743736
p.set_favorite_node = nodeId
@@ -751,11 +744,7 @@ def setFavorite(self, nodeId: Union[int, str]):
751744
def removeFavorite(self, nodeId: Union[int, str]):
752745
"""Tell the node to set the specified node ID to be un-favorited on the NodeDB on the device"""
753746
self.ensureSessionKey()
754-
if isinstance(nodeId, str):
755-
if nodeId.startswith("!"):
756-
nodeId = int(nodeId[1:], 16)
757-
else:
758-
nodeId = int(nodeId)
747+
nodeId = to_node_num(nodeId)
759748

760749
p = admin_pb2.AdminMessage()
761750
p.remove_favorite_node = nodeId
@@ -769,11 +758,7 @@ def removeFavorite(self, nodeId: Union[int, str]):
769758
def setIgnored(self, nodeId: Union[int, str]):
770759
"""Tell the node to set the specified node ID to be ignored on the NodeDB on the device"""
771760
self.ensureSessionKey()
772-
if isinstance(nodeId, str):
773-
if nodeId.startswith("!"):
774-
nodeId = int(nodeId[1:], 16)
775-
else:
776-
nodeId = int(nodeId)
761+
nodeId = to_node_num(nodeId)
777762

778763
p = admin_pb2.AdminMessage()
779764
p.set_ignored_node = nodeId
@@ -787,11 +772,7 @@ def setIgnored(self, nodeId: Union[int, str]):
787772
def removeIgnored(self, nodeId: Union[int, str]):
788773
"""Tell the node to set the specified node ID to be un-ignored on the NodeDB on the device"""
789774
self.ensureSessionKey()
790-
if isinstance(nodeId, str):
791-
if nodeId.startswith("!"):
792-
nodeId = int(nodeId[1:], 16)
793-
else:
794-
nodeId = int(nodeId)
775+
nodeId = to_node_num(nodeId)
795776

796777
p = admin_pb2.AdminMessage()
797778
p.remove_ignored_node = nodeId
@@ -1014,10 +995,7 @@ def _sendAdmin(
1014995
): # unless a special channel index was used, we want to use the admin index
1015996
adminIndex = self.iface.localNode._getAdminChannelIndex()
1016997
logger.debug(f"adminIndex:{adminIndex}")
1017-
if isinstance(self.nodeNum, int):
1018-
nodeid = self.nodeNum
1019-
else: # assume string starting with !
1020-
nodeid = int(self.nodeNum[1:],16)
998+
nodeid = to_node_num(self.nodeNum)
1021999
if "adminSessionPassKey" in self.iface._getOrCreateByNum(nodeid):
10221000
p.session_passkey = self.iface._getOrCreateByNum(nodeid).get("adminSessionPassKey")
10231001
return self.iface.sendData(
@@ -1038,10 +1016,7 @@ def ensureSessionKey(self):
10381016
f"Not ensuring session key, because protocol use is disabled by noProto"
10391017
)
10401018
else:
1041-
if isinstance(self.nodeNum, int):
1042-
nodeid = self.nodeNum
1043-
else: # assume string starting with !
1044-
nodeid = int(self.nodeNum[1:],16)
1019+
nodeid = to_node_num(self.nodeNum)
10451020
if self.iface._getOrCreateByNum(nodeid).get("adminSessionPassKey") is None:
10461021
self.requestConfig(admin_pb2.AdminMessage.SESSIONKEY_CONFIG)
10471022

meshtastic/serial_interface.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,16 @@ def __repr__(self):
9494

9595
def close(self) -> None:
9696
"""Close a connection to the device"""
97-
if self.stream: # Stream can be null if we were already closed
98-
self.stream.flush() # FIXME: why are there these two flushes with 100ms sleeps? This shouldn't be necessary
99-
time.sleep(0.1)
100-
self.stream.flush()
101-
time.sleep(0.1)
97+
if hasattr(self, "stream") and self.stream and getattr(self.stream, "is_open", False):
98+
try:
99+
self.stream.flush()
100+
time.sleep(0.1)
101+
except Exception as e:
102+
logger.debug(f"Exception during flush: {e}")
103+
try:
104+
self.stream.close()
105+
except Exception as e:
106+
logger.debug(f"Exception during close: {e}")
107+
self.stream = None
102108
logger.debug("Closing Serial stream")
103109
StreamInterface.close(self)

meshtastic/supported_device.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,18 @@ def __init__(
217217
usb_product_id_in_hex="0059",
218218
)
219219

220+
tdeck = SupportedDevice(
221+
name="T-Deck",
222+
version="",
223+
for_firmware="t-deck", # Confirmed firmware identifier
224+
device_class="esp32",
225+
baseport_on_linux="ttyACM",
226+
baseport_on_mac="cu.usbmodem",
227+
baseport_on_windows="COM",
228+
usb_vendor_id_in_hex="303a", # Espressif Systems (VERIFIED)
229+
usb_product_id_in_hex="1001", # VERIFIED from actual device
230+
)
231+
220232

221233

222234
supported_devices = [
@@ -239,4 +251,5 @@ def __init__(
239251
rak11200,
240252
nano_g1,
241253
seeed_xiao_s3,
254+
tdeck, # T-Deck support added
242255
]

meshtastic/util.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,3 +719,20 @@ def message_to_json(message: Message, multiline: bool=False) -> str:
719719
except TypeError:
720720
json = MessageToJson(message, including_default_value_fields=True) # type: ignore[call-arg] # pylint: disable=E1123
721721
return stripnl(json) if not multiline else json
722+
723+
724+
def to_node_num(node_id: Union[int, str]) -> int:
725+
"""
726+
Normalize a node id from int | '!hex' | '0xhex' | 'decimal' to int.
727+
"""
728+
if isinstance(node_id, int):
729+
return node_id
730+
s = str(node_id).strip()
731+
if s.startswith("!"):
732+
s = s[1:]
733+
if s.lower().startswith("0x"):
734+
return int(s, 16)
735+
try:
736+
return int(s, 10)
737+
except ValueError:
738+
return int(s, 16)

0 commit comments

Comments
 (0)