diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index fff1d73..5f68444 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -234,6 +234,13 @@ def onConnected(interface): print(f"Setting canned plugin message to {args.set_canned_message}") interface.getNode(args.dest, False).set_canned_message(args.set_canned_message) + # TODO: add to export-config and configure + if args.set_ringtone: + closeNow = True + waitForAckNak = True + print(f"Setting ringtone to {args.set_ringtone}") + interface.getNode(args.dest, False).set_ringtone(args.set_ringtone) + if args.pos_fields: # If --pos-fields invoked with args, set position fields closeNow = True @@ -580,6 +587,11 @@ def onConnected(interface): print("") interface.getNode(args.dest).get_canned_message() + if args.get_ringtone: + closeNow = True + print("") + interface.getNode(args.dest).get_ringtone() + if args.info: print("") # If we aren't trying to talk to our local node, don't show it @@ -860,6 +872,9 @@ def initParser(): parser.add_argument("--get-canned-message", help="Show the canned message plugin message", action="store_true") + parser.add_argument("--get-ringtone", help="Show the stored ringtone", + action="store_true") + parser.add_argument("--nodes", help="Print Node List in a pretty formatted table", action="store_true") @@ -926,7 +941,10 @@ def initParser(): "--set-owner", help="Set device owner name", action="store") parser.add_argument( - "--set-canned-message", help="Set the canned messages plugin message (up to 1000 characters).", action="store") + "--set-canned-message", help="Set the canned messages plugin message (up to 200 characters).", action="store") + + parser.add_argument( + "--set-ringtone", help="Set the Notification Ringtone (up to 230 characters).", action="store") parser.add_argument( "--set-owner-short", help="Set device owner short name", action="store") diff --git a/meshtastic/node.py b/meshtastic/node.py index af91883..821c191 100644 --- a/meshtastic/node.py +++ b/meshtastic/node.py @@ -26,8 +26,9 @@ class Node: self.partialChannels = None self.noProto = noProto self.cannedPluginMessage = None - self.cannedPluginMessageMessages = None + self.ringtone = None + self.ringtonePart = None self.gotResponse = None @@ -379,6 +380,73 @@ class Node: p.set_config.lora.CopyFrom(channelSet.lora_config) self._sendAdmin(p) + def onResponseRequestRingtone(self, p): + """Handle the response packet for requesting ringtone part 1""" + logging.debug(f'onResponseRequestRingtone() p:{p}') + errorFound = False + if "routing" in p["decoded"]: + if p["decoded"]["routing"]["errorReason"] != "NONE": + errorFound = True + print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}') + if errorFound is False: + if "decoded" in p: + if "admin" in p["decoded"]: + if "raw" in p["decoded"]["admin"]: + self.ringtonePart = p["decoded"]["admin"]["raw"].get_ringtone_response + logging.debug(f'self.ringtonePart:{self.ringtonePart}') + self.gotResponse = True + + def get_ringtone(self): + """Get the ringtone. Concatenate all pieces together and return a single string.""" + logging.debug(f'in get_ringtone()') + if not self.ringtone: + + p1 = admin_pb2.AdminMessage() + p1.get_ringtone_request = True + self.gotResponse = False + self._sendAdmin(p1, wantResponse=True, onResponse=self.onResponseRequestRingtone) + while self.gotResponse is False: + time.sleep(0.1) + + logging.debug(f'self.ringtone:{self.ringtone}') + + self.ringtone = "" + if self.ringtonePart: + self.ringtone += self.ringtonePart + + print(f'ringtone:{self.ringtone}') + logging.debug(f'ringtone:{self.ringtone}') + return self.ringtone + + def set_ringtone(self, ringtone): + """Set the ringtone. The ringtone length must be less than 230 character.""" + + if len(ringtone) > 230: + our_exit("Warning: The ringtone must be less than 230 characters.") + + # split into chunks + chunks = [] + chunks_size = 230 + for i in range(0, len(ringtone), chunks_size): + chunks.append(ringtone[i: i + chunks_size]) + + # for each chunk, send a message to set the values + #for i in range(0, len(chunks)): + for i, chunk in enumerate(chunks): + p = admin_pb2.AdminMessage() + + # TODO: should be a way to improve this + if i == 0: + p.set_ringtone_message = chunk + + logging.debug(f"Setting ringtone '{chunk}' part {i+1}") + # If sending to a remote node, wait for ACK/NAK + if self == self.iface.localNode: + onResponse = None + else: + onResponse = self.onAckNak + return self._sendAdmin(p, onResponse=onResponse) + def onResponseRequestCannedMessagePluginMessageMessages(self, p): """Handle the response packet for requesting canned message plugin message part 1""" logging.debug(f'onResponseRequestCannedMessagePluginMessageMessages() p:{p}')