Skip to content

Commit 93441a4

Browse files
authored
Merge pull request #414 from meshtastic/ringtone-support
get and set RTTTL ringtone
2 parents 2cf1ce2 + 7b8a83a commit 93441a4

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

meshtastic/__main__.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,13 @@ def onConnected(interface):
234234
print(f"Setting canned plugin message to {args.set_canned_message}")
235235
interface.getNode(args.dest, False).set_canned_message(args.set_canned_message)
236236

237+
# TODO: add to export-config and configure
238+
if args.set_ringtone:
239+
closeNow = True
240+
waitForAckNak = True
241+
print(f"Setting ringtone to {args.set_ringtone}")
242+
interface.getNode(args.dest, False).set_ringtone(args.set_ringtone)
243+
237244
if args.pos_fields:
238245
# If --pos-fields invoked with args, set position fields
239246
closeNow = True
@@ -580,6 +587,11 @@ def setSimpleConfig(modem_preset):
580587
print("")
581588
interface.getNode(args.dest).get_canned_message()
582589

590+
if args.get_ringtone:
591+
closeNow = True
592+
print("")
593+
interface.getNode(args.dest).get_ringtone()
594+
583595
if args.info:
584596
print("")
585597
# If we aren't trying to talk to our local node, don't show it
@@ -860,6 +872,9 @@ def initParser():
860872
parser.add_argument("--get-canned-message", help="Show the canned message plugin message",
861873
action="store_true")
862874

875+
parser.add_argument("--get-ringtone", help="Show the stored ringtone",
876+
action="store_true")
877+
863878
parser.add_argument("--nodes", help="Print Node List in a pretty formatted table",
864879
action="store_true")
865880

@@ -926,7 +941,10 @@ def initParser():
926941
"--set-owner", help="Set device owner name", action="store")
927942

928943
parser.add_argument(
929-
"--set-canned-message", help="Set the canned messages plugin message (up to 1000 characters).", action="store")
944+
"--set-canned-message", help="Set the canned messages plugin message (up to 200 characters).", action="store")
945+
946+
parser.add_argument(
947+
"--set-ringtone", help="Set the Notification Ringtone (up to 230 characters).", action="store")
930948

931949
parser.add_argument(
932950
"--set-owner-short", help="Set device owner short name", action="store")

meshtastic/node.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ def __init__(self, iface, nodeNum, noProto=False):
2626
self.partialChannels = None
2727
self.noProto = noProto
2828
self.cannedPluginMessage = None
29-
3029
self.cannedPluginMessageMessages = None
30+
self.ringtone = None
31+
self.ringtonePart = None
3132

3233
self.gotResponse = None
3334

@@ -379,6 +380,73 @@ def setURL(self, url):
379380
p.set_config.lora.CopyFrom(channelSet.lora_config)
380381
self._sendAdmin(p)
381382

383+
def onResponseRequestRingtone(self, p):
384+
"""Handle the response packet for requesting ringtone part 1"""
385+
logging.debug(f'onResponseRequestRingtone() p:{p}')
386+
errorFound = False
387+
if "routing" in p["decoded"]:
388+
if p["decoded"]["routing"]["errorReason"] != "NONE":
389+
errorFound = True
390+
print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}')
391+
if errorFound is False:
392+
if "decoded" in p:
393+
if "admin" in p["decoded"]:
394+
if "raw" in p["decoded"]["admin"]:
395+
self.ringtonePart = p["decoded"]["admin"]["raw"].get_ringtone_response
396+
logging.debug(f'self.ringtonePart:{self.ringtonePart}')
397+
self.gotResponse = True
398+
399+
def get_ringtone(self):
400+
"""Get the ringtone. Concatenate all pieces together and return a single string."""
401+
logging.debug(f'in get_ringtone()')
402+
if not self.ringtone:
403+
404+
p1 = admin_pb2.AdminMessage()
405+
p1.get_ringtone_request = True
406+
self.gotResponse = False
407+
self._sendAdmin(p1, wantResponse=True, onResponse=self.onResponseRequestRingtone)
408+
while self.gotResponse is False:
409+
time.sleep(0.1)
410+
411+
logging.debug(f'self.ringtone:{self.ringtone}')
412+
413+
self.ringtone = ""
414+
if self.ringtonePart:
415+
self.ringtone += self.ringtonePart
416+
417+
print(f'ringtone:{self.ringtone}')
418+
logging.debug(f'ringtone:{self.ringtone}')
419+
return self.ringtone
420+
421+
def set_ringtone(self, ringtone):
422+
"""Set the ringtone. The ringtone length must be less than 230 character."""
423+
424+
if len(ringtone) > 230:
425+
our_exit("Warning: The ringtone must be less than 230 characters.")
426+
427+
# split into chunks
428+
chunks = []
429+
chunks_size = 230
430+
for i in range(0, len(ringtone), chunks_size):
431+
chunks.append(ringtone[i: i + chunks_size])
432+
433+
# for each chunk, send a message to set the values
434+
#for i in range(0, len(chunks)):
435+
for i, chunk in enumerate(chunks):
436+
p = admin_pb2.AdminMessage()
437+
438+
# TODO: should be a way to improve this
439+
if i == 0:
440+
p.set_ringtone_message = chunk
441+
442+
logging.debug(f"Setting ringtone '{chunk}' part {i+1}")
443+
# If sending to a remote node, wait for ACK/NAK
444+
if self == self.iface.localNode:
445+
onResponse = None
446+
else:
447+
onResponse = self.onAckNak
448+
return self._sendAdmin(p, onResponse=onResponse)
449+
382450
def onResponseRequestCannedMessagePluginMessageMessages(self, p):
383451
"""Handle the response packet for requesting canned message plugin message part 1"""
384452
logging.debug(f'onResponseRequestCannedMessagePluginMessageMessages() p:{p}')

0 commit comments

Comments
 (0)