mirror of
https://github.com/meshtastic/python.git
synced 2025-12-26 01:17:51 -05:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
069056edad | ||
|
|
19bd510975 | ||
|
|
7979efc0a1 | ||
|
|
66866a4c65 | ||
|
|
e6fb066fe5 | ||
|
|
5841979566 | ||
|
|
529f50edc6 | ||
|
|
5895e8fb4d | ||
|
|
49dcf71116 | ||
|
|
5778552380 | ||
|
|
592ecc9997 | ||
|
|
1aaa205cc9 | ||
|
|
ff5a0927fa | ||
|
|
607127d46e | ||
|
|
cf61a5d39d |
11
.github/workflows/update_protobufs.yml
vendored
11
.github/workflows/update_protobufs.yml
vendored
@@ -15,6 +15,17 @@ jobs:
|
||||
run: |
|
||||
git pull --recurse-submodules
|
||||
git submodule update --remote --recursive
|
||||
|
||||
- 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
|
||||
|
||||
- name: Re-generate protocol buffers
|
||||
run: |
|
||||
./bin/regen-protos.sh
|
||||
|
||||
- name: Commit update
|
||||
run: |
|
||||
git config --global user.name 'github-actions'
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
# workaround for import bug in protoc https://github.com/protocolbuffers/protobuf/issues/1491#issuecomment-690618628
|
||||
|
||||
if [[ $OSTYPE == 'darwin'* ]]; then
|
||||
sed -i -E 's/^\(import.*_pb2\)/from . \1/' meshtastic/*.py
|
||||
sed -i '' -E 's/^\(import.*_pb2\)/from . \1/' meshtastic/*.py
|
||||
# automate the current workaround (may be related to Meshtastic-protobufs issue #27 https://github.com/meshtastic/Meshtastic-protobufs/issues/27)
|
||||
sed -i '' -E "s/^None = 0/globals()['None'] = 0/" meshtastic/mesh_pb2.py
|
||||
else
|
||||
sed -i -E 's/^import.*_pb2/from . \0/' meshtastic/*.py
|
||||
sed -i -e 's/^import.*_pb2/from . \0/' meshtastic/*.py
|
||||
# automate the current workaround (may be related to Meshtastic-protobufs issue #27 https://github.com/meshtastic/Meshtastic-protobufs/issues/27)
|
||||
sed -i -e "s/^None = 0/globals()['None'] = 0/" meshtastic/mesh_pb2.py
|
||||
fi
|
||||
|
||||
|
||||
# automate the current workaround (may be related to Meshtastic-protobufs issue #27 https://github.com/meshtastic/Meshtastic-protobufs/issues/27)
|
||||
sed -i '' -e "s/^None = 0/globals()['None'] = 0/" meshtastic/mesh_pb2.py
|
||||
|
||||
@@ -301,12 +301,11 @@ def onConnected(interface):
|
||||
print(f"Reading GPIO mask 0x{bitmask:x} from {args.dest}")
|
||||
interface.mask = bitmask
|
||||
rhc.readGPIOs(args.dest, bitmask, None)
|
||||
if not interface.noProto:
|
||||
# wait up to X seconds for a response
|
||||
for _ in range(10):
|
||||
time.sleep(1)
|
||||
if interface.gotResponse:
|
||||
break
|
||||
# wait up to X seconds for a response
|
||||
for _ in range(10):
|
||||
time.sleep(1)
|
||||
if interface.gotResponse:
|
||||
break
|
||||
logging.debug(f'end of gpio_rd')
|
||||
|
||||
if args.gpio_watch:
|
||||
@@ -781,7 +780,12 @@ def initParser():
|
||||
"--ch-disable", help="Disable the specified channel", action="store_true", dest="ch_disable", default=False)
|
||||
|
||||
parser.add_argument(
|
||||
"--ch-set", help="Set a channel parameter", nargs=2, action='append')
|
||||
"--ch-set", help=("Set a channel parameter. To see channel settings available:'--ch-set all all --ch-index 0'. "
|
||||
"Can set the 'psk' using this command. To disable encryption on primary channel:'--ch-set psk none --ch-index 0'. "
|
||||
"To set encryption with a new random key on second channel:'--ch-set psk random --ch-index 1'. "
|
||||
"To set encryption back to the default:'--ch-set default --ch-index 0'. To set encryption with your "
|
||||
"own key: '--ch-set psk 0x1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b --ch-index 0'."),
|
||||
nargs=2, action='append')
|
||||
|
||||
parser.add_argument(
|
||||
"--ch-longslow", help="Change to the long-range and slow channel", action='store_true')
|
||||
|
||||
@@ -10,8 +10,17 @@ def onGPIOreceive(packet, interface):
|
||||
"""Callback for received GPIO responses
|
||||
"""
|
||||
logging.debug(f"packet:{packet} interface:{interface}")
|
||||
gpioValue = 0
|
||||
hw = packet["decoded"]["remotehw"]
|
||||
gpioValue = hw["gpioValue"]
|
||||
if "gpioValue" in hw:
|
||||
gpioValue = hw["gpioValue"]
|
||||
else:
|
||||
if not "gpioMask" in hw:
|
||||
# we did get a reply, but due to protobufs, 0 for numeric value is not sent
|
||||
# see https://developers.google.com/protocol-buffers/docs/proto3#default
|
||||
# so, we set it here
|
||||
gpioValue = 0
|
||||
|
||||
#print(f'mask:{interface.mask}')
|
||||
value = int(gpioValue) & int(interface.mask)
|
||||
print(f'Received RemoteHardware typ={hw["typ"]}, gpio_value={gpioValue} value={value}')
|
||||
|
||||
@@ -1755,18 +1755,18 @@ def test_main_gpio_rd_no_dest(capsys):
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_globals")
|
||||
@patch('time.sleep')
|
||||
def test_main_gpio_rd(caplog, capsys):
|
||||
"""Test --gpio_rd with a named gpio channel"""
|
||||
# Note: On the Heltec v2.1, there is a GPIO pin GPIO 13 that does not have a
|
||||
# red arrow (meaning ok to use for our purposes)
|
||||
# See https://resource.heltec.cn/download/WiFi_LoRa_32/WIFI_LoRa_32_V2.pdf
|
||||
# To find out the mask for GPIO 13, let us assign n as 13.
|
||||
# 1. Subtract 1 from n (n is now 12)
|
||||
# 2. Find the 2^n or 2^12 (4096)
|
||||
# 3. Convert 4096 decimal to hex (0x1000)
|
||||
# 1. Find the 2^n or 2^13 (8192)
|
||||
# 2. Convert 8192 decimal to hex (0x2000)
|
||||
# You can use python:
|
||||
# >>> print(hex(2**12))
|
||||
# 0x1000
|
||||
# >>> print(hex(2**13))
|
||||
# 0x2000
|
||||
sys.argv = ['', '--gpio-rd', '0x1000', '--dest', '!1234']
|
||||
Globals.getInstance().set_args(sys.argv)
|
||||
|
||||
@@ -1796,6 +1796,52 @@ def test_main_gpio_rd(caplog, capsys):
|
||||
}
|
||||
}
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
iface.localNode.getChannelByName.return_value = channel
|
||||
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
main()
|
||||
onGPIOreceive(packet, mo)
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Connected to radio', out, re.MULTILINE)
|
||||
assert re.search(r'Reading GPIO mask 0x1000 ', out, re.MULTILINE)
|
||||
assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=4096', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_globals")
|
||||
@patch('time.sleep')
|
||||
def test_main_gpio_rd_with_no_gpioMask(caplog, capsys):
|
||||
"""Test --gpio_rd with a named gpio channel"""
|
||||
sys.argv = ['', '--gpio-rd', '0x1000', '--dest', '!1234']
|
||||
Globals.getInstance().set_args(sys.argv)
|
||||
|
||||
channel = Channel(index=1, role=1)
|
||||
channel.settings.modem_config = 3
|
||||
channel.settings.psk = b'\x01'
|
||||
|
||||
# Note: Intentionally do not have gpioValue in response as that is the
|
||||
# default value
|
||||
packet = {
|
||||
'from': 682968668,
|
||||
'to': 682968612,
|
||||
'channel': 1,
|
||||
'decoded': {
|
||||
'portnum': 'REMOTE_HARDWARE_APP',
|
||||
'payload': b'\x08\x05\x18\x80 ',
|
||||
'requestId': 1629980484,
|
||||
'remotehw': {
|
||||
'typ': 'READ_GPIOS_REPLY',
|
||||
'raw': 'faked',
|
||||
'id': 1693085229,
|
||||
'rxTime': 1640294262,
|
||||
'rxSnr': 4.75,
|
||||
'hopLimit': 3,
|
||||
'wantAck': True,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
iface.localNode.getChannelByName.return_value = channel
|
||||
@@ -1803,14 +1849,112 @@ def test_main_gpio_rd(caplog, capsys):
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
main()
|
||||
onGPIOreceive(packet, mo)
|
||||
assert re.search(r'readGPIOs nodeid:!1234 mask:4096', caplog.text, re.MULTILINE)
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Connected to radio', out, re.MULTILINE)
|
||||
assert re.search(r'Reading GPIO mask 0x1000 ', out, re.MULTILINE)
|
||||
assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=4096', out, re.MULTILINE)
|
||||
assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=0', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_globals")
|
||||
def test_main_gpio_watch(caplog, capsys):
|
||||
"""Test --gpio_watch with a named gpio channel"""
|
||||
sys.argv = ['', '--gpio-watch', '0x1000', '--dest', '!1234']
|
||||
Globals.getInstance().set_args(sys.argv)
|
||||
|
||||
def my_sleep(amount):
|
||||
print(f'{amount}')
|
||||
sys.exit(3)
|
||||
|
||||
channel = Channel(index=1, role=1)
|
||||
channel.settings.modem_config = 3
|
||||
channel.settings.psk = b'\x01'
|
||||
|
||||
packet = {
|
||||
|
||||
'from': 682968668,
|
||||
'to': 682968612,
|
||||
'channel': 1,
|
||||
'decoded': {
|
||||
'portnum': 'REMOTE_HARDWARE_APP',
|
||||
'payload': b'\x08\x05\x18\x80 ',
|
||||
'requestId': 1629980484,
|
||||
'remotehw': {
|
||||
'typ': 'READ_GPIOS_REPLY',
|
||||
'gpioValue': '4096',
|
||||
'raw': 'faked',
|
||||
'id': 1693085229,
|
||||
'rxTime': 1640294262,
|
||||
'rxSnr': 4.75,
|
||||
'hopLimit': 3,
|
||||
'wantAck': True,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
with patch('time.sleep', side_effect=my_sleep):
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
iface.localNode.getChannelByName.return_value = channel
|
||||
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
main()
|
||||
onGPIOreceive(packet, mo)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 3
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Connected to radio', out, re.MULTILINE)
|
||||
assert re.search(r'Watching GPIO mask 0x1000 ', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_globals")
|
||||
def test_main_gpio_wrb(caplog, capsys):
|
||||
"""Test --gpio_wrb with a named gpio channel"""
|
||||
sys.argv = ['', '--gpio-wrb', '4', '1', '--dest', '!1234']
|
||||
Globals.getInstance().set_args(sys.argv)
|
||||
|
||||
channel = Channel(index=1, role=1)
|
||||
channel.settings.modem_config = 3
|
||||
channel.settings.psk = b'\x01'
|
||||
|
||||
packet = {
|
||||
|
||||
'from': 682968668,
|
||||
'to': 682968612,
|
||||
'channel': 1,
|
||||
'decoded': {
|
||||
'portnum': 'REMOTE_HARDWARE_APP',
|
||||
'payload': b'\x08\x05\x18\x80 ',
|
||||
'requestId': 1629980484,
|
||||
'remotehw': {
|
||||
'typ': 'READ_GPIOS_REPLY',
|
||||
'gpioValue': '16',
|
||||
'raw': 'faked',
|
||||
'id': 1693085229,
|
||||
'rxTime': 1640294262,
|
||||
'rxSnr': 4.75,
|
||||
'hopLimit': 3,
|
||||
'wantAck': True,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
iface.localNode.getChannelByName.return_value = channel
|
||||
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
main()
|
||||
onGPIOreceive(packet, mo)
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Connected to radio', out, re.MULTILINE)
|
||||
assert re.search(r'Writing GPIO mask 0x10 with value 0x10 to !1234', out, re.MULTILINE)
|
||||
assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=16 value=0', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_globals")
|
||||
def test_main_getPref_valid_field(capsys):
|
||||
|
||||
2
proto
2
proto
Submodule proto updated: 6c39b5bf47...07ed86d8b4
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.2.75",
|
||||
version="1.2.77",
|
||||
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