mirror of
https://github.com/meshtastic/python.git
synced 2025-12-26 09:27:52 -05:00
Compare commits
27 Commits
1.3alpha.1
...
1.3alpha.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92c7b2db69 | ||
|
|
ff94ad968c | ||
|
|
c6071c57ec | ||
|
|
e3e3562c2c | ||
|
|
06b5b8fa83 | ||
|
|
4b95b0ff30 | ||
|
|
42f2ed571d | ||
|
|
f3791c5c6d | ||
|
|
4cff344971 | ||
|
|
594b307e94 | ||
|
|
8a5fd16469 | ||
|
|
4fa93989fa | ||
|
|
032072d2f3 | ||
|
|
ce7b1d9916 | ||
|
|
d015da3ca1 | ||
|
|
a956c8068c | ||
|
|
2124e292f1 | ||
|
|
115739a9bb | ||
|
|
cc2c16b957 | ||
|
|
b9245c6c1f | ||
|
|
d21f7811fa | ||
|
|
8dbd6431f7 | ||
|
|
c7b2bbf700 | ||
|
|
682fdb7ef4 | ||
|
|
9c79f9d80e | ||
|
|
c55b1188e8 | ||
|
|
d5e4eaf2d8 |
6
.github/workflows/update_protobufs.yml
vendored
6
.github/workflows/update_protobufs.yml
vendored
@@ -18,9 +18,9 @@ jobs:
|
||||
|
||||
- name: Download nanopb
|
||||
run: |
|
||||
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.4-linux-x86.tar.gz
|
||||
tar xvzf nanopb-0.4.4-linux-x86.tar.gz
|
||||
mv nanopb-0.4.4-linux-x86 nanopb-0.4.4
|
||||
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.6-linux-x86.tar.gz
|
||||
tar xvzf nanopb-0.4.6-linux-x86.tar.gz
|
||||
mv nanopb-0.4.6-linux-x86 nanopb-0.4.6
|
||||
|
||||
- name: Re-generate protocol buffers
|
||||
run: |
|
||||
|
||||
68
.vscode/launch.json
vendored
68
.vscode/launch.json
vendored
@@ -42,7 +42,71 @@
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug" ]
|
||||
"args": ["--debug"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic debug getPref",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug", "--get", "power.is_power_saving"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic debug getPref telemetry",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug", "--get", "telemetry.environment_update_interval"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic debug info",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug", "--info"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic debug set region",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug", "--set", "lora.region", "1"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic debug setPref",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug", "--set", "power.is_power_saving", "1"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic debug setPref telemetry.environment_measurement_enabled",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug", "--set", "telemetry.environment_measurement_enabled", "1"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic debug setPref telemetry.environment_screen_enabled",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug", "--set", "telemetry.environment_screen_enabled", "1"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic debug setPref telemetry",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug", "--set", "telemetry.environment_measurement_enabled", "1"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic setpref",
|
||||
@@ -92,7 +156,7 @@
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--debug", "--sendtext", "pytest"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "meshtastic showNodes",
|
||||
"type": "python",
|
||||
|
||||
2
TODO.md
2
TODO.md
@@ -34,7 +34,7 @@ Basic functionality is complete now.
|
||||
- DONE add fromId and toId to received messages dictionaries
|
||||
- make command line options for displaying/changing config
|
||||
- update nodedb as nodes change
|
||||
- radioConfig - getter/setter syntax: https://www.python-course.eu/python3_properties.php
|
||||
- localConfig - getter/setter syntax: https://www.python-course.eu/python3_properties.php
|
||||
- let user change radio params via commandline options
|
||||
- keep nodedb up-to-date based on received MeshPackets
|
||||
- handle radio reboots and redownload db when that happens. Look for a special FromRadio.rebooted packet
|
||||
|
||||
@@ -7,7 +7,7 @@ Source code on [github](https://github.com/meshtastic/Meshtastic-python)
|
||||
|
||||
properties of SerialInterface:
|
||||
|
||||
- radioConfig - Current radio configuration and device settings, if you write to this the new settings will be applied to
|
||||
- localConfig - Current radio configuration and device settings, if you write to this the new settings will be applied to
|
||||
the device.
|
||||
- nodes - The database of received nodes. Includes always up-to-date location and username information for each
|
||||
node in the mesh. This is a read-only datastructure.
|
||||
|
||||
@@ -52,78 +52,72 @@ def onConnection(interface, topic=pub.AUTO_TOPIC): # pylint: disable=W0613
|
||||
print(f"Connection changed: {topic.getName()}")
|
||||
|
||||
|
||||
def getPref(attributes, name):
|
||||
def getPref(config, comp_name):
|
||||
"""Get a channel or preferences value"""
|
||||
|
||||
camel_name = meshtastic.util.snake_to_camel(name)
|
||||
name = splitCompoundName(comp_name)
|
||||
|
||||
camel_name = meshtastic.util.snake_to_camel(name[1])
|
||||
# Note: protobufs has the keys in snake_case, so snake internally
|
||||
snake_name = meshtastic.util.camel_to_snake(name)
|
||||
snake_name = meshtastic.util.camel_to_snake(name[1])
|
||||
logging.debug(f'snake_name:{snake_name} camel_name:{camel_name}')
|
||||
logging.debug(f'use camel:{Globals.getInstance().get_camel_case()}')
|
||||
|
||||
objDesc = attributes.DESCRIPTOR
|
||||
field = objDesc.fields_by_name.get(snake_name)
|
||||
if not field:
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"{attributes.__class__.__name__} does not have an attribute called {camel_name}, so you can not get it.")
|
||||
else:
|
||||
print(f"{attributes.__class__.__name__} does not have an attribute called {snake_name}, so you can not get it.")
|
||||
print(f"Choices in sorted order are:")
|
||||
names = []
|
||||
for f in objDesc.fields:
|
||||
tmp_name = f'{f.name}'
|
||||
if Globals.getInstance().get_camel_case():
|
||||
tmp_name = meshtastic.util.snake_to_camel(tmp_name)
|
||||
names.append(tmp_name)
|
||||
for temp_name in sorted(names):
|
||||
print(f" {temp_name}")
|
||||
return
|
||||
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 (not pref) or (not config_type):
|
||||
return False
|
||||
|
||||
# read the value
|
||||
val = getattr(attributes, snake_name)
|
||||
config_values = getattr(config, config_type.name)
|
||||
pref_value = getattr(config_values, pref.name)
|
||||
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"{camel_name}: {str(val)}")
|
||||
logging.debug(f"{camel_name}: {str(val)}")
|
||||
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"{snake_name}: {str(val)}")
|
||||
logging.debug(f"{snake_name}: {str(val)}")
|
||||
print(f"{str(config_type.name)}.{snake_name}: {str(pref_value)}")
|
||||
logging.debug(f"{str(config_type.name)}.{snake_name}: {str(pref_value)}")
|
||||
return True
|
||||
|
||||
def splitCompoundName(comp_name):
|
||||
name = comp_name.split(".",1)
|
||||
if len(name) != 2:
|
||||
name[0]=comp_name
|
||||
name.append(comp_name)
|
||||
return name
|
||||
|
||||
def setPref(attributes, name, valStr):
|
||||
def setPref(config, comp_name, valStr):
|
||||
"""Set a channel or preferences value"""
|
||||
|
||||
snake_name = meshtastic.util.camel_to_snake(name)
|
||||
camel_name = meshtastic.util.snake_to_camel(name)
|
||||
name = splitCompoundName(comp_name)
|
||||
|
||||
snake_name = meshtastic.util.camel_to_snake(name[1])
|
||||
camel_name = meshtastic.util.snake_to_camel(name[1])
|
||||
logging.debug(f'snake_name:{snake_name}')
|
||||
logging.debug(f'camel_name:{camel_name}')
|
||||
|
||||
objDesc = attributes.DESCRIPTOR
|
||||
field = objDesc.fields_by_name.get(snake_name)
|
||||
if not field:
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"{attributes.__class__.__name__} does not have an attribute called {camel_name}, so you can not set it.")
|
||||
else:
|
||||
print(f"{attributes.__class__.__name__} does not have an attribute called {snake_name}, so you can not set it.")
|
||||
print(f"Choices in sorted order are:")
|
||||
names = []
|
||||
for f in objDesc.fields:
|
||||
tmp_name = f'{f.name}'
|
||||
if Globals.getInstance().get_camel_case():
|
||||
tmp_name = meshtastic.util.snake_to_camel(tmp_name)
|
||||
names.append(tmp_name)
|
||||
for temp_name in sorted(names):
|
||||
print(f" {temp_name}")
|
||||
return
|
||||
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 (not pref) or (not config_type):
|
||||
return False
|
||||
|
||||
val = meshtastic.util.fromStr(valStr)
|
||||
logging.debug(f'valStr:{valStr} val:{val}')
|
||||
|
||||
if snake_name == 'wifi_password' and len(valStr) < 8:
|
||||
print(f"Warning: wifi_password must be 8 or more characters.")
|
||||
return
|
||||
if snake_name == 'psk' and len(valStr) < 8:
|
||||
print(f"Warning: wifi.psk must be 8 or more characters.")
|
||||
return
|
||||
|
||||
enumType = field.enum_type
|
||||
enumType = pref.enum_type
|
||||
# pylint: disable=C0123
|
||||
if enumType and type(val) == str:
|
||||
# We've failed so far to convert this string into an enum, try to find it by reflection
|
||||
@@ -132,9 +126,9 @@ def setPref(attributes, name, valStr):
|
||||
val = e.number
|
||||
else:
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"{camel_name} does not have an enum called {val}, so you can not set it.")
|
||||
print(f"{name[0]}.{camel_name} does not have an enum called {val}, so you can not set it.")
|
||||
else:
|
||||
print(f"{snake_name} does not have an enum called {val}, so you can not set it.")
|
||||
print(f"{name[0]}.{snake_name} does not have an enum called {val}, so you can not set it.")
|
||||
print(f"Choices in sorted order are:")
|
||||
names = []
|
||||
for f in enumType.values:
|
||||
@@ -147,23 +141,27 @@ def setPref(attributes, name, valStr):
|
||||
# note: 'ignore_incoming' is a repeating field
|
||||
if snake_name != 'ignore_incoming':
|
||||
try:
|
||||
setattr(attributes, snake_name, val)
|
||||
config_values = getattr(config, config_type.name)
|
||||
setattr(config_values, pref.name, val)
|
||||
except TypeError:
|
||||
# The setter didn't like our arg type guess try again as a string
|
||||
setattr(attributes, snake_name, valStr)
|
||||
config_values = getattr(config, config_type.name)
|
||||
setattr(config_values, pref.name, valStr)
|
||||
else:
|
||||
if val == 0:
|
||||
# clear values
|
||||
print("Clearing ignore_incoming list")
|
||||
del attributes.ignore_incoming[:]
|
||||
del config_type.message_type.ignore_incoming[:]
|
||||
else:
|
||||
print(f"Adding '{val}' to the ignore_incoming list")
|
||||
attributes.ignore_incoming.extend([val])
|
||||
config_type.message_type.ignore_incoming.extend([val])
|
||||
|
||||
if Globals.getInstance().get_camel_case():
|
||||
print(f"Set {camel_name} to {valStr}")
|
||||
print(f"Set {name[0]}.{camel_name} to {valStr}")
|
||||
else:
|
||||
print(f"Set {snake_name} to {valStr}")
|
||||
print(f"Set {name[0]}.{snake_name} to {valStr}")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def onConnected(interface):
|
||||
@@ -183,18 +181,18 @@ def onConnected(interface):
|
||||
alt = 0
|
||||
lat = 0.0
|
||||
lon = 0.0
|
||||
prefs = interface.localNode.radioConfig.preferences
|
||||
localConfig = interface.localNode.localConfig
|
||||
if args.setalt:
|
||||
alt = int(args.setalt)
|
||||
prefs.fixed_position = True
|
||||
localConfig.fixed_position = True
|
||||
print(f"Fixing altitude at {alt} meters")
|
||||
if args.setlat:
|
||||
lat = float(args.setlat)
|
||||
prefs.fixed_position = True
|
||||
localConfig.fixed_position = True
|
||||
print(f"Fixing latitude at {lat} degrees")
|
||||
if args.setlon:
|
||||
lon = float(args.setlon)
|
||||
prefs.fixed_position = True
|
||||
localConfig.fixed_position = True
|
||||
print(f"Fixing longitude at {lon} degrees")
|
||||
|
||||
print("Setting device position")
|
||||
@@ -224,7 +222,7 @@ def onConnected(interface):
|
||||
if args.pos_fields:
|
||||
# If --pos-fields invoked with args, set position fields
|
||||
closeNow = True
|
||||
prefs = interface.getNode(args.dest).radioConfig.preferences
|
||||
localConfig = interface.getNode(args.dest).localConfig
|
||||
allFields = 0
|
||||
|
||||
try:
|
||||
@@ -239,34 +237,21 @@ def onConnected(interface):
|
||||
|
||||
else:
|
||||
print(f"Setting position fields to {allFields}")
|
||||
setPref(prefs, 'position_flags', f'{allFields:d}')
|
||||
setPref(localConfig, 'position_flags', f'{allFields:d}')
|
||||
print("Writing modified preferences to device")
|
||||
interface.getNode(args.dest).writeConfig()
|
||||
|
||||
elif args.pos_fields is not None:
|
||||
# If --pos-fields invoked without args, read and display current value
|
||||
closeNow = True
|
||||
prefs = interface.getNode(args.dest).radioConfig.preferences
|
||||
localConfig = interface.getNode(args.dest).localConfig
|
||||
|
||||
fieldNames = []
|
||||
for bit in config_pb2.PositionFlags.values():
|
||||
if prefs.position_flags & bit:
|
||||
if localConfig.position_flags & bit:
|
||||
fieldNames.append(config_pb2.PositionFlags.Name(bit))
|
||||
print(' '.join(fieldNames))
|
||||
|
||||
if args.set_team:
|
||||
closeNow = True
|
||||
try:
|
||||
v_team = meshtastic.mesh_pb2.Team.Value(args.set_team.upper())
|
||||
except ValueError:
|
||||
v_team = 0
|
||||
print(f"ERROR: Team \'{args.set_team}\' not found.")
|
||||
print("Try a team name from the sorted list below, or use 'CLEAR' for unaffiliated:")
|
||||
print(sorted(meshtastic.mesh_pb2.Team.keys()))
|
||||
else:
|
||||
print(f"Setting team to {meshtastic.mesh_pb2.Team.Name(v_team)}")
|
||||
interface.getNode(args.dest).setOwner(team=v_team)
|
||||
|
||||
if args.set_ham:
|
||||
closeNow = True
|
||||
print(f"Setting Ham ID to {args.set_ham} and turning off encryption")
|
||||
@@ -339,14 +324,22 @@ def onConnected(interface):
|
||||
# handle settings
|
||||
if args.set:
|
||||
closeNow = True
|
||||
prefs = interface.getNode(args.dest).radioConfig.preferences
|
||||
node = interface.getNode(args.dest)
|
||||
|
||||
# Handle the int/float/bool arguments
|
||||
for pref in args.set:
|
||||
setPref(prefs, pref[0], pref[1])
|
||||
found = setPref(node.localConfig, pref[0], pref[1])
|
||||
if not found:
|
||||
found = setPref(node.moduleConfig, pref[0], pref[1])
|
||||
|
||||
print("Writing modified preferences to device")
|
||||
interface.getNode(args.dest).writeConfig()
|
||||
if found:
|
||||
print("Writing modified preferences to device")
|
||||
interface.getNode(args.dest).writeConfig()
|
||||
else:
|
||||
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]}.")
|
||||
|
||||
if args.configure:
|
||||
with open(args.configure[0], encoding='utf8') as file:
|
||||
@@ -377,35 +370,35 @@ def onConnected(interface):
|
||||
alt = 0
|
||||
lat = 0.0
|
||||
lon = 0.0
|
||||
prefs = interface.localNode.radioConfig.preferences
|
||||
localConfig = interface.localNode.localConfig
|
||||
|
||||
if 'alt' in configuration['location']:
|
||||
alt = int(configuration['location']['alt'])
|
||||
prefs.fixed_position = True
|
||||
localConfig.fixed_position = True
|
||||
print(f"Fixing altitude at {alt} meters")
|
||||
if 'lat' in configuration['location']:
|
||||
lat = float(configuration['location']['lat'])
|
||||
prefs.fixed_position = True
|
||||
localConfig.fixed_position = True
|
||||
print(f"Fixing latitude at {lat} degrees")
|
||||
if 'lon' in configuration['location']:
|
||||
lon = float(configuration['location']['lon'])
|
||||
prefs.fixed_position = True
|
||||
localConfig.fixed_position = True
|
||||
print(f"Fixing longitude at {lon} degrees")
|
||||
print("Setting device position")
|
||||
interface.sendPosition(lat, lon, alt)
|
||||
interface.localNode.writeConfig()
|
||||
|
||||
if 'user_prefs' in configuration:
|
||||
prefs = interface.getNode(args.dest).radioConfig.preferences
|
||||
localConfig = interface.getNode(args.dest).localConfig
|
||||
for pref in configuration['user_prefs']:
|
||||
setPref(prefs, pref, str(configuration['user_prefs'][pref]))
|
||||
setPref(localConfig, pref, str(configuration['user_prefs'][pref]))
|
||||
print("Writing modified preferences to device")
|
||||
interface.getNode(args.dest).writeConfig()
|
||||
|
||||
if 'userPrefs' in configuration:
|
||||
prefs = interface.getNode(args.dest).radioConfig.preferences
|
||||
localConfig = interface.getNode(args.dest).localConfig
|
||||
for pref in configuration['userPrefs']:
|
||||
setPref(prefs, pref, str(configuration['userPrefs'][pref]))
|
||||
setPref(localConfig, pref, str(configuration['userPrefs'][pref]))
|
||||
print("Writing modified preferences to device")
|
||||
interface.getNode(args.dest).writeConfig()
|
||||
|
||||
@@ -454,69 +447,56 @@ def onConnected(interface):
|
||||
print(f"Deleting channel {channelIndex}")
|
||||
ch = interface.getNode(args.dest).deleteChannel(channelIndex)
|
||||
|
||||
ch_changes = [args.ch_vlongslow, args.ch_longslow, args.ch_longfast,
|
||||
args.ch_midslow, args.ch_midfast,
|
||||
args.ch_shortslow, args.ch_shortfast]
|
||||
any_primary_channel_changes = any(x for x in ch_changes)
|
||||
if args.ch_set or any_primary_channel_changes or args.ch_enable or args.ch_disable:
|
||||
def setSimpleConfig(modem_preset):
|
||||
"""Set one of the simple modem_config"""
|
||||
# Completely new radio settings
|
||||
chs = config_pb2.Config.LoRaConfig()
|
||||
chs.modem_preset = modem_preset
|
||||
prefs = interface.getNode(args.dest).localConfig
|
||||
prefs.lora.CopyFrom(chs)
|
||||
interface.getNode(args.dest).writeConfig()
|
||||
|
||||
# handle the simple radio set commands
|
||||
if args.ch_vlongslow:
|
||||
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.VLongSlow)
|
||||
|
||||
if args.ch_longslow:
|
||||
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.LongSlow)
|
||||
|
||||
if args.ch_longfast:
|
||||
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.LongFast)
|
||||
|
||||
if args.ch_midslow:
|
||||
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.MidSlow)
|
||||
|
||||
if args.ch_midfast:
|
||||
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.MidFast)
|
||||
|
||||
if args.ch_shortslow:
|
||||
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.ShortSlow)
|
||||
|
||||
if args.ch_shortfast:
|
||||
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.ShortFast)
|
||||
|
||||
if args.ch_set or args.ch_enable or args.ch_disable:
|
||||
closeNow = True
|
||||
|
||||
channelIndex = our_globals.get_channel_index()
|
||||
if channelIndex is None:
|
||||
if any_primary_channel_changes:
|
||||
# we assume that they want the primary channel if they're setting range values
|
||||
channelIndex = 0
|
||||
else:
|
||||
meshtastic.util.our_exit("Warning: Need to specify '--ch-index'.", 1)
|
||||
meshtastic.util.our_exit("Warning: Need to specify '--ch-index'.", 1)
|
||||
ch = interface.getNode(args.dest).channels[channelIndex]
|
||||
|
||||
if any_primary_channel_changes or args.ch_enable or args.ch_disable:
|
||||
if args.ch_enable or args.ch_disable:
|
||||
|
||||
if channelIndex == 0 and not any_primary_channel_changes:
|
||||
if channelIndex == 0:
|
||||
meshtastic.util.our_exit("Warning: Cannot enable/disable PRIMARY channel.")
|
||||
|
||||
if channelIndex != 0:
|
||||
if any_primary_channel_changes:
|
||||
meshtastic.util.our_exit("Warning: Standard channel settings can only be applied to the PRIMARY channel")
|
||||
|
||||
enable = True # default to enable
|
||||
if args.ch_enable:
|
||||
enable = True
|
||||
if args.ch_disable:
|
||||
enable = False
|
||||
|
||||
def setSimpleChannel(modem_config):
|
||||
"""Set one of the simple modem_config only based channels"""
|
||||
|
||||
# Completely new channel settings
|
||||
chs = channel_pb2.ChannelSettings()
|
||||
chs.modem_config = modem_config
|
||||
chs.psk = bytes([1]) # Use default channel psk 1
|
||||
|
||||
ch.settings.CopyFrom(chs)
|
||||
|
||||
# handle the simple channel set commands
|
||||
if args.ch_vlongslow:
|
||||
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.VLongSlow)
|
||||
|
||||
if args.ch_longslow:
|
||||
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.LongSlow)
|
||||
|
||||
if args.ch_longfast:
|
||||
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.LongFast)
|
||||
|
||||
if args.ch_midslow:
|
||||
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.MidSlow)
|
||||
|
||||
if args.ch_midfast:
|
||||
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.MidFast)
|
||||
|
||||
if args.ch_shortslow:
|
||||
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.ShortSlow)
|
||||
|
||||
if args.ch_shortfast:
|
||||
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.ShortFast)
|
||||
|
||||
# Handle the channel settings
|
||||
for pref in (args.ch_set or []):
|
||||
if pref[0] == "psk":
|
||||
@@ -552,12 +532,21 @@ def onConnected(interface):
|
||||
|
||||
if args.get:
|
||||
closeNow = True
|
||||
prefs = interface.getNode(args.dest).radioConfig.preferences
|
||||
localConfig = interface.getNode(args.dest).localConfig
|
||||
moduleConfig = interface.getNode(args.dest).moduleConfig
|
||||
|
||||
# Handle the int/float/bool arguments
|
||||
for pref in args.get:
|
||||
getPref(prefs, pref[0])
|
||||
found = getPref(localConfig, pref[0])
|
||||
if not found:
|
||||
found = getPref(moduleConfig, 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("Completed getting preferences")
|
||||
|
||||
if args.nodes:
|
||||
@@ -641,7 +630,7 @@ def export_config(interface):
|
||||
if alt:
|
||||
config += f" alt: {alt}\n"
|
||||
config += "\n"
|
||||
preferences = f'{interface.localNode.radioConfig.preferences}'
|
||||
preferences = f'{interface.localNode.localConfig}'
|
||||
prefs = preferences.splitlines()
|
||||
if prefs:
|
||||
if Globals.getInstance().get_camel_case():
|
||||
@@ -849,9 +838,6 @@ def initParser():
|
||||
parser.add_argument(
|
||||
"--set-owner-short", help="Set device owner short name", action="store")
|
||||
|
||||
parser.add_argument(
|
||||
"--set-team", help="Set team affiliation (an invalid team will list valid values)", action="store")
|
||||
|
||||
parser.add_argument(
|
||||
"--set-ham", help="Set licensed Ham ID and turn off encryption", action="store")
|
||||
|
||||
@@ -913,13 +899,6 @@ def initParser():
|
||||
parser.add_argument("--noproto", help="Don't start the API, just function as a dumb serial terminal.",
|
||||
action="store_true")
|
||||
|
||||
parser.add_argument('--setchan', dest='deprecated', nargs=2, action='append',
|
||||
help='Deprecated, use "--ch-set param value" instead')
|
||||
parser.add_argument('--set-router', dest='deprecated',
|
||||
action='store_true', help='Deprecated, use "--set is_router true" instead')
|
||||
parser.add_argument('--unset-router', dest='deprecated',
|
||||
action='store_false', help='Deprecated, use "--set is_router false" instead')
|
||||
|
||||
have_tunnel = platform.system() == 'Linux'
|
||||
if have_tunnel:
|
||||
parser.add_argument('--tunnel', action='store_true',
|
||||
|
||||
@@ -14,7 +14,7 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x63onfig.proto\"\xf1\x11\n\x06\x43onfig\x12&\n\x06\x64\x65vice\x18\x01 \x01(\x0b\x32\x14.Config.DeviceConfigH\x00\x12*\n\x08position\x18\x02 \x01(\x0b\x32\x16.Config.PositionConfigH\x00\x12$\n\x05power\x18\x03 \x01(\x0b\x32\x13.Config.PowerConfigH\x00\x12\"\n\x04wifi\x18\x04 \x01(\x0b\x32\x12.Config.WiFiConfigH\x00\x12(\n\x07\x64isplay\x18\x05 \x01(\x0b\x32\x15.Config.DisplayConfigH\x00\x12\"\n\x04lora\x18\x06 \x01(\x0b\x32\x12.Config.LoRaConfigH\x00\x1a\xd8\x01\n\x0c\x44\x65viceConfig\x12\'\n\x04role\x18\x01 \x01(\x0e\x32\x19.Config.DeviceConfig.Role\x12\x17\n\x0fserial_disabled\x18\x02 \x01(\x08\x12\x15\n\rfactory_reset\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x62ug_log_enabled\x18\x04 \x01(\x08\x12\x12\n\nntp_server\x18\x05 \x01(\t\"@\n\x04Role\x12\n\n\x06\x43lient\x10\x00\x12\x0e\n\nClientMute\x10\x01\x12\n\n\x06Router\x10\x02\x12\x10\n\x0cRouterClient\x10\x03\x1a\x86\x03\n\x0ePositionConfig\x12\x1f\n\x17position_broadcast_secs\x18\x01 \x01(\r\x12)\n!position_broadcast_smart_disabled\x18\x02 \x01(\x08\x12\x16\n\x0e\x66ixed_position\x18\x03 \x01(\x08\x12\x14\n\x0cgps_disabled\x18\x05 \x01(\x08\x12\x1b\n\x13gps_update_interval\x18\x06 \x01(\r\x12\x18\n\x10gps_attempt_time\x18\x07 \x01(\r\x12\x16\n\x0eposition_flags\x18\n \x01(\r\"\xaa\x01\n\rPositionFlags\x12\x11\n\rPOS_UNDEFINED\x10\x00\x12\x10\n\x0cPOS_ALTITUDE\x10\x01\x12\x0f\n\x0bPOS_ALT_MSL\x10\x02\x12\x0f\n\x0bPOS_GEO_SEP\x10\x04\x12\x0b\n\x07POS_DOP\x10\x08\x12\r\n\tPOS_HVDOP\x10\x10\x12\x11\n\rPOS_SATINVIEW\x10 \x12\x0f\n\x0bPOS_SEQ_NOS\x10@\x12\x12\n\rPOS_TIMESTAMP\x10\x80\x01\x1a\x8f\x04\n\x0bPowerConfig\x12\x39\n\x0e\x63harge_current\x18\x01 \x01(\x0e\x32!.Config.PowerConfig.ChargeCurrent\x12\x17\n\x0fis_power_saving\x18\x02 \x01(\x08\x12\x19\n\x11is_always_powered\x18\x03 \x01(\x08\x12&\n\x1eon_battery_shutdown_after_secs\x18\x04 \x01(\r\x12\x1f\n\x17\x61\x64\x63_multiplier_override\x18\x06 \x01(\x02\x12\x1b\n\x13wait_bluetooth_secs\x18\x07 \x01(\r\x12\x1d\n\x15mesh_sds_timeout_secs\x18\t \x01(\r\x12\x10\n\x08sds_secs\x18\n \x01(\r\x12\x0f\n\x07ls_secs\x18\x0b \x01(\r\x12\x15\n\rmin_wake_secs\x18\x0c \x01(\r\"\xd1\x01\n\rChargeCurrent\x12\x0b\n\x07MAUnset\x10\x00\x12\t\n\x05MA100\x10\x01\x12\t\n\x05MA190\x10\x02\x12\t\n\x05MA280\x10\x03\x12\t\n\x05MA360\x10\x04\x12\t\n\x05MA450\x10\x05\x12\t\n\x05MA550\x10\x06\x12\t\n\x05MA630\x10\x07\x12\t\n\x05MA700\x10\x08\x12\t\n\x05MA780\x10\t\x12\t\n\x05MA880\x10\n\x12\t\n\x05MA960\x10\x0b\x12\n\n\x06MA1000\x10\x0c\x12\n\n\x06MA1080\x10\r\x12\n\n\x06MA1160\x10\x0e\x12\n\n\x06MA1240\x10\x0f\x12\n\n\x06MA1320\x10\x10\x1aK\n\nWiFiConfig\x12\x0c\n\x04ssid\x18\x01 \x01(\t\x12\x0b\n\x03psk\x18\x02 \x01(\t\x12\x0f\n\x07\x61p_mode\x18\x03 \x01(\x08\x12\x11\n\tap_hidden\x18\x04 \x01(\x08\x1a\x8f\x02\n\rDisplayConfig\x12\x16\n\x0escreen_on_secs\x18\x01 \x01(\r\x12=\n\ngps_format\x18\x02 \x01(\x0e\x32).Config.DisplayConfig.GpsCoordinateFormat\x12!\n\x19\x61uto_screen_carousel_secs\x18\x03 \x01(\r\"\x83\x01\n\x13GpsCoordinateFormat\x12\x10\n\x0cGpsFormatDec\x10\x00\x12\x10\n\x0cGpsFormatDMS\x10\x01\x12\x10\n\x0cGpsFormatUTM\x10\x02\x12\x11\n\rGpsFormatMGRS\x10\x03\x12\x10\n\x0cGpsFormatOLC\x10\x04\x12\x11\n\rGpsFormatOSGR\x10\x05\x1a\x93\x04\n\nLoRaConfig\x12\x10\n\x08tx_power\x18\x01 \x01(\x05\x12\x34\n\x0cmodem_preset\x18\x02 \x01(\x0e\x32\x1e.Config.LoRaConfig.ModemPreset\x12\x11\n\tbandwidth\x18\x03 \x01(\r\x12\x15\n\rspread_factor\x18\x04 \x01(\r\x12\x13\n\x0b\x63oding_rate\x18\x05 \x01(\r\x12\x18\n\x10\x66requency_offset\x18\x06 \x01(\x02\x12-\n\x06region\x18\x07 \x01(\x0e\x32\x1d.Config.LoRaConfig.RegionCode\x12\x11\n\thop_limit\x18\x08 \x01(\r\x12\x13\n\x0btx_disabled\x18\t \x01(\x08\x12\x17\n\x0fignore_incoming\x18g \x03(\r\"\x81\x01\n\nRegionCode\x12\t\n\x05Unset\x10\x00\x12\x06\n\x02US\x10\x01\x12\t\n\x05\x45U433\x10\x02\x12\t\n\x05\x45U868\x10\x03\x12\x06\n\x02\x43N\x10\x04\x12\x06\n\x02JP\x10\x05\x12\x07\n\x03\x41NZ\x10\x06\x12\x06\n\x02KR\x10\x07\x12\x06\n\x02TW\x10\x08\x12\x06\n\x02RU\x10\t\x12\x06\n\x02IN\x10\n\x12\t\n\x05NZ865\x10\x0b\x12\x06\n\x02TH\x10\x0c\"p\n\x0bModemPreset\x12\x0c\n\x08LongFast\x10\x00\x12\x0c\n\x08LongSlow\x10\x01\x12\r\n\tVLongSlow\x10\x02\x12\x0b\n\x07MidSlow\x10\x03\x12\x0b\n\x07MidFast\x10\x04\x12\r\n\tShortSlow\x10\x05\x12\r\n\tShortFast\x10\x06\x42\x10\n\x0epayloadVariantBH\n\x13\x63om.geeksville.meshB\x0c\x43onfigProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x63onfig.proto\"\xf8\x11\n\x06\x43onfig\x12&\n\x06\x64\x65vice\x18\x01 \x01(\x0b\x32\x14.Config.DeviceConfigH\x00\x12*\n\x08position\x18\x02 \x01(\x0b\x32\x16.Config.PositionConfigH\x00\x12$\n\x05power\x18\x03 \x01(\x0b\x32\x13.Config.PowerConfigH\x00\x12\"\n\x04wifi\x18\x04 \x01(\x0b\x32\x12.Config.WiFiConfigH\x00\x12(\n\x07\x64isplay\x18\x05 \x01(\x0b\x32\x15.Config.DisplayConfigH\x00\x12\"\n\x04lora\x18\x06 \x01(\x0b\x32\x12.Config.LoRaConfigH\x00\x1a\xd8\x01\n\x0c\x44\x65viceConfig\x12\'\n\x04role\x18\x01 \x01(\x0e\x32\x19.Config.DeviceConfig.Role\x12\x17\n\x0fserial_disabled\x18\x02 \x01(\x08\x12\x15\n\rfactory_reset\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x62ug_log_enabled\x18\x04 \x01(\x08\x12\x12\n\nntp_server\x18\x05 \x01(\t\"@\n\x04Role\x12\n\n\x06\x43lient\x10\x00\x12\x0e\n\nClientMute\x10\x01\x12\n\n\x06Router\x10\x02\x12\x10\n\x0cRouterClient\x10\x03\x1a\xa8\x03\n\x0ePositionConfig\x12\x1f\n\x17position_broadcast_secs\x18\x01 \x01(\r\x12)\n!position_broadcast_smart_disabled\x18\x02 \x01(\x08\x12\x16\n\x0e\x66ixed_position\x18\x03 \x01(\x08\x12\x14\n\x0cgps_disabled\x18\x05 \x01(\x08\x12\x1b\n\x13gps_update_interval\x18\x06 \x01(\r\x12\x18\n\x10gps_attempt_time\x18\x07 \x01(\r\x12\x16\n\x0eposition_flags\x18\n \x01(\r\"\xcc\x01\n\rPositionFlags\x12\x11\n\rPOS_UNDEFINED\x10\x00\x12\x10\n\x0cPOS_ALTITUDE\x10\x01\x12\x0f\n\x0bPOS_ALT_MSL\x10\x02\x12\x0f\n\x0bPOS_GEO_SEP\x10\x04\x12\x0b\n\x07POS_DOP\x10\x08\x12\r\n\tPOS_HVDOP\x10\x10\x12\x11\n\rPOS_SATINVIEW\x10 \x12\x0f\n\x0bPOS_SEQ_NOS\x10@\x12\x12\n\rPOS_TIMESTAMP\x10\x80\x01\x12\x10\n\x0bPOS_HEADING\x10\x80\x02\x12\x0e\n\tPOS_SPEED\x10\x80\x04\x1a\xf4\x03\n\x0bPowerConfig\x12\x39\n\x0e\x63harge_current\x18\x01 \x01(\x0e\x32!.Config.PowerConfig.ChargeCurrent\x12\x17\n\x0fis_power_saving\x18\x02 \x01(\x08\x12&\n\x1eon_battery_shutdown_after_secs\x18\x04 \x01(\r\x12\x1f\n\x17\x61\x64\x63_multiplier_override\x18\x06 \x01(\x02\x12\x1b\n\x13wait_bluetooth_secs\x18\x07 \x01(\r\x12\x1d\n\x15mesh_sds_timeout_secs\x18\t \x01(\r\x12\x10\n\x08sds_secs\x18\n \x01(\r\x12\x0f\n\x07ls_secs\x18\x0b \x01(\r\x12\x15\n\rmin_wake_secs\x18\x0c \x01(\r\"\xd1\x01\n\rChargeCurrent\x12\x0b\n\x07MAUnset\x10\x00\x12\t\n\x05MA100\x10\x01\x12\t\n\x05MA190\x10\x02\x12\t\n\x05MA280\x10\x03\x12\t\n\x05MA360\x10\x04\x12\t\n\x05MA450\x10\x05\x12\t\n\x05MA550\x10\x06\x12\t\n\x05MA630\x10\x07\x12\t\n\x05MA700\x10\x08\x12\t\n\x05MA780\x10\t\x12\t\n\x05MA880\x10\n\x12\t\n\x05MA960\x10\x0b\x12\n\n\x06MA1000\x10\x0c\x12\n\n\x06MA1080\x10\r\x12\n\n\x06MA1160\x10\x0e\x12\n\n\x06MA1240\x10\x0f\x12\n\n\x06MA1320\x10\x10\x1aK\n\nWiFiConfig\x12\x0c\n\x04ssid\x18\x01 \x01(\t\x12\x0b\n\x03psk\x18\x02 \x01(\t\x12\x0f\n\x07\x61p_mode\x18\x03 \x01(\x08\x12\x11\n\tap_hidden\x18\x04 \x01(\x08\x1a\x8f\x02\n\rDisplayConfig\x12\x16\n\x0escreen_on_secs\x18\x01 \x01(\r\x12=\n\ngps_format\x18\x02 \x01(\x0e\x32).Config.DisplayConfig.GpsCoordinateFormat\x12!\n\x19\x61uto_screen_carousel_secs\x18\x03 \x01(\r\"\x83\x01\n\x13GpsCoordinateFormat\x12\x10\n\x0cGpsFormatDec\x10\x00\x12\x10\n\x0cGpsFormatDMS\x10\x01\x12\x10\n\x0cGpsFormatUTM\x10\x02\x12\x11\n\rGpsFormatMGRS\x10\x03\x12\x10\n\x0cGpsFormatOLC\x10\x04\x12\x11\n\rGpsFormatOSGR\x10\x05\x1a\x93\x04\n\nLoRaConfig\x12\x10\n\x08tx_power\x18\x01 \x01(\x05\x12\x34\n\x0cmodem_preset\x18\x02 \x01(\x0e\x32\x1e.Config.LoRaConfig.ModemPreset\x12\x11\n\tbandwidth\x18\x03 \x01(\r\x12\x15\n\rspread_factor\x18\x04 \x01(\r\x12\x13\n\x0b\x63oding_rate\x18\x05 \x01(\r\x12\x18\n\x10\x66requency_offset\x18\x06 \x01(\x02\x12-\n\x06region\x18\x07 \x01(\x0e\x32\x1d.Config.LoRaConfig.RegionCode\x12\x11\n\thop_limit\x18\x08 \x01(\r\x12\x13\n\x0btx_disabled\x18\t \x01(\x08\x12\x17\n\x0fignore_incoming\x18g \x03(\r\"\x81\x01\n\nRegionCode\x12\t\n\x05Unset\x10\x00\x12\x06\n\x02US\x10\x01\x12\t\n\x05\x45U433\x10\x02\x12\t\n\x05\x45U868\x10\x03\x12\x06\n\x02\x43N\x10\x04\x12\x06\n\x02JP\x10\x05\x12\x07\n\x03\x41NZ\x10\x06\x12\x06\n\x02KR\x10\x07\x12\x06\n\x02TW\x10\x08\x12\x06\n\x02RU\x10\t\x12\x06\n\x02IN\x10\n\x12\t\n\x05NZ865\x10\x0b\x12\x06\n\x02TH\x10\x0c\"p\n\x0bModemPreset\x12\x0c\n\x08LongFast\x10\x00\x12\x0c\n\x08LongSlow\x10\x01\x12\r\n\tVLongSlow\x10\x02\x12\x0b\n\x07MedSlow\x10\x03\x12\x0b\n\x07MedFast\x10\x04\x12\r\n\tShortSlow\x10\x05\x12\r\n\tShortFast\x10\x06\x42\x10\n\x0epayloadVariantBH\n\x13\x63om.geeksville.meshB\x0c\x43onfigProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3')
|
||||
|
||||
|
||||
|
||||
@@ -91,29 +91,29 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\014ConfigProtosH\003Z!github.com/meshtastic/gomeshproto'
|
||||
_CONFIG._serialized_start=17
|
||||
_CONFIG._serialized_end=2306
|
||||
_CONFIG._serialized_end=2313
|
||||
_CONFIG_DEVICECONFIG._serialized_start=264
|
||||
_CONFIG_DEVICECONFIG._serialized_end=480
|
||||
_CONFIG_DEVICECONFIG_ROLE._serialized_start=416
|
||||
_CONFIG_DEVICECONFIG_ROLE._serialized_end=480
|
||||
_CONFIG_POSITIONCONFIG._serialized_start=483
|
||||
_CONFIG_POSITIONCONFIG._serialized_end=873
|
||||
_CONFIG_POSITIONCONFIG._serialized_end=907
|
||||
_CONFIG_POSITIONCONFIG_POSITIONFLAGS._serialized_start=703
|
||||
_CONFIG_POSITIONCONFIG_POSITIONFLAGS._serialized_end=873
|
||||
_CONFIG_POWERCONFIG._serialized_start=876
|
||||
_CONFIG_POWERCONFIG._serialized_end=1403
|
||||
_CONFIG_POWERCONFIG_CHARGECURRENT._serialized_start=1194
|
||||
_CONFIG_POWERCONFIG_CHARGECURRENT._serialized_end=1403
|
||||
_CONFIG_WIFICONFIG._serialized_start=1405
|
||||
_CONFIG_WIFICONFIG._serialized_end=1480
|
||||
_CONFIG_DISPLAYCONFIG._serialized_start=1483
|
||||
_CONFIG_DISPLAYCONFIG._serialized_end=1754
|
||||
_CONFIG_DISPLAYCONFIG_GPSCOORDINATEFORMAT._serialized_start=1623
|
||||
_CONFIG_DISPLAYCONFIG_GPSCOORDINATEFORMAT._serialized_end=1754
|
||||
_CONFIG_LORACONFIG._serialized_start=1757
|
||||
_CONFIG_LORACONFIG._serialized_end=2288
|
||||
_CONFIG_LORACONFIG_REGIONCODE._serialized_start=2045
|
||||
_CONFIG_LORACONFIG_REGIONCODE._serialized_end=2174
|
||||
_CONFIG_LORACONFIG_MODEMPRESET._serialized_start=2176
|
||||
_CONFIG_LORACONFIG_MODEMPRESET._serialized_end=2288
|
||||
_CONFIG_POSITIONCONFIG_POSITIONFLAGS._serialized_end=907
|
||||
_CONFIG_POWERCONFIG._serialized_start=910
|
||||
_CONFIG_POWERCONFIG._serialized_end=1410
|
||||
_CONFIG_POWERCONFIG_CHARGECURRENT._serialized_start=1201
|
||||
_CONFIG_POWERCONFIG_CHARGECURRENT._serialized_end=1410
|
||||
_CONFIG_WIFICONFIG._serialized_start=1412
|
||||
_CONFIG_WIFICONFIG._serialized_end=1487
|
||||
_CONFIG_DISPLAYCONFIG._serialized_start=1490
|
||||
_CONFIG_DISPLAYCONFIG._serialized_end=1761
|
||||
_CONFIG_DISPLAYCONFIG_GPSCOORDINATEFORMAT._serialized_start=1630
|
||||
_CONFIG_DISPLAYCONFIG_GPSCOORDINATEFORMAT._serialized_end=1761
|
||||
_CONFIG_LORACONFIG._serialized_start=1764
|
||||
_CONFIG_LORACONFIG._serialized_end=2295
|
||||
_CONFIG_LORACONFIG_REGIONCODE._serialized_start=2052
|
||||
_CONFIG_LORACONFIG_REGIONCODE._serialized_end=2181
|
||||
_CONFIG_LORACONFIG_MODEMPRESET._serialized_start=2183
|
||||
_CONFIG_LORACONFIG_MODEMPRESET._serialized_end=2295
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
@@ -362,11 +362,9 @@ class MeshInterface:
|
||||
|
||||
def waitForConfig(self):
|
||||
"""Block until radio config is received. Returns True if config has been received."""
|
||||
# TODO
|
||||
return True
|
||||
#success = self._timeout.waitForSet(self, attrs=('myInfo', 'nodes')) and self.localNode.waitForConfig()
|
||||
#if not success:
|
||||
#raise Exception("Timed out waiting for interface config")
|
||||
success = self._timeout.waitForSet(self, attrs=('myInfo', 'nodes')) and self.localNode.waitForConfig()
|
||||
if not success:
|
||||
raise Exception("Timed out waiting for interface config")
|
||||
|
||||
def getMyNodeInfo(self):
|
||||
"""Get info about my node."""
|
||||
@@ -424,10 +422,8 @@ class MeshInterface:
|
||||
"""We need to send a heartbeat message to the device every X seconds"""
|
||||
def callback():
|
||||
self.heartbeatTimer = None
|
||||
# TODO
|
||||
# prefs = self.localNode.radioConfig.preferences
|
||||
#i = prefs.phone_timeout_secs / 2
|
||||
i = 0
|
||||
prefs = self.localNode.localConfig
|
||||
i = prefs.power.ls_secs / 2
|
||||
logging.debug(f"Sending heartbeat, interval {i}")
|
||||
if i != 0:
|
||||
self.heartbeatTimer = threading.Timer(i, callback)
|
||||
@@ -536,29 +532,44 @@ class MeshInterface:
|
||||
# stream API fromRadio.config_complete_id
|
||||
logging.debug(f"Config complete ID {self.configId}")
|
||||
self._handleConfigComplete()
|
||||
|
||||
elif fromRadio.HasField("packet"):
|
||||
self._handlePacketFromRadio(fromRadio.packet)
|
||||
|
||||
elif fromRadio.rebooted:
|
||||
# Tell clients the device went away. Careful not to call the overridden
|
||||
# subclass version that closes the serial port
|
||||
MeshInterface._disconnected(self)
|
||||
|
||||
self._startConfig() # redownload the node db etc...
|
||||
elif fromRadio.config:
|
||||
logging.debug("Hey! We got some configs")
|
||||
|
||||
elif fromRadio.config or fromRadio.moduleConfig:
|
||||
if fromRadio.config.HasField("device"):
|
||||
logging.debug("device!")
|
||||
# TODO: do something with this config
|
||||
self.localNode.localConfig.device.CopyFrom(fromRadio.config.device)
|
||||
elif fromRadio.config.HasField("position"):
|
||||
logging.debug("position!")
|
||||
self.localNode.localConfig.position.CopyFrom(fromRadio.config.position)
|
||||
elif fromRadio.config.HasField("power"):
|
||||
logging.debug("power!")
|
||||
self.localNode.localConfig.power.CopyFrom(fromRadio.config.power)
|
||||
elif fromRadio.config.HasField("wifi"):
|
||||
logging.debug("wifi!")
|
||||
self.localNode.localConfig.wifi.CopyFrom(fromRadio.config.wifi)
|
||||
elif fromRadio.config.HasField("display"):
|
||||
logging.debug("display!")
|
||||
self.localNode.localConfig.display.CopyFrom(fromRadio.config.display)
|
||||
elif fromRadio.config.HasField("lora"):
|
||||
logging.debug("lora!")
|
||||
self.localNode.localConfig.lora.CopyFrom(fromRadio.config.lora)
|
||||
|
||||
elif fromRadio.moduleConfig.HasField("mqtt"):
|
||||
self.localNode.moduleConfig.mqtt.CopyFrom(fromRadio.moduleConfig.mqtt)
|
||||
elif fromRadio.moduleConfig.HasField("serial"):
|
||||
self.localNode.moduleConfig.serial.CopyFrom(fromRadio.moduleConfig.serial)
|
||||
elif fromRadio.moduleConfig.HasField("external_notification"):
|
||||
self.localNode.moduleConfig.external_notification.CopyFrom(fromRadio.moduleConfig.external_notification)
|
||||
elif fromRadio.moduleConfig.HasField("range_test"):
|
||||
self.localNode.moduleConfig.range_test.CopyFrom(fromRadio.moduleConfig.range_test)
|
||||
elif fromRadio.moduleConfig.HasField("telemetry"):
|
||||
self.localNode.moduleConfig.telemetry.CopyFrom(fromRadio.moduleConfig.telemetry)
|
||||
elif fromRadio.moduleConfig.HasField("canned_message"):
|
||||
self.localNode.moduleConfig.canned_message.CopyFrom(fromRadio.moduleConfig.canned_message)
|
||||
|
||||
else:
|
||||
logging.debug("Unexpected FromRadio payload")
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,22 +5,22 @@ import logging
|
||||
import base64
|
||||
import time
|
||||
from google.protobuf.json_format import MessageToJson
|
||||
from meshtastic import portnums_pb2, apponly_pb2, admin_pb2, channel_pb2
|
||||
from meshtastic import portnums_pb2, apponly_pb2, admin_pb2, channel_pb2, localonly_pb2
|
||||
from meshtastic.util import pskToString, stripnl, Timeout, our_exit, fromPSK
|
||||
|
||||
|
||||
class Node:
|
||||
"""A model of a (local or remote) node in the mesh
|
||||
|
||||
Includes methods for radioConfig and channels
|
||||
Includes methods for localConfig, moduleConfig and channels
|
||||
"""
|
||||
|
||||
def __init__(self, iface, nodeNum, noProto=False):
|
||||
"""Constructor"""
|
||||
self.iface = iface
|
||||
self.nodeNum = nodeNum
|
||||
self.radioConfig = None
|
||||
self.partialConfig = None
|
||||
self.localConfig = localonly_pb2.LocalConfig()
|
||||
self.moduleConfig = localonly_pb2.LocalModuleConfig()
|
||||
self.channels = None
|
||||
self._timeout = Timeout(maxSecs=300)
|
||||
self.partialChannels = None
|
||||
@@ -55,28 +55,22 @@ class Node:
|
||||
def showInfo(self):
|
||||
"""Show human readable description of our node"""
|
||||
prefs = ""
|
||||
if self.radioConfig and self.radioConfig.preferences:
|
||||
prefs = stripnl(MessageToJson(self.radioConfig.preferences))
|
||||
if self.localConfig:
|
||||
prefs = stripnl(MessageToJson(self.localConfig))
|
||||
print(f"Preferences: {prefs}\n")
|
||||
prefs = ""
|
||||
if self.moduleConfig:
|
||||
prefs = stripnl(MessageToJson(self.moduleConfig))
|
||||
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}")
|
||||
self.radioConfig = None
|
||||
self.partialConfig = []
|
||||
self.channels = None
|
||||
self.partialChannels = [] # We keep our channels in a temp array until finished
|
||||
|
||||
# Note: We do not get the canned plugin message, unless get_canned_message() is called
|
||||
self.cannedPluginMessage = None
|
||||
|
||||
self.cannedPluginMessagePart1 = None
|
||||
self.cannedPluginMessagePart2 = None
|
||||
self.cannedPluginMessagePart3 = None
|
||||
self.cannedPluginMessagePart4 = None
|
||||
|
||||
self._requestSettings()
|
||||
self._requestChannel(0)
|
||||
|
||||
def turnOffEncryptionOnPrimaryChannel(self):
|
||||
"""Turn off encryption on primary channel."""
|
||||
@@ -86,25 +80,109 @@ class Node:
|
||||
|
||||
def waitForConfig(self, attribute='channels'):
|
||||
"""Block until radio config is received. Returns True if config has been received."""
|
||||
return self._timeout.waitForSet(self, attrs=('config', attribute))
|
||||
return self._timeout.waitForSet(self, attrs=('localConfig', attribute))
|
||||
|
||||
def writeConfig(self):
|
||||
"""Write the current (edited) radioConfig to the device"""
|
||||
if self.radioConfig is None:
|
||||
our_exit("Error: No RadioConfig has been read")
|
||||
"""Write the current (edited) localConfig to the device"""
|
||||
if self.localConfig is None:
|
||||
our_exit("Error: No localConfig has been read")
|
||||
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_radio.CopyFrom(self.radioConfig)
|
||||
if self.localConfig.device:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_config.device.CopyFrom(self.localConfig.device)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote device")
|
||||
time.sleep(0.1)
|
||||
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote config")
|
||||
if self.localConfig.position:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_config.position.CopyFrom(self.localConfig.position)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote position")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.localConfig.power:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_config.power.CopyFrom(self.localConfig.power)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote power")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.localConfig.wifi:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_config.wifi.CopyFrom(self.localConfig.wifi)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote wifi")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.localConfig.display:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_config.display.CopyFrom(self.localConfig.display)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote display")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.localConfig.lora:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_config.lora.CopyFrom(self.localConfig.lora)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote lora")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.moduleConfig.mqtt:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_module_config.mqtt.CopyFrom(self.moduleConfig.mqtt)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote module: mqtt")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.moduleConfig.serial:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_module_config.serial.CopyFrom(self.moduleConfig.serial)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote module: serial")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.moduleConfig.external_notification:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_module_config.external_notification.CopyFrom(self.moduleConfig.external_notification)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote module: external_notification")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.moduleConfig.store_forward:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_module_config.store_forward.CopyFrom(self.moduleConfig.store_forward)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote module: store_forward")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.moduleConfig.range_test:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_module_config.range_test.CopyFrom(self.moduleConfig.range_test)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote module: range_test")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.moduleConfig.telemetry:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_module_config.telemetry.CopyFrom(self.moduleConfig.telemetry)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote module: telemetry")
|
||||
time.sleep(0.1)
|
||||
|
||||
if self.moduleConfig.canned_message:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_module_config.canned_message.CopyFrom(self.moduleConfig.canned_message)
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote module: canned_message")
|
||||
time.sleep(0.1)
|
||||
|
||||
def writeChannel(self, channelIndex, adminIndex=0):
|
||||
"""Write the current (edited) channel to the device"""
|
||||
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_channel.CopyFrom(self.channels[channelIndex])
|
||||
|
||||
self._sendAdmin(p, adminIndex=adminIndex)
|
||||
logging.debug(f"Wrote channel {channelIndex}")
|
||||
|
||||
@@ -165,7 +243,7 @@ class Node:
|
||||
else:
|
||||
return 0
|
||||
|
||||
def setOwner(self, long_name=None, short_name=None, is_licensed=False, team=None):
|
||||
def setOwner(self, long_name=None, short_name=None, is_licensed=False):
|
||||
"""Set device owner name"""
|
||||
logging.debug(f"in setOwner nodeNum:{self.nodeNum}")
|
||||
nChars = 3
|
||||
@@ -194,14 +272,11 @@ class Node:
|
||||
short_name = short_name[:nChars]
|
||||
p.set_owner.short_name = short_name
|
||||
p.set_owner.is_licensed = is_licensed
|
||||
if team is not None:
|
||||
p.set_owner.team = team
|
||||
|
||||
# Note: These debug lines are used in unit tests
|
||||
logging.debug(f'p.set_owner.long_name:{p.set_owner.long_name}:')
|
||||
logging.debug(f'p.set_owner.short_name:{p.set_owner.short_name}:')
|
||||
logging.debug(f'p.set_owner.is_licensed:{p.set_owner.is_licensed}')
|
||||
logging.debug(f'p.set_owner.team:{p.set_owner.team}')
|
||||
return self._sendAdmin(p)
|
||||
|
||||
def getURL(self, includeAll: bool = True):
|
||||
@@ -218,8 +293,8 @@ class Node:
|
||||
|
||||
def setURL(self, url):
|
||||
"""Set mesh network URL"""
|
||||
if self.radioConfig is None:
|
||||
our_exit("Warning: No RadioConfig has been read")
|
||||
if self.localConfig is None:
|
||||
our_exit("Warning: No Config has been read")
|
||||
|
||||
# URLs are of the form https://www.meshtastic.org/d/#{base64_channel_set}
|
||||
# Split on '/#' to find the base64 encoded channel settings
|
||||
@@ -252,66 +327,6 @@ class Node:
|
||||
self.writeChannel(ch.index)
|
||||
i = i + 1
|
||||
|
||||
|
||||
def onResponseRequestSettings(self, p):
|
||||
"""Handle the response packets for requesting settings _requestSettings()"""
|
||||
logging.debug(f'onResponseRequestSetting() 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"]}')
|
||||
# TODO
|
||||
#if errorFound is False:
|
||||
#self.partialConfig[p["decoded"]["admin"]["payloadVariant"]] = p["decoded"]["admin"]["raw"].get_config_response
|
||||
#logging.debug(f'self.partialConfig:{self.partialConfig}')
|
||||
#self._timeout.reset() # We made foreward progress
|
||||
#self.gotResponse = True
|
||||
|
||||
def _requestSettings(self):
|
||||
"""Done with initial config messages, now send regular
|
||||
MeshPackets to ask for settings."""
|
||||
|
||||
# TODO: should we check that localNode has an 'admin' channel?
|
||||
# Show progress message for super slow operations
|
||||
if self != self.iface.localNode:
|
||||
print("Requesting preferences from remote node.")
|
||||
print("Be sure:")
|
||||
print(" 1. There is a SECONDARY channel named 'admin'.")
|
||||
print(" 2. The '--seturl' was used to configure.")
|
||||
print(" 3. All devices have the same modem config. (i.e., '--ch-longfast')")
|
||||
print(" 4. All devices have been rebooted after all of the above. (optional, but recommended)")
|
||||
print("Note: This could take a while (it requests remote channel configs, then writes config)")
|
||||
|
||||
p1 = admin_pb2.AdminMessage()
|
||||
p1.get_config_request = admin_pb2.AdminMessage.ConfigType.DEVICE_CONFIG
|
||||
self._sendAdmin(p1, wantResponse=True, onResponse=self.onResponseRequestSettings)
|
||||
|
||||
p2 = admin_pb2.AdminMessage()
|
||||
p2.get_config_request = admin_pb2.AdminMessage.ConfigType.POSITION_CONFIG
|
||||
self._sendAdmin(p2, wantResponse=True, onResponse=self.onResponseRequestSettings)
|
||||
|
||||
p3 = admin_pb2.AdminMessage()
|
||||
p3.get_config_request = admin_pb2.AdminMessage.ConfigType.POWER_CONFIG
|
||||
self._sendAdmin(p3, wantResponse=True, onResponse=self.onResponseRequestSettings)
|
||||
|
||||
p4 = admin_pb2.AdminMessage()
|
||||
p4.get_config_request = admin_pb2.AdminMessage.ConfigType.WIFI_CONFIG
|
||||
self._sendAdmin(p4, wantResponse=True, onResponse=self.onResponseRequestSettings)
|
||||
|
||||
p5 = admin_pb2.AdminMessage()
|
||||
p5.get_config_request = admin_pb2.AdminMessage.ConfigType.DISPLAY_CONFIG
|
||||
self._sendAdmin(p5, wantResponse=True, onResponse=self.onResponseRequestSettings)
|
||||
|
||||
p6 = admin_pb2.AdminMessage()
|
||||
p6.get_config_request = admin_pb2.AdminMessage.ConfigType.LORA_CONFIG
|
||||
self._sendAdmin(p6, wantResponse=True, onResponse=self.onResponseRequestSettings)
|
||||
|
||||
# TODO Assemble radioConfig
|
||||
|
||||
logging.debug("Received config, now fetching channels...")
|
||||
self._requestChannel(0) # now start fetching channels
|
||||
|
||||
def onResponseRequestCannedMessagePluginMessagePart1(self, p):
|
||||
"""Handle the response packet for requesting canned message plugin message part 1"""
|
||||
logging.debug(f'onResponseRequestCannedMessagePluginMessagePart1() p:{p}')
|
||||
|
||||
@@ -789,63 +789,6 @@ def test_main_setalt(capsys):
|
||||
assert err == ''
|
||||
mo.assert_called()
|
||||
|
||||
|
||||
# TODO
|
||||
#@pytest.mark.unit
|
||||
#@pytest.mark.usefixtures("reset_globals")
|
||||
#def test_main_set_team_valid(capsys):
|
||||
# """Test --set-team"""
|
||||
# sys.argv = ['', '--set-team', 'CYAN']
|
||||
# Globals.getInstance().set_args(sys.argv)
|
||||
#
|
||||
# mocked_node = MagicMock(autospec=Node)
|
||||
# def mock_setOwner(team):
|
||||
# print('inside mocked setOwner')
|
||||
# print(f'{team}')
|
||||
# mocked_node.setOwner.side_effect = mock_setOwner
|
||||
#
|
||||
# iface = MagicMock(autospec=SerialInterface)
|
||||
# iface.localNode.return_value = mocked_node
|
||||
#
|
||||
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
||||
# with patch('meshtastic.mesh_pb2.Team') as mm:
|
||||
# mm.Name.return_value = 'FAKENAME'
|
||||
# mm.Value.return_value = 'FAKEVAL'
|
||||
# main()
|
||||
# out, err = capsys.readouterr()
|
||||
# assert re.search(r'Connected to radio', out, re.MULTILINE)
|
||||
# assert re.search(r'Setting team to', out, re.MULTILINE)
|
||||
# assert err == ''
|
||||
# mo.assert_called()
|
||||
# mm.Name.assert_called()
|
||||
# mm.Value.assert_called()
|
||||
#
|
||||
|
||||
# TODO
|
||||
#@pytest.mark.unit
|
||||
#@pytest.mark.usefixtures("reset_globals")
|
||||
#def test_main_set_team_invalid(capsys):
|
||||
# """Test --set-team using an invalid team name"""
|
||||
# sys.argv = ['', '--set-team', 'NOTCYAN']
|
||||
# Globals.getInstance().set_args(sys.argv)
|
||||
#
|
||||
# iface = MagicMock(autospec=SerialInterface)
|
||||
#
|
||||
# def throw_an_exception(exc):
|
||||
# raise ValueError("Fake exception.")
|
||||
#
|
||||
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
||||
# with patch('meshtastic.mesh_pb2.Team') as mm:
|
||||
# mm.Value.side_effect = throw_an_exception
|
||||
# main()
|
||||
# out, err = capsys.readouterr()
|
||||
# assert re.search(r'Connected to radio', out, re.MULTILINE)
|
||||
# assert re.search(r'ERROR: Team', out, re.MULTILINE)
|
||||
# assert err == ''
|
||||
# mo.assert_called()
|
||||
# mm.Value.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_globals")
|
||||
def test_main_seturl(capsys):
|
||||
@@ -1541,24 +1484,6 @@ def test_main_get_with_invalid(capsys):
|
||||
mo.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_globals")
|
||||
def test_main_setchan(capsys):
|
||||
"""Test --setchan (deprecated)"""
|
||||
sys.argv = ['', '--setchan', 'a', 'b']
|
||||
Globals.getInstance().set_args(sys.argv)
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
|
||||
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
main()
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
_, err = capsys.readouterr()
|
||||
assert re.search(r'usage:', err, re.MULTILINE)
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_globals")
|
||||
def test_main_onReceive_empty(caplog, capsys):
|
||||
|
||||
@@ -164,19 +164,6 @@ from ..channel_pb2 import Channel
|
||||
# assert err == ''
|
||||
|
||||
|
||||
# TODO
|
||||
#@pytest.mark.unit
|
||||
#def test_setOwner_and_team(caplog):
|
||||
# """Test setOwner"""
|
||||
# anode = Node('foo', 'bar', noProto=True)
|
||||
# with caplog.at_level(logging.DEBUG):
|
||||
# anode.setOwner(long_name ='Test123', short_name='123', team=1)
|
||||
# assert re.search(r'p.set_owner.long_name:Test123:', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.short_name:123:', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.is_licensed:False', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.team:1', caplog.text, re.MULTILINE)
|
||||
|
||||
|
||||
# TODO
|
||||
#@pytest.mark.unit
|
||||
#def test_setOwnerShort(caplog):
|
||||
@@ -197,7 +184,6 @@ from ..channel_pb2 import Channel
|
||||
# assert re.search(r'p.set_owner.long_name:Test123:', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.short_name:Tst:', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.is_licensed:False', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)
|
||||
|
||||
|
||||
# TODO
|
||||
@@ -210,7 +196,6 @@ from ..channel_pb2 import Channel
|
||||
# assert re.search(r'p.set_owner.long_name:Tnt:', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.short_name:Tnt:', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.is_licensed:False', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)
|
||||
|
||||
|
||||
# TODO
|
||||
@@ -223,7 +208,6 @@ from ..channel_pb2 import Channel
|
||||
# assert re.search(r'p.set_owner.long_name:A B C:', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.short_name:ABC:', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.is_licensed:True', caplog.text, re.MULTILINE)
|
||||
# assert re.search(r'p.set_owner.team:0', caplog.text, re.MULTILINE)
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
@@ -214,26 +214,6 @@ def test_smoke1_set_owner():
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_set_team():
|
||||
"""Test --set-team """
|
||||
# unset the team
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set-team CLEAR')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Setting team to CLEAR', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --set-team CYAN')
|
||||
assert re.search(r'Setting team to CYAN', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'CYAN', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smoke1
|
||||
def test_smoke1_ch_set_modem_config():
|
||||
"""Test --ch-set modem_config"""
|
||||
|
||||
@@ -219,26 +219,6 @@ def test_smokevirt_set_owner():
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smokevirt
|
||||
def test_smokevirt_set_team():
|
||||
"""Test --set-team """
|
||||
# unset the team
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --set-team CLEAR')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^Setting team to CLEAR', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --set-team CYAN')
|
||||
assert re.search(r'Setting team to CYAN', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
# pause for the radio
|
||||
time.sleep(PAUSE_AFTER_REBOOT)
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --info')
|
||||
assert re.search(r'CYAN', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.smokevirt
|
||||
def test_smokevirt_ch_values():
|
||||
"""Test --ch-longslow, --ch-longfast, --ch-mediumslow, --ch-mediumsfast,
|
||||
|
||||
2
proto
2
proto
Submodule proto updated: 94a4dbb842...c63a16c32f
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="1.3alpha.16",
|
||||
version="1.3alpha.19",
|
||||
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