Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions exampleConfig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# example config using camelCase keys
owner: Bob TBeam

channelUrl: https://www.meshtastic.org/d/#CgUYAyIBAQ

location:
lat: 35.88888
lon: -93.88888
alt: 304

userPrefs:
region: 1
isAlwaysPowered: 'true'
sendOwnerInterval: 2
screenOnSecs: 31536000
waitBluetoothSecs: 31536000
1 change: 1 addition & 0 deletions example_config.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# example configuration file with snake_case keys
owner: Bob TBeam

channel_url: https://www.meshtastic.org/d/#CgUYAyIBAQ
Expand Down
118 changes: 80 additions & 38 deletions meshtastic/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from meshtastic.globals import Globals
from meshtastic.__init__ import BROADCAST_ADDR


def onReceive(packet, interface):
"""Callback invoked when a packet arrives"""
our_globals = Globals.getInstance()
Expand Down Expand Up @@ -56,43 +55,63 @@ def onConnection(interface, topic=pub.AUTO_TOPIC): # pylint: disable=W0613
def getPref(attributes, name):
"""Get a channel or preferences value"""

camel_name = meshtastic.util.snake_to_camel(name)
# Note: protobufs has the keys in snake_case, so snake internally
snake_name = meshtastic.util.camel_to_snake(name)
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(name)
field = objDesc.fields_by_name.get(snake_name)
if not field:
print(f"{attributes.__class__.__name__} does not have an attribute called {name}, so you can not get it.")
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:
names.append(f'{f.name}')
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

# okay - try to read the value
try:
try:
val = getattr(attributes, name)
except TypeError:
# The getter didn't like our arg type guess try again as a string
val = getattr(attributes, name)

# succeeded!
print(f"{name}: {str(val)}")
except Exception as ex:
print(f"Can't get {name} due to {ex}")
# read the value
val = getattr(attributes, snake_name)

if Globals.getInstance().get_camel_case():
print(f"{camel_name}: {str(val)}")
logging.debug(f"{camel_name}: {str(val)}")
else:
print(f"{snake_name}: {str(val)}")
logging.debug(f"{snake_name}: {str(val)}")


def setPref(attributes, name, valStr):
"""Set a channel or preferences value"""

snake_name = meshtastic.util.camel_to_snake(name)
camel_name = meshtastic.util.snake_to_camel(name)
logging.debug(f'snake_name:{snake_name}')
logging.debug(f'camel_name:{camel_name}')

objDesc = attributes.DESCRIPTOR
field = objDesc.fields_by_name.get(name)
field = objDesc.fields_by_name.get(snake_name)
if not field:
print(f"{attributes.__class__.__name__} does not have an attribute called {name}, so you can not set it.")
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:
names.append(f'{f.name}')
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
Expand All @@ -107,27 +126,27 @@ def setPref(attributes, name, valStr):
if e:
val = e.number
else:
print(f"{name} does not have an enum called {val}, so you can not set it.")
if Globals.getInstance().get_camel_case():
print(f"{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"Choices in sorted order are:")
names = []
for f in enumType.values:
names.append(f'{f.name}')
tmp_name = f'{f.name}'
if Globals.getInstance().get_camel_case():
tmp_name = meshtastic.util.snake_to_camel(tmp_name)
names.append(name)
for temp_name in sorted(names):
print(f" {temp_name}")
return

# okay - try to read the value
try:
try:
setattr(attributes, name, val)
except TypeError:
# The setter didn't like our arg type guess try again as a string
setattr(attributes, name, valStr)

# succeeded!
print(f"Set {name} to {valStr}")
except Exception as ex:
print(f"Can't set {name} due to {ex}")
setattr(attributes, snake_name, val)

if Globals.getInstance().get_camel_case():
print(f"Set {camel_name} to {valStr}")
else:
print(f"Set {snake_name} to {valStr}")


def onConnected(interface):
Expand Down Expand Up @@ -311,6 +330,10 @@ def onConnected(interface):
print("Setting channel url to", configuration['channel_url'])
interface.getNode(args.dest).setURL(configuration['channel_url'])

if 'channelUrl' in configuration:
print("Setting channel url to", configuration['channelUrl'])
interface.getNode(args.dest).setURL(configuration['channelUrl'])

if 'location' in configuration:
alt = 0
lat = 0.0
Expand Down Expand Up @@ -340,6 +363,13 @@ def onConnected(interface):
print("Writing modified preferences to device")
interface.getNode(args.dest).writeConfig()

if 'userPrefs' in configuration:
prefs = interface.getNode(args.dest).radioConfig.preferences
for pref in configuration['userPrefs']:
setPref(prefs, pref, str(configuration['userPrefs'][pref]))
print("Writing modified preferences to device")
interface.getNode(args.dest).writeConfig()

if args.export_config:
# export the configuration (the opposite of '--configure')
closeNow = True
Expand Down Expand Up @@ -548,7 +578,10 @@ def export_config(interface):
if owner:
config += f"owner: {owner}\n\n"
if channel_url:
config += f"channel_url: {channel_url}\n\n"
if Globals.getInstance().get_camel_case():
config += f"channelUrl: {channel_url}\n\n"
else:
config += f"channel_url: {channel_url}\n\n"
if lat or lon or alt:
config += "location:\n"
if lat:
Expand All @@ -561,9 +594,16 @@ def export_config(interface):
preferences = f'{interface.localNode.radioConfig.preferences}'
prefs = preferences.splitlines()
if prefs:
config += "user_prefs:\n"
if Globals.getInstance().get_camel_case():
config += "userPrefs:\n"
else:
config += "user_prefs:\n"
for pref in prefs:
config += f" {meshtastic.util.quoteBooleans(pref)}\n"
if Globals.getInstance().get_camel_case():
# Note: This may not work if the value has '_'
config += f" {meshtastic.util.snake_to_camel(meshtastic.util.quoteBooleans(pref))}\n"
else:
config += f" {meshtastic.util.quoteBooleans(pref)}\n"
print(config)
return config

Expand Down Expand Up @@ -692,10 +732,12 @@ def initParser():
action="store_true")

parser.add_argument(
"--get", help="Get a preferences field. Use an invalid field such as '0' to get a list of all fields.", nargs=1, action='append')
"--get", help=("Get a preferences field. Use an invalid field such as '0' to get a list of all fields."
" Can use either snake_case or camelCase format. (ex: 'ls_secs' or 'lsSecs')"),
nargs=1, action='append')

parser.add_argument(
"--set", help="Set a preferences field", nargs=2, action='append')
"--set", help="Set a preferences field. Can use either snake_case or camelCase format. (ex: 'ls_secs' or 'lsSecs')", nargs=2, action='append')

parser.add_argument(
"--seturl", help="Set a channel URL", action="store")
Expand Down
12 changes: 12 additions & 0 deletions meshtastic/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def __init__(self):
self.channel_index = None
self.logfile = None
self.tunnelInstance = None
# TODO: to migrate to camel_case for v1.3 change this value to True
self.camel_case = False

def reset(self):
"""Reset all of our globals. If you add a member, add it to this method, too."""
Expand All @@ -38,6 +40,8 @@ def reset(self):
self.channel_index = None
self.logfile = None
self.tunnelInstance = None
# TODO: to migrate to camel_case for v1.3 change this value to True
self.camel_case = False

# setters
def set_args(self, args):
Expand All @@ -60,6 +64,10 @@ def set_tunnelInstance(self, tunnelInstance):
"""Set the tunnelInstance"""
self.tunnelInstance = tunnelInstance

def set_camel_case(self):
"""Force using camelCase for things like prefs/set/set"""
self.camel_case = True

# getters
def get_args(self):
"""Get args"""
Expand All @@ -80,3 +88,7 @@ def get_logfile(self):
def get_tunnelInstance(self):
"""Get tunnelInstance"""
return self.tunnelInstance

def get_camel_case(self):
"""Get whether or not to use camelCase"""
return self.camel_case
2 changes: 0 additions & 2 deletions meshtastic/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from meshtastic.util import pskToString, stripnl, Timeout, our_exit, fromPSK




class Node:
"""A model of a (local or remote) node in the mesh

Expand Down
Loading