mirror of
https://github.com/meshtastic/python.git
synced 2025-12-26 09:27:52 -05:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f91479605 | ||
|
|
bbebddea78 | ||
|
|
45be828183 | ||
|
|
e0753d4745 | ||
|
|
21f2e185f2 | ||
|
|
4bfedf6aa9 | ||
|
|
193c3faca5 | ||
|
|
1f47c225b3 | ||
|
|
1b372fca8d | ||
|
|
5e7b6027fa | ||
|
|
64bd5deb4b | ||
|
|
d0fdb9b570 | ||
|
|
f37755209e | ||
|
|
297c0dbc0e | ||
|
|
7de17f7c94 | ||
|
|
55f6494681 | ||
|
|
b2cfebc5a7 | ||
|
|
802768e0cc | ||
|
|
f68e4112e1 | ||
|
|
19b4cd65ce |
@@ -53,10 +53,11 @@ def onConnection(interface, topic=pub.AUTO_TOPIC): # pylint: disable=W0613
|
||||
print(f"Connection changed: {topic.getName()}")
|
||||
|
||||
|
||||
def getPref(config, comp_name):
|
||||
def getPref(node, comp_name):
|
||||
"""Get a channel or preferences value"""
|
||||
|
||||
name = splitCompoundName(comp_name)
|
||||
wholeField = name[0] == name[1] # We want the whole field
|
||||
|
||||
camel_name = meshtastic.util.snake_to_camel(name[1])
|
||||
# Note: protobufs has the keys in snake_case, so snake internally
|
||||
@@ -64,26 +65,49 @@ def getPref(config, comp_name):
|
||||
logging.debug(f'snake_name:{snake_name} camel_name:{camel_name}')
|
||||
logging.debug(f'use camel:{Globals.getInstance().get_camel_case()}')
|
||||
|
||||
objDesc = config.DESCRIPTOR
|
||||
print()
|
||||
config_type = objDesc.fields_by_name.get(name[0])
|
||||
pref = False
|
||||
if config_type:
|
||||
pref = config_type.message_type.fields_by_name.get(snake_name)
|
||||
# First validate the input
|
||||
localConfig = node.localConfig
|
||||
moduleConfig = node.moduleConfig
|
||||
found = False
|
||||
for config in [localConfig, moduleConfig]:
|
||||
objDesc = config.DESCRIPTOR
|
||||
config_type = objDesc.fields_by_name.get(name[0])
|
||||
pref = False
|
||||
if config_type:
|
||||
pref = config_type.message_type.fields_by_name.get(snake_name)
|
||||
if pref or wholeField:
|
||||
found = True
|
||||
break
|
||||
|
||||
if (not pref) or (not config_type):
|
||||
if not found:
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"{localConfig.__class__.__name__} and {moduleConfig.__class__.__name__} do not have an attribute {snake_name}.")
|
||||
else:
|
||||
print(f"{localConfig.__class__.__name__} and {moduleConfig.__class__.__name__} do not have attribute {snake_name}.")
|
||||
print("Choices are...")
|
||||
printConfig(localConfig)
|
||||
printConfig(moduleConfig)
|
||||
return False
|
||||
|
||||
# read the value
|
||||
config_values = getattr(config, config_type.name)
|
||||
pref_value = getattr(config_values, pref.name)
|
||||
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"{str(config_type.name)}.{camel_name}: {str(pref_value)}")
|
||||
logging.debug(f"{str(config_type.name)}.{camel_name}: {str(pref_value)}")
|
||||
else:
|
||||
print(f"{str(config_type.name)}.{snake_name}: {str(pref_value)}")
|
||||
logging.debug(f"{str(config_type.name)}.{snake_name}: {str(pref_value)}")
|
||||
# Check if we need to request the config
|
||||
if len(config.ListFields()) != 0:
|
||||
# read the value
|
||||
config_values = getattr(config, config_type.name)
|
||||
if not wholeField:
|
||||
pref_value = getattr(config_values, pref.name)
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"{str(config_type.name)}.{camel_name}: {str(pref_value)}")
|
||||
logging.debug(f"{str(config_type.name)}.{camel_name}: {str(pref_value)}")
|
||||
else:
|
||||
print(f"{str(config_type.name)}.{snake_name}: {str(pref_value)}")
|
||||
logging.debug(f"{str(config_type.name)}.{snake_name}: {str(pref_value)}")
|
||||
else:
|
||||
print(f"{str(config_type.name)}:\n{str(config_values)}")
|
||||
logging.debug(f"{str(config_type.name)}: {str(config_values)}")
|
||||
else:
|
||||
# Always show whole field for remote node
|
||||
node.requestConfig(config_type)
|
||||
|
||||
return True
|
||||
|
||||
def splitCompoundName(comp_name):
|
||||
@@ -298,7 +322,7 @@ def onConnected(interface):
|
||||
|
||||
if args.device_metadata:
|
||||
closeNow = True
|
||||
interface.getNode(args.dest).getMetadata()
|
||||
interface.getNode(args.dest, False).getMetadata()
|
||||
|
||||
if args.begin_edit:
|
||||
closeNow = True
|
||||
@@ -382,18 +406,26 @@ def onConnected(interface):
|
||||
# handle settings
|
||||
if args.set:
|
||||
closeNow = True
|
||||
node = interface.getNode(args.dest)
|
||||
waitForAckNak = True
|
||||
node = interface.getNode(args.dest, False)
|
||||
|
||||
# Handle the int/float/bool arguments
|
||||
pref = None
|
||||
for pref in args.set:
|
||||
found = setPref(node.localConfig, pref[0], pref[1])
|
||||
if not found:
|
||||
found = setPref(node.moduleConfig, pref[0], pref[1])
|
||||
found = False
|
||||
field = splitCompoundName(pref[0].lower())[0]
|
||||
for config in [node.localConfig, node.moduleConfig]:
|
||||
config_type = config.DESCRIPTOR.fields_by_name.get(field)
|
||||
if config_type:
|
||||
if len(config.ListFields()) == 0:
|
||||
node.requestConfig(config.DESCRIPTOR.fields_by_name.get(field))
|
||||
found = setPref(config, pref[0], pref[1])
|
||||
if found:
|
||||
break
|
||||
|
||||
if found:
|
||||
print("Writing modified preferences to device")
|
||||
interface.getNode(args.dest).writeConfig(splitCompoundName(pref[0].lower())[0])
|
||||
node.writeConfig(field)
|
||||
else:
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"{node.localConfig.__class__.__name__} and {node.moduleConfig.__class__.__name__} do not have an attribute {pref[0]}.")
|
||||
@@ -459,15 +491,15 @@ def onConnected(interface):
|
||||
localConfig = interface.getNode(args.dest).localConfig
|
||||
for section in configuration['config']:
|
||||
for pref in configuration['config'][section]:
|
||||
setPref(localConfig, f"{section}.{pref}", str(configuration['config'][section][pref]))
|
||||
interface.getNode(args.dest).writeConfig(section)
|
||||
setPref(localConfig, f"{meshtastic.util.camel_to_snake(section)}.{pref}", str(configuration['config'][section][pref]))
|
||||
interface.getNode(args.dest).writeConfig(meshtastic.util.camel_to_snake(section))
|
||||
|
||||
if 'module_config' in configuration:
|
||||
moduleConfig = interface.getNode(args.dest).moduleConfig
|
||||
for section in configuration['module_config']:
|
||||
for pref in configuration['module_config'][section]:
|
||||
setPref(moduleConfig, f"{section}.{pref}", str(configuration['module_config'][section][pref]))
|
||||
interface.getNode(args.dest).writeConfig(section)
|
||||
setPref(moduleConfig, f"{meshtastic.util.camel_to_snake(section)}.{pref}", str(configuration['module_config'][section][pref]))
|
||||
interface.getNode(args.dest).writeConfig(meshtastic.util.camel_to_snake(section))
|
||||
|
||||
interface.getNode(args.dest, False).commitSettingsTransaction()
|
||||
print("Writing modified configuration to device")
|
||||
@@ -597,36 +629,28 @@ def onConnected(interface):
|
||||
# If we aren't trying to talk to our local node, don't show it
|
||||
if args.dest == BROADCAST_ADDR:
|
||||
interface.showInfo()
|
||||
|
||||
print("")
|
||||
interface.getNode(args.dest).showInfo()
|
||||
closeNow = True # FIXME, for now we leave the link up while talking to remote nodes
|
||||
print("")
|
||||
print("")
|
||||
interface.getNode(args.dest).showInfo()
|
||||
closeNow = True
|
||||
print("")
|
||||
else:
|
||||
print("Showing info of remote node is not supported.")
|
||||
print("Use the '--get' command for a specific configuration (e.g. 'lora') instead.")
|
||||
|
||||
if args.get:
|
||||
closeNow = True
|
||||
localConfig = interface.getNode(args.dest).localConfig
|
||||
moduleConfig = interface.getNode(args.dest).moduleConfig
|
||||
|
||||
# Handle the int/float/bool arguments
|
||||
node = interface.getNode(args.dest, False)
|
||||
for pref in args.get:
|
||||
found = getPref(localConfig, pref[0])
|
||||
if not found:
|
||||
found = getPref(moduleConfig, pref[0])
|
||||
found = getPref(node, pref[0])
|
||||
|
||||
if not found:
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"{localConfig.__class__.__name__} and {moduleConfig.__class__.__name__} do not have an attribute {pref[0]}.")
|
||||
else:
|
||||
print(f"{localConfig.__class__.__name__} and {moduleConfig.__class__.__name__} do not have attribute {pref[0]}.")
|
||||
print("Choices are...")
|
||||
printConfig(localConfig)
|
||||
printConfig(moduleConfig)
|
||||
else:
|
||||
if found:
|
||||
print("Completed getting preferences")
|
||||
|
||||
if args.nodes:
|
||||
closeNow = True
|
||||
if args.dest != BROADCAST_ADDR:
|
||||
print("Showing node list of a remote node is not supported.")
|
||||
return
|
||||
interface.showNodes()
|
||||
|
||||
if args.qr:
|
||||
|
||||
@@ -14,13 +14,12 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
from meshtastic import channel_pb2 as meshtastic_dot_channel__pb2
|
||||
from meshtastic import config_pb2 as meshtastic_dot_config__pb2
|
||||
from meshtastic import device_metadata_pb2 as meshtastic_dot_device__metadata__pb2
|
||||
from meshtastic import mesh_pb2 as meshtastic_dot_mesh__pb2
|
||||
from meshtastic import module_config_pb2 as meshtastic_dot_module__config__pb2
|
||||
from meshtastic import connection_status_pb2 as meshtastic_dot_connection__status__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16meshtastic/admin.proto\x1a\x18meshtastic/channel.proto\x1a\x17meshtastic/config.proto\x1a meshtastic/device_metadata.proto\x1a\x15meshtastic/mesh.proto\x1a\x1emeshtastic/module_config.proto\x1a\"meshtastic/connection_status.proto\"\xd8\x0c\n\x0c\x41\x64minMessage\x12\x1d\n\x13get_channel_request\x18\x01 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x02 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_owner_request\x18\x03 \x01(\x08H\x00\x12#\n\x12get_owner_response\x18\x04 \x01(\x0b\x32\x05.UserH\x00\x12\x36\n\x12get_config_request\x18\x05 \x01(\x0e\x32\x18.AdminMessage.ConfigTypeH\x00\x12&\n\x13get_config_response\x18\x06 \x01(\x0b\x32\x07.ConfigH\x00\x12\x43\n\x19get_module_config_request\x18\x07 \x01(\x0e\x32\x1e.AdminMessage.ModuleConfigTypeH\x00\x12\x33\n\x1aget_module_config_response\x18\x08 \x01(\x0b\x32\r.ModuleConfigH\x00\x12\x34\n*get_canned_message_module_messages_request\x18\n \x01(\x08H\x00\x12\x35\n+get_canned_message_module_messages_response\x18\x0b \x01(\tH\x00\x12%\n\x1bget_device_metadata_request\x18\x0c \x01(\x08H\x00\x12\x37\n\x1cget_device_metadata_response\x18\r \x01(\x0b\x32\x0f.DeviceMetadataH\x00\x12\x1e\n\x14get_ringtone_request\x18\x0e \x01(\x08H\x00\x12\x1f\n\x15get_ringtone_response\x18\x0f \x01(\tH\x00\x12.\n$get_device_connection_status_request\x18\x10 \x01(\x08H\x00\x12H\n%get_device_connection_status_response\x18\x11 \x01(\x0b\x32\x17.DeviceConnectionStatusH\x00\x12&\n\x0cset_ham_mode\x18\x12 \x01(\x0b\x32\x0e.HamParametersH\x00\x12\x1a\n\tset_owner\x18 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18! \x01(\x0b\x32\x08.ChannelH\x00\x12\x1d\n\nset_config\x18\" \x01(\x0b\x32\x07.ConfigH\x00\x12*\n\x11set_module_config\x18# \x01(\x0b\x32\r.ModuleConfigH\x00\x12,\n\"set_canned_message_module_messages\x18$ \x01(\tH\x00\x12\x1e\n\x14set_ringtone_message\x18% \x01(\tH\x00\x12\x1d\n\x13\x62\x65gin_edit_settings\x18@ \x01(\x08H\x00\x12\x1e\n\x14\x63ommit_edit_settings\x18\x41 \x01(\x08H\x00\x12\x1c\n\x12reboot_ota_seconds\x18_ \x01(\x05H\x00\x12\x18\n\x0e\x65xit_simulator\x18` \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18\x61 \x01(\x05H\x00\x12\x1a\n\x10shutdown_seconds\x18\x62 \x01(\x05H\x00\x12\x17\n\rfactory_reset\x18\x63 \x01(\x05H\x00\x12\x16\n\x0cnodedb_reset\x18\x64 \x01(\x05H\x00\"\x95\x01\n\nConfigType\x12\x11\n\rDEVICE_CONFIG\x10\x00\x12\x13\n\x0fPOSITION_CONFIG\x10\x01\x12\x10\n\x0cPOWER_CONFIG\x10\x02\x12\x12\n\x0eNETWORK_CONFIG\x10\x03\x12\x12\n\x0e\x44ISPLAY_CONFIG\x10\x04\x12\x0f\n\x0bLORA_CONFIG\x10\x05\x12\x14\n\x10\x42LUETOOTH_CONFIG\x10\x06\"\xd3\x01\n\x10ModuleConfigType\x12\x0f\n\x0bMQTT_CONFIG\x10\x00\x12\x11\n\rSERIAL_CONFIG\x10\x01\x12\x13\n\x0f\x45XTNOTIF_CONFIG\x10\x02\x12\x17\n\x13STOREFORWARD_CONFIG\x10\x03\x12\x14\n\x10RANGETEST_CONFIG\x10\x04\x12\x14\n\x10TELEMETRY_CONFIG\x10\x05\x12\x14\n\x10\x43\x41NNEDMSG_CONFIG\x10\x06\x12\x10\n\x0c\x41UDIO_CONFIG\x10\x07\x12\x19\n\x15REMOTEHARDWARE_CONFIG\x10\x08\x42\x11\n\x0fpayload_variant\"[\n\rHamParameters\x12\x11\n\tcall_sign\x18\x01 \x01(\t\x12\x10\n\x08tx_power\x18\x02 \x01(\x05\x12\x11\n\tfrequency\x18\x03 \x01(\x02\x12\x12\n\nshort_name\x18\x04 \x01(\tB`\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16meshtastic/admin.proto\x1a\x18meshtastic/channel.proto\x1a\x17meshtastic/config.proto\x1a\x15meshtastic/mesh.proto\x1a\x1emeshtastic/module_config.proto\x1a\"meshtastic/connection_status.proto\"\xd8\x0c\n\x0c\x41\x64minMessage\x12\x1d\n\x13get_channel_request\x18\x01 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x02 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_owner_request\x18\x03 \x01(\x08H\x00\x12#\n\x12get_owner_response\x18\x04 \x01(\x0b\x32\x05.UserH\x00\x12\x36\n\x12get_config_request\x18\x05 \x01(\x0e\x32\x18.AdminMessage.ConfigTypeH\x00\x12&\n\x13get_config_response\x18\x06 \x01(\x0b\x32\x07.ConfigH\x00\x12\x43\n\x19get_module_config_request\x18\x07 \x01(\x0e\x32\x1e.AdminMessage.ModuleConfigTypeH\x00\x12\x33\n\x1aget_module_config_response\x18\x08 \x01(\x0b\x32\r.ModuleConfigH\x00\x12\x34\n*get_canned_message_module_messages_request\x18\n \x01(\x08H\x00\x12\x35\n+get_canned_message_module_messages_response\x18\x0b \x01(\tH\x00\x12%\n\x1bget_device_metadata_request\x18\x0c \x01(\x08H\x00\x12\x37\n\x1cget_device_metadata_response\x18\r \x01(\x0b\x32\x0f.DeviceMetadataH\x00\x12\x1e\n\x14get_ringtone_request\x18\x0e \x01(\x08H\x00\x12\x1f\n\x15get_ringtone_response\x18\x0f \x01(\tH\x00\x12.\n$get_device_connection_status_request\x18\x10 \x01(\x08H\x00\x12H\n%get_device_connection_status_response\x18\x11 \x01(\x0b\x32\x17.DeviceConnectionStatusH\x00\x12&\n\x0cset_ham_mode\x18\x12 \x01(\x0b\x32\x0e.HamParametersH\x00\x12\x1a\n\tset_owner\x18 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18! \x01(\x0b\x32\x08.ChannelH\x00\x12\x1d\n\nset_config\x18\" \x01(\x0b\x32\x07.ConfigH\x00\x12*\n\x11set_module_config\x18# \x01(\x0b\x32\r.ModuleConfigH\x00\x12,\n\"set_canned_message_module_messages\x18$ \x01(\tH\x00\x12\x1e\n\x14set_ringtone_message\x18% \x01(\tH\x00\x12\x1d\n\x13\x62\x65gin_edit_settings\x18@ \x01(\x08H\x00\x12\x1e\n\x14\x63ommit_edit_settings\x18\x41 \x01(\x08H\x00\x12\x1c\n\x12reboot_ota_seconds\x18_ \x01(\x05H\x00\x12\x18\n\x0e\x65xit_simulator\x18` \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18\x61 \x01(\x05H\x00\x12\x1a\n\x10shutdown_seconds\x18\x62 \x01(\x05H\x00\x12\x17\n\rfactory_reset\x18\x63 \x01(\x05H\x00\x12\x16\n\x0cnodedb_reset\x18\x64 \x01(\x05H\x00\"\x95\x01\n\nConfigType\x12\x11\n\rDEVICE_CONFIG\x10\x00\x12\x13\n\x0fPOSITION_CONFIG\x10\x01\x12\x10\n\x0cPOWER_CONFIG\x10\x02\x12\x12\n\x0eNETWORK_CONFIG\x10\x03\x12\x12\n\x0e\x44ISPLAY_CONFIG\x10\x04\x12\x0f\n\x0bLORA_CONFIG\x10\x05\x12\x14\n\x10\x42LUETOOTH_CONFIG\x10\x06\"\xd3\x01\n\x10ModuleConfigType\x12\x0f\n\x0bMQTT_CONFIG\x10\x00\x12\x11\n\rSERIAL_CONFIG\x10\x01\x12\x13\n\x0f\x45XTNOTIF_CONFIG\x10\x02\x12\x17\n\x13STOREFORWARD_CONFIG\x10\x03\x12\x14\n\x10RANGETEST_CONFIG\x10\x04\x12\x14\n\x10TELEMETRY_CONFIG\x10\x05\x12\x14\n\x10\x43\x41NNEDMSG_CONFIG\x10\x06\x12\x10\n\x0c\x41UDIO_CONFIG\x10\x07\x12\x19\n\x15REMOTEHARDWARE_CONFIG\x10\x08\x42\x11\n\x0fpayload_variant\"[\n\rHamParameters\x12\x11\n\tcall_sign\x18\x01 \x01(\t\x12\x10\n\x08tx_power\x18\x02 \x01(\x05\x12\x11\n\tfrequency\x18\x03 \x01(\x02\x12\x12\n\nshort_name\x18\x04 \x01(\tB`\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
|
||||
|
||||
@@ -46,12 +45,12 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\013AdminProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_ADMINMESSAGE._serialized_start=203
|
||||
_ADMINMESSAGE._serialized_end=1827
|
||||
_ADMINMESSAGE_CONFIGTYPE._serialized_start=1445
|
||||
_ADMINMESSAGE_CONFIGTYPE._serialized_end=1594
|
||||
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_start=1597
|
||||
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_end=1808
|
||||
_HAMPARAMETERS._serialized_start=1829
|
||||
_HAMPARAMETERS._serialized_end=1920
|
||||
_ADMINMESSAGE._serialized_start=169
|
||||
_ADMINMESSAGE._serialized_end=1793
|
||||
_ADMINMESSAGE_CONFIGTYPE._serialized_start=1411
|
||||
_ADMINMESSAGE_CONFIGTYPE._serialized_end=1560
|
||||
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_start=1563
|
||||
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_end=1774
|
||||
_HAMPARAMETERS._serialized_start=1795
|
||||
_HAMPARAMETERS._serialized_end=1886
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -170,18 +170,18 @@ class MeshInterface:
|
||||
return table
|
||||
|
||||
|
||||
def getNode(self, nodeId, requestConfig=True):
|
||||
def getNode(self, nodeId, requestChannels=True):
|
||||
"""Return a node object which contains device settings and channel info"""
|
||||
if nodeId in (LOCAL_ADDR, BROADCAST_ADDR):
|
||||
return self.localNode
|
||||
else:
|
||||
n = meshtastic.node.Node(self, nodeId)
|
||||
# Only request device settings and channel info when necessary
|
||||
if requestConfig:
|
||||
logging.debug("About to requestConfig")
|
||||
n.requestConfig()
|
||||
if requestChannels:
|
||||
logging.debug("About to requestChannels")
|
||||
n.requestChannels()
|
||||
if not n.waitForConfig():
|
||||
our_exit("Error: Timed out waiting for node config")
|
||||
our_exit("Error: Timed out waiting for channels")
|
||||
return n
|
||||
|
||||
def sendText(self, text: AnyStr,
|
||||
@@ -522,7 +522,7 @@ class MeshInterface:
|
||||
Done with initial config messages, now send regular MeshPackets
|
||||
to ask for settings and channels
|
||||
"""
|
||||
self.localNode.requestConfig()
|
||||
self.localNode.requestChannels()
|
||||
|
||||
def _handleFromRadio(self, fromRadioBytes):
|
||||
"""
|
||||
@@ -615,6 +615,10 @@ class MeshInterface:
|
||||
self.localNode.moduleConfig.telemetry.CopyFrom(fromRadio.moduleConfig.telemetry)
|
||||
elif fromRadio.moduleConfig.HasField("canned_message"):
|
||||
self.localNode.moduleConfig.canned_message.CopyFrom(fromRadio.moduleConfig.canned_message)
|
||||
elif fromRadio.moduleConfig.HasField("audio"):
|
||||
self.localNode.moduleConfig.audio.CopyFrom(fromRadio.moduleConfig.audio)
|
||||
elif fromRadio.moduleConfig.HasField("remote_hardware"):
|
||||
self.localNode.moduleConfig.remote_hardware.CopyFrom(fromRadio.moduleConfig.remote_hardware)
|
||||
|
||||
else:
|
||||
logging.debug("Unexpected FromRadio payload")
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@ import base64
|
||||
import time
|
||||
from google.protobuf.json_format import MessageToJson
|
||||
from meshtastic import portnums_pb2, apponly_pb2, admin_pb2, channel_pb2, localonly_pb2
|
||||
from meshtastic.util import pskToString, stripnl, Timeout, our_exit, fromPSK
|
||||
from meshtastic.util import pskToString, stripnl, Timeout, our_exit, fromPSK, camel_to_snake
|
||||
|
||||
|
||||
class Node:
|
||||
@@ -61,13 +61,60 @@ class Node:
|
||||
print(f"Module preferences: {prefs}\n")
|
||||
self.showChannels()
|
||||
|
||||
def requestConfig(self):
|
||||
"""Send regular MeshPackets to ask for settings and channels."""
|
||||
logging.debug(f"requestConfig for nodeNum:{self.nodeNum}")
|
||||
def requestChannels(self):
|
||||
"""Send regular MeshPackets to ask channels."""
|
||||
logging.debug(f"requestChannels for nodeNum:{self.nodeNum}")
|
||||
self.channels = None
|
||||
self.partialChannels = [] # We keep our channels in a temp array until finished
|
||||
|
||||
self._requestChannel(0)
|
||||
|
||||
def onResponseRequestSettings(self, p):
|
||||
"""Handle the response packets for requesting settings _requestSettings()"""
|
||||
logging.debug(f'onResponseRequestSetting() p:{p}')
|
||||
if "routing" in p["decoded"]:
|
||||
if p["decoded"]["routing"]["errorReason"] != "NONE":
|
||||
print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}')
|
||||
self.iface._acknowledgment.receivedNak = True
|
||||
else:
|
||||
self.iface._acknowledgment.receivedAck = True
|
||||
print("")
|
||||
adminMessage = p["decoded"]["admin"]
|
||||
if "getConfigResponse" in adminMessage:
|
||||
resp = adminMessage["getConfigResponse"]
|
||||
field = list(resp.keys())[0]
|
||||
config_type = self.localConfig.DESCRIPTOR.fields_by_name.get(camel_to_snake(field))
|
||||
config_values = getattr(self.localConfig, config_type.name)
|
||||
elif "getModuleConfigResponse" in adminMessage:
|
||||
resp = adminMessage["getModuleConfigResponse"]
|
||||
field = list(resp.keys())[0]
|
||||
config_type = self.moduleConfig.DESCRIPTOR.fields_by_name.get(camel_to_snake(field))
|
||||
config_values = getattr(self.moduleConfig, config_type.name)
|
||||
else:
|
||||
print("Did not receive a valid response. Make sure to have a shared channel named 'admin'.")
|
||||
return
|
||||
for key, value in resp[field].items():
|
||||
setattr(config_values, camel_to_snake(key), value)
|
||||
print(f"{str(camel_to_snake(field))}:\n{str(config_values)}")
|
||||
|
||||
def requestConfig(self, configType):
|
||||
if self == self.iface.localNode:
|
||||
onResponse = None
|
||||
else:
|
||||
onResponse = self.onResponseRequestSettings
|
||||
print("Requesting current config from remote node (this can take a while).")
|
||||
|
||||
msgIndex = configType.index
|
||||
if configType.containing_type.full_name == "LocalConfig":
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.get_config_request = msgIndex
|
||||
self._sendAdmin(p, wantResponse=True, onResponse=onResponse)
|
||||
else:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.get_module_config_request = msgIndex
|
||||
self._sendAdmin(p, wantResponse=True, onResponse=onResponse)
|
||||
if onResponse:
|
||||
self.iface.waitForAckNak()
|
||||
|
||||
def turnOffEncryptionOnPrimaryChannel(self):
|
||||
"""Turn off encryption on primary channel."""
|
||||
@@ -186,7 +233,14 @@ class Node:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_module_config.audio.CopyFrom(self.moduleConfig.audio)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote module: audo")
|
||||
logging.debug("Wrote module: audio")
|
||||
time.sleep(0.3)
|
||||
|
||||
if self.moduleConfig.remote_hardware:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_module_config.remote_hardware.CopyFrom(self.moduleConfig.remote_hardware)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote module: remote_hardware")
|
||||
time.sleep(0.3)
|
||||
|
||||
def writeConfig(self, config_name):
|
||||
@@ -226,11 +280,17 @@ class Node:
|
||||
p.set_module_config.canned_message.CopyFrom(self.moduleConfig.canned_message)
|
||||
elif config_name == 'audio':
|
||||
p.set_module_config.audio.CopyFrom(self.moduleConfig.audio)
|
||||
elif config_name == 'remote_hardware':
|
||||
p.set_module_config.remote_hardware.CopyFrom(self.moduleConfig.remote_hardware)
|
||||
else:
|
||||
our_exit(f"Error: No valid config with name {config_name}")
|
||||
|
||||
logging.debug(f"Wrote: {config_name}")
|
||||
self._sendAdmin(p)
|
||||
if self == self.iface.localNode:
|
||||
onResponse = None
|
||||
else:
|
||||
onResponse = self.onAckNak
|
||||
self._sendAdmin(p, onResponse=onResponse)
|
||||
|
||||
def writeChannel(self, channelIndex, adminIndex=0):
|
||||
"""Write the current (edited) channel to the device"""
|
||||
|
||||
@@ -23,7 +23,7 @@ def test_RemoteHardwareClient():
|
||||
def test_onGPIOreceive(capsys):
|
||||
"""Test onGPIOreceive"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
packet = {'decoded': {'remotehw': {'typ': 'foo', 'gpioValue': '4096' }}}
|
||||
packet = {'decoded': {'remotehw': {'type': 'foo', 'gpioValue': '4096' }}}
|
||||
onGPIOreceive(packet, iface)
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Received RemoteHardware', out)
|
||||
|
||||
Submodule protobufs updated: 1d0b4dd242...2b55d8421b
2
setup.py
2
setup.py
@@ -12,7 +12,7 @@ with open("README.md", "r") as fh:
|
||||
# This call to setup() does all the work
|
||||
setup(
|
||||
name="meshtastic",
|
||||
version="2.0.11",
|
||||
version="2.1.2",
|
||||
description="Python API & client shell for talking to Meshtastic devices",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
|
||||
Reference in New Issue
Block a user