Compare commits

...

194 Commits

Author SHA1 Message Date
mkinney
d8b9665946 Merge pull request #299 from mkinney/master
update to latest protobufs
2022-03-11 15:07:34 -08:00
Mike Kinney
e655beb01c update to latest protobufs 2022-03-11 15:04:09 -08:00
mkinney
aa1dcb7f99 Merge pull request #298 from mkinney/master
refactor code to util; add duplicate check
2022-03-08 10:53:33 -08:00
Mike Kinney
1a2519d647 refactor code to util 2022-03-08 10:45:11 -08:00
Mike Kinney
a3572efaa6 add duplicate check 2022-03-08 10:44:14 -08:00
github-actions
e28f0d5509 bump version 2022-03-08 06:16:57 +00:00
mkinney
789a14054f Update release.yml 2022-03-07 22:16:03 -08:00
github-actions
4655b5c732 bump version 2022-03-08 06:04:02 +00:00
mkinney
81ebd8c8e7 Merge pull request #296 from mkinney/fix_release_version
keep sha ref and use it for subsequent checkouts
2022-03-07 22:02:28 -08:00
Mike Kinney
7998520e4a keep sha ref and use it for subsequent checkouts 2022-03-07 21:59:46 -08:00
mkinney
460196a62b Merge pull request #295 from mkinney/bug_when_ports_not_sorted
do not checkout the code again
2022-03-07 21:48:28 -08:00
Mike Kinney
22f43851bd do not checkout the code again 2022-03-07 21:44:11 -08:00
mkinney
91bb63eb97 Merge pull request #294 from mkinney/bug_when_ports_not_sorted
fix when ports are not sorted
2022-03-07 21:25:42 -08:00
Mike Kinney
ede1b5f08b fix when ports are not sorted 2022-03-07 21:21:41 -08:00
mkinney
a26c157c65 Merge pull request #292 from mkinney/handle_ignore_incoming
handle ignore_incoming repeated field
2022-03-03 17:14:09 -08:00
Mike Kinney
bcf00a1f8d handle ignore_incoming repeated field 2022-03-03 17:11:22 -08:00
Jm Casler
749a94e6e4 updating proto submodule to latest 2022-03-02 18:49:49 -08:00
github-actions
fc9d1e077c bump version 2022-03-02 21:56:05 +00:00
mkinney
a40f0b4038 Merge pull request #291 from mkinney/1_3_python
min req of python is 3.7 now; bump nanopb version
2022-03-02 13:55:09 -08:00
Mike Kinney
dbf54396f3 min req of python is 3.7 now; bump nanopb version 2022-03-02 13:29:19 -08:00
github-actions
3fe881e45a bump version 2022-03-02 19:43:05 +00:00
mkinney
af03c5163c Merge pull request #290 from mkinney/master
change version per pypi reqs
2022-03-02 11:42:09 -08:00
Mike Kinney
58de84945f change version per pypi reqs 2022-03-02 11:39:07 -08:00
github-actions
a2d4252002 bump version 2022-03-02 19:32:52 +00:00
mkinney
0689fc19a9 Merge pull request #289 from mkinney/1_3_initial
got lint and pytest working
2022-03-02 11:31:49 -08:00
Mike Kinney
68530f6e11 change medium to mid 2022-03-02 11:29:38 -08:00
Mike Kinney
fd752bedc5 change version format 2022-03-02 11:24:13 -08:00
Mike Kinney
cac880eb1a change to alpha 2022-03-02 11:15:47 -08:00
Mike Kinney
2c66cd4a95 change the name not the package 2022-03-02 10:50:08 -08:00
Mike Kinney
64e428f182 change package name and version 2022-03-02 10:44:35 -08:00
Mike Kinney
6f2efdcefe got lint and pytest working 2022-03-02 10:28:07 -08:00
github-actions
9214b2ffcc bump version 2022-03-02 00:20:31 +00:00
mkinney
cfb14d4b77 Merge pull request #287 from mkinney/changes_to_smokevirt
increase timeout; ensure secondary channel is deleted before trying t…
2022-03-01 16:19:14 -08:00
Mike Kinney
5965615e17 increase timeout; ensure secondary channel is deleted before trying to add it 2022-03-02 00:04:21 +00:00
Jm Casler
40eb7d8515 updating proto submodule to latest 2022-02-28 22:03:42 -08:00
Jm Casler
e2f36a9bea updating proto submodule to latest 2022-02-28 19:36:02 -08:00
Jm Casler
a0ba644488 updating proto submodule to latest 2022-02-27 10:01:44 -08:00
Jm Casler
2f67f344b7 updating proto submodule to latest 2022-02-27 09:57:16 -08:00
Jm Casler
8bb208aed1 updating proto submodule to latest 2022-02-27 09:52:34 -08:00
Jm Casler
48b145a592 updating proto submodule to latest 2022-02-27 01:00:38 -08:00
Jm Casler
65de9200fb updating proto submodule to latest 2022-02-27 00:48:57 -08:00
Jm Casler
e51d7a7a18 updating proto submodule to latest 2022-02-27 00:38:09 -08:00
Jm Casler
c4af50d63a updating proto submodule to latest 2022-02-26 21:22:33 -08:00
Jm Casler
933fe8953a updating proto submodule to latest 2022-02-26 21:09:20 -08:00
mkinney
66aa492d50 Merge pull request #283 from mkinney/add_cm
add cm
2022-02-25 23:44:13 -08:00
Mike Kinney
730934f520 add cm 2022-02-25 23:36:05 -08:00
mkinney
d2ec09eaf8 Merge pull request #281 from prampec/extend_canned_message_length
Canned message - Extend messages length
2022-02-25 22:58:57 -08:00
mkinney
7fd3b313b2 Update release.yml 2022-02-25 22:15:36 -08:00
github-actions
89f1549741 bump version 2022-02-26 06:11:26 +00:00
github-actions
e91015f5c8 bump version 2022-02-26 06:07:50 +00:00
mkinney
d9c3edfb12 Update release.yml 2022-02-25 22:06:27 -08:00
mkinney
cbf9696f47 Merge pull request #282 from mkinney/master
improve the release process
2022-02-25 22:04:48 -08:00
Mike Kinney
24e556b9a7 improve the release process 2022-02-25 22:01:21 -08:00
mkinney
eaf29512b6 Update standalone_readme.txt 2022-02-25 21:38:23 -08:00
Jm Casler
0c1e0ec375 updating proto submodule to latest 2022-02-22 17:10:04 -08:00
Balazs Kelemen
b56a054f50 Canned message - Extend messages length 2022-02-21 22:06:03 +01:00
Jm Casler
33ff4e36de updating proto submodule to latest 2022-02-20 01:32:53 -08:00
Jm Casler
bf879934e6 updating proto submodule to latest 2022-02-19 23:48:24 -08:00
Jm Casler
b878fa3a80 updating proto submodule to latest 2022-02-19 23:17:50 -08:00
Jm Casler
901849f176 updating proto submodule to latest 2022-02-19 23:10:53 -08:00
Jm Casler
371c0d22c2 updating proto submodule to latest 2022-02-19 22:55:38 -08:00
mkinney
4f7f38e0a7 Update setup.py 2022-02-18 11:16:49 -08:00
mkinney
85dca2e14e Merge pull request #278 from mkinney/fix_smoke1
add detection of duplicate ports to findPorts; fix smoke1 test
2022-02-18 11:16:25 -08:00
Mike Kinney
e53a5023f1 add detection of duplicate ports to findPorts; fix smoke1 test 2022-02-18 11:13:48 -08:00
mkinney
ce8b75d96d Merge pull request #277 from mkinney/win11_delay_only
only delay on win11
2022-02-18 10:12:16 -08:00
Mike Kinney
26f65c4fee only delay on win11 2022-02-18 10:08:53 -08:00
mkinney
1ba1e51ca4 Merge pull request #276 from mkinney/keep_devpath_on_serial
keep the devPath used on serial connections
2022-02-18 10:03:43 -08:00
Mike Kinney
f674afc412 keep the devPath used on serial connections 2022-02-18 09:59:09 -08:00
mkinney
db90b898e1 Update setup.py 2022-02-16 10:16:10 -08:00
mkinney
71621c2225 Merge pull request #269 from mkinney/two_serials
if we have a duplicate serial port use the appropriate one
2022-02-16 10:12:57 -08:00
Mike Kinney
ed36fca4a2 remove testing prints 2022-02-16 10:10:32 -08:00
Mike Kinney
fdd3699ba5 if we have a duplicate serial port use the appropriate one 2022-02-16 10:08:57 -08:00
Jm Casler
7d4b39643b updating proto submodule to latest 2022-02-14 20:35:46 -08:00
Jm Casler
7698cd2c7d updating proto submodule to latest 2022-02-14 20:08:31 -08:00
Jm Casler
03c744df54 updating proto submodule to latest 2022-02-14 19:55:21 -08:00
Jm Casler
90978d1f35 updating proto submodule to latest 2022-02-14 19:42:06 -08:00
Jm Casler
68a2bf271a updating proto submodule to latest 2022-02-14 17:59:45 -08:00
Jm Casler
8301384c53 updating proto submodule to latest 2022-02-14 16:59:26 -08:00
Jm Casler
045592212a updating proto submodule to latest 2022-02-14 16:56:59 -08:00
mkinney
45d879e607 Update setup.py 2022-02-12 21:19:20 -08:00
mkinney
3e44ee1eba Merge pull request #266 from mkinney/increase_sleep_for_win11
increase sleep for win11
2022-02-12 21:18:53 -08:00
Mike Kinney
36c5fc8d3c increase sleep for win11 2022-02-12 21:16:11 -08:00
mkinney
38ceb85ad9 Update setup.py 2022-02-10 15:15:46 -08:00
mkinney
6d18d9226d Merge pull request #263 from mkinney/add_rak11200
Add rak11200
2022-02-10 15:15:15 -08:00
Mike Kinney
6d5ed2129a add rak11200 2022-02-10 15:12:28 -08:00
Mike Kinney
5cfb6ffa11 add examples to lint and fix warnings 2022-02-10 14:51:22 -08:00
mkinney
363b268ccf Update setup.py 2022-02-03 10:03:31 -08:00
mkinney
e6cddb0084 Merge pull request #260 from mkinney/update_protobufs
update protobufs to latest
2022-02-03 10:01:31 -08:00
Mike Kinney
5e77bf62b9 update protobufs to latest 2022-02-03 09:59:03 -08:00
github-actions
4905c0b179 Update protobuf submodule 2022-02-03 15:00:36 +00:00
Ben Meadors
43ab3be804 Update update_protobufs.yml 2022-02-03 08:59:32 -06:00
github-actions
14a6e581bc Update protobuf submodule 2022-02-03 14:38:02 +00:00
mkinney
cadad32bdb Update setup.py 2022-02-01 17:44:37 -08:00
mkinney
71c6411d1a Merge pull request #257 from mkinney/add_techo_info
add T-Echo info
2022-02-01 17:41:19 -08:00
Mike Kinney
85e8fad16f add T-Echo info 2022-02-01 17:18:05 -08:00
mkinney
67398222d4 Update setup.py 2022-02-01 13:56:03 -08:00
mkinney
1a82bdee75 Merge pull request #256 from mkinney/update_proto2
fix regen-protos script
2022-02-01 13:55:42 -08:00
Mike Kinney
9fff26c3db fix regen-protos script 2022-02-01 13:53:14 -08:00
mkinney
172f6c577d Merge pull request #254 from mkinney/force_win_encoding
specify a code page on windows
2022-02-01 12:03:08 -08:00
Mike Kinney
ff5652058d fix lint complaining about long lines 2022-02-01 12:00:58 -08:00
Mike Kinney
5241fabb33 change encoding to utf8 for windows 2022-02-01 11:56:07 -08:00
Mike Kinney
6c9aa5794f specify a code page on windows 2022-02-01 11:44:02 -08:00
mkinney
7c8cb375a3 Merge pull request #252 from mkinney/update_sd_info
add info about 19003
2022-01-30 23:11:22 -08:00
Mike Kinney
a6e770f548 add info about 19003 2022-01-30 22:38:35 -08:00
mkinney
eb7683450f Merge pull request #251 from mkinney/update_sd
add more info about some devices; fix tlora info
2022-01-30 21:15:40 -08:00
Mike Kinney
ee739d3414 add more info about some devices; fix tlora info 2022-01-30 17:36:15 -08:00
mkinney
b864bbdd5f Update setup.py 2022-01-29 21:48:57 -08:00
mkinney
5a740eddc3 Merge pull request #250 from mkinney/bugfix_for_owner_short
fix bug
2022-01-29 21:48:17 -08:00
Mike Kinney
fdced6f225 fix bug 2022-01-29 21:37:34 -08:00
mkinney
3d772845f9 Merge pull request #249 from mkinney/device_detection
Device detection
2022-01-29 21:11:40 -08:00
Mike Kinney
72326d467e only show active windows ports 2022-01-29 20:53:09 -08:00
Mike Kinney
a0944961b5 fix lint warnings 2022-01-29 20:47:58 -08:00
Mike Kinney
1fa61ece93 add windows device and port detection 2022-01-29 20:45:29 -08:00
Mike Kinney
288d0bb884 add detection on mac 2022-01-29 17:12:36 -08:00
Mike Kinney
28a2aa47e8 add device and port detection on linux 2022-01-30 00:57:56 +00:00
mkinney
069056edad Update setup.py 2022-01-27 17:12:50 -08:00
github-actions
19bd510975 Update protobuf submodule 2022-01-28 01:12:41 +00:00
mkinney
7979efc0a1 Merge pull request #247 from mkinney/remote_hardware
remote hardware tests
2022-01-27 17:11:37 -08:00
Mike Kinney
66866a4c65 fix logic 2022-01-27 17:09:13 -08:00
Mike Kinney
e6fb066fe5 get last couple of lines covered in remote_hardware 2022-01-27 17:05:16 -08:00
Mike Kinney
5841979566 remove line 2022-01-27 17:00:53 -08:00
Mike Kinney
529f50edc6 remote hardware tests 2022-01-27 16:54:47 -08:00
github-actions
5895e8fb4d Update protobuf submodule 2022-01-27 14:21:10 +00:00
mkinney
49dcf71116 Update setup.py 2022-01-26 20:32:45 -08:00
Jm Casler
5778552380 updating proto submodule to latest 2022-01-26 13:35:48 -08:00
Jm Casler
592ecc9997 updating proto submodule to latest 2022-01-26 12:27:52 -08:00
mkinney
1aaa205cc9 Merge pull request #246 from mkinney/update_help
add more info on --ch-set help
2022-01-26 11:22:05 -08:00
Mike Kinney
ff5a0927fa add more info on --ch-set help 2022-01-26 11:16:01 -08:00
mkinney
607127d46e Update regen-protos.sh 2022-01-23 15:15:14 -08:00
mkinney
cf61a5d39d Update update_protobufs.yml 2022-01-23 15:09:44 -08:00
mkinney
69b2599abb Update setup.py 2022-01-23 14:51:38 -08:00
mkinney
533e50de9d Update release.yml 2022-01-23 14:51:21 -08:00
mkinney
12b99f80dc Update release.yml 2022-01-23 14:48:59 -08:00
mkinney
0193ca052f Update setup.py 2022-01-23 14:47:26 -08:00
mkinney
e0af620cbe Merge pull request #245 from mkinney/standalone_readme
add readme.txt to release for standalone zip files
2022-01-23 14:47:06 -08:00
Mike Kinney
80367232ae add readme.txt to release for standalone zip files 2022-01-23 14:44:59 -08:00
mkinney
1c480bd74f Update setup.py 2022-01-23 14:25:01 -08:00
mkinney
ba05de263c Update release.yml 2022-01-23 14:24:48 -08:00
mkinney
f045c3bc2b Update setup.py 2022-01-23 14:17:05 -08:00
mkinney
9ec5f33a85 Update release.yml 2022-01-23 14:16:50 -08:00
mkinney
e1cc657059 Update setup.py 2022-01-23 14:10:58 -08:00
mkinney
9c3dce4bbb Update release.yml 2022-01-23 14:10:43 -08:00
mkinney
5418539275 Update setup.py 2022-01-23 14:04:51 -08:00
mkinney
3103640688 Update release.yml 2022-01-23 14:04:36 -08:00
mkinney
86beb2f212 Update setup.py 2022-01-23 14:03:05 -08:00
mkinney
dd1c96fcba Update release.yml 2022-01-23 14:02:48 -08:00
mkinney
b282baadb7 Update setup.py 2022-01-23 13:55:08 -08:00
mkinney
fccb38fced Update release.yml 2022-01-23 13:54:53 -08:00
mkinney
700a7e27d3 Update setup.py 2022-01-23 13:51:06 -08:00
mkinney
bb1c40c7f8 Update release.yml 2022-01-23 13:50:49 -08:00
mkinney
407490c654 Update setup.py 2022-01-23 13:38:54 -08:00
mkinney
dfd61af346 Update release.yml 2022-01-23 13:38:36 -08:00
mkinney
a85b4ad985 Update setup.py 2022-01-23 13:35:02 -08:00
mkinney
eacffa79fa Update release.yml 2022-01-23 13:34:47 -08:00
mkinney
ca5449f1b8 Update release.yml 2022-01-23 13:21:50 -08:00
mkinney
6751f5bd53 Update release.yml 2022-01-23 13:12:17 -08:00
mkinney
c5c70fe83e Update setup.py 2022-01-23 13:10:06 -08:00
mkinney
0c0cd81253 Update release.yml 2022-01-23 13:09:40 -08:00
mkinney
553a03e40f Update setup.py 2022-01-23 12:53:51 -08:00
mkinney
b50190aeb0 Update release.yml 2022-01-23 12:53:32 -08:00
mkinney
bc231a8a9d Update setup.py 2022-01-23 12:34:36 -08:00
mkinney
c1c9cb8139 Update release.yml 2022-01-23 12:34:12 -08:00
mkinney
0a915e305d Update setup.py 2022-01-23 12:09:55 -08:00
mkinney
308eb1f321 Update release.yml 2022-01-23 12:09:36 -08:00
mkinney
d576c0e30b Update setup.py 2022-01-23 12:01:41 -08:00
mkinney
e63d4c3a30 Update release.yml 2022-01-23 12:01:17 -08:00
mkinney
2041e81101 Update setup.py 2022-01-23 11:49:04 -08:00
mkinney
f396374fa8 Update release.yml 2022-01-23 11:48:13 -08:00
mkinney
1a0db63f32 Merge pull request #244 from mkinney/release_improvements
improve the release process
2022-01-23 11:44:33 -08:00
Mike Kinney
0d32a83e66 improve the release process 2022-01-23 11:41:49 -08:00
mkinney
7ac3328db8 Merge pull request #243 from mkinney/short_name
Short name
2022-01-23 11:25:06 -08:00
Mike Kinney
4f72987a29 add some config tests 2022-01-23 11:22:05 -08:00
Mike Kinney
aa5af53348 add option to configure just the owner short name 2022-01-23 11:17:41 -08:00
Jm Casler
030ee8554c updating proto submodule to latest 2022-01-23 09:10:37 -08:00
mkinney
80d447d64b Update setup.py 2022-01-21 17:15:26 -08:00
mkinney
bfac5a418c Merge pull request #239 from meshtastic/update-protos-for-shutdown
Shutdown command (should mirror reboot)
2022-01-21 17:05:26 -08:00
mkinney
a3b09f028a Merge pull request #242 from mkinney/help_update_protos_for_shutdown
ignore new pb file
2022-01-21 17:00:19 -08:00
Mike Kinney
930292aaad ignore new pb file 2022-01-21 16:59:17 -08:00
mkinney
1d3b59a7e0 Merge pull request #240 from mkinney/help_update_protos_for_shutdown
update protos
2022-01-21 16:56:59 -08:00
Mike Kinney
d54b518bfd update protos 2022-01-21 16:55:09 -08:00
Ben Meadors
ccb8bb83a6 Consistent spacing 2022-01-21 18:33:09 -06:00
Ben Meadors
076e865f77 Node level test 2022-01-21 18:20:50 -06:00
Ben Meadors
8ceb9faf2d Shutdown command 2022-01-21 18:11:26 -06:00
github-actions
b15e5f516a Update protobuf submodule 2022-01-21 23:58:36 +00:00
github-actions
e161d75986 Update protobuf submodule 2022-01-20 22:18:17 +00:00
mkinney
084473a340 Update README.md
add pypi downloads
2022-01-20 10:10:42 -08:00
Jm Casler
74d6d4d634 updating proto submodule to latest 2022-01-19 18:18:59 -08:00
github-actions
38ac4298a0 Update protobuf submodule 2022-01-19 23:56:04 +00:00
mkinney
9b2c0e7954 Merge pull request #237 from mkinney/master
regen proto from updated protobufs
2022-01-16 17:06:35 -08:00
Mike Kinney
62472034f1 regen proto from updated protobufs 2022-01-17 00:26:31 +00:00
github-actions
13cfc19841 Update protobuf submodule 2022-01-17 00:21:35 +00:00
mkinney
4955ab8df2 Update setup.py 2022-01-16 12:48:35 -08:00
mkinney
de39c98e50 Merge pull request #236 from mkinney/fix_enum_listing
fix enum listing; add tests for pref values
2022-01-16 12:47:49 -08:00
Mike Kinney
51378bb0eb fix enum listing; add tests for pref values 2022-01-16 12:45:28 -08:00
71 changed files with 4842 additions and 619 deletions

View File

@@ -1,90 +0,0 @@
name: Build and publish standalone executables
on: workflow_dispatch
jobs:
build-and-publish-mac:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Setup code signing
env:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
run: |
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
security default-keychain -s meshtastic.keychain
security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
security import certificate.p12 -k meshtastic.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
- name: Build
env:
MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }}
run: |
pip install pyinstaller
pip install -r requirements.txt
pip install .
pyinstaller -F -n meshtastic --collect-all meshtastic --codesign-identity "$MACOS_SIGNING_IDENTITY" meshtastic/__main__.py
- uses: actions/upload-artifact@v2
with:
name: meshtastic_mac
path: dist
build-and-publish-ubuntu:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Build
run: |
pip install pyinstaller
pip install -r requirements.txt
pip install .
pyinstaller -F -n meshtastic --collect-all meshtastic meshtastic/__main__.py
- uses: actions/upload-artifact@v2
with:
name: meshtastic_ubuntu
path: dist
build-and-publish-windows:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Build
run: |
pip install pyinstaller
pip install -r requirements.txt
pip install .
pyinstaller -F -n meshtastic --collect-all meshtastic meshtastic/__main__.py
- uses: actions/upload-artifact@v2
with:
name: meshtastic_windows
path: dist

View File

@@ -35,7 +35,7 @@ jobs:
which meshtastic
meshtastic --version
- name: Run pylint
run: pylint meshtastic
run: pylint meshtastic examples/
- name: Run tests with pytest
run: pytest --cov=meshtastic
- name: Generate coverage report

View File

@@ -1,35 +0,0 @@
name: Publish PyPI
on: workflow_dispatch
jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install pypa/build
run: >-
python -m
pip install
build
--user
- name: Build a binary wheel and a source tarball
run: >-
python -m
build
--sdist
--wheel
--outdir dist/
.
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
username: __token__
password: ${{ secrets.PYPI_API_TOKEN }}

198
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,198 @@
name: Make Release
on: workflow_dispatch
jobs:
release_create:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_version.outputs.version }}
upload_url: ${{ steps.create_release.outputs.upload_url }}
new_sha: ${{ steps.commit_updated.outputs.sha }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Bump version
run: >-
bin/bump_version.py
- name: Commit updated version.py
id: commit_updated
run: |
git config --global user.name 'github-actions'
git config --global user.email 'bot@noreply.github.com'
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
git add setup.py
git commit -m "bump version" && git push || echo "No changes to commit"
git log -n 1 --pretty=format:"%H" | tail -n 1 | awk '{print "::set-output name=sha::"$0}'
- name: Get version
id: get_version
run: >-
bin/show_version.py
- name: Create GitHub release
uses: actions/create-release@v1
id: create_release
with:
draft: true
prerelease: true
release_name: Meshtastic Python ${{ steps.get_version.outputs.version }}
tag_name: ${{ steps.get_version.outputs.version }}
body: |
Autogenerated by github action, developer should edit as required before publishing...
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install pypa/build
run: >-
python -m
pip install
build
--user
- name: Build a binary wheel and a source tarball
run: >-
python -m
build
--sdist
--wheel
--outdir dist/
.
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
build-and-publish-mac:
runs-on: macos-latest
needs: release_create
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ needs.release_create.outputs.new_sha }}
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Setup code signing
env:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
run: |
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
security default-keychain -s meshtastic.keychain
security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
security import certificate.p12 -k meshtastic.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
- name: Build
env:
MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }}
run: |
pip install pyinstaller
pip install -r requirements.txt
pip install .
pyinstaller -F -n meshtastic --collect-all meshtastic --codesign-identity "$MACOS_SIGNING_IDENTITY" meshtastic/__main__.py
- name: Add mac to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.release_create.outputs.upload_url }}
asset_path: dist/meshtastic
asset_name: meshtastic_mac
asset_content_type: application/zip
build-and-publish-ubuntu:
runs-on: ubuntu-latest
needs: release_create
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ needs.release_create.outputs.new_sha }}
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Build
run: |
pip install pyinstaller
pip install -r requirements.txt
pip install .
pyinstaller -F -n meshtastic --collect-all meshtastic meshtastic/__main__.py
- name: Add ubuntu to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.release_create.outputs.upload_url }}
asset_path: dist/meshtastic
asset_name: meshtastic_ubuntu
asset_content_type: application/zip
- name: Add readme.txt to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.release_create.outputs.upload_url }}
asset_path: standalone_readme.txt
asset_name: readme.txt
asset_content_type: text/plain
build-and-publish-windows:
runs-on: windows-latest
needs: release_create
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ needs.release_create.outputs.new_sha }}
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Build
run: |
pip install pyinstaller
pip install -r requirements.txt
pip install .
pyinstaller -F -n meshtastic --collect-all meshtastic meshtastic/__main__.py
- name: Add windows to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.release_create.outputs.upload_url }}
asset_path: dist/meshtastic.exe
asset_name: meshtastic_windows
asset_content_type: application/zip

View File

@@ -15,10 +15,22 @@ 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'
git config --global user.email 'bot@noreply.github.com'
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
git add proto
git add meshtastic
git commit -m "Update protobuf submodule" && git push || echo "No changes to commit"

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ dist
log_*
.eggs
nanopb-0.4.4
nanopb-0.4.5
.*swp
.coverage
*.py-E

View File

@@ -7,7 +7,7 @@
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=mqtt_pb2.py,channel_pb2.py,environmental_measurement_pb2.py,admin_pb2.py,radioconfig_pb2.py,deviceonly_pb2.py,apponly_pb2.py,remote_hardware_pb2.py,portnums_pb2.py,mesh_pb2.py,storeforward_pb2.py
ignore-patterns=mqtt_pb2.py,channel_pb2.py,telemetry_pb2.py,admin_pb2.py,radioconfig_pb2.py,deviceonly_pb2.py,apponly_pb2.py,remote_hardware_pb2.py,portnums_pb2.py,mesh_pb2.py,storeforward_pb2.py,cannedmessages_pb2.py
@@ -23,7 +23,7 @@ ignore-patterns=mqtt_pb2.py,channel_pb2.py,environmental_measurement_pb2.py,admi
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
#
disable=invalid-name,fixme,logging-fstring-interpolation,too-many-statements,too-many-branches,too-many-locals,no-member,f-string-without-interpolation,protected-access,no-self-use,pointless-string-statement,too-few-public-methods,broad-except,no-else-return,no-else-raise,bare-except
disable=invalid-name,fixme,logging-fstring-interpolation,too-many-statements,too-many-branches,too-many-locals,no-member,f-string-without-interpolation,protected-access,no-self-use,pointless-string-statement,too-few-public-methods,broad-except,no-else-return,no-else-raise,bare-except,too-many-public-methods
[BASIC]
@@ -41,7 +41,7 @@ bad-names=foo,bar,baz,toto,tutu,tata
max-line-length=150
# Maximum number of lines in a module
max-module-lines=1200
max-module-lines=1400

View File

@@ -16,12 +16,18 @@ docs:
# lint the codebase
lint:
pylint meshtastic
pylint meshtastic examples
# show the slowest unit tests
slow:
pytest -m unit --durations=5
proto: FORCE
git submodule update --init --recursive
git pull --rebase
git submodule update --remote --merge
./bin/regen-protos.sh
# run the coverage report and open results in a browser
cov:
pytest --cov-report html --cov=meshtastic

View File

@@ -3,6 +3,7 @@
[![Open in Visual Studio Code](https://open.vscode.dev/badges/open-in-vscode.svg)](https://open.vscode.dev/meshtastic/Meshtastic-python)
![Unit Tests](https://github.com/meshtastic/Meshtastic-python/actions/workflows/ci.yml/badge.svg)
[![codecov](https://codecov.io/gh/meshtastic/Meshtastic-python/branch/master/graph/badge.svg?token=TIWPJL73KV)](https://codecov.io/gh/meshtastic/Meshtastic-python)
![PyPI - Downloads](https://img.shields.io/pypi/dm/meshtastic)
A python client for using [Meshtastic](https://www.meshtastic.org) devices. This small library (and example application) provides an easy API for sending and receiving messages over mesh radios. It also provides access to any of the operations/data available in the device user interface or the Android application. Events are delivered using a publish-subscribe model, and you can subscribe to only the message types you are interested in.

25
bin/bump_version.py Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env python
"""Bump the version number"""
version_filename = "setup.py"
lines = None
with open(version_filename, 'r', encoding='utf-8') as f:
lines = f.readlines()
with open(version_filename, 'w', encoding='utf-8') as f:
for line in lines:
if line.lstrip().startswith("version="):
# get rid of quotes around the version
line = line.replace('"', '')
# get rid of trailing comma
line = line.replace(",", "")
# split on '='
words = line.split("=")
# split the version into parts (by period)
v = words[1].split(".")
ver = f'{v[0]}.{v[1]}.{int(v[2]) + 1}'
f.write(f' version="{ver}",\n')
else:
f.write(line)

View File

@@ -1,15 +1,15 @@
#!/bin/bash
./nanopb-0.4.4/generator-bin/protoc -I=proto --python_out meshtastic `ls proto/*.proto`
./nanopb-0.4.5/generator-bin/protoc -I=proto --python_out meshtastic `ls proto/*.proto`
# 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

20
bin/show_version.py Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env python
"""Show the version number"""
version_filename = "setup.py"
lines = None
with open(version_filename, 'r', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
if line.lstrip().startswith("version="):
# get rid of quotes around the version
line2 = line.replace('"', '')
# get rid of the trailing comma
line2 = line2.replace(',', '')
# split on =
words = line2.split("=")
# Note: This format is for github actions
print(f'::set-output name=version::{words[1].strip()}')

View File

@@ -1,5 +1,6 @@
# example config using camelCase keys
owner: Bob TBeam
ownerShort: BOB
channelUrl: https://www.meshtastic.org/d/#CgUYAyIBAQ

View File

@@ -1,5 +1,6 @@
# example configuration file with snake_case keys
owner: Bob TBeam
owner_short: BOB
channel_url: https://www.meshtastic.org/d/#CgUYAyIBAQ
@@ -14,3 +15,4 @@ user_prefs:
send_owner_interval: 2
screen_on_secs: 31536000
wait_bluetooth_secs: 31536000
location_share: 'LocEnabled'

23
examples/info_example.py Normal file
View File

@@ -0,0 +1,23 @@
"""Simple program to demo how to use meshtastic library.
To run: python examples/info.py
"""
import meshtastic
import meshtastic.serial_interface
iface = meshtastic.serial_interface.SerialInterface()
# call showInfo() just to ensure values are populated
#info = iface.showInfo()
if iface.myInfo:
#print(f'myInfo:{iface.myInfo}')
print(f'firmware_version:{iface.myInfo.firmware_version}')
if iface.nodes:
for n in iface.nodes.values():
if n['num'] == iface.myInfo.my_node_num:
print(n['user']['hwModel'])
break
iface.close()

View File

@@ -13,7 +13,7 @@ if len(sys.argv) < 2:
print(f"usage: {sys.argv[0]} host")
sys.exit(1)
def onConnection(interface, topic=pub.AUTO_TOPIC):
def onConnection(interface, topic=pub.AUTO_TOPIC): # pylint: disable=unused-argument
"""This is called when we (re)connect to the radio."""
print(interface.myInfo)
interface.close()

View File

@@ -14,11 +14,11 @@ if len(sys.argv) < 2:
print(f"usage: {sys.argv[0]} host")
sys.exit(1)
def onReceive(packet, interface):
def onReceive(packet, interface): # pylint: disable=unused-argument
"""called when a packet arrives"""
print(f"Received: {packet}")
def onConnection(interface, topic=pub.AUTO_TOPIC):
def onConnection(interface, topic=pub.AUTO_TOPIC): # pylint: disable=unused-argument
"""called when we (re)connect to the radio"""
# defaults to broadcast, specify a destination ID if you wish
interface.sendText("hello mesh")

View File

@@ -0,0 +1,24 @@
"""Program to scan for hardware
To run: python examples/scan_for_devices.py
"""
import sys
from meshtastic.util import detect_supported_devices, get_unique_vendor_ids, active_ports_on_supported_devices
# simple arg check
if len(sys.argv) != 1:
print(f"usage: {sys.argv[0]}")
print("Detect which device we might have.")
sys.exit(3)
vids = get_unique_vendor_ids()
print(f'Searching for all devices with these vendor ids {vids}')
sds = detect_supported_devices()
if len(sds) > 0:
print('Detected possible devices:')
for d in sds:
print(f' name:{d.name}{d.version} firmware:{d.for_firmware}')
ports = active_ports_on_supported_devices(sds)
print(f'ports:{ports}')

6
examples/show_ports.py Normal file
View File

@@ -0,0 +1,6 @@
"""Simple program to show serial ports.
"""
from meshtastic.util import findPorts
print(findPorts())

20
info/mac/heltec.txt Normal file
View File

@@ -0,0 +1,20 @@
ioreg -p IOUSB > /tmp/d
> | +-o CP2102 USB to UART Bridge Controller@14400000 <class AppleUSBDevice, id 0x10005c048, registered, matched, active, busy 0 (9 ms), retain 12>
system_profiler SPUSBDataType > /tmp/b
37a38,50
> CP2102 USB to UART Bridge Controller:
>
> Product ID: 0xea60
> Vendor ID: 0x10c4 (Silicon Laboratories, Inc.)
> Version: 1.00
> Serial Number: 0001
> Speed: Up to 12 Mb/s
> Manufacturer: Silicon Labs
> Location ID: 0x14400000 / 53
> Current Available (mA): 500
> Current Required (mA): 100
> Extra Operating Current (mA): 0

52
info/mac/rak11200.txt Normal file
View File

@@ -0,0 +1,52 @@
% ioreg -p IOUSB > /tmp/a
# only a solid red light (pins GRND and BOOT0 jumpered)
% ioreg -p IOUSB > /tmp/b
# solid red light and solid green light
% ioreg -p IOUSB > /tmp/c
# nothing plugged in
% diff /tmp/a /tmp/c
13c13
< +-o AppleUSBXHCI Root Hub Simulation@14000000 <class AppleUSBRootHubDevice, id 0x100000589, registered, matched, active, busy 0 (15 ms), retain 11>
---
> +-o AppleUSBXHCI Root Hub Simulation@14000000 <class AppleUSBRootHubDevice, id 0x100000589, registered, matched, active, busy 0 (15 ms), retain 10>
18d17
< +-o USB Serial@14300000 <class AppleUSBDevice, id 0x100004ca4, registered, matched, active, busy 0 (10 ms), retain 12>
% diff /tmp/b /tmp/c
13c13
< +-o AppleUSBXHCI Root Hub Simulation@14000000 <class AppleUSBRootHubDevice, id 0x100000589, registered, matched, active, busy 0 (15 ms), retain 11>
---
> +-o AppleUSBXHCI Root Hub Simulation@14000000 <class AppleUSBRootHubDevice, id 0x100000589, registered, matched, active, busy 0 (15 ms), retain 10>
18d17
< +-o USB Serial@14300000 <class AppleUSBDevice, id 0x100004ce5, registered, matched, active, busy 0 (11 ms), retain 12>
system_profiler SPUSBDataType > /tmp/d
# red solid
system_profiler SPUSBDataType > /tmp/e
# nothing
% diff /tmp/d /tmp/e
38,48d37
< USB Serial:
<
< Product ID: 0x7523
< Vendor ID: 0x1a86
< Version: 2.64
< Speed: Up to 12 Mb/s
< Location ID: 0x14300000 / 33
< Current Available (mA): 500
< Current Required (mA): 98
< Extra Operating Current (mA): 0

View File

@@ -0,0 +1,68 @@
> | +-o WisCore RAK4631 Board@14400000 <class AppleUSBDevice, id 0x10005c158, registered, matched, active, busy 0 (18 ms), retain 14>
/dev/cu.usbmodem14401
% ls -al /dev/*modem*
crw-rw-rw- 1 root wheel 0x9000005 Jan 29 15:32 /dev/cu.usbmodem14401
crw-rw-rw- 1 root wheel 0x9000004 Jan 29 15:31 /dev/tty.usbmodem14401
Note: On a Mac Air, output is:
% system_profiler SPUSBDataType
USB:
USB 3.1 Bus:
Host Controller Driver: AppleT8103USBXHCI
USB 3.1 Bus:
Host Controller Driver: AppleT8103USBXHCI
WisCore RAK4631 Board:
Product ID: 0x8029
Vendor ID: 0x239a
Version: 1.00
Serial Number: E6CF9502B1D410D8
Speed: Up to 12 Mb/s
Manufacturer: RAKwireless
Location ID: 0x01100000 / 2
Current Available (mA): 500
Current Required (mA): 100
Extra Operating Current (mA): 0
However, in FTHR840BOOT mode, it shows this:
% system_profiler SPUSBDataType
USB:
USB 3.1 Bus:
Host Controller Driver: AppleT8103USBXHCI
USB 3.1 Bus:
Host Controller Driver: AppleT8103USBXHCI
Feather nRF52840 Express:
Product ID: 0x0029
Vendor ID: 0x239a
Version: 1.00
Serial Number: E6CF9502B1D410D8
Speed: Up to 12 Mb/s
Manufacturer: Adafruit Industries
Location ID: 0x01100000 / 1
Current Available (mA): 500
Current Required (mA): 100
Extra Operating Current (mA): 0
Media:
nRF UF2:
Capacity: 33.7 MB (33,690,112 bytes)
Removable Media: Yes
BSD Name: disk4
Logical Unit: 0
Partition Map Type: Unknown
S.M.A.R.T. status: Verified
USB Interface: 2
$ cat /Volumes/FTHR840BOOT/INFO_UF2.TXT
UF2 Bootloader 0.3.2-109-gd6b28e6-dirty lib/nrfx (v2.0.0) lib/tinyusb (0.6.0-272-g4e6aa0d8) lib/uf2 (heads/master)
Model: Adafruit Feather nRF52840 Express
Board-ID: nRF52840-Feather-revD
SoftDevice: S140 version 6.1.1
Date: Jun 16 2020

18
info/mac/rak4631_5005.txt Normal file
View File

@@ -0,0 +1,18 @@
no device plugged in
% ioreg -p IOUSB > /tmp/a
device plugged in, in "boot" mode
% ioreg -p IOUSB > /tmp/b
device plugged in, botted to Meshtastic firmware
% ioreg -p IOUSB > /tmp/c
(venv) sweet Meshtastic-python % diff /tmp/a /tmp/b (with most info removed)
> | +-o Feather nRF52840 Express@14400000 <class AppleUSBDevice, id 0x10005c0ff, registered, matched, active, busy 0 (22 ms), retain 16>
diff /tmp/a /tmp/c (with most info removed)
> | +-o WisCore RAK4631 Board@14400000 <class AppleUSBDevice, id 0x10005c134, registered, matched, active, busy 0 (17 ms), retain 14>
Meshtastic detected port on /dev/cu.usbmodem14401

21
info/mac/tbeam.txt Normal file
View File

@@ -0,0 +1,21 @@
meshtastic detected port: /dev/cu.usbmodem53230050571
ioreg -p IOUSB > /tmp/c
> | +-o USB Single Serial@14400000 <class AppleUSBDevice, id 0x10005bff7, registered, matched, active, busy 0 (15 ms), retain 14>
system_profiler SPUSBDataType > /tmp/a
> USB Single Serial:
>
> Product ID: 0x55d4
> Vendor ID: 0x1a86
> Version: 4.43
> Serial Number: 5323005057
> Speed: Up to 12 Mb/s
> Location ID: 0x14400000 / 50
> Current Available (mA): 500
> Current Required (mA): 134
> Extra Operating Current (mA): 0

40
info/mac/techo.txt Normal file
View File

@@ -0,0 +1,40 @@
in boot mode:
% mount
<snip>
/dev/disk122 on /Volumes/TECHOBOOT (msdos, local, nodev, nosuid, noowners)
% ls -al /Volumes/TECHOBOOT
total 3735
drwxrwxrwx@ 1 bob staff 2048 Feb 1 16:47 .
drwxr-xr-x 5 root wheel 160 Feb 1 16:47 ..
drwxrwxrwx 1 bob staff 512 Feb 1 16:47 .fseventsd
-rwxrwxrwx 1 bob staff 1908736 Oct 13 08:37 CURRENT.UF2
-rwxrwxrwx 1 bob staff 129 Oct 13 08:37 INDEX.HTM
-rwxrwxrwx 1 bob staff 237 Oct 13 08:37 INFO_UF2.TXT
# nothing plugged in
% ioreg -p IOUSB > /tmp/a
# not boot mode
% ioreg -p IOUSB > /tmp/b
# bootmode
% ioreg -p IOUSB > /tmp/c
% diff /tmp/a /tmp/b
<snip>
> | +-o TTGO_eink@14300000 <class AppleUSBDevice, id 0x100060fe4, registered, matched, active, busy 0 (18 ms), retain 14>
% diff /tmp/a /tmp/c
<snip>
> | +-o T-Echo v1@14300000 <class AppleUSBDevice, id 0x100061000, registered, matched, active, busy 0 (25 ms), retain 16>
contents of: INFO_UF2.TXT
UF2 Bootloader 0.6.1-2-g1224915 lib/nrfx (v2.0.0) lib/tinyusb (0.10.1-293-gaf8e5a90) lib/uf2 (remotes/origin/configupdate-9-gadbb8c7)
Model: LilyGo T-Echo
Board-ID: nRF52840-TEcho-v1
SoftDevice: S140 version 6.1.1
Date: Oct 13 2021

16
info/mac/tlora.txt Normal file
View File

@@ -0,0 +1,16 @@
diff of ioreg -p IOUSB
> | +-o USB Single Serial@14300000 <class AppleUSBDevice, id 0x10005bf0f, registered, matched, active, busy 0 (18 ms), retain 14>
Diff of system_profiler SPUSBDataType
< USB Single Serial:
<
< Product ID: 0x55d4
< Vendor ID: 0x1a86
< Version: 4.43
< Speed: Up to 12 Mb/s
< Location ID: 0x14300000 / 46
< Current Available (mA): 500
< Current Required (mA): 134
< Extra Operating Current (mA): 0

85
info/mac/tlora_2.1.6.txt Normal file
View File

@@ -0,0 +1,85 @@
lsusb
Bus 001 Device 001: ID 0bda:2172 Realtek Semiconductor Corp. BillBoard Device Serial: 00000000000000000
Bus 000 Device 002: ID 2109:0817 VIA Labs, Inc. USB3.0 Hub Serial: 000000000
Bus 000 Device 003: ID 2109:0715 VIA Labs, Inc. VLI Product String Serial: 000000075003
Bus 000 Device 004: ID 0bda:0306 Realtek Semiconductor Corp. USB3.0-CRW Serial: 60000719201300000
Bus 000 Device 005: ID 2109:0817 VIA Labs, Inc. USB3.0 Hub Serial: 000000000
Bus 000 Device 001: ID 2109:2817 VIA Labs, Inc. USB2.0 Hub Serial: 000000000
Bus 000 Device 009: ID 1a86:55d4 1a86 USB Single Serial Serial: 533C005215
Bus 000 Device 006: ID 2109:2817 VIA Labs, Inc. USB2.0 Hub Serial: 000000000
Bus 000 Device 007: ID 2109:8817 VIA Labs, Inc. USB Billboard Device Serial: 0000000000000001
Bus 000 Device 008: ID 2109:8817 VIA Labs, Inc. USB Billboard Device Serial: 0000000000000001
Bus 002 Device 001: ID 1a40:0101 TERMINUS TECHNOLOGY INC. USB 2.0 Hub
Bus 002 Device 003: ID 0922:001f Dymo Corporation DYMO LabelWriter 4XL Serial: 17032316350940
Bus 002 Device 002: ID 046d:082d Logitech Inc. HD Pro Webcam C920 Serial: A21C905F
Bus 000 Device 000: ID 0bda:2172 Realtek Semiconductor Corp. USB 3.1 Bus
Bus 000 Device 000: ID 2109:0817 VIA Labs, Inc. USB 3.1 Bus
Bus 000 Device 001: ID 1d6b:1100 Linux Foundation USB 3.0 Bus
% lsusb -v (with parts snipped)
USB2.0 Hub :
Product ID: 0x2817
Vendor ID: 0x2109 (VIA Labs, Inc.)
Version: 6.03
Serial Number: 000000000
Speed: Up to 480 Mb/s
Manufacturer: VIA Labs, Inc.
Location ID: 0x00100000 / 1
Current Available (mA): 500
Current Required (mA): 0
Extra Operating Current (mA): 0
USB Single Serial:
Product ID: 0x55d4
Vendor ID: 0x1a86
Version: 4.43
Serial Number: 533C005215
Speed: Up to 12 Mb/s
Location ID: 0x00140000 / 9
Current Available (mA): 500
Current Required (mA): 134
Extra Operating Current (mA): 0
USB2.0 Hub :
Product ID: 0x2817
Vendor ID: 0x2109 (VIA Labs, Inc.)
Version: 6.03
Serial Number: 000000000
Speed: Up to 480 Mb/s
Manufacturer: VIA Labs, Inc.
Location ID: 0x00110000 / 6
Current Available (mA): 500
Current Required (mA): 0
Extra Operating Current (mA): 0
USB Billboard Device :
Product ID: 0x8817
Vendor ID: 0x2109 (VIA Labs, Inc.)
Version: 0.01
Serial Number: 0000000000000001
Speed: Up to 480 Mb/s
Manufacturer: VIA Labs, Inc.
Location ID: 0x00115000 / 7
Current Available (mA): 500
Current Required (mA): 100
Extra Operating Current (mA): 0
USB Billboard Device :
Product ID: 0x8817
Vendor ID: 0x2109 (VIA Labs, Inc.)
Version: 0.01
Serial Number: 0000000000000001
Speed: Up to 480 Mb/s
Manufacturer: VIA Labs, Inc.
Location ID: 0x00150000 / 8
Current Available (mA): 500
Current Required (mA): 100
Extra Operating Current (mA): 0

3
info/readme.txt Normal file
View File

@@ -0,0 +1,3 @@
Gathering OS-level info for devices.
This info might be helpful for developers detecting info about devices.

67
info/ubuntu/diy.txt Normal file
View File

@@ -0,0 +1,67 @@
lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
Bus 001 Device 003: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
lsusb -d 10c4: -v
Bus 001 Device 004: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x10c4 Silicon Labs
idProduct 0xea60 CP210x UART Bridge
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0020
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 2
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0

85
info/ubuntu/heltec_v2.txt Normal file
View File

@@ -0,0 +1,85 @@
Run on Ubuntu 20
Command:
lsusb -d 10c4: -v
Output:
Bus 001 Device 091: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x10c4 Silicon Labs
idProduct 0xea60 CP210x UART Bridge
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0020
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 2
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Command:
esptool.py chip_id
Output:
esptool.py v3.2
Found 3 serial ports
Serial port /dev/ttyUSB0
Connecting....
Detecting chip type... Unsupported detection protocol, switching and trying again...
Connecting.....
Detecting chip type... ESP32
Chip is ESP32-D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: 24:0a:c4:fc:be:f0
Uploading stub...
Running stub...
Stub running...
Warning: ESP32 has no Chip ID. Reading MAC instead.
MAC: 24:0a:c4:fc:be:f0
Hard resetting via RTS pin...

View File

@@ -0,0 +1,118 @@
Note: Meshtastic firmware was installed when running these commands
$ ls -al /dev/ttyACM*
crw-rw---- 1 root dialout 166, 0 Jan 29 21:50 /dev/ttyACM0
lsusb -d 239a: -v
Bus 001 Device 097: ID 239a:8029
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 239 Miscellaneous Device
bDeviceSubClass 2
bDeviceProtocol 1 Interface Association
bMaxPacketSize0 64
idVendor 0x239a
idProduct 0x8029
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x004b
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Association:
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 2
bFunctionClass 2 Communications
bFunctionSubClass 2 Abstract (modem)
bFunctionProtocol 0
iFunction 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 0
iInterface 4
CDC Header:
bcdCDC 1.20
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
CDC ACM:
bmCapabilities 0x02
line coding and serial state
CDC Union:
bMasterInterface 0
bSlaveInterface 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 16
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
$ lsusb
Bus 002 Device 005: ID 046d:c31c Logitech, Inc. Keyboard K120
Bus 002 Device 002: ID 8087:8000 Intel Corp.
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 097: ID 239a:8029
Bus 001 Device 002: ID 8087:8008 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Note: esptool.py chip_id does not detect device

View File

@@ -0,0 +1,148 @@
Note: Device has Meshtastic firmware installed.
$ ls -al /dev/ttyACM*
crw-rw---- 1 root dialout 166, 0 Jan 29 21:44 /dev/ttyACM0
$ lsusb -d 239a: -v
Bus 001 Device 098: ID 239a:0029
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 239 Miscellaneous Device
bDeviceSubClass 2
bDeviceProtocol 1 Interface Association
bMaxPacketSize0 64
idVendor 0x239a
idProduct 0x0029
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0062
bNumInterfaces 3
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Association:
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 2
bFunctionClass 2 Communications
bFunctionSubClass 2 Abstract (modem)
bFunctionProtocol 0
iFunction 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 0
iInterface 4
CDC Header:
bcdCDC 1.20
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
CDC ACM:
bmCapabilities 0x02
line coding and serial state
CDC Union:
bMasterInterface 0
bSlaveInterface 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 16
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 8 Mass Storage
bInterfaceSubClass 6 SCSI
bInterfaceProtocol 80 Bulk-Only
iInterface 5
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
$ lsusb
Bus 002 Device 005: ID 046d:c31c Logitech, Inc. Keyboard K120
Bus 002 Device 002: ID 8087:8000 Intel Corp.
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 098: ID 239a:0029
Bus 001 Device 002: ID 8087:8008 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Note: esptool.py chip_id does not detect device

1
info/ubuntu/readme.txt Normal file
View File

@@ -0,0 +1 @@
info run on ubuntu

94
info/ubuntu/tbeam.txt Normal file
View File

@@ -0,0 +1,94 @@
Run on Ubuntu 20
Command:
lsusb -d 1a86: -v
Output:
Bus 001 Device 096: ID 1a86:55d4 QinHeng Electronics
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x1a86 QinHeng Electronics
idProduct 0x55d4
bcdDevice 4.43
iManufacturer 0
iProduct 2
iSerial 3
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0043
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 134mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 1 AT-commands (v.25ter)
iInterface 0
CDC Header:
bcdCDC 1.10
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
CDC ACM:
bmCapabilities 0x02
line coding and serial state
CDC Union:
bMasterInterface 0
bSlaveInterface 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0020 1x 32 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0

141
info/ubuntu/techo.txt Normal file
View File

@@ -0,0 +1,141 @@
$ lsusb
Bus 002 Device 005: ID 046d:c31c Logitech, Inc. Keyboard K120
Bus 002 Device 002: ID 8087:8000 Intel Corp.
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 107: ID 239a:0029
Bus 001 Device 002: ID 8087:8008 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ lsusb -d 239a: -v
Bus 001 Device 107: ID 239a:0029
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 239 Miscellaneous Device
bDeviceSubClass 2
bDeviceProtocol 1 Interface Association
bMaxPacketSize0 64
idVendor 0x239a
idProduct 0x0029
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0062
bNumInterfaces 3
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Association:
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 2
bFunctionClass 2 Communications
bFunctionSubClass 2 Abstract (modem)
bFunctionProtocol 0
iFunction 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 0
iInterface 4
CDC Header:
bcdCDC 1.20
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
CDC ACM:
bmCapabilities 0x02
line coding and serial state
CDC Union:
bMasterInterface 0
bSlaveInterface 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 16
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 8 Mass Storage
bInterfaceSubClass 6 SCSI
bInterfaceProtocol 80 Bulk-Only
iInterface 5
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0

107
info/ubuntu/tlora.txt Normal file
View File

@@ -0,0 +1,107 @@
Run on Ubuntu 20
Note: Device has Meshtastic firmware installed
$ lsusb
Bus 002 Device 005: ID 046d:c31c Logitech, Inc. Keyboard K120
Bus 002 Device 002: ID 8087:8000 Intel Corp.
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 099: ID 1a86:55d4 QinHeng Electronics
Bus 001 Device 002: ID 8087:8008 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ lsusb -d 1a86: -v
Bus 001 Device 099: ID 1a86:55d4 QinHeng Electronics
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x1a86 QinHeng Electronics
idProduct 0x55d4
bcdDevice 4.43
iManufacturer 0
iProduct 2
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0043
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 134mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 1 AT-commands (v.25ter)
iInterface 0
CDC Header:
bcdCDC 1.10
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
CDC ACM:
bmCapabilities 0x02
line coding and serial state
CDC Union:
bMasterInterface 0
bSlaveInterface 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0020 1x 32 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0

106
info/windows/heltec.txt Normal file
View File

@@ -0,0 +1,106 @@
Run from Windows 10
Might work... (nope)
Get-PnpDevice -Class 'USB' -PresentOnly | Format-List
> Get-PnpDevice -PresentOnly | Format-List > b
> Compare-Object (get-content a) (Get-Content b)
InputObject SideIndicator
----------- -------------
Caption : CP2102 USB to UART Bridge Controller <=
Description : CP2102 USB to UART Bridge Controller <=
Name : CP2102 USB to UART Bridge Controller <=
Status : Error <=
ConfigManagerErrorCode : CM_PROB_FAILED_INSTALL <=
DeviceID : USB\VID_10C4&PID_EA60\0001 <=
PNPDeviceID : USB\VID_10C4&PID_EA60\0001 <=
CompatibleID : {USB\Class_FF&SubClass_00&Prot_00, USB\Class_FF&SubClass_00, USB\Class_FF} <=
HardwareID : {USB\VID_10C4&PID_EA60&REV_0100, USB\VID_10C4&PID_EA60} <=
FriendlyName : CP2102 USB to UART Bridge Controller <=
InstanceId : USB\VID_10C4&PID_EA60\0001 <=
Problem : CM_PROB_FAILED_INSTALL <=
ClassGuid : <=
Manufacturer : <=
PNPClass : <=
Class : <=
Service : <=
InstallDate : <=
Availability : <=
ConfigManagerUserConfig : False <=
CreationClassName : Win32_PnPEntity <=
ErrorCleared : <=
ErrorDescription : <=
LastErrorCode : <=
PowerManagementCapabilities : <=
PowerManagementSupported : <=
StatusInfo : <=
SystemCreationClassName : Win32_ComputerSystem <=
SystemName : DESKTOP-FRFQN8H <=
Present : True <=
PSComputerName : <=
ProblemDescription : <=
<=
> Get-PnpDevice -DeviceID 'USB\VID_10C4&PID_EA60\0001'
Status Class FriendlyName InstanceId
------ ----- ------------ ----------
Error CP2102 USB to UART Bridge Controller USB\VID_...
> Get-PnpDevice -PresentOnly -DeviceID 'USB\VID_10C4&PID_EA60\0001'
Get-PnpDevice : No matching Win32_PnPEntity objects found by CIM query for instances of the ROOT\cimv2\Win32_PnPEntity
class on the CIM server: SELECT * FROM Win32_PnPEntity WHERE ((DeviceId LIKE 'USB\\VID[_]10C4&PID[_]EA60\\0001'))
AND ((Present = TRUE)). Verify query parameters and retry.
At line:1 char:1
+ Get-PnpDevice -PresentOnly -DeviceID 'USB\VID_10C4&PID_EA60\0001'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Win32_PnPEntity:String) [Get-PnpDevice], CimJobException
+ FullyQualifiedErrorId : CmdletizationQuery_NotFound,Get-PnpDevice
> Get-PnpDevice -PresentOnly -DeviceID 'USB\VID_10C4&PID_EA60\0001'
Status Class FriendlyName InstanceId
------ ----- ------------ ----------
Error CP2102 USB to UART Bridge Controller USB\VID_...
If need to install driver
Get-PnpDevice -DeviceID 'USB\VID_10C4&PID_EA60\0001' | Format-List
Caption : CP2102 USB to UART Bridge Controller
Description : CP2102 USB to UART Bridge Controller
InstallDate :
Name : CP2102 USB to UART Bridge Controller
Status : Error
Availability :
ConfigManagerErrorCode : CM_PROB_FAILED_INSTALL
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
DeviceID : USB\VID_10C4&PID_EA60\0001
ErrorCleared :
ErrorDescription :
LastErrorCode :
PNPDeviceID : USB\VID_10C4&PID_EA60\0001
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
ClassGuid :
CompatibleID : {USB\Class_FF&SubClass_00&Prot_00, USB\Class_FF&SubClass_00, USB\Class_FF}
HardwareID : {USB\VID_10C4&PID_EA60&REV_0100, USB\VID_10C4&PID_EA60}
Manufacturer :
PNPClass :
Present : True
Service :
PSComputerName :
Class :
FriendlyName : CP2102 USB to UART Bridge Controller
InstanceId : USB\VID_10C4&PID_EA60\0001
Problem : CM_PROB_FAILED_INSTALL
ProblemDescription :

View File

@@ -0,0 +1,78 @@
Run from Windows 10
> Get-PnpDevice -PresentOnly | Format-List >a
> Get-PnpDevice -PresentOnly | Format-List >b
> Compare-Object (get-content a) (Get-Content b)
InputObject Side
Indi
cato
r
----------- ----
Caption : USB Serial Device (COM4) =>
Description : USB Serial Device =>
Name : USB Serial Device (COM4) =>
DeviceID : USB\VID_239A&PID_8029&MI_00\6&E8876D1&0&0000 =>
PNPDeviceID : USB\VID_239A&PID_8029&MI_00\6&E8876D1&0&0000 =>
ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318} =>
CompatibleID : {USB\Class_02&SubClass_02&Prot_00, USB\Class_02&SubClass_02, USB\Class_02} =>
HardwareID : {USB\VID_239A&PID_8029&REV_0100&MI_00, USB\VID_239A&PID_8029&MI_00} =>
PNPClass : Ports =>
Service : usbser =>
Class : Ports =>
FriendlyName : USB Serial Device (COM4) =>
InstanceId : USB\VID_239A&PID_8029&MI_00\6&E8876D1&0&0000 =>
Caption : USB Composite Device =>
Description : USB Composite Device =>
Name : USB Composite Device =>
DeviceID : USB\VID_239A&PID_8029\E6CF9502B1D410D8 =>
PNPDeviceID : USB\VID_239A&PID_8029\E6CF9502B1D410D8 =>
ClassGuid : {36fc9e60-c465-11cf-8056-444553540000} =>
CompatibleID : {USB\DevClass_00&SubClass_00&Prot_00, USB\DevClass_00&SubClass_00, USB\DevClass_00, =>
USB\COMPOSITE} =>
HardwareID : {USB\VID_239A&PID_8029&REV_0100, USB\VID_239A&PID_8029} =>
Manufacturer : (Standard USB Host Controller) =>
PNPClass : USB =>
Service : usbccgp =>
Class : USB =>
FriendlyName : USB Composite Device =>
InstanceId : USB\VID_239A&PID_8029\E6CF9502B1D410D8 =>
InstallDate : =>
Status : OK =>
Availability : =>
ConfigManagerErrorCode : CM_PROB_NONE =>
ConfigManagerUserConfig : False =>
CreationClassName : Win32_PnPEntity =>
ErrorCleared : =>
ErrorDescription : =>
LastErrorCode : =>
PowerManagementCapabilities : =>
PowerManagementSupported : =>
StatusInfo : =>
SystemCreationClassName : Win32_ComputerSystem =>
SystemName : DESKTOP-FRFQN8H =>
Present : True =>
PSComputerName : =>
Problem : CM_PROB_NONE =>
ProblemDescription : =>
InstallDate : =>
Status : OK =>
Availability : =>
ConfigManagerErrorCode : CM_PROB_NONE =>
ConfigManagerUserConfig : False =>
CreationClassName : Win32_PnPEntity =>
ErrorCleared : =>
ErrorDescription : =>
LastErrorCode : =>
PowerManagementCapabilities : =>
PowerManagementSupported : =>
StatusInfo : =>
SystemCreationClassName : Win32_ComputerSystem =>
SystemName : DESKTOP-FRFQN8H =>
Manufacturer : Microsoft =>
Present : True =>
PSComputerName : =>
Problem : CM_PROB_NONE =>
ProblemDescription : =>
=>
=>

View File

@@ -0,0 +1,254 @@
Run from Windows 10
> Get-PnpDevice -PresentOnly | Format-List >a
> Get-PnpDevice -PresentOnly | Format-List >b
> Compare-Object (get-content a) (Get-Content b)
In "boot" mode:
InputObject
-----------
Caption : FTHR840BOOT
Description : nRF UF2
Name : FTHR840BOOT
DeviceID : SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&27E1626&0&D121BD1C90B
93EA2&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
PNPDeviceID : SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&27E1626&0&D121BD1C90B
93EA2&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
ClassGuid : {eec5ad98-8080-425f-922a-dabf3de3f69a}
CompatibleID : {wpdbusenum\fs, SWD\Generic}
Manufacturer : Adafruit
PNPClass : WPD
Service : WUDFWpdFs
Class : WPD
FriendlyName : FTHR840BOOT
InstanceId : SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&27E1626&0&D121BD1C90B
93EA2&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
DeviceID : STORAGE\VOLUME\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&27E1626&0&D121BD1C90B
93EA2&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
PNPDeviceID : STORAGE\VOLUME\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&27E1626&0&D121BD1C90B
93EA2&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
InstanceId : STORAGE\VOLUME\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&27E1626&0&D121BD1C90B
93EA2&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
Caption : USB Mass Storage Device
Description : USB Mass Storage Device
Name : USB Mass Storage Device
DeviceID : USB\VID_239A&PID_0029&MI_02\6&175793A&0&0002
PNPDeviceID : USB\VID_239A&PID_0029&MI_02\6&175793A&0&0002
CompatibleID : {USB\Class_08&SubClass_06&Prot_50, USB\Class_08&SubClass_06, USB\Class_08}
HardwareID : {USB\VID_239A&PID_0029&REV_0100&MI_02, USB\VID_239A&PID_0029&MI_02}
Manufacturer : Compatible USB storage device
Service : USBSTOR
FriendlyName : USB Mass Storage Device
InstanceId : USB\VID_239A&PID_0029&MI_02\6&175793A&0&0002
Caption : USB Serial Device (COM5)
Description : USB Serial Device
Name : USB Serial Device (COM5)
DeviceID : USB\VID_239A&PID_0029&MI_00\6&175793A&0&0000
PNPDeviceID : USB\VID_239A&PID_0029&MI_00\6&175793A&0&0000
ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318}
CompatibleID : {USB\Class_02&SubClass_02&Prot_00, USB\Class_02&SubClass_02, USB\Class_02}
HardwareID : {USB\VID_239A&PID_0029&REV_0100&MI_00, USB\VID_239A&PID_0029&MI_00}
PNPClass : Ports
Service : usbser
Class : Ports
FriendlyName : USB Serial Device (COM5)
InstanceId : USB\VID_239A&PID_0029&MI_00\6&175793A&0&0000
DeviceID : USB\VID_239A&PID_0029\D121BD1C90B93EA2
PNPDeviceID : USB\VID_239A&PID_0029\D121BD1C90B93EA2
ClassGuid : {36fc9e60-c465-11cf-8056-444553540000}
HardwareID : {USB\VID_239A&PID_0029&REV_0100, USB\VID_239A&PID_0029}
PNPClass : USB
Class : USB
InstanceId : USB\VID_239A&PID_0029\D121BD1C90B93EA2
Caption : USB Composite Device
Description : USB Composite Device
Name : USB Composite Device
ClassGuid : {36fc9e60-c465-11cf-8056-444553540000}
CompatibleID : {USB\DevClass_00&SubClass_00&Prot_00, USB\DevClass_00&SubClass_00, USB\DevClass_00,
USB\COMPOSITE}
Manufacturer : (Standard USB Host Controller)
PNPClass : USB
Service : usbccgp
Class : USB
FriendlyName : USB Composite Device
Caption : Volume
Description : Volume
Name : Volume
ClassGuid : {71a27cdd-812a-11d0-bec7-08002be2092f}
HardwareID : {STORAGE\Volume}
PNPClass : Volume
Service : volume
Class : Volume
FriendlyName : Volume
HardwareID :
Caption : Adafruit nRF UF2 USB Device
Name : Adafruit nRF UF2 USB Device
DeviceID : USBSTOR\DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0\7&27E1626&0&D121BD1C90B93EA2&0
PNPDeviceID : USBSTOR\DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0\7&27E1626&0&D121BD1C90B93EA2&0
CompatibleID : {USBSTOR\Disk, USBSTOR\RAW, GenDisk}
HardwareID : {USBSTOR\DiskAdafruitnRF_UF2_________1.0_, USBSTOR\DiskAdafruitnRF_UF2_________,
USBSTOR\DiskAdafruit, USBSTOR\AdafruitnRF_UF2_________1...}
FriendlyName : Adafruit nRF UF2 USB Device
InstanceId : USBSTOR\DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0\7&27E1626&0&D121BD1C90B93EA2&0
Description : Disk drive
ClassGuid : {4d36e967-e325-11ce-bfc1-08002be10318}
Manufacturer : (Standard disk drives)
PNPClass : DiskDrive
Service : disk
Class : DiskDrive
CompatibleID :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Manufacturer : Microsoft
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
When you press the RST to load Meshtastic:
> Get-PnpDevice -PresentOnly | Format-List >b
> Compare-Object (get-content a) (Get-Content b)
InputObject Side
Indi
cato
r
----------- ----
DeviceID : USB\VID_239A&PID_8029\D121BD1C90B93EA2 =>
PNPDeviceID : USB\VID_239A&PID_8029\D121BD1C90B93EA2 =>
HardwareID : {USB\VID_239A&PID_8029&REV_0100, USB\VID_239A&PID_8029} =>
InstanceId : USB\VID_239A&PID_8029\D121BD1C90B93EA2 =>
Caption : USB Composite Device =>
Description : USB Composite Device =>
Name : USB Composite Device =>
ClassGuid : {36fc9e60-c465-11cf-8056-444553540000} =>
CompatibleID : {USB\DevClass_00&SubClass_00&Prot_00, USB\DevClass_00&SubClass_00, USB\DevClass_00, =>
USB\COMPOSITE} =>
Manufacturer : (Standard USB Host Controller) =>
PNPClass : USB =>
Service : usbccgp =>
Class : USB =>
FriendlyName : USB Composite Device =>
Caption : USB Serial Device (COM6) =>
Description : USB Serial Device =>
Name : USB Serial Device (COM6) =>
DeviceID : USB\VID_239A&PID_8029&MI_00\6&39B279E2&0&0000 =>
PNPDeviceID : USB\VID_239A&PID_8029&MI_00\6&39B279E2&0&0000 =>
ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318} =>
CompatibleID : {USB\Class_02&SubClass_02&Prot_00, USB\Class_02&SubClass_02, USB\Class_02} =>
HardwareID : {USB\VID_239A&PID_8029&REV_0100&MI_00, USB\VID_239A&PID_8029&MI_00} =>
PNPClass : Ports =>
Service : usbser =>
Class : Ports =>
FriendlyName : USB Serial Device (COM6) =>
InstanceId : USB\VID_239A&PID_8029&MI_00\6&39B279E2&0&0000 =>
InstallDate : =>
Status : OK =>
Availability : =>
ConfigManagerErrorCode : CM_PROB_NONE =>
ConfigManagerUserConfig : False =>
CreationClassName : Win32_PnPEntity =>
ErrorCleared : =>
ErrorDescription : =>
LastErrorCode : =>
PowerManagementCapabilities : =>
PowerManagementSupported : =>
StatusInfo : =>
SystemCreationClassName : Win32_ComputerSystem =>
SystemName : DESKTOP-FRFQN8H =>
Present : True =>
PSComputerName : =>
Problem : CM_PROB_NONE =>
ProblemDescription : =>
InstallDate : =>
Status : OK =>
Availability : =>
ConfigManagerErrorCode : CM_PROB_NONE =>
ConfigManagerUserConfig : False =>
CreationClassName : Win32_PnPEntity =>
ErrorCleared : =>
ErrorDescription : =>
LastErrorCode : =>
PowerManagementCapabilities : =>
PowerManagementSupported : =>
StatusInfo : =>
SystemCreationClassName : Win32_ComputerSystem =>
SystemName : DESKTOP-FRFQN8H =>
Manufacturer : Microsoft =>
Present : True =>
PSComputerName : =>
Problem : CM_PROB_NONE =>
ProblemDescription : =>
=>

42
info/windows/tbeam.txt Normal file
View File

@@ -0,0 +1,42 @@
Run from Windows 10
> Get-PnpDevice -PresentOnly | Format-List >a
> Get-PnpDevice -PresentOnly | Format-List >b
> Compare-Object (get-content a) (Get-Content b)
InputObject SideIndicator
----------- -------------
Caption : USB-Enhanced-SERIAL CH9102 (COM7) =>
Description : USB-Enhanced-SERIAL CH9102 =>
Name : USB-Enhanced-SERIAL CH9102 (COM7) =>
DeviceID : USB\VID_1A86&PID_55D4\5323005057 =>
PNPDeviceID : USB\VID_1A86&PID_55D4\5323005057 =>
ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318} =>
CompatibleID : {USB\Class_02&SubClass_02&Prot_01, USB\Class_02&SubClass_02, USB\Class_02} =>
HardwareID : {USB\VID_1A86&PID_55D4&REV_0443, USB\VID_1A86&PID_55D4} =>
Manufacturer : wch.cn =>
PNPClass : Ports =>
Service : CH343SER_A64 =>
Class : Ports =>
FriendlyName : USB-Enhanced-SERIAL CH9102 (COM7) =>
InstanceId : USB\VID_1A86&PID_55D4\5323005057 =>
InstallDate : =>
Status : OK =>
Availability : =>
ConfigManagerErrorCode : CM_PROB_NONE =>
ConfigManagerUserConfig : False =>
CreationClassName : Win32_PnPEntity =>
ErrorCleared : =>
ErrorDescription : =>
LastErrorCode : =>
PowerManagementCapabilities : =>
PowerManagementSupported : =>
StatusInfo : =>
SystemCreationClassName : Win32_ComputerSystem =>
SystemName : DESKTOP-FRFQN8H =>
Present : True =>
PSComputerName : =>
Problem : CM_PROB_NONE =>
ProblemDescription : =>
=>

302
info/windows/techo.txt Normal file
View File

@@ -0,0 +1,302 @@
PS > Get-PnpDevice -PresentOnly | Format-List >a
PS > Get-PnpDevice -PresentOnly | Format-List >b
PS > Compare-Object (get-content a) (get-content b)
Note: Not in boot mode
InputObject Side
Indi
cato
r
----------- ----
DeviceID : USB\VID_239A&PID_4405\D02012062C578951 =>
PNPDeviceID : USB\VID_239A&PID_4405\D02012062C578951 =>
HardwareID : {USB\VID_239A&PID_4405&REV_0100, USB\VID_239A&PID_4405} =>
InstanceId : USB\VID_239A&PID_4405\D02012062C578951 =>
Caption : USB Composite Device =>
Description : USB Composite Device =>
Name : USB Composite Device =>
ClassGuid : {36fc9e60-c465-11cf-8056-444553540000} =>
CompatibleID : {USB\DevClass_00&SubClass_00&Prot_00, USB\DevClass_00&SubClass_00, USB\DevClass_00, =>
USB\COMPOSITE} =>
Manufacturer : (Standard USB Host Controller) =>
PNPClass : USB =>
Service : usbccgp =>
Class : USB =>
FriendlyName : USB Composite Device =>
Caption : USB Serial Device (COM10) =>
Description : USB Serial Device =>
Name : USB Serial Device (COM10) =>
DeviceID : USB\VID_239A&PID_4405&MI_00\6&1B68A3E6&0&0000 =>
PNPDeviceID : USB\VID_239A&PID_4405&MI_00\6&1B68A3E6&0&0000 =>
ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318} =>
CompatibleID : {USB\Class_02&SubClass_02&Prot_00, USB\Class_02&SubClass_02, USB\Class_02} =>
HardwareID : {USB\VID_239A&PID_4405&REV_0100&MI_00, USB\VID_239A&PID_4405&MI_00} =>
PNPClass : Ports =>
Service : usbser =>
Class : Ports =>
FriendlyName : USB Serial Device (COM10) =>
InstanceId : USB\VID_239A&PID_4405&MI_00\6&1B68A3E6&0&0000 =>
InstallDate : =>
Status : OK =>
Availability : =>
ConfigManagerErrorCode : CM_PROB_NONE =>
ConfigManagerUserConfig : False =>
CreationClassName : Win32_PnPEntity =>
ErrorCleared : =>
ErrorDescription : =>
LastErrorCode : =>
PowerManagementCapabilities : =>
PowerManagementSupported : =>
StatusInfo : =>
SystemCreationClassName : Win32_ComputerSystem =>
SystemName : DESKTOP-FRFQN8H =>
Present : True =>
PSComputerName : =>
Problem : CM_PROB_NONE =>
ProblemDescription : =>
InstallDate : =>
Status : OK =>
Availability : =>
ConfigManagerErrorCode : CM_PROB_NONE =>
ConfigManagerUserConfig : False =>
CreationClassName : Win32_PnPEntity =>
ErrorCleared : =>
ErrorDescription : =>
LastErrorCode : =>
PowerManagementCapabilities : =>
PowerManagementSupported : =>
StatusInfo : =>
SystemCreationClassName : Win32_ComputerSystem =>
SystemName : DESKTOP-FRFQN8H =>
Manufacturer : Microsoft =>
Present : True =>
PSComputerName : =>
Problem : CM_PROB_NONE =>
ProblemDescription : =>
=>
in boot mode
PS > Get-PnpDevice -PresentOnly | Format-List >c
PS > Compare-Object (get-content a) (get-content c)
InputObject
-----------
Caption : Adafruit nRF UF2 USB Device
Name : Adafruit nRF UF2 USB Device
DeviceID : USBSTOR\DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0\7&10304CB2&0&D02012062C578951&0
PNPDeviceID : USBSTOR\DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0\7&10304CB2&0&D02012062C578951&0
CompatibleID : {USBSTOR\Disk, USBSTOR\RAW, GenDisk}
HardwareID : {USBSTOR\DiskAdafruitnRF_UF2_________1.0_, USBSTOR\DiskAdafruitnRF_UF2_________,
USBSTOR\DiskAdafruit, USBSTOR\AdafruitnRF_UF2_________1...}
FriendlyName : Adafruit nRF UF2 USB Device
InstanceId : USBSTOR\DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0\7&10304CB2&0&D02012062C578951&0
Caption : USB Mass Storage Device
Description : USB Mass Storage Device
Name : USB Mass Storage Device
DeviceID : USB\VID_239A&PID_0029&MI_02\6&2AE8D65&0&0002
PNPDeviceID : USB\VID_239A&PID_0029&MI_02\6&2AE8D65&0&0002
CompatibleID : {USB\Class_08&SubClass_06&Prot_50, USB\Class_08&SubClass_06, USB\Class_08}
HardwareID : {USB\VID_239A&PID_0029&REV_0100&MI_02, USB\VID_239A&PID_0029&MI_02}
Manufacturer : Compatible USB storage device
Service : USBSTOR
FriendlyName : USB Mass Storage Device
InstanceId : USB\VID_239A&PID_0029&MI_02\6&2AE8D65&0&0002
Caption : USB Serial Device (COM11)
Description : USB Serial Device
Name : USB Serial Device (COM11)
DeviceID : USB\VID_239A&PID_0029&MI_00\6&2AE8D65&0&0000
PNPDeviceID : USB\VID_239A&PID_0029&MI_00\6&2AE8D65&0&0000
ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318}
CompatibleID : {USB\Class_02&SubClass_02&Prot_00, USB\Class_02&SubClass_02, USB\Class_02}
HardwareID : {USB\VID_239A&PID_0029&REV_0100&MI_00, USB\VID_239A&PID_0029&MI_00}
PNPClass : Ports
Service : usbser
Class : Ports
FriendlyName : USB Serial Device (COM11)
InstanceId : USB\VID_239A&PID_0029&MI_00\6&2AE8D65&0&0000
ClassGuid : {36fc9e60-c465-11cf-8056-444553540000}
PNPClass : USB
Class : USB
Caption : USB Composite Device
Description : USB Composite Device
Name : USB Composite Device
DeviceID : USB\VID_239A&PID_0029\D02012062C578951
PNPDeviceID : USB\VID_239A&PID_0029\D02012062C578951
ClassGuid : {36fc9e60-c465-11cf-8056-444553540000}
CompatibleID : {USB\DevClass_00&SubClass_00&Prot_00, USB\DevClass_00&SubClass_00, USB\DevClass_00,
USB\COMPOSITE}
HardwareID : {USB\VID_239A&PID_0029&REV_0100, USB\VID_239A&PID_0029}
Manufacturer : (Standard USB Host Controller)
PNPClass : USB
Service : usbccgp
Class : USB
FriendlyName : USB Composite Device
InstanceId : USB\VID_239A&PID_0029\D02012062C578951
DeviceID : STORAGE\VOLUME\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&10304CB2&0&D02012062C
578951&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
PNPDeviceID : STORAGE\VOLUME\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&10304CB2&0&D02012062C
578951&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
InstanceId : STORAGE\VOLUME\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&10304CB2&0&D02012062C
578951&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
Caption : Volume
Description : Volume
Name : Volume
ClassGuid : {71a27cdd-812a-11d0-bec7-08002be2092f}
HardwareID : {STORAGE\Volume}
PNPClass : Volume
Service : volume
Class : Volume
FriendlyName : Volume
Description : Disk drive
ClassGuid : {4d36e967-e325-11ce-bfc1-08002be10318}
Manufacturer : (Standard disk drives)
PNPClass : DiskDrive
Service : disk
Class : DiskDrive
Caption : TECHOBOOT
Description : nRF UF2
Name : TECHOBOOT
DeviceID : SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&10304CB2&0&D02012062C
578951&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
PNPDeviceID : SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&10304CB2&0&D02012062C
578951&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
ClassGuid : {eec5ad98-8080-425f-922a-dabf3de3f69a}
CompatibleID : {wpdbusenum\fs, SWD\Generic}
HardwareID :
Manufacturer : Adafruit
PNPClass : WPD
Service : WUDFWpdFs
Class : WPD
FriendlyName : TECHOBOOT
InstanceId : SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_ADAFRUIT&PROD_NRF_UF2&REV_1.0#7&10304CB2&0&D02012062C
578951&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}
CompatibleID :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Manufacturer : Microsoft
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
InstallDate :
Status : OK
Availability :
ConfigManagerErrorCode : CM_PROB_NONE
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
ErrorCleared :
ErrorDescription :
LastErrorCode :
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP-FRFQN8H
Manufacturer : Microsoft
Present : True
PSComputerName :
Problem : CM_PROB_NONE
ProblemDescription :
PS > Get-Volume
DriveLetter FriendlyName FileSystemType DriveType HealthStatus OperationalStatus SizeRemaining Size
----------- ------------ -------------- --------- ------------ ----------------- ------------- ----
Recovery NTFS Fixed Healthy OK 301.99 MB 854 MB
C NTFS Fixed Healthy OK 22.3 GB 56.67 GB
D TECHOBOOT FAT Removable Healthy OK 30.05 MB 31.88 MB

41
info/windows/tlora.txt Normal file
View File

@@ -0,0 +1,41 @@
Run from Windows 10
PS > Get-PnpDevice -PresentOnly | Format-List > a
PS > Get-PnpDevice -PresentOnly | Format-List > b
PS > Compare-Object (get-content a) (Get-Content b)
InputObject SideIndicator
----------- -------------
Caption : USB-Enhanced-SERIAL CH9102 (COM3) <=
Description : USB-Enhanced-SERIAL CH9102 <=
Name : USB-Enhanced-SERIAL CH9102 (COM3) <=
DeviceID : USB\VID_1A86&PID_55D4\5&27435A1F&0&1 <=
PNPDeviceID : USB\VID_1A86&PID_55D4\5&27435A1F&0&1 <=
ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318} <=
CompatibleID : {USB\Class_02&SubClass_02&Prot_01, USB\Class_02&SubClass_02, USB\Class_02} <=
HardwareID : {USB\VID_1A86&PID_55D4&REV_0443, USB\VID_1A86&PID_55D4} <=
Manufacturer : wch.cn <=
PNPClass : Ports <=
Service : CH343SER_A64 <=
Class : Ports <=
FriendlyName : USB-Enhanced-SERIAL CH9102 (COM3) <=
InstanceId : USB\VID_1A86&PID_55D4\5&27435A1F&0&1 <=
InstallDate : <=
Status : OK <=
Availability : <=
ConfigManagerErrorCode : CM_PROB_NONE <=
ConfigManagerUserConfig : False <=
CreationClassName : Win32_PnPEntity <=
ErrorCleared : <=
ErrorDescription : <=
LastErrorCode : <=
PowerManagementCapabilities : <=
PowerManagementSupported : <=
StatusInfo : <=
SystemCreationClassName : Win32_ComputerSystem <=
SystemName : DESKTOP-FRFQN8H <=
Present : True <=
PSComputerName : <=
Problem : CM_PROB_NONE <=
ProblemDescription : <=
<=

71
info/windows/tlora_v1.txt Normal file
View File

@@ -0,0 +1,71 @@
InputObject SideIn
dicato
r
----------- ------
Caption : Silicon Labs CP210x USB to UART Bridge (COM5) =>
Description : Silicon Labs CP210x USB to UART Bridge =>
Name : Silicon Labs CP210x USB to UART Bridge (COM5) =>
DeviceID : USB\VID_10C4&PID_EA60\0001 =>
PNPDeviceID : USB\VID_10C4&PID_EA60\0001 =>
HardwareID : {USB\VID_10C4&PID_EA60&REV_0100, USB\VID_10C4&PID_EA60} =>
Manufacturer : Silicon Laboratories =>
Service : silabser =>
FriendlyName : Silicon Labs CP210x USB to UART Bridge (COM5) =>
InstanceId : USB\VID_10C4&PID_EA60\0001 =>
CompatibleID : {USB\Class_ff&SubClass_00&Prot_00, USB\Class_ff&SubClass_00, USB\Class_ff} =>
ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318} =>
PNPClass : Ports =>
Class : Ports =>
InstallDate : =>
Status : OK =>
Availability : =>
ConfigManagerErrorCode : CM_PROB_NONE =>
ConfigManagerUserConfig : False =>
CreationClassName : Win32_PnPEntity =>
ErrorCleared : =>
ErrorDescription : =>
LastErrorCode : =>
PowerManagementCapabilities : =>
PowerManagementSupported : =>
StatusInfo : =>
SystemCreationClassName : Win32_ComputerSystem =>
SystemName : MTI-ATPLT1 =>
Present : True =>
PSComputerName : =>
Problem : CM_PROB_NONE =>
ProblemDescription : =>
Caption : Microsoft Serial Mouse =>
Description : Microsoft Serial Mouse =>
InstallDate : =>
Name : Microsoft Serial Mouse =>
Status : Error =>
Availability : =>
ConfigManagerErrorCode : CM_PROB_FAILED_START =>
ConfigManagerUserConfig : False =>
CreationClassName : Win32_PnPEntity =>
DeviceID : SILABENM\MOUSE\C&1EBF522&0&0000 =>
ErrorCleared : =>
ErrorDescription : =>
LastErrorCode : =>
PNPDeviceID : SILABENM\MOUSE\C&1EBF522&0&0000 =>
PowerManagementCapabilities : =>
PowerManagementSupported : =>
StatusInfo : =>
SystemCreationClassName : Win32_ComputerSystem =>
SystemName : MTI-ATPLT1 =>
ClassGuid : {4d36e96f-e325-11ce-bfc1-08002be10318} =>
CompatibleID : {SERIAL_MOUSE} =>
HardwareID : {*PNP0F01} =>
Manufacturer : Microsoft =>
PNPClass : Mouse =>
Present : True =>
Service : sermouse =>
PSComputerName : =>
Class : Mouse =>
FriendlyName : Microsoft Serial Mouse =>
InstanceId : SILABENM\MOUSE\C&1EBF522&0&0000 =>
Problem : CM_PROB_FAILED_START =>
ProblemDescription : =>
=>
=>

View File

@@ -79,7 +79,7 @@ from google.protobuf.json_format import MessageToJson
from meshtastic.util import fixme, catchAndIgnore, stripnl, DeferredExecution, Timeout
from meshtastic.node import Node
from meshtastic import (mesh_pb2, portnums_pb2, apponly_pb2, admin_pb2,
environmental_measurement_pb2, remote_hardware_pb2,
telemetry_pb2, remote_hardware_pb2,
channel_pb2, radioconfig_pb2, util)
@@ -181,7 +181,6 @@ protocols = {
portnums_pb2.PortNum.NODEINFO_APP: KnownProtocol("user", mesh_pb2.User, _onNodeInfoReceive),
portnums_pb2.PortNum.ADMIN_APP: KnownProtocol("admin", admin_pb2.AdminMessage),
portnums_pb2.PortNum.ROUTING_APP: KnownProtocol("routing", mesh_pb2.Routing),
portnums_pb2.PortNum.ENVIRONMENTAL_MEASUREMENT_APP: KnownProtocol("environmental", environmental_measurement_pb2.EnvironmentalMeasurement),
portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol(
"remotehw", remote_hardware_pb2.HardwareMessage)
portnums_pb2.PortNum.TELEMETRY_APP: KnownProtocol("telemetry", telemetry_pb2.Telemetry),
portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol("remotehw", remote_hardware_pb2.HardwareMessage)
}

View File

@@ -134,18 +134,27 @@ def setPref(attributes, name, valStr):
print(f"Choices in sorted order are:")
names = []
for f in enumType.values:
tmp_name = f'{f.name}'
if Globals.getInstance().get_camel_case():
tmp_name = meshtastic.util.snake_to_camel(tmp_name)
names.append(name)
# Note: We must use the value of the enum (regardless if camel or snake case)
names.append(f'{f.name}')
for temp_name in sorted(names):
print(f" {temp_name}")
return
try:
setattr(attributes, snake_name, val)
except TypeError:
# The setter didn't like our arg type guess try again as a string
setattr(attributes, snake_name, valStr)
# note: 'ignore_incoming' is a repeating field
if snake_name != 'ignore_incoming':
try:
setattr(attributes, snake_name, val)
except TypeError:
# The setter didn't like our arg type guess try again as a string
setattr(attributes, snake_name, valStr)
else:
if val == 0:
# clear values
print("Clearing ignore_incoming list")
del attributes.ignore_incoming[:]
else:
print(f"Adding '{val}' to the ignore_incoming list")
attributes.ignore_incoming.extend([val])
if Globals.getInstance().get_camel_case():
print(f"Set {camel_name} to {valStr}")
@@ -197,6 +206,17 @@ def onConnected(interface):
print(f"Setting device owner to {args.set_owner}")
interface.getNode(args.dest).setOwner(args.set_owner)
if args.set_owner_short:
closeNow = True
print(f"Setting device owner short to {args.set_owner_short}")
interface.getNode(args.dest).setOwner(long_name=None, short_name=args.set_owner_short)
# TODO: add to export-config and configure
if args.set_canned_message:
closeNow = True
print(f"Setting canned plugin message to {args.set_canned_message}")
interface.getNode(args.dest).set_canned_message(args.set_canned_message)
if args.pos_fields:
# If --pos-fields invoked with args, set position fields
closeNow = True
@@ -254,6 +274,10 @@ def onConnected(interface):
closeNow = True
interface.getNode(args.dest).reboot()
if args.shutdown:
closeNow = True
interface.getNode(args.dest).shutdown()
if args.sendtext:
closeNow = True
channelIndex = 0
@@ -294,12 +318,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:
@@ -330,6 +353,14 @@ def onConnected(interface):
print(f"Setting device owner to {configuration['owner']}")
interface.getNode(args.dest).setOwner(configuration['owner'])
if 'owner_short' in configuration:
print(f"Setting device owner short to {configuration['owner_short']}")
interface.getNode(args.dest).setOwner(long_name=None, short_name=configuration['owner_short'])
if 'ownerShort' in configuration:
print(f"Setting device owner short to {configuration['ownerShort']}")
interface.getNode(args.dest).setOwner(long_name=None, short_name=configuration['ownerShort'])
if 'channel_url' in configuration:
print("Setting channel url to", configuration['channel_url'])
interface.getNode(args.dest).setURL(configuration['channel_url'])
@@ -419,8 +450,8 @@ def onConnected(interface):
print(f"Deleting channel {channelIndex}")
ch = interface.getNode(args.dest).deleteChannel(channelIndex)
ch_changes = [args.ch_longslow, args.ch_longfast,
args.ch_mediumslow, args.ch_mediumfast,
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:
@@ -461,23 +492,26 @@ def onConnected(interface):
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.Bw125Cr48Sf4096)
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.LongSlow)
if args.ch_longfast:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.Bw31_25Cr48Sf512)
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.LongFast)
if args.ch_mediumslow:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.Bw250Cr46Sf2048)
if args.ch_midslow:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.MidSlow)
if args.ch_mediumfast:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.Bw250Cr47Sf1024)
if args.ch_midfast:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.MidFast)
if args.ch_shortslow:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.Bw125Cr45Sf128)
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.ShortSlow)
if args.ch_shortfast:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.Bw500Cr45Sf128)
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.ShortFast)
# Handle the channel settings
for pref in (args.ch_set or []):
@@ -496,6 +530,11 @@ def onConnected(interface):
print(f"Writing modified channels to device")
interface.getNode(args.dest).writeChannel(channelIndex)
if args.get_canned_message:
closeNow = True
print("")
interface.getNode(args.dest).get_canned_message()
if args.info:
print("")
# If we aren't trying to talk to our local node, don't show it
@@ -567,6 +606,7 @@ def subscribe():
def export_config(interface):
"""used in--export-config"""
owner = interface.getLongName()
owner_short = interface.getShortName()
channel_url = interface.localNode.getURL()
myinfo = interface.getMyNodeInfo()
pos = myinfo.get('position')
@@ -581,6 +621,8 @@ def export_config(interface):
config = "# start of Meshtastic configure yaml\n"
if owner:
config += f"owner: {owner}\n\n"
if owner_short:
config += f"owner_short: {owner_short}\n\n"
if channel_url:
if Globals.getInstance().get_camel_case():
config += f"channelUrl: {channel_url}\n\n"
@@ -729,6 +771,9 @@ def initParser():
parser.add_argument("--info", help="Read and display the radio config information",
action="store_true")
parser.add_argument("--get-canned-message", help="Show the canned message plugin message",
action="store_true")
parser.add_argument("--nodes", help="Print Node List in a pretty formatted table",
action="store_true")
@@ -763,7 +808,15 @@ 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-vlongslow", help="Change to the very long-range and slow channel", action='store_true')
parser.add_argument(
"--ch-longslow", help="Change to the long-range and slow channel", action='store_true')
@@ -772,10 +825,10 @@ def initParser():
"--ch-longfast", help="Change to the long-range and fast channel", action='store_true')
parser.add_argument(
"--ch-mediumslow", help="Change to the medium-range and slow channel", action='store_true')
"--ch-midslow", help="Change to the mid-range and slow channel", action='store_true')
parser.add_argument(
"--ch-mediumfast", help="Change to the medium-range and fast channel", action='store_true')
"--ch-midfast", help="Change to the mid-range and fast channel", action='store_true')
parser.add_argument(
"--ch-shortslow", help="Change to the short-range and slow channel", action='store_true')
@@ -783,10 +836,15 @@ def initParser():
parser.add_argument(
"--ch-shortfast", help="Change to the short-range and fast channel", action='store_true')
parser.add_argument(
"--set-owner", help="Set device owner name", action="store")
parser.add_argument(
"--set-canned-message", help="Set the canned messages plugin message (up to 1000 characters).", action="store")
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")
@@ -805,6 +863,9 @@ def initParser():
parser.add_argument(
"--reboot", help="Tell the destination node to reboot", action="store_true")
parser.add_argument(
"--shutdown", help="Tell the destination node to shutdown", action="store_true")
parser.add_argument(
"--reply", help="Reply to received messages",
action="store_true")

View File

@@ -12,8 +12,8 @@ _sym_db = _symbol_database.Default()
from . import channel_pb2 as channel__pb2
from . import radioconfig_pb2 as radioconfig__pb2
from . import mesh_pb2 as mesh__pb2
from . import radioconfig_pb2 as radioconfig__pb2
DESCRIPTOR = _descriptor.FileDescriptor(
@@ -21,9 +21,9 @@ DESCRIPTOR = _descriptor.FileDescriptor(
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\013AdminProtosH\003Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\x0b\x61\x64min.proto\x1a\rchannel.proto\x1a\x11radioconfig.proto\x1a\nmesh.proto\"\xbd\x03\n\x0c\x41\x64minMessage\x12!\n\tset_radio\x18\x01 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1a\n\tset_owner\x18\x02 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18\x03 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_radio_request\x18\x04 \x01(\x08H\x00\x12*\n\x12get_radio_response\x18\x05 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1d\n\x13get_channel_request\x18\x06 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x07 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_owner_request\x18\x08 \x01(\x08H\x00\x12#\n\x12get_owner_response\x18\t \x01(\x0b\x32\x05.UserH\x00\x12\x1d\n\x13\x63onfirm_set_channel\x18 \x01(\x08H\x00\x12\x1b\n\x11\x63onfirm_set_radio\x18! \x01(\x08H\x00\x12\x18\n\x0e\x65xit_simulator\x18\" \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18# \x01(\x05H\x00\x42\t\n\x07variantBG\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
serialized_pb=b'\n\x0b\x61\x64min.proto\x1a\rchannel.proto\x1a\nmesh.proto\x1a\x11radioconfig.proto\"\xa1\x08\n\x0c\x41\x64minMessage\x12!\n\tset_radio\x18\x01 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1a\n\tset_owner\x18\x02 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18\x03 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_radio_request\x18\x04 \x01(\x08H\x00\x12*\n\x12get_radio_response\x18\x05 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1d\n\x13get_channel_request\x18\x06 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x07 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_owner_request\x18\x08 \x01(\x08H\x00\x12#\n\x12get_owner_response\x18\t \x01(\x0b\x32\x05.UserH\x00\x12\x1d\n\x13\x63onfirm_set_channel\x18 \x01(\x08H\x00\x12\x1b\n\x11\x63onfirm_set_radio\x18! \x01(\x08H\x00\x12\x18\n\x0e\x65xit_simulator\x18\" \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18# \x01(\x05H\x00\x12\x31\n\'get_canned_message_module_part1_request\x18$ \x01(\x08H\x00\x12\x32\n(get_canned_message_module_part1_response\x18% \x01(\tH\x00\x12\x31\n\'get_canned_message_module_part2_request\x18& \x01(\x08H\x00\x12\x32\n(get_canned_message_module_part2_response\x18\' \x01(\tH\x00\x12\x31\n\'get_canned_message_module_part3_request\x18( \x01(\x08H\x00\x12\x32\n(get_canned_message_module_part3_response\x18) \x01(\tH\x00\x12\x31\n\'get_canned_message_module_part4_request\x18* \x01(\x08H\x00\x12\x32\n(get_canned_message_module_part4_response\x18+ \x01(\tH\x00\x12)\n\x1fset_canned_message_module_part1\x18, \x01(\tH\x00\x12)\n\x1fset_canned_message_module_part2\x18- \x01(\tH\x00\x12)\n\x1fset_canned_message_module_part3\x18. \x01(\tH\x00\x12)\n\x1fset_canned_message_module_part4\x18/ \x01(\tH\x00\x12\x1a\n\x10shutdown_seconds\x18\x33 \x01(\x05H\x00\x42\t\n\x07variantBG\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
,
dependencies=[channel__pb2.DESCRIPTOR,radioconfig__pb2.DESCRIPTOR,mesh__pb2.DESCRIPTOR,])
dependencies=[channel__pb2.DESCRIPTOR,mesh__pb2.DESCRIPTOR,radioconfig__pb2.DESCRIPTOR,])
@@ -126,6 +126,97 @@ _ADMINMESSAGE = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='get_canned_message_module_part1_request', full_name='AdminMessage.get_canned_message_module_part1_request', index=13,
number=36, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='get_canned_message_module_part1_response', full_name='AdminMessage.get_canned_message_module_part1_response', index=14,
number=37, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='get_canned_message_module_part2_request', full_name='AdminMessage.get_canned_message_module_part2_request', index=15,
number=38, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='get_canned_message_module_part2_response', full_name='AdminMessage.get_canned_message_module_part2_response', index=16,
number=39, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='get_canned_message_module_part3_request', full_name='AdminMessage.get_canned_message_module_part3_request', index=17,
number=40, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='get_canned_message_module_part3_response', full_name='AdminMessage.get_canned_message_module_part3_response', index=18,
number=41, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='get_canned_message_module_part4_request', full_name='AdminMessage.get_canned_message_module_part4_request', index=19,
number=42, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='get_canned_message_module_part4_response', full_name='AdminMessage.get_canned_message_module_part4_response', index=20,
number=43, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='set_canned_message_module_part1', full_name='AdminMessage.set_canned_message_module_part1', index=21,
number=44, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='set_canned_message_module_part2', full_name='AdminMessage.set_canned_message_module_part2', index=22,
number=45, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='set_canned_message_module_part3', full_name='AdminMessage.set_canned_message_module_part3', index=23,
number=46, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='set_canned_message_module_part4', full_name='AdminMessage.set_canned_message_module_part4', index=24,
number=47, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='shutdown_seconds', full_name='AdminMessage.shutdown_seconds', index=25,
number=51, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
@@ -142,7 +233,7 @@ _ADMINMESSAGE = _descriptor.Descriptor(
index=0, containing_type=None, fields=[]),
],
serialized_start=62,
serialized_end=507,
serialized_end=1119,
)
_ADMINMESSAGE.fields_by_name['set_radio'].message_type = radioconfig__pb2._RADIOCONFIG
@@ -190,6 +281,45 @@ _ADMINMESSAGE.fields_by_name['exit_simulator'].containing_oneof = _ADMINMESSAGE.
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['reboot_seconds'])
_ADMINMESSAGE.fields_by_name['reboot_seconds'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part1_request'])
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part1_request'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part1_response'])
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part1_response'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part2_request'])
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part2_request'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part2_response'])
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part2_response'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part3_request'])
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part3_request'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part3_response'])
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part3_response'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part4_request'])
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part4_request'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part4_response'])
_ADMINMESSAGE.fields_by_name['get_canned_message_module_part4_response'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['set_canned_message_module_part1'])
_ADMINMESSAGE.fields_by_name['set_canned_message_module_part1'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['set_canned_message_module_part2'])
_ADMINMESSAGE.fields_by_name['set_canned_message_module_part2'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['set_canned_message_module_part3'])
_ADMINMESSAGE.fields_by_name['set_canned_message_module_part3'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['set_canned_message_module_part4'])
_ADMINMESSAGE.fields_by_name['set_canned_message_module_part4'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['shutdown_seconds'])
_ADMINMESSAGE.fields_by_name['shutdown_seconds'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
DESCRIPTOR.message_types_by_name['AdminMessage'] = _ADMINMESSAGE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)

View File

@@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: cannedmessages.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='cannedmessages.proto',
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\031CannedMessageConfigProtosH\003Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\x14\x63\x61nnedmessages.proto\"w\n\x19\x43\x61nnedMessageModuleConfig\x12\x15\n\rmessagesPart1\x18\x0b \x01(\t\x12\x15\n\rmessagesPart2\x18\x0c \x01(\t\x12\x15\n\rmessagesPart3\x18\r \x01(\t\x12\x15\n\rmessagesPart4\x18\x0e \x01(\tBU\n\x13\x63om.geeksville.meshB\x19\x43\x61nnedMessageConfigProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
)
_CANNEDMESSAGEMODULECONFIG = _descriptor.Descriptor(
name='CannedMessageModuleConfig',
full_name='CannedMessageModuleConfig',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='messagesPart1', full_name='CannedMessageModuleConfig.messagesPart1', index=0,
number=11, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='messagesPart2', full_name='CannedMessageModuleConfig.messagesPart2', index=1,
number=12, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='messagesPart3', full_name='CannedMessageModuleConfig.messagesPart3', index=2,
number=13, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='messagesPart4', full_name='CannedMessageModuleConfig.messagesPart4', index=3,
number=14, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=24,
serialized_end=143,
)
DESCRIPTOR.message_types_by_name['CannedMessageModuleConfig'] = _CANNEDMESSAGEMODULECONFIG
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
CannedMessageModuleConfig = _reflection.GeneratedProtocolMessageType('CannedMessageModuleConfig', (_message.Message,), {
'DESCRIPTOR' : _CANNEDMESSAGEMODULECONFIG,
'__module__' : 'cannedmessages_pb2'
# @@protoc_insertion_point(class_scope:CannedMessageModuleConfig)
})
_sym_db.RegisterMessage(CannedMessageModuleConfig)
DESCRIPTOR._options = None
# @@protoc_insertion_point(module_scope)

View File

@@ -18,7 +18,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\rChannelProtosH\003Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\rchannel.proto\"\x91\x03\n\x0f\x43hannelSettings\x12\x10\n\x08tx_power\x18\x01 \x01(\x05\x12\x32\n\x0cmodem_config\x18\x03 \x01(\x0e\x32\x1c.ChannelSettings.ModemConfig\x12\x11\n\tbandwidth\x18\x06 \x01(\r\x12\x15\n\rspread_factor\x18\x07 \x01(\r\x12\x13\n\x0b\x63oding_rate\x18\x08 \x01(\r\x12\x13\n\x0b\x63hannel_num\x18\t \x01(\r\x12\x0b\n\x03psk\x18\x04 \x01(\x0c\x12\x0c\n\x04name\x18\x05 \x01(\t\x12\n\n\x02id\x18\n \x01(\x07\x12\x16\n\x0euplink_enabled\x18\x10 \x01(\x08\x12\x18\n\x10\x64ownlink_enabled\x18\x11 \x01(\x08\"\x8a\x01\n\x0bModemConfig\x12\x12\n\x0e\x42w125Cr45Sf128\x10\x00\x12\x12\n\x0e\x42w500Cr45Sf128\x10\x01\x12\x14\n\x10\x42w31_25Cr48Sf512\x10\x02\x12\x13\n\x0f\x42w125Cr48Sf4096\x10\x03\x12\x13\n\x0f\x42w250Cr46Sf2048\x10\x04\x12\x13\n\x0f\x42w250Cr47Sf1024\x10\x05\"\x8b\x01\n\x07\x43hannel\x12\r\n\x05index\x18\x01 \x01(\x05\x12\"\n\x08settings\x18\x02 \x01(\x0b\x32\x10.ChannelSettings\x12\x1b\n\x04role\x18\x03 \x01(\x0e\x32\r.Channel.Role\"0\n\x04Role\x12\x0c\n\x08\x44ISABLED\x10\x00\x12\x0b\n\x07PRIMARY\x10\x01\x12\r\n\tSECONDARY\x10\x02\x42I\n\x13\x63om.geeksville.meshB\rChannelProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
serialized_pb=b'\n\rchannel.proto\"\xf6\x02\n\x0f\x43hannelSettings\x12\x10\n\x08tx_power\x18\x01 \x01(\x05\x12\x32\n\x0cmodem_config\x18\x03 \x01(\x0e\x32\x1c.ChannelSettings.ModemConfig\x12\x11\n\tbandwidth\x18\x06 \x01(\r\x12\x15\n\rspread_factor\x18\x07 \x01(\r\x12\x13\n\x0b\x63oding_rate\x18\x08 \x01(\r\x12\x13\n\x0b\x63hannel_num\x18\t \x01(\r\x12\x0b\n\x03psk\x18\x04 \x01(\x0c\x12\x0c\n\x04name\x18\x05 \x01(\t\x12\n\n\x02id\x18\n \x01(\x07\x12\x16\n\x0euplink_enabled\x18\x10 \x01(\x08\x12\x18\n\x10\x64ownlink_enabled\x18\x11 \x01(\x08\"p\n\x0bModemConfig\x12\r\n\tVLongSlow\x10\x00\x12\x0c\n\x08LongSlow\x10\x01\x12\x0c\n\x08LongFast\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\"\x8b\x01\n\x07\x43hannel\x12\r\n\x05index\x18\x01 \x01(\x05\x12\"\n\x08settings\x18\x02 \x01(\x0b\x32\x10.ChannelSettings\x12\x1b\n\x04role\x18\x03 \x01(\x0e\x32\r.Channel.Role\"0\n\x04Role\x12\x0c\n\x08\x44ISABLED\x10\x00\x12\x0b\n\x07PRIMARY\x10\x01\x12\r\n\tSECONDARY\x10\x02\x42I\n\x13\x63om.geeksville.meshB\rChannelProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
)
@@ -30,34 +30,38 @@ _CHANNELSETTINGS_MODEMCONFIG = _descriptor.EnumDescriptor(
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='Bw125Cr45Sf128', index=0, number=0,
name='VLongSlow', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='Bw500Cr45Sf128', index=1, number=1,
name='LongSlow', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='Bw31_25Cr48Sf512', index=2, number=2,
name='LongFast', index=2, number=2,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='Bw125Cr48Sf4096', index=3, number=3,
name='MidSlow', index=3, number=3,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='Bw250Cr46Sf2048', index=4, number=4,
name='MidFast', index=4, number=4,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='Bw250Cr47Sf1024', index=5, number=5,
name='ShortSlow', index=5, number=5,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ShortFast', index=6, number=6,
serialized_options=None,
type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=281,
serialized_end=419,
serialized_start=280,
serialized_end=392,
)
_sym_db.RegisterEnumDescriptor(_CHANNELSETTINGS_MODEMCONFIG)
@@ -82,8 +86,8 @@ _CHANNEL_ROLE = _descriptor.EnumDescriptor(
],
containing_type=None,
serialized_options=None,
serialized_start=513,
serialized_end=561,
serialized_start=486,
serialized_end=534,
)
_sym_db.RegisterEnumDescriptor(_CHANNEL_ROLE)
@@ -186,7 +190,7 @@ _CHANNELSETTINGS = _descriptor.Descriptor(
oneofs=[
],
serialized_start=18,
serialized_end=419,
serialized_end=392,
)
@@ -231,8 +235,8 @@ _CHANNEL = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=422,
serialized_end=561,
serialized_start=395,
serialized_end=534,
)
_CHANNELSETTINGS.fields_by_name['modem_config'].enum_type = _CHANNELSETTINGS_MODEMCONFIG

View File

@@ -13,7 +13,6 @@ _sym_db = _symbol_database.Default()
from . import channel_pb2 as channel__pb2
from . import mesh_pb2 as mesh__pb2
from . import radioconfig_pb2 as radioconfig__pb2
DESCRIPTOR = _descriptor.FileDescriptor(
@@ -21,74 +20,13 @@ DESCRIPTOR = _descriptor.FileDescriptor(
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\nDeviceOnlyH\003Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\x10\x64\x65viceonly.proto\x1a\rchannel.proto\x1a\nmesh.proto\x1a\x11radioconfig.proto\"\x80\x01\n\x11LegacyRadioConfig\x12\x39\n\x0bpreferences\x18\x01 \x01(\x0b\x32$.LegacyRadioConfig.LegacyPreferences\x1a\x30\n\x11LegacyPreferences\x12\x1b\n\x06region\x18\x0f \x01(\x0e\x32\x0b.RegionCode\"\x8f\x02\n\x0b\x44\x65viceState\x12\'\n\x0blegacyRadio\x18\x01 \x01(\x0b\x32\x12.LegacyRadioConfig\x12\x1c\n\x07my_node\x18\x02 \x01(\x0b\x32\x0b.MyNodeInfo\x12\x14\n\x05owner\x18\x03 \x01(\x0b\x32\x05.User\x12\x1a\n\x07node_db\x18\x04 \x03(\x0b\x32\t.NodeInfo\x12\"\n\rreceive_queue\x18\x05 \x03(\x0b\x32\x0b.MeshPacket\x12\x0f\n\x07version\x18\x08 \x01(\r\x12$\n\x0frx_text_message\x18\x07 \x01(\x0b\x32\x0b.MeshPacket\x12\x0f\n\x07no_save\x18\t \x01(\x08\x12\x15\n\rdid_gps_reset\x18\x0b \x01(\x08J\x04\x08\x0c\x10\r\")\n\x0b\x43hannelFile\x12\x1a\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x08.ChannelBF\n\x13\x63om.geeksville.meshB\nDeviceOnlyH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
serialized_pb=b'\n\x10\x64\x65viceonly.proto\x1a\rchannel.proto\x1a\nmesh.proto\"\xe6\x01\n\x0b\x44\x65viceState\x12\x1c\n\x07my_node\x18\x02 \x01(\x0b\x32\x0b.MyNodeInfo\x12\x14\n\x05owner\x18\x03 \x01(\x0b\x32\x05.User\x12\x1a\n\x07node_db\x18\x04 \x03(\x0b\x32\t.NodeInfo\x12\"\n\rreceive_queue\x18\x05 \x03(\x0b\x32\x0b.MeshPacket\x12\x0f\n\x07version\x18\x08 \x01(\r\x12$\n\x0frx_text_message\x18\x07 \x01(\x0b\x32\x0b.MeshPacket\x12\x0f\n\x07no_save\x18\t \x01(\x08\x12\x15\n\rdid_gps_reset\x18\x0b \x01(\x08J\x04\x08\x0c\x10\r\")\n\x0b\x43hannelFile\x12\x1a\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x08.ChannelBF\n\x13\x63om.geeksville.meshB\nDeviceOnlyH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
,
dependencies=[channel__pb2.DESCRIPTOR,mesh__pb2.DESCRIPTOR,radioconfig__pb2.DESCRIPTOR,])
dependencies=[channel__pb2.DESCRIPTOR,mesh__pb2.DESCRIPTOR,])
_LEGACYRADIOCONFIG_LEGACYPREFERENCES = _descriptor.Descriptor(
name='LegacyPreferences',
full_name='LegacyRadioConfig.LegacyPreferences',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='region', full_name='LegacyRadioConfig.LegacyPreferences.region', index=0,
number=15, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=147,
serialized_end=195,
)
_LEGACYRADIOCONFIG = _descriptor.Descriptor(
name='LegacyRadioConfig',
full_name='LegacyRadioConfig',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='preferences', full_name='LegacyRadioConfig.preferences', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[_LEGACYRADIOCONFIG_LEGACYPREFERENCES, ],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=67,
serialized_end=195,
)
_DEVICESTATE = _descriptor.Descriptor(
name='DeviceState',
full_name='DeviceState',
@@ -97,63 +35,56 @@ _DEVICESTATE = _descriptor.Descriptor(
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='legacyRadio', full_name='DeviceState.legacyRadio', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='my_node', full_name='DeviceState.my_node', index=1,
name='my_node', full_name='DeviceState.my_node', index=0,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='owner', full_name='DeviceState.owner', index=2,
name='owner', full_name='DeviceState.owner', index=1,
number=3, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='node_db', full_name='DeviceState.node_db', index=3,
name='node_db', full_name='DeviceState.node_db', index=2,
number=4, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='receive_queue', full_name='DeviceState.receive_queue', index=4,
name='receive_queue', full_name='DeviceState.receive_queue', index=3,
number=5, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='version', full_name='DeviceState.version', index=5,
name='version', full_name='DeviceState.version', index=4,
number=8, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='rx_text_message', full_name='DeviceState.rx_text_message', index=6,
name='rx_text_message', full_name='DeviceState.rx_text_message', index=5,
number=7, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='no_save', full_name='DeviceState.no_save', index=7,
name='no_save', full_name='DeviceState.no_save', index=6,
number=9, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='did_gps_reset', full_name='DeviceState.did_gps_reset', index=8,
name='did_gps_reset', full_name='DeviceState.did_gps_reset', index=7,
number=11, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
@@ -171,8 +102,8 @@ _DEVICESTATE = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=198,
serialized_end=469,
serialized_start=48,
serialized_end=278,
)
@@ -202,40 +133,20 @@ _CHANNELFILE = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=471,
serialized_end=512,
serialized_start=280,
serialized_end=321,
)
_LEGACYRADIOCONFIG_LEGACYPREFERENCES.fields_by_name['region'].enum_type = radioconfig__pb2._REGIONCODE
_LEGACYRADIOCONFIG_LEGACYPREFERENCES.containing_type = _LEGACYRADIOCONFIG
_LEGACYRADIOCONFIG.fields_by_name['preferences'].message_type = _LEGACYRADIOCONFIG_LEGACYPREFERENCES
_DEVICESTATE.fields_by_name['legacyRadio'].message_type = _LEGACYRADIOCONFIG
_DEVICESTATE.fields_by_name['my_node'].message_type = mesh__pb2._MYNODEINFO
_DEVICESTATE.fields_by_name['owner'].message_type = mesh__pb2._USER
_DEVICESTATE.fields_by_name['node_db'].message_type = mesh__pb2._NODEINFO
_DEVICESTATE.fields_by_name['receive_queue'].message_type = mesh__pb2._MESHPACKET
_DEVICESTATE.fields_by_name['rx_text_message'].message_type = mesh__pb2._MESHPACKET
_CHANNELFILE.fields_by_name['channels'].message_type = channel__pb2._CHANNEL
DESCRIPTOR.message_types_by_name['LegacyRadioConfig'] = _LEGACYRADIOCONFIG
DESCRIPTOR.message_types_by_name['DeviceState'] = _DEVICESTATE
DESCRIPTOR.message_types_by_name['ChannelFile'] = _CHANNELFILE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
LegacyRadioConfig = _reflection.GeneratedProtocolMessageType('LegacyRadioConfig', (_message.Message,), {
'LegacyPreferences' : _reflection.GeneratedProtocolMessageType('LegacyPreferences', (_message.Message,), {
'DESCRIPTOR' : _LEGACYRADIOCONFIG_LEGACYPREFERENCES,
'__module__' : 'deviceonly_pb2'
# @@protoc_insertion_point(class_scope:LegacyRadioConfig.LegacyPreferences)
})
,
'DESCRIPTOR' : _LEGACYRADIOCONFIG,
'__module__' : 'deviceonly_pb2'
# @@protoc_insertion_point(class_scope:LegacyRadioConfig)
})
_sym_db.RegisterMessage(LegacyRadioConfig)
_sym_db.RegisterMessage(LegacyRadioConfig.LegacyPreferences)
DeviceState = _reflection.GeneratedProtocolMessageType('DeviceState', (_message.Message,), {
'DESCRIPTOR' : _DEVICESTATE,
'__module__' : 'deviceonly_pb2'

View File

@@ -1,83 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: environmental_measurement.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='environmental_measurement.proto',
package='',
syntax='proto3',
serialized_options=b'Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\x1f\x65nvironmental_measurement.proto\"g\n\x18\x45nvironmentalMeasurement\x12\x13\n\x0btemperature\x18\x01 \x01(\x02\x12\x19\n\x11relative_humidity\x18\x02 \x01(\x02\x12\x1b\n\x13\x62\x61rometric_pressure\x18\x03 \x01(\x02\x42#Z!github.com/meshtastic/gomeshprotob\x06proto3'
)
_ENVIRONMENTALMEASUREMENT = _descriptor.Descriptor(
name='EnvironmentalMeasurement',
full_name='EnvironmentalMeasurement',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='temperature', full_name='EnvironmentalMeasurement.temperature', index=0,
number=1, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='relative_humidity', full_name='EnvironmentalMeasurement.relative_humidity', index=1,
number=2, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='barometric_pressure', full_name='EnvironmentalMeasurement.barometric_pressure', index=2,
number=3, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=35,
serialized_end=138,
)
DESCRIPTOR.message_types_by_name['EnvironmentalMeasurement'] = _ENVIRONMENTALMEASUREMENT
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
EnvironmentalMeasurement = _reflection.GeneratedProtocolMessageType('EnvironmentalMeasurement', (_message.Message,), {
'DESCRIPTOR' : _ENVIRONMENTALMEASUREMENT,
'__module__' : 'environmental_measurement_pb2'
# @@protoc_insertion_point(class_scope:EnvironmentalMeasurement)
})
_sym_db.RegisterMessage(EnvironmentalMeasurement)
DESCRIPTOR._options = None
# @@protoc_insertion_point(module_scope)

View File

@@ -254,11 +254,12 @@ class MeshInterface:
meshPacket.decoded.payload = data
meshPacket.decoded.portnum = portNum
meshPacket.decoded.want_response = wantResponse
meshPacket.id = self._generatePacketId()
if onResponse is not None:
self._addResponseHandler(meshPacket.id, onResponse)
p = self._sendPacket(meshPacket, destinationId,
wantAck=wantAck, hopLimit=hopLimit)
if onResponse is not None:
self._addResponseHandler(p.id, onResponse)
return p
def sendPosition(self, latitude=0.0, longitude=0.0, altitude=0, timeSec=0,
@@ -631,11 +632,13 @@ class MeshInterface:
# asObj = DotMap(asDict)
topic = "meshtastic.receive" # Generic unknown packet type
decoded = asDict["decoded"]
# The default MessageToDict converts byte arrays into base64 strings.
# We don't want that - it messes up data payload. So slam in the correct
# byte array.
decoded["payload"] = meshPacket.decoded.payload
decoded = None
if 'decoded' in asDict:
decoded = asDict["decoded"]
# The default MessageToDict converts byte arrays into base64 strings.
# We don't want that - it messes up data payload. So slam in the correct
# byte array.
decoded["payload"] = meshPacket.decoded.payload
# UNKNOWN_APP is the default protobuf portnum value, and therefore if not
# set it will not be populated at all to make API usage easier, set

View File

File diff suppressed because one or more lines are too long

View File

@@ -3,6 +3,7 @@
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.util import pskToString, stripnl, Timeout, our_exit, fromPSK
@@ -24,6 +25,15 @@ class Node:
self.partialChannels = None
self.noProto = noProto
self.cannedPluginMessage = None
self.cannedPluginMessagePart1 = None
self.cannedPluginMessagePart2 = None
self.cannedPluginMessagePart3 = None
self.cannedPluginMessagePart4 = None
self.gotResponse = None
def showChannels(self):
"""Show human readable description of our channels."""
print("Channels:")
@@ -56,6 +66,14 @@ class Node:
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()
def turnOffEncryptionOnPrimaryChannel(self):
@@ -64,9 +82,9 @@ class Node:
print("Writing modified channels to device")
self.writeChannel(0)
def waitForConfig(self):
def waitForConfig(self, attribute='channels'):
"""Block until radio config is received. Returns True if config has been received."""
return self._timeout.waitForSet(self, attrs=('radioConfig', 'channels'))
return self._timeout.waitForSet(self, attrs=('radioConfig', attribute))
def writeConfig(self):
"""Write the current (edited) radioConfig to the device"""
@@ -237,7 +255,7 @@ class Node:
"""Handle the response packet for requesting settings _requestSettings()"""
logging.debug(f'onResponseRequestSetting() p:{p}')
errorFound = False
if 'routing' in p["decoded"]:
if "routing" in p["decoded"]:
if p["decoded"]["routing"]["errorReason"] != "NONE":
errorFound = True
print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}')
@@ -268,6 +286,156 @@ class Node:
return self._sendAdmin(p, wantResponse=True, onResponse=self.onResponseRequestSettings)
def onResponseRequestCannedMessagePluginMessagePart1(self, p):
"""Handle the response packet for requesting canned message plugin message part 1"""
logging.debug(f'onResponseRequestCannedMessagePluginMessagePart1() 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"]}')
if errorFound is False:
if "decoded" in p:
if "admin" in p["decoded"]:
if "raw" in p["decoded"]["admin"]:
self.cannedPluginMessagePart1 = p["decoded"]["admin"]["raw"].get_canned_message_plugin_part1_response
logging.debug(f'self.cannedPluginMessagePart1:{self.cannedPluginMessagePart1}')
self.gotResponse = True
def onResponseRequestCannedMessagePluginMessagePart2(self, p):
"""Handle the response packet for requesting canned message plugin message part 2"""
logging.debug(f'onResponseRequestCannedMessagePluginMessagePart2() 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"]}')
if errorFound is False:
if "decoded" in p:
if "admin" in p["decoded"]:
if "raw" in p["decoded"]["admin"]:
self.cannedPluginMessagePart2 = p["decoded"]["admin"]["raw"].get_canned_message_plugin_part2_response
logging.debug(f'self.cannedPluginMessagePart2:{self.cannedPluginMessagePart2}')
self.gotResponse = True
def onResponseRequestCannedMessagePluginMessagePart3(self, p):
"""Handle the response packet for requesting canned message plugin message part 3"""
logging.debug(f'onResponseRequestCannedMessagePluginMessagePart3() 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"]}')
if errorFound is False:
if "decoded" in p:
if "admin" in p["decoded"]:
if "raw" in p["decoded"]["admin"]:
self.cannedPluginMessagePart3 = p["decoded"]["admin"]["raw"].get_canned_message_plugin_part3_response
logging.debug(f'self.cannedPluginMessagePart3:{self.cannedPluginMessagePart3}')
self.gotResponse = True
def onResponseRequestCannedMessagePluginMessagePart4(self, p):
"""Handle the response packet for requesting canned message plugin message part 4"""
logging.debug(f'onResponseRequestCannedMessagePluginMessagePart4() 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"]}')
if errorFound is False:
if "decoded" in p:
if "admin" in p["decoded"]:
if "raw" in p["decoded"]["admin"]:
self.cannedPluginMessagePart4 = p["decoded"]["admin"]["raw"].get_canned_message_plugin_part4_response
logging.debug(f'self.cannedPluginMessagePart4:{self.cannedPluginMessagePart4}')
self.gotResponse = True
def get_canned_message(self):
"""Get the canned message string. Concatenate all pieces together and return a single string."""
logging.debug(f'in get_canned_message()')
if not self.cannedPluginMessage:
p1 = admin_pb2.AdminMessage()
p1.get_canned_message_plugin_part1_request = True
self.gotResponse = False
self._sendAdmin(p1, wantResponse=True, onResponse=self.onResponseRequestCannedMessagePluginMessagePart1)
while self.gotResponse is False:
time.sleep(0.1)
p2 = admin_pb2.AdminMessage()
p2.get_canned_message_plugin_part2_request = True
self.gotResponse = False
self._sendAdmin(p2, wantResponse=True, onResponse=self.onResponseRequestCannedMessagePluginMessagePart2)
while self.gotResponse is False:
time.sleep(0.1)
p3 = admin_pb2.AdminMessage()
p3.get_canned_message_plugin_part3_request = True
self.gotResponse = False
self._sendAdmin(p3, wantResponse=True, onResponse=self.onResponseRequestCannedMessagePluginMessagePart3)
while self.gotResponse is False:
time.sleep(0.1)
p4 = admin_pb2.AdminMessage()
p4.get_canned_message_plugin_part4_request = True
self.gotResponse = False
self._sendAdmin(p4, wantResponse=True, onResponse=self.onResponseRequestCannedMessagePluginMessagePart4)
while self.gotResponse is False:
time.sleep(0.1)
# TODO: This feels wrong to have a sleep here. Is there a way to ensure that
# all requests are complete? Perhaps change to a while loop any parts are None... maybe?
time.sleep(3)
logging.debug(f'self.cannedPluginMessagePart1:{self.cannedPluginMessagePart1}')
logging.debug(f'self.cannedPluginMessagePart2:{self.cannedPluginMessagePart2}')
logging.debug(f'self.cannedPluginMessagePart3:{self.cannedPluginMessagePart3}')
logging.debug(f'self.cannedPluginMessagePart4:{self.cannedPluginMessagePart4}')
self.cannedPluginMessage = ""
if self.cannedPluginMessagePart1:
self.cannedPluginMessage += self.cannedPluginMessagePart1
if self.cannedPluginMessagePart2:
self.cannedPluginMessage += self.cannedPluginMessagePart2
if self.cannedPluginMessagePart3:
self.cannedPluginMessage += self.cannedPluginMessagePart3
if self.cannedPluginMessagePart4:
self.cannedPluginMessage += self.cannedPluginMessagePart4
print(f'canned_plugin_message:{self.cannedPluginMessage}')
logging.debug(f'canned_plugin_message:{self.cannedPluginMessage}')
return self.cannedPluginMessage
def set_canned_message(self, message):
"""Set the canned message. Split into parts of 200 chars each."""
if len(message) > 800:
our_exit("Warning: The canned message must be less than 800 characters.")
# split into chunks
chunks = []
chunks_size = 200
for i in range(0, len(message), chunks_size):
chunks.append(message[i: i + chunks_size])
# for each chunk, send a message to set the values
#for i in range(0, len(chunks)):
for i, chunk in enumerate(chunks):
p = admin_pb2.AdminMessage()
# TODO: should be a way to improve this
if i == 0:
p.set_canned_message_plugin_part1 = chunk
elif i == 1:
p.set_canned_message_plugin_part2 = chunk
elif i == 2:
p.set_canned_message_plugin_part3 = chunk
elif i == 3:
p.set_canned_message_plugin_part4 = chunk
logging.debug(f"Setting canned message '{chunk}' part {i+1}")
self._sendAdmin(p)
def exitSimulator(self):
"""Tell a simulator node to exit (this message
is ignored for other nodes)"""
@@ -285,6 +453,14 @@ class Node:
return self._sendAdmin(p)
def shutdown(self, secs: int = 10):
"""Tell the node to shutdown."""
p = admin_pb2.AdminMessage()
p.shutdown_seconds = secs
logging.info(f"Telling node to shutdown in {secs} seconds")
return self._sendAdmin(p)
def _fixupChannels(self):
"""Fixup indexes and add disabled channels as needed"""

View File

@@ -19,7 +19,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\010PortnumsH\003Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\x0eportnums.proto*\xcb\x02\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12!\n\x1d\x45NVIRONMENTAL_MEASUREMENT_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x10\n\x0bPRIVATE_APP\x10\x80\x02\x12\x13\n\x0e\x41TAK_FORWARDER\x10\x81\x02\x12\x08\n\x03MAX\x10\xff\x03\x42\x44\n\x13\x63om.geeksville.meshB\x08PortnumsH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
serialized_pb=b'\n\x0eportnums.proto*\xbb\x02\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12\x11\n\rTELEMETRY_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x10\n\x0bPRIVATE_APP\x10\x80\x02\x12\x13\n\x0e\x41TAK_FORWARDER\x10\x81\x02\x12\x08\n\x03MAX\x10\xff\x03\x42\x44\n\x13\x63om.geeksville.meshB\x08PortnumsH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
)
_PORTNUM = _descriptor.EnumDescriptor(
@@ -77,7 +77,7 @@ _PORTNUM = _descriptor.EnumDescriptor(
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ENVIRONMENTAL_MEASUREMENT_APP', index=12, number=67,
name='TELEMETRY_APP', index=12, number=67,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
@@ -100,7 +100,7 @@ _PORTNUM = _descriptor.EnumDescriptor(
containing_type=None,
serialized_options=None,
serialized_start=19,
serialized_end=350,
serialized_end=334,
)
_sym_db.RegisterEnumDescriptor(_PORTNUM)
@@ -117,7 +117,7 @@ IP_TUNNEL_APP = 33
SERIAL_APP = 64
STORE_FORWARD_APP = 65
RANGE_TEST_APP = 66
ENVIRONMENTAL_MEASUREMENT_APP = 67
TELEMETRY_APP = 67
ZPS_APP = 68
PRIVATE_APP = 256
ATAK_FORWARDER = 257

View File

File diff suppressed because one or more lines are too long

View File

@@ -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}')

View File

@@ -24,8 +24,10 @@ class SerialInterface(StreamInterface):
"""
self.noProto = noProto
if devPath is None:
ports = meshtastic.util.findPorts()
self.devPath = devPath
if self.devPath is None:
ports = meshtastic.util.findPorts(True)
logging.debug(f"ports:{ports}")
if len(ports) == 0:
meshtastic.util.our_exit("Warning: No Meshtastic devices detected.")
@@ -34,21 +36,21 @@ class SerialInterface(StreamInterface):
message += f" Ports detected:{ports}"
meshtastic.util.our_exit(message)
else:
devPath = ports[0]
self.devPath = ports[0]
logging.debug(f"Connecting to {devPath}")
logging.debug(f"Connecting to {self.devPath}")
# first we need to set the HUPCL so the device will not reboot based on RTS and/or DTR
# see https://github.com/pyserial/pyserial/issues/124
if platform.system() != 'Windows':
with open(devPath, encoding='utf8') as f:
with open(self.devPath, encoding='utf8') as f:
attrs = termios.tcgetattr(f)
attrs[2] = attrs[2] & ~termios.HUPCL
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
f.close()
time.sleep(0.1)
self.stream = serial.Serial(devPath, 921600, exclusive=True, timeout=0.5, write_timeout=0)
self.stream = serial.Serial(self.devPath, 921600, exclusive=True, timeout=0.5, write_timeout=0)
self.stream.flush()
time.sleep(0.1)

View File

@@ -8,7 +8,7 @@ import serial
from meshtastic.mesh_interface import MeshInterface
from meshtastic.util import stripnl
from meshtastic.util import stripnl, is_windows11
START1 = 0x94
@@ -38,6 +38,8 @@ class StreamInterface(MeshInterface):
self._rxBuf = bytes() # empty
self._wantExit = False
self.is_windows11 = is_windows11()
# FIXME, figure out why daemon=True causes reader thread to exit too early
self._rxThread = threading.Thread(target=self.__reader, args=(), daemon=True)
@@ -88,8 +90,12 @@ class StreamInterface(MeshInterface):
if self.stream: # ignore writes when stream is closed
self.stream.write(b)
self.stream.flush()
# we sleep here to give the TBeam a chance to work
time.sleep(0.1)
# win11 might need a bit more time, too
if self.is_windows11:
time.sleep(1.0)
else:
# we sleep here to give the TBeam a chance to work
time.sleep(0.1)
def _readBytes(self, length):
"""Read an array of bytes from our stream"""

89
meshtastic/supported_device.py Executable file
View File

@@ -0,0 +1,89 @@
""" Supported Meshtastic Devices - This is a class and collection of Meshtastic devices.
It is used for auto detection as to which device might be connected.
"""
# Goal is to detect which device and port to use from the supported devices
# without installing any libraries that are not currently in the python meshtastic library
class SupportedDevice():
"""Devices supported on Meshtastic"""
def __init__(self, name, version=None, for_firmware=None, device_class="esp32",
baseport_on_linux=None, baseport_on_mac=None, baseport_on_windows="COM",
usb_vendor_id_in_hex=None, usb_product_id_in_hex=None):
""" constructor """
self.name = name
self.version = version
self.for_firmware = for_firmware
self.device_class = device_class # could be "nrf52"
# when you run "lsusb -d xxxx:" in linux
self.usb_vendor_id_in_hex = usb_vendor_id_in_hex # store in lower case
self.usb_product_id_in_hex = usb_product_id_in_hex # store in lower case
self.baseport_on_linux = baseport_on_linux # ex: ttyUSB or ttyACM
self.baseport_on_mac = baseport_on_mac
self.baseport_on_windows = baseport_on_windows
# supported devices
tbeam_v0_7 = SupportedDevice(name="T-Beam", version="0.7", for_firmware="tbeam0.7",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tbeam_v1_1 = SupportedDevice(name="T-Beam", version="1.1", for_firmware="tbeam",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tbeam_M8N = SupportedDevice(name="T-Beam", version="M8N", for_firmware="tbeam",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tbeam_M8N_SX1262 = SupportedDevice(name="T-Beam", version="M8N_SX1262", for_firmware="tbeam",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tlora_v1_1 = SupportedDevice(name="T-Lora", version="1.1", for_firmware="tlora-v1",
baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial",
usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
tlora_v1_3 = SupportedDevice(name="T-Lora", version="1.3", for_firmware="tlora-v1-3",
baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial",
usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
tlora_v2_0 = SupportedDevice(name="T-Lora", version="2.0", for_firmware="tlora-v2-1",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tlora_v2_1 = SupportedDevice(name="T-Lora", version="2.1", for_firmware="tlora-v2-1",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
tlora_v2_1_1_6 = SupportedDevice(name="T-Lora", version="2.1-1.6", for_firmware="tlora-v2-1-1.6",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
heltec_v1 = SupportedDevice(name="Heltec", version="1", for_firmware="heltec-v1",
baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
heltec_v2_0 = SupportedDevice(name="Heltec", version="2.0", for_firmware="heltec-v2.0",
baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
heltec_v2_1 = SupportedDevice(name="Heltec", version="2.1", for_firmware="heltec-v2.1",
baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
rak11200 = SupportedDevice(name="RAK 11200", version="", for_firmware="rak11200",
baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="7523")
meshtastic_diy_v1 = SupportedDevice(name="Meshtastic DIY", version="1", for_firmware="meshtastic-diy-v1",
baseport_on_linux="ttyUSB", baseport_on_mac="cu.usbserial-",
usb_vendor_id_in_hex="10c4", usb_product_id_in_hex="ea60")
# Note: The T-Echo reports product id in boot mode
techo_1 = SupportedDevice(name="T-Echo", version="1", for_firmware="t-echo-1", device_class="nrf52",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="239a", usb_product_id_in_hex="0029")
rak4631_5005 = SupportedDevice(name="RAK 4631 5005", version="", for_firmware="rak4631_5005",
device_class="nrf52",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="239a", usb_product_id_in_hex="0029")
# Note: The 19003 reports same product id as 5005 in boot mode
rak4631_19003 = SupportedDevice(name="RAK 4631 19003", version="", for_firmware="rak4631_19003",
device_class="nrf52",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="239a", usb_product_id_in_hex="8029")
supported_devices = [tbeam_v0_7, tbeam_v1_1, tbeam_M8N, tbeam_M8N_SX1262,
tlora_v1_1, tlora_v1_3, tlora_v2_0, tlora_v2_1, tlora_v2_1_1_6,
heltec_v1, heltec_v2_0, heltec_v2_1,
meshtastic_diy_v1, techo_1, rak4631_5005, rak4631_19003,
rak11200]

104
meshtastic/telemetry_pb2.py Normal file
View File

@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: telemetry.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='telemetry.proto',
package='',
syntax='proto3',
serialized_options=b'Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\x0ftelemetry.proto\"\x92\x01\n\tTelemetry\x12\x13\n\x0btemperature\x18\x01 \x01(\x02\x12\x19\n\x11relative_humidity\x18\x02 \x01(\x02\x12\x1b\n\x13\x62\x61rometric_pressure\x18\x03 \x01(\x02\x12\x16\n\x0egas_resistance\x18\x04 \x01(\x02\x12\x0f\n\x07voltage\x18\x05 \x01(\x02\x12\x0f\n\x07\x63urrent\x18\x06 \x01(\x02\x42#Z!github.com/meshtastic/gomeshprotob\x06proto3'
)
_TELEMETRY = _descriptor.Descriptor(
name='Telemetry',
full_name='Telemetry',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='temperature', full_name='Telemetry.temperature', index=0,
number=1, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='relative_humidity', full_name='Telemetry.relative_humidity', index=1,
number=2, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='barometric_pressure', full_name='Telemetry.barometric_pressure', index=2,
number=3, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='gas_resistance', full_name='Telemetry.gas_resistance', index=3,
number=4, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='voltage', full_name='Telemetry.voltage', index=4,
number=5, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='current', full_name='Telemetry.current', index=5,
number=6, type=2, cpp_type=6, label=1,
has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=20,
serialized_end=166,
)
DESCRIPTOR.message_types_by_name['Telemetry'] = _TELEMETRY
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
Telemetry = _reflection.GeneratedProtocolMessageType('Telemetry', (_message.Message,), {
'DESCRIPTOR' : _TELEMETRY,
'__module__' : 'telemetry_pb2'
# @@protoc_insertion_point(class_scope:Telemetry)
})
_sym_db.RegisterMessage(Telemetry)
DESCRIPTOR._options = None
# @@protoc_insertion_point(module_scope)

View File

@@ -149,7 +149,7 @@ def testAll(numTests=5):
This is called from the cli with the "--test" option.
"""
ports = meshtastic.util.findPorts()
ports = meshtastic.util.findPorts(True)
if len(ports) < 2:
meshtastic.util.our_exit("Warning: Must have at least two devices connected to USB.")

View File

@@ -46,7 +46,7 @@ def test_main_init_parser_version(capsys):
assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 0
out, err = capsys.readouterr()
assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out)
assert re.match(r'[0-9]+\.[0-9]+[\.a][0-9]', out)
assert err == ''
@@ -62,7 +62,7 @@ def test_main_main_version(capsys):
assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 0
out, err = capsys.readouterr()
assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out)
assert re.match(r'[0-9]+\.[0-9]+[\.a][0-9]', out)
assert err == ''
@@ -425,6 +425,60 @@ def test_main_set_owner_to_bob(capsys):
mo.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_owner_short_to_bob(capsys):
"""Test --set-owner-short bob"""
sys.argv = ['', '--set-owner-short', 'bob']
Globals.getInstance().set_args(sys.argv)
iface = MagicMock(autospec=SerialInterface)
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'Setting device owner short to bob', out, re.MULTILINE)
assert err == ''
mo.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_canned_messages(capsys):
"""Test --set-canned-message """
sys.argv = ['', '--set-canned-message', 'foo']
Globals.getInstance().set_args(sys.argv)
iface = MagicMock(autospec=SerialInterface)
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'Setting canned plugin message to foo', out, re.MULTILINE)
assert err == ''
mo.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_get_canned_messages(capsys, caplog, iface_with_nodes):
"""Test --get-canned-message """
sys.argv = ['', '--get-canned-message']
Globals.getInstance().set_args(sys.argv)
iface = iface_with_nodes
iface.localNode.cannedPluginMessage = 'foo'
with caplog.at_level(logging.DEBUG):
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'canned_plugin_message:foo', out, re.MULTILINE)
assert err == ''
mo.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_ham_to_KI123(capsys):
@@ -478,6 +532,30 @@ def test_main_reboot(capsys):
mo.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_shutdown(capsys):
"""Test --shutdown"""
sys.argv = ['', '--shutdown']
Globals.getInstance().set_args(sys.argv)
mocked_node = MagicMock(autospec=Node)
def mock_shutdown():
print('inside mocked shutdown')
mocked_node.shutdown.side_effect = mock_shutdown
iface = MagicMock(autospec=SerialInterface)
iface.getNode.return_value = mocked_node
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
main()
out, err = capsys.readouterr()
assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'inside mocked shutdown', out, re.MULTILINE)
assert err == ''
mo.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_sendtext(capsys):
@@ -889,10 +967,12 @@ def test_main_configure_with_snake_case(capsys):
out, err = capsys.readouterr()
assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'Setting device owner', out, re.MULTILINE)
assert re.search(r'Setting device owner short', out, re.MULTILINE)
assert re.search(r'Setting channel url', out, re.MULTILINE)
assert re.search(r'Fixing altitude', out, re.MULTILINE)
assert re.search(r'Fixing latitude', out, re.MULTILINE)
assert re.search(r'Fixing longitude', out, re.MULTILINE)
assert re.search(r'Set location_share to LocEnabled', out, re.MULTILINE)
assert re.search(r'Writing modified preferences', out, re.MULTILINE)
assert err == ''
mo.assert_called()
@@ -915,6 +995,7 @@ def test_main_configure_with_camel_case_keys(capsys):
out, err = capsys.readouterr()
assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'Setting device owner', out, re.MULTILINE)
assert re.search(r'Setting device owner short', out, re.MULTILINE)
assert re.search(r'Setting channel url', out, re.MULTILINE)
assert re.search(r'Fixing altitude', out, re.MULTILINE)
assert re.search(r'Fixing latitude', out, re.MULTILINE)
@@ -1204,8 +1285,8 @@ def test_main_ch_enable_primary_channel(capsys):
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_range_options(capsys):
"""Test changing the various range options."""
range_options = ['--ch-longslow', '--ch-longfast', '--ch-mediumslow',
'--ch-mediumfast', '--ch-shortslow', '--ch-shortfast']
range_options = ['--ch-vlongslow', '--ch-longslow', '--ch-longfast', '--ch-midslow',
'--ch-midfast', '--ch-shortslow', '--ch-shortfast']
for range_option in range_options:
sys.argv = ['', f"{range_option}" ]
Globals.getInstance().set_args(sys.argv)
@@ -1579,6 +1660,7 @@ def test_main_export_config(capsys):
iface = MagicMock(autospec=SerialInterface)
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
mo.getLongName.return_value = 'foo'
mo.getShortName.return_value = 'oof'
mo.localNode.getURL.return_value = 'bar'
mo.getMyNodeInfo().get.return_value = { 'latitudeI': 1100000000, 'longitudeI': 1200000000,
'altitude': 100, 'batteryLevel': 34, 'latitude': 110.0,
@@ -1595,6 +1677,7 @@ position_flags: 35"""
assert not re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'owner: foo', out, re.MULTILINE)
assert re.search(r'owner_short: oof', out, re.MULTILINE)
assert re.search(r'channel_url: bar', out, re.MULTILINE)
assert re.search(r'location:', out, re.MULTILINE)
assert re.search(r'lat: 110.0', out, re.MULTILINE)
@@ -1709,18 +1792,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)
@@ -1750,6 +1833,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
@@ -1757,14 +1886,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):
@@ -1963,6 +2190,27 @@ def test_main_setPref_valid_field_invalid_enum(capsys, caplog):
setPref(prefs, 'charge_current', 'foo')
out, err = capsys.readouterr()
assert re.search(r'charge_current does not have an enum called foo', out, re.MULTILINE)
assert re.search(r'Choices in sorted order are', out, re.MULTILINE)
assert re.search(r'MA100', out, re.MULTILINE)
assert re.search(r'MA280', out, re.MULTILINE)
assert err == ''
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_valid_field_invalid_enum_where_enums_are_camel_cased_values(capsys, caplog):
"""Test setPref() with a valid field but invalid enum value"""
radioConfig = RadioConfig()
prefs = radioConfig.preferences
with caplog.at_level(logging.DEBUG):
setPref(prefs, 'location_share', 'foo')
out, err = capsys.readouterr()
assert re.search(r'location_share does not have an enum called foo', out, re.MULTILINE)
assert re.search(r'Choices in sorted order are', out, re.MULTILINE)
assert re.search(r'LocDisabled', out, re.MULTILINE)
assert re.search(r'LocEnabled', out, re.MULTILINE)
assert err == ''
@@ -2083,6 +2331,54 @@ def test_main_setPref_invalid_field_camel(capsys):
assert err == ''
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_ignore_incoming_123(capsys):
"""Test setPref() with ignore_incoming"""
class Field:
"""Simple class for testing."""
def __init__(self, name, enum_type):
"""constructor"""
self.name = name
self.enum_type = enum_type
ignore_incoming_field = Field('ignore_incoming', 'list')
prefs = MagicMock()
prefs.DESCRIPTOR.fields_by_name.get.return_value = ignore_incoming_field
setPref(prefs, 'ignore_incoming', '123')
out, err = capsys.readouterr()
assert re.search(r"Adding '123' to the ignore_incoming list", out, re.MULTILINE)
assert re.search(r'Set ignore_incoming to 123', out, re.MULTILINE)
assert err == ''
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setPref_ignore_incoming_0(capsys):
"""Test setPref() with ignore_incoming"""
class Field:
"""Simple class for testing."""
def __init__(self, name, enum_type):
"""constructor"""
self.name = name
self.enum_type = enum_type
ignore_incoming_field = Field('ignore_incoming', 'list')
prefs = MagicMock()
prefs.DESCRIPTOR.fields_by_name.get.return_value = ignore_incoming_field
setPref(prefs, 'ignore_incoming', '0')
out, err = capsys.readouterr()
assert re.search(r'Clearing ignore_incoming list', out, re.MULTILINE)
assert re.search(r'Set ignore_incoming to 0', out, re.MULTILINE)
assert err == ''
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_ch_set_psk_no_ch_index(capsys):

View File

@@ -213,13 +213,13 @@ def test_handleFromRadio_with_my_info(caplog):
# It "translates" to this:
# my_info {
# my_node_num: 682584012
# num_bands: 13
# firmware_version: "1.2.49.5354c49"
# reboot_count: 13
# bitrate: 17.088470458984375
# message_timeout_msec: 300000
# min_app_version: 20200
# max_channels: 8
# has_wifi: true
# }
from_radio_bytes = b'\x1a,\x08\xcc\xcf\xbd\xc5\x02\x18\r2\x0e1.2.49.5354c49P\r]0\xb5\x88Ah\xe0\xa7\x12p\xe8\x9d\x01x\x08\x90\x01\x01'
iface = MeshInterface(noProto=True)
@@ -227,7 +227,6 @@ def test_handleFromRadio_with_my_info(caplog):
iface._handleFromRadio(from_radio_bytes)
iface.close()
assert re.search(r'Received myinfo', caplog.text, re.MULTILINE)
assert re.search(r'num_bands: 13', caplog.text, re.MULTILINE)
assert re.search(r'max_channels: 8', caplog.text, re.MULTILINE)

View File

@@ -11,6 +11,9 @@ from ..serial_interface import SerialInterface
from ..admin_pb2 import AdminMessage
from ..channel_pb2 import Channel
from ..radioconfig_pb2 import RadioConfig
#from ..cannedmessages_pb2 import (CannedMessagePluginMessagePart1, CannedMessagePluginMessagePart2,
# CannedMessagePluginMessagePart3, CannedMessagePluginMessagePart4,
# CannedMessagePluginMessagePart5)
from ..util import Timeout
@@ -43,6 +46,122 @@ def test_node_requestConfig(capsys):
assert err == ''
#@pytest.mark.unit
#def test_node_get_canned_message_with_all_parts(capsys):
# """Test run get_canned_message()"""
# iface = MagicMock(autospec=SerialInterface)
# amesg = MagicMock(autospec=AdminMessage)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# with patch('meshtastic.admin_pb2.AdminMessage', return_value=amesg):
# # we have a sleep in this method, so override it so it goes fast
# with patch('time.sleep'):
# anode = Node(mo, 'bar')
# anode.cannedPluginMessagePart1 = 'a'
# anode.cannedPluginMessagePart2 = 'b'
# anode.cannedPluginMessagePart3 = 'c'
# anode.cannedPluginMessagePart4 = 'd'
# anode.cannedPluginMessagePart5 = 'e'
# anode.get_canned_message()
# out, err = capsys.readouterr()
# assert re.search(r'canned_plugin_message:abcde', out, re.MULTILINE)
# assert err == ''
#
#
#@pytest.mark.unit
#def test_node_get_canned_message_with_some_parts(capsys):
# """Test run get_canned_message()"""
# iface = MagicMock(autospec=SerialInterface)
# amesg = MagicMock(autospec=AdminMessage)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# with patch('meshtastic.admin_pb2.AdminMessage', return_value=amesg):
# # we have a sleep in this method, so override it so it goes fast
# with patch('time.sleep'):
# anode = Node(mo, 'bar')
# anode.cannedPluginMessagePart1 = 'a'
# anode.get_canned_message()
# out, err = capsys.readouterr()
# assert re.search(r'canned_plugin_message:a', out, re.MULTILINE)
# assert err == ''
#
#
#@pytest.mark.unit
#def test_node_set_canned_message_one_part(caplog):
# """Test run set_canned_message()"""
# iface = MagicMock(autospec=SerialInterface)
# amesg = MagicMock(autospec=AdminMessage)
# with caplog.at_level(logging.DEBUG):
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# with patch('meshtastic.admin_pb2.AdminMessage', return_value=amesg):
# anode = Node(mo, 'bar')
# anode.set_canned_message('foo')
# assert re.search(r"Setting canned message 'foo' part 1", caplog.text, re.MULTILINE)
# assert not re.search(r"Setting canned message '' part 2", caplog.text, re.MULTILINE)
#
#
#@pytest.mark.unit
#def test_node_set_canned_message_200(caplog):
# """Test run set_canned_message() 200 characters long"""
# iface = MagicMock(autospec=SerialInterface)
# amesg = MagicMock(autospec=AdminMessage)
# with caplog.at_level(logging.DEBUG):
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# with patch('meshtastic.admin_pb2.AdminMessage', return_value=amesg):
# anode = Node(mo, 'bar')
# message_200_chars_long = 'a' * 200
# anode.set_canned_message(message_200_chars_long)
# assert re.search(r" part 1", caplog.text, re.MULTILINE)
# assert not re.search(r"Setting canned message '' part 2", caplog.text, re.MULTILINE)
#
#
#@pytest.mark.unit
#def test_node_set_canned_message_201(caplog):
# """Test run set_canned_message() 201 characters long"""
# iface = MagicMock(autospec=SerialInterface)
# amesg = MagicMock(autospec=AdminMessage)
# with caplog.at_level(logging.DEBUG):
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# with patch('meshtastic.admin_pb2.AdminMessage', return_value=amesg):
# anode = Node(mo, 'bar')
# message_201_chars_long = 'a' * 201
# anode.set_canned_message(message_201_chars_long)
# assert re.search(r" part 1", caplog.text, re.MULTILINE)
# assert re.search(r"Setting canned message 'a' part 2", caplog.text, re.MULTILINE)
#
#
#@pytest.mark.unit
#def test_node_set_canned_message_1000(caplog):
# """Test run set_canned_message() 1000 characters long"""
# iface = MagicMock(autospec=SerialInterface)
# amesg = MagicMock(autospec=AdminMessage)
# with caplog.at_level(logging.DEBUG):
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# with patch('meshtastic.admin_pb2.AdminMessage', return_value=amesg):
# anode = Node(mo, 'bar')
# message_1000_chars_long = 'a' * 1000
# anode.set_canned_message(message_1000_chars_long)
# assert re.search(r" part 1", caplog.text, re.MULTILINE)
# assert re.search(r" part 2", caplog.text, re.MULTILINE)
# assert re.search(r" part 3", caplog.text, re.MULTILINE)
# assert re.search(r" part 4", caplog.text, re.MULTILINE)
# assert re.search(r" part 5", caplog.text, re.MULTILINE)
#
#
#@pytest.mark.unit
#def test_node_set_canned_message_1001(capsys):
# """Test run set_canned_message() 1001 characters long"""
# iface = MagicMock(autospec=SerialInterface)
# with pytest.raises(SystemExit) as pytest_wrapped_e:
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar')
# message_1001_chars_long = 'a' * 1001
# anode.set_canned_message(message_1001_chars_long)
# assert pytest_wrapped_e.type == SystemExit
# assert pytest_wrapped_e.value.code == 1
# out, err = capsys.readouterr()
# assert re.search(r'Warning: The canned message', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit
def test_setOwner_and_team(caplog):
"""Test setOwner"""
@@ -55,6 +174,15 @@ def test_setOwner_and_team(caplog):
assert re.search(r'p.set_owner.team:1', caplog.text, re.MULTILINE)
@pytest.mark.unit
def test_setOwnerShort(caplog):
"""Test setOwner"""
anode = Node('foo', 'bar', noProto=True)
with caplog.at_level(logging.DEBUG):
anode.setOwner(long_name=None, short_name='123')
assert re.search(r'p.set_owner.short_name:123:', caplog.text, re.MULTILINE)
@pytest.mark.unit
def test_setOwner_no_short_name(caplog):
"""Test setOwner"""
@@ -119,6 +247,15 @@ def test_reboot(caplog):
assert re.search(r'Telling node to reboot', caplog.text, re.MULTILINE)
@pytest.mark.unit
def test_shutdown(caplog):
"""Test shutdown"""
anode = Node('foo', 'bar', noProto=True)
with caplog.at_level(logging.DEBUG):
anode.shutdown()
assert re.search(r'Telling node to shutdown', caplog.text, re.MULTILINE)
@pytest.mark.unit
def test_setURL_empty_url(capsys):
"""Test reboot"""
@@ -144,7 +281,7 @@ def test_setURL_valid_URL(caplog):
anode.channels = channels
anode.setURL(url)
assert re.search(r'Channel i:0', caplog.text, re.MULTILINE)
assert re.search(r'modem_config: Bw125Cr48Sf4096', caplog.text, re.MULTILINE)
assert re.search(r'modem_config: MidSlow', caplog.text, re.MULTILINE)
assert re.search(r'psk: "\\001"', caplog.text, re.MULTILINE)
assert re.search(r'role: PRIMARY', caplog.text, re.MULTILINE)
@@ -198,7 +335,7 @@ def test_showChannels(capsys):
# primary channel
assert re.search(r'Primary channel URL', out, re.MULTILINE)
assert re.search(r'PRIMARY psk=default ', out, re.MULTILINE)
assert re.search(r'"modemConfig": "Bw125Cr48Sf4096"', out, re.MULTILINE)
assert re.search(r'"modemConfig": "MidSlow"', out, re.MULTILINE)
assert re.search(r'"psk": "AQ=="', out, re.MULTILINE)
# secondary channel
assert re.search(r'SECONDARY psk=secret ', out, re.MULTILINE)
@@ -676,6 +813,352 @@ def test_requestChannel_localNode(caplog):
assert not re.search(r'from remote node', caplog.text, re.MULTILINE)
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart1(caplog):
# """Test onResponseRequestCannedMessagePluginMessagePart1()"""
#
# part1 = CannedMessagePluginMessagePart1()
# part1.text = 'foo1'
#
# msg1 = MagicMock(autospec=AdminMessage)
# msg1.get_canned_message_plugin_part1_response = part1
#
# packet = {
# 'from': 682968612,
# 'to': 682968612,
# 'decoded': {
# 'portnum': 'ADMIN_APP',
# 'payload': 'faked',
# 'requestId': 927039000,
# 'admin': {
# 'getCannedMessagePluginPart1Response': {'text': 'foo1'},
# 'raw': msg1
# }
# },
# 'id': 589440320,
# 'rxTime': 1642710843,
# 'hopLimit': 3,
# 'priority': 'RELIABLE',
# 'raw': 'faked',
# 'fromId': '!28b54624',
# 'toId': '!28b54624'
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart1(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart1', caplog.text, re.MULTILINE)
# assert anode.cannedPluginMessagePart1 == 'foo1'
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart2(caplog):
# """Test onResponseRequestCannedMessagePluginMessagePart2()"""
#
# part2 = CannedMessagePluginMessagePart2()
# part2.text = 'foo2'
#
# msg2 = MagicMock(autospec=AdminMessage)
# msg2.get_canned_message_plugin_part2_response = part2
#
# packet = {
# 'from': 682968612,
# 'to': 682968612,
# 'decoded': {
# 'portnum': 'ADMIN_APP',
# 'payload': 'faked',
# 'requestId': 927039000,
# 'admin': {
# 'getCannedMessagePluginPart2Response': {'text': 'foo2'},
# 'raw': msg2
# }
# },
# 'id': 589440320,
# 'rxTime': 1642710843,
# 'hopLimit': 3,
# 'priority': 'RELIABLE',
# 'raw': 'faked',
# 'fromId': '!28b54624',
# 'toId': '!28b54624'
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart2(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart2', caplog.text, re.MULTILINE)
# assert anode.cannedPluginMessagePart2 == 'foo2'
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart3(caplog):
# """Test onResponseRequestCannedMessagePluginMessagePart3()"""
#
# part3 = CannedMessagePluginMessagePart3()
# part3.text = 'foo3'
#
# msg3 = MagicMock(autospec=AdminMessage)
# msg3.get_canned_message_plugin_part3_response = part3
#
# packet = {
# 'from': 682968612,
# 'to': 682968612,
# 'decoded': {
# 'portnum': 'ADMIN_APP',
# 'payload': 'faked',
# 'requestId': 927039000,
# 'admin': {
# 'getCannedMessagePluginPart3Response': {'text': 'foo3'},
# 'raw': msg3
# }
# },
# 'id': 589440320,
# 'rxTime': 1642710843,
# 'hopLimit': 3,
# 'priority': 'RELIABLE',
# 'raw': 'faked',
# 'fromId': '!28b54624',
# 'toId': '!28b54624'
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart3(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart3', caplog.text, re.MULTILINE)
# assert anode.cannedPluginMessagePart3 == 'foo3'
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart4(caplog):
# """Test onResponseRequestCannedMessagePluginMessagePart4()"""
#
# part4 = CannedMessagePluginMessagePart4()
# part4.text = 'foo4'
#
# msg4 = MagicMock(autospec=AdminMessage)
# msg4.get_canned_message_plugin_part4_response = part4
#
# packet = {
# 'from': 682968612,
# 'to': 682968612,
# 'decoded': {
# 'portnum': 'ADMIN_APP',
# 'payload': 'faked',
# 'requestId': 927039000,
# 'admin': {
# 'getCannedMessagePluginPart4Response': {'text': 'foo4'},
# 'raw': msg4
# }
# },
# 'id': 589440320,
# 'rxTime': 1642710843,
# 'hopLimit': 3,
# 'priority': 'RELIABLE',
# 'raw': 'faked',
# 'fromId': '!28b54624',
# 'toId': '!28b54624'
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart4(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart4', caplog.text, re.MULTILINE)
# assert anode.cannedPluginMessagePart4 == 'foo4'
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart5(caplog):
# """Test onResponseRequestCannedMessagePluginMessagePart5()"""
#
# part5 = CannedMessagePluginMessagePart5()
# part5.text = 'foo5'
#
# msg5 = MagicMock(autospec=AdminMessage)
# msg5.get_canned_message_plugin_part5_response = part5
#
#
# packet = {
# 'from': 682968612,
# 'to': 682968612,
# 'decoded': {
# 'portnum': 'ADMIN_APP',
# 'payload': 'faked',
# 'requestId': 927039000,
# 'admin': {
# 'getCannedMessagePluginPart5Response': {'text': 'foo5'},
# 'raw': msg5
# }
# },
# 'id': 589440320,
# 'rxTime': 1642710843,
# 'hopLimit': 3,
# 'priority': 'RELIABLE',
# 'raw': 'faked',
# 'fromId': '!28b54624',
# 'toId': '!28b54624'
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart5(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart5', caplog.text, re.MULTILINE)
# assert anode.cannedPluginMessagePart5 == 'foo5'
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart1_error(caplog, capsys):
# """Test onResponseRequestCannedMessagePluginMessagePart1() with error"""
#
# packet = {
# 'decoded': {
# 'routing': {
# 'errorReason': 'some made up error',
# },
# },
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart1(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart1', caplog.text, re.MULTILINE)
# out, err = capsys.readouterr()
# assert re.search(r'Error on response', out)
# assert err == ''
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart2_error(caplog, capsys):
# """Test onResponseRequestCannedMessagePluginMessagePart2() with error"""
#
# packet = {
# 'decoded': {
# 'routing': {
# 'errorReason': 'some made up error',
# },
# },
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart2(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart2', caplog.text, re.MULTILINE)
# out, err = capsys.readouterr()
# assert re.search(r'Error on response', out)
# assert err == ''
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart3_error(caplog, capsys):
# """Test onResponseRequestCannedMessagePluginMessagePart3() with error"""
#
# packet = {
# 'decoded': {
# 'routing': {
# 'errorReason': 'some made up error',
# },
# },
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart3(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart3', caplog.text, re.MULTILINE)
# out, err = capsys.readouterr()
# assert re.search(r'Error on response', out)
# assert err == ''
#
#
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart4_error(caplog, capsys):
# """Test onResponseRequestCannedMessagePluginMessagePart4() with error"""
#
# packet = {
# 'decoded': {
# 'routing': {
# 'errorReason': 'some made up error',
# },
# },
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart4(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart4', caplog.text, re.MULTILINE)
# out, err = capsys.readouterr()
# assert re.search(r'Error on response', out)
# assert err == ''
#
#
#@pytest.mark.unit
#def test_onResponseRequestCannedMessagePluginMesagePart5_error(caplog, capsys):
# """Test onResponseRequestCannedMessagePluginMessagePart5() with error"""
#
# packet = {
# 'decoded': {
# 'routing': {
# 'errorReason': 'some made up error',
# },
# },
# }
#
# iface = MagicMock(autospec=SerialInterface)
# with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
# anode = Node(mo, 'bar', noProto=True)
# # Note: Have to do this next line because every call to MagicMock object/method returns a new magic mock
# mo.localNode = anode
#
# with caplog.at_level(logging.DEBUG):
# anode.onResponseRequestCannedMessagePluginMessagePart5(packet)
# assert re.search(r'onResponseRequestCannedMessagePluginMessagePart5', caplog.text, re.MULTILINE)
# out, err = capsys.readouterr()
# assert re.search(r'Error on response', out)
# assert err == ''
@pytest.mark.unit
def test_onResponseRequestChannel(caplog):
"""Test onResponseRequestChannel()"""

View File

@@ -160,7 +160,7 @@ def test_smoke1_send_hello():
def test_smoke1_port():
"""Test --port"""
# first, get the ports
ports = findPorts()
ports = findPorts(True)
# hopefully there is just one
assert len(ports) == 1
port = ports[0]

View File

@@ -21,7 +21,7 @@ from ..util import findPorts
# seconds to pause after running a meshtastic command
PAUSE_AFTER_COMMAND = 0.1
PAUSE_AFTER_REBOOT = 0.1
PAUSE_AFTER_REBOOT = 0.2
#TODO: need to fix the virtual device to have a reboot. When you issue the command
@@ -358,6 +358,11 @@ def test_smokevirt_ch_set_downlink_and_uplink():
@pytest.mark.smokevirt
def test_smokevirt_ch_add_and_ch_del():
"""Test --ch-add"""
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --ch-index 1 --ch-del')
assert re.search(r'Deleting channel 1', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_REBOOT)
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --ch-add testing')
assert re.search(r'Writing modified channels to device', out, re.MULTILINE)
assert return_value == 0
@@ -375,7 +380,7 @@ def test_smokevirt_ch_add_and_ch_del():
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_REBOOT)
# make sure the secondar channel is not there
# make sure the secondary channel is not there
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --info')
assert re.match(r'Connected to radio', out)
assert not re.search(r'SECONDARY', out, re.MULTILINE)
@@ -386,6 +391,11 @@ def test_smokevirt_ch_add_and_ch_del():
@pytest.mark.smokevirt
def test_smokevirt_ch_enable_and_disable():
"""Test --ch-enable and --ch-disable"""
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --ch-index 1 --ch-del')
assert re.search(r'Deleting channel 1', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_REBOOT)
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --ch-add testing')
assert re.search(r'Writing modified channels to device', out, re.MULTILINE)
assert return_value == 0
@@ -434,6 +444,11 @@ def test_smokevirt_ch_enable_and_disable():
@pytest.mark.smokevirt
def test_smokevirt_ch_del_a_disabled_non_primary_channel():
"""Test --ch-del will work on a disabled non-primary channel."""
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --ch-index 1 --ch-del')
assert re.search(r'Deleting channel 1', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_REBOOT)
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --ch-add testing')
assert re.search(r'Writing modified channels to device', out, re.MULTILINE)
assert return_value == 0

View File

@@ -11,7 +11,10 @@ from meshtastic.util import (fixme, stripnl, pskToString, our_exit,
quoteBooleans, catchAndIgnore,
remove_keys_from_dict, Timeout, hexstr,
ipstr, readnet_u16, findPorts, convert_mac_addr,
snake_to_camel, camel_to_snake)
snake_to_camel, camel_to_snake, eliminate_duplicate_port,
is_windows11, active_ports_on_supported_devices)
from meshtastic.supported_device import SupportedDevice
@pytest.mark.unit
@@ -247,6 +250,54 @@ def test_findPorts_when_none_found(patch_comports):
patch_comports.assert_called()
@pytest.mark.unitslow
@patch('serial.tools.list_ports.comports')
def test_findPorts_when_duplicate_found_and_duplicate_option_used(patch_comports):
"""Test findPorts()"""
class TempPort:
""" temp class for port"""
def __init__(self, device=None, vid=None):
self.device = device
self.vid = vid
fake1 = TempPort('/dev/cu.usbserial-1430', vid='fake1')
fake2 = TempPort('/dev/cu.wchusbserial1430', vid='fake2')
patch_comports.return_value = [fake1, fake2]
assert findPorts(eliminate_duplicates=True) == ['/dev/cu.wchusbserial1430']
patch_comports.assert_called()
@pytest.mark.unitslow
@patch('serial.tools.list_ports.comports')
def test_findPorts_when_duplicate_found_and_duplicate_option_used_ports_reversed(patch_comports):
"""Test findPorts()"""
class TempPort:
""" temp class for port"""
def __init__(self, device=None, vid=None):
self.device = device
self.vid = vid
fake1 = TempPort('/dev/cu.usbserial-1430', vid='fake1')
fake2 = TempPort('/dev/cu.wchusbserial1430', vid='fake2')
patch_comports.return_value = [fake2, fake1]
assert findPorts(eliminate_duplicates=True) == ['/dev/cu.wchusbserial1430']
patch_comports.assert_called()
@pytest.mark.unitslow
@patch('serial.tools.list_ports.comports')
def test_findPorts_when_duplicate_found_and_duplicate_option_not_used(patch_comports):
"""Test findPorts()"""
class TempPort:
""" temp class for port"""
def __init__(self, device=None, vid=None):
self.device = device
self.vid = vid
fake1 = TempPort('/dev/cu.usbserial-1430', vid='fake1')
fake2 = TempPort('/dev/cu.wchusbserial1430', vid='fake2')
patch_comports.return_value = [fake1, fake2]
assert findPorts() == ['/dev/cu.usbserial-1430', '/dev/cu.wchusbserial1430']
patch_comports.assert_called()
@pytest.mark.unitslow
def test_convert_mac_addr():
"""Test convert_mac_addr()"""
@@ -272,3 +323,136 @@ def test_camel_to_snake():
assert camel_to_snake('Foo') == 'foo'
assert camel_to_snake('fooBar') == 'foo_bar'
assert camel_to_snake('fooBarBaz') == 'foo_bar_baz'
@pytest.mark.unit
def test_eliminate_duplicate_port():
"""Test eliminate_duplicate_port()"""
assert not eliminate_duplicate_port([])
assert eliminate_duplicate_port(['/dev/fake']) == ['/dev/fake']
assert eliminate_duplicate_port(['/dev/fake', '/dev/fake1']) == ['/dev/fake', '/dev/fake1']
assert eliminate_duplicate_port(['/dev/fake', '/dev/fake1', '/dev/fake2']) == ['/dev/fake', '/dev/fake1', '/dev/fake2']
assert eliminate_duplicate_port(['/dev/cu.usbserial-1430', '/dev/cu.wchusbserial1430']) == ['/dev/cu.wchusbserial1430']
assert eliminate_duplicate_port(['/dev/cu.wchusbserial1430', '/dev/cu.usbserial-1430']) == ['/dev/cu.wchusbserial1430']
assert eliminate_duplicate_port(['/dev/cu.SLAB_USBtoUART', '/dev/cu.usbserial-0001']) == ['/dev/cu.usbserial-0001']
assert eliminate_duplicate_port(['/dev/cu.usbserial-0001', '/dev/cu.SLAB_USBtoUART']) == ['/dev/cu.usbserial-0001']
assert eliminate_duplicate_port(['/dev/cu.usbmodem11301', '/dev/cu.wchusbserial11301']) == ['/dev/cu.wchusbserial11301']
assert eliminate_duplicate_port(['/dev/cu.wchusbserial11301', '/dev/cu.usbmodem11301']) == ['/dev/cu.wchusbserial11301']
assert eliminate_duplicate_port(['/dev/cu.usbmodem53230051441', '/dev/cu.wchusbserial53230051441']) == ['/dev/cu.wchusbserial53230051441']
assert eliminate_duplicate_port(['/dev/cu.wchusbserial53230051441', '/dev/cu.usbmodem53230051441']) == ['/dev/cu.wchusbserial53230051441']
@patch('platform.version', return_value='10.0.22000.194')
@patch('platform.release', return_value='10')
@patch('platform.system', return_value='Windows')
def test_is_windows11_true(patched_platform, patched_release, patched_version):
"""Test is_windows11()"""
assert is_windows11() is True
patched_platform.assert_called()
patched_release.assert_called()
patched_version.assert_called()
@patch('platform.version', return_value='10.0.a2200.foo') # made up
@patch('platform.release', return_value='10')
@patch('platform.system', return_value='Windows')
def test_is_windows11_true2(patched_platform, patched_release, patched_version):
"""Test is_windows11()"""
assert is_windows11() is False
patched_platform.assert_called()
patched_release.assert_called()
patched_version.assert_called()
@patch('platform.version', return_value='10.0.17763') # windows 10 home
@patch('platform.release', return_value='10')
@patch('platform.system', return_value='Windows')
def test_is_windows11_false(patched_platform, patched_release, patched_version):
"""Test is_windows11()"""
assert is_windows11() is False
patched_platform.assert_called()
patched_release.assert_called()
patched_version.assert_called()
@patch('platform.release', return_value='8.1')
@patch('platform.system', return_value='Windows')
def test_is_windows11_false_win8_1(patched_platform, patched_release):
"""Test is_windows11()"""
assert is_windows11() is False
patched_platform.assert_called()
patched_release.assert_called()
@pytest.mark.unit
@patch('platform.system', return_value='Linux')
def test_active_ports_on_supported_devices_empty(mock_platform):
"""Test active_ports_on_supported_devices()"""
sds = set()
assert active_ports_on_supported_devices(sds) == set()
mock_platform.assert_called()
@pytest.mark.unit
@patch('subprocess.getstatusoutput')
@patch('platform.system', return_value='Linux')
def test_active_ports_on_supported_devices_linux(mock_platform, mock_sp):
"""Test active_ports_on_supported_devices()"""
mock_sp.return_value = (None, 'crw-rw-rw- 1 root wheel 0x9000000 Feb 8 22:22 /dev/ttyUSBfake')
fake_device = SupportedDevice(name='a', for_firmware='heltec-v2.1', baseport_on_linux='ttyUSB')
fake_supported_devices = [fake_device]
assert active_ports_on_supported_devices(fake_supported_devices) == {'/dev/ttyUSBfake'}
mock_platform.assert_called()
mock_sp.assert_called()
@pytest.mark.unit
@patch('subprocess.getstatusoutput')
@patch('platform.system', return_value='Darwin')
def test_active_ports_on_supported_devices_mac(mock_platform, mock_sp):
"""Test active_ports_on_supported_devices()"""
mock_sp.return_value = (None, 'crw-rw-rw- 1 root wheel 0x9000000 Feb 8 22:22 /dev/cu.usbserial-foo')
fake_device = SupportedDevice(name='a', for_firmware='heltec-v2.1', baseport_on_linux='cu.usbserial-')
fake_supported_devices = [fake_device]
assert active_ports_on_supported_devices(fake_supported_devices) == {'/dev/cu.usbserial-foo'}
mock_platform.assert_called()
mock_sp.assert_called()
@pytest.mark.unit
@patch('meshtastic.util.detect_windows_port', return_value={'COM2'})
@patch('platform.system', return_value='Windows')
def test_active_ports_on_supported_devices_win(mock_platform, mock_dwp):
"""Test active_ports_on_supported_devices()"""
fake_device = SupportedDevice(name='a', for_firmware='heltec-v2.1')
fake_supported_devices = [fake_device]
assert active_ports_on_supported_devices(fake_supported_devices) == {'COM2'}
mock_platform.assert_called()
mock_dwp.assert_called()
@pytest.mark.unit
@patch('subprocess.getstatusoutput')
@patch('platform.system', return_value='Darwin')
def test_active_ports_on_supported_devices_mac_no_duplicates_check(mock_platform, mock_sp):
"""Test active_ports_on_supported_devices()"""
mock_sp.return_value = (None, ('crw-rw-rw- 1 root wheel 0x9000005 Mar 8 10:05 /dev/cu.usbmodem53230051441\n'
'crw-rw-rw- 1 root wheel 0x9000003 Mar 8 10:06 /dev/cu.wchusbserial53230051441'))
fake_device = SupportedDevice(name='a', for_firmware='tbeam', baseport_on_mac='cu.usbmodem')
fake_supported_devices = [fake_device]
assert active_ports_on_supported_devices(fake_supported_devices, False) == {'/dev/cu.usbmodem53230051441', '/dev/cu.wchusbserial53230051441'}
mock_platform.assert_called()
mock_sp.assert_called()
@pytest.mark.unit
@patch('subprocess.getstatusoutput')
@patch('platform.system', return_value='Darwin')
def test_active_ports_on_supported_devices_mac_duplicates_check(mock_platform, mock_sp):
"""Test active_ports_on_supported_devices()"""
mock_sp.return_value = (None, ('crw-rw-rw- 1 root wheel 0x9000005 Mar 8 10:05 /dev/cu.usbmodem53230051441\n'
'crw-rw-rw- 1 root wheel 0x9000003 Mar 8 10:06 /dev/cu.wchusbserial53230051441'))
fake_device = SupportedDevice(name='a', for_firmware='tbeam', baseport_on_mac='cu.usbmodem')
fake_supported_devices = [fake_device]
assert active_ports_on_supported_devices(fake_supported_devices, True) == {'/dev/cu.wchusbserial53230051441'}
mock_platform.assert_called()
mock_sp.assert_called()

View File

@@ -10,10 +10,13 @@ import time
import platform
import logging
import threading
import subprocess
import serial
import serial.tools.list_ports
import pkg_resources
from meshtastic.supported_device import supported_devices
"""Some devices such as a seger jlink we never want to accidentally open"""
blacklistVids = dict.fromkeys([0x1366])
@@ -111,8 +114,9 @@ def catchAndIgnore(reason, closure):
logging.error(f"Exception thrown in {reason}: {ex}")
def findPorts():
def findPorts(eliminate_duplicates=False):
"""Find all ports that might have meshtastic devices
eliminate_duplicates will run the eliminate_duplicate_port() on the collection
Returns:
list -- a list of device paths
@@ -121,6 +125,8 @@ def findPorts():
filter(lambda port: port.vid is not None and port.vid not in blacklistVids,
serial.tools.list_ports.comports())))
l.sort()
if eliminate_duplicates:
l = eliminate_duplicate_port(l)
return l
@@ -257,3 +263,283 @@ def snake_to_camel(a_string):
def camel_to_snake(a_string):
"""convert camelCase to snake_case"""
return ''.join(['_'+i.lower() if i.isupper() else i for i in a_string]).lstrip('_')
def detect_supported_devices():
"""detect supported devices"""
system = platform.system()
#print(f'system:{system}')
possible_devices = set()
if system == "Linux":
# if linux, run lsusb and list ports
# linux: use lsusb
# Bus 001 Device 091: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
_, lsusb_output = subprocess.getstatusoutput('lsusb')
vids = get_unique_vendor_ids()
for vid in vids:
#print(f'looking for {vid}...')
search = f' {vid}:'
#print(f'search:"{search}"')
if re.search(search, lsusb_output, re.MULTILINE):
#print(f'Found vendor id that matches')
devices = get_devices_with_vendor_id(vid)
# check device id
for device in devices:
#print(f'device:{device} device.usb_product_id_in_hex:{device.usb_product_id_in_hex}')
if device.usb_product_id_in_hex:
search = f' {vid}:{device.usb_product_id_in_hex} '
#print(f'search:"{search}"')
if re.search(search, lsusb_output, re.MULTILINE):
# concatenate the devices with vendor id to possibles
possible_devices.add(device)
else:
# if there is a supported device witout a product id, then it
# might be a match... so, concatenate
possible_devices.add(device)
elif system == "Windows":
# if windows, run Get-PnpDevice
_, sp_output = subprocess.getstatusoutput('powershell.exe "[Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8;'
'Get-PnpDevice -PresentOnly | Format-List"')
#print(f'sp_output:{sp_output}')
vids = get_unique_vendor_ids()
for vid in vids:
#print(f'looking for {vid.upper()}...')
search = f'DeviceID.*{vid.upper()}&'
#search = f'{vid.upper()}'
#print(f'search:"{search}"')
if re.search(search, sp_output, re.MULTILINE):
#print(f'Found vendor id that matches')
devices = get_devices_with_vendor_id(vid)
# check device id
for device in devices:
#print(f'device:{device} device.usb_product_id_in_hex:{device.usb_product_id_in_hex}')
if device.usb_product_id_in_hex:
search = f'DeviceID.*{vid.upper()}&PID_{device.usb_product_id_in_hex.upper()}'
#print(f'search:"{search}"')
if re.search(search, sp_output, re.MULTILINE):
# concatenate the devices with vendor id to possibles
possible_devices.add(device)
# do a check to see if there is a Windows driver issue
if detect_windows_needs_driver(device, False):
print("WARNING: Need to install driver.")
else:
# if there is a supported device witout a product id, then it
# might be a match... so, concatenate
possible_devices.add(device)
elif system == "Darwin":
# run: system_profiler SPUSBDataType
# Note: If in boot mode, the 19003 reports same product ID as 5005.
_, sp_output = subprocess.getstatusoutput('system_profiler SPUSBDataType')
vids = get_unique_vendor_ids()
for vid in vids:
#print(f'looking for {vid}...')
search = f'Vendor ID: 0x{vid}'
#print(f'search:"{search}"')
if re.search(search, sp_output, re.MULTILINE):
#print(f'Found vendor id that matches')
devices = get_devices_with_vendor_id(vid)
# check device id
for device in devices:
#print(f'device:{device} device.usb_product_id_in_hex:{device.usb_product_id_in_hex}')
if device.usb_product_id_in_hex:
search = f'Product ID: 0x{device.usb_product_id_in_hex}'
#print(f'search:"{search}"')
if re.search(search, sp_output, re.MULTILINE):
# concatenate the devices with vendor id to possibles
possible_devices.add(device)
else:
# if there is a supported device witout a product id, then it
# might be a match... so, concatenate
possible_devices.add(device)
return possible_devices
def detect_windows_needs_driver(sd, print_reason=False):
"""detect if Windows user needs to install driver for a supported device"""
need_to_install_driver = False
if sd:
system = platform.system()
#print(f'in detect_windows_needs_driver system:{system}')
if system == "Windows":
# if windows, see if we can find a DeviceId with the vendor id
# Get-PnpDevice | Where-Object{ ($_.DeviceId -like '*10C4*')} | Format-List
command = 'powershell.exe "[Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8; Get-PnpDevice | Where-Object{ ($_.DeviceId -like '
command += f"'*{sd.usb_vendor_id_in_hex.upper()}*'"
command += ')} | Format-List"'
#print(f'command:{command}')
_, sp_output = subprocess.getstatusoutput(command)
#print(f'sp_output:{sp_output}')
search = f'CM_PROB_FAILED_INSTALL'
#print(f'search:"{search}"')
if re.search(search, sp_output, re.MULTILINE):
need_to_install_driver = True
# if the want to see the reason
if print_reason:
print(sp_output)
return need_to_install_driver
def eliminate_duplicate_port(ports):
"""Sometimes we detect 2 serial ports, but we really only need to use one of the ports.
ports is a list of ports
return a list with a single port to use, if it meets the duplicate port conditions
examples:
Ports: ['/dev/cu.usbserial-1430', '/dev/cu.wchusbserial1430'] => ['/dev/cu.wchusbserial1430']
Ports: ['/dev/cu.usbmodem11301', '/dev/cu.wchusbserial11301'] => ['/dev/cu.wchusbserial11301']
Ports: ['/dev/cu.SLAB_USBtoUART', '/dev/cu.usbserial-0001'] => ['/dev/cu.usbserial-0001']
"""
new_ports = []
if len(ports) != 2:
new_ports = ports
else:
ports.sort()
if 'usbserial' in ports[0] and 'wchusbserial' in ports[1]:
first = ports[0].replace("usbserial-", "")
second = ports[1].replace("wchusbserial", "")
if first == second:
new_ports.append(ports[1])
elif 'usbmodem' in ports[0] and 'wchusbserial' in ports[1]:
first = ports[0].replace("usbmodem", "")
second = ports[1].replace("wchusbserial", "")
if first == second:
new_ports.append(ports[1])
elif 'SLAB_USBtoUART' in ports[0] and 'usbserial' in ports[1]:
new_ports.append(ports[1])
else:
new_ports = ports
return new_ports
def is_windows11():
"""Detect if Windows 11"""
is_win11 = False
if platform.system() == "Windows":
if float(platform.release()) >= 10.0:
patch = platform.version().split('.')[2]
# in case they add some number suffix later, just get first 5 chars of patch
patch = patch[:5]
try:
if int(patch) >= 22000:
is_win11 = True
except Exception as e:
print(f'problem detecting win11 e:{e}')
return is_win11
def get_unique_vendor_ids():
"""Return a set of unique vendor ids"""
vids = set()
for d in supported_devices:
if d.usb_vendor_id_in_hex:
vids.add(d.usb_vendor_id_in_hex)
return vids
def get_devices_with_vendor_id(vid):
"""Return a set of unique devices with the vendor id"""
sd = set()
for d in supported_devices:
if d.usb_vendor_id_in_hex == vid:
sd.add(d)
return sd
def active_ports_on_supported_devices(sds, eliminate_duplicates=False):
"""Return a set of active ports based on the supplied supported devices"""
ports = set()
baseports = set()
system = platform.system()
# figure out what possible base ports there are
for d in sds:
if system == "Linux":
baseports.add(d.baseport_on_linux)
elif system == "Darwin":
baseports.add(d.baseport_on_mac)
elif system == "Windows":
baseports.add(d.baseport_on_windows)
for bp in baseports:
if system == "Linux":
# see if we have any devices (ignoring any stderr output)
command = f'ls -al /dev/{bp}* 2> /dev/null'
#print(f'command:{command}')
_, ls_output = subprocess.getstatusoutput(command)
#print(f'ls_output:{ls_output}')
# if we got output, there are ports
if len(ls_output) > 0:
#print('got output')
# for each line of output
lines = ls_output.split('\n')
#print(f'lines:{lines}')
for line in lines:
parts = line.split(' ')
#print(f'parts:{parts}')
port = parts[-1]
#print(f'port:{port}')
ports.add(port)
elif system == "Darwin":
# see if we have any devices (ignoring any stderr output)
command = f'ls -al /dev/{bp}* 2> /dev/null'
#print(f'command:{command}')
_, ls_output = subprocess.getstatusoutput(command)
#print(f'ls_output:{ls_output}')
# if we got output, there are ports
if len(ls_output) > 0:
#print('got output')
# for each line of output
lines = ls_output.split('\n')
#print(f'lines:{lines}')
for line in lines:
parts = line.split(' ')
#print(f'parts:{parts}')
port = parts[-1]
#print(f'port:{port}')
ports.add(port)
elif system == "Windows":
# for each device in supported devices found
for d in sds:
# find the port(s)
com_ports = detect_windows_port(d)
#print(f'com_ports:{com_ports}')
# add all ports
for com_port in com_ports:
ports.add(com_port)
if eliminate_duplicates:
ports = eliminate_duplicate_port(list(ports))
ports.sort()
ports = set(ports)
return ports
def detect_windows_port(sd):
"""detect if Windows port"""
ports = set()
if sd:
system = platform.system()
if system == "Windows":
command = ('powershell.exe "[Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8;'
'Get-PnpDevice -PresentOnly | Where-Object{ ($_.DeviceId -like ')
command += f"'*{sd.usb_vendor_id_in_hex.upper()}*'"
command += ')} | Format-List"'
#print(f'command:{command}')
_, sp_output = subprocess.getstatusoutput(command)
#print(f'sp_output:{sp_output}')
p = re.compile(r'\(COM(.*)\)')
for x in p.findall(sp_output):
#print(f'x:{x}')
ports.add(f'COM{x}')
return ports

2
proto

Submodule proto updated: d7b2791b7c...82bc2e2fdd

View File

@@ -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.56",
version="1.3alpha.5",
description="Python API & client shell for talking to Meshtastic devices",
long_description=long_description,
long_description_content_type="text/markdown",
@@ -22,8 +22,7 @@ setup(
license="MIT",
classifiers=[
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
@@ -38,7 +37,7 @@ setup(
extras_require={
'tunnel': ["pytap2>=2.0.0"]
},
python_requires='>=3.6',
python_requires='>=3.7',
entry_points={
"console_scripts": [
"meshtastic=meshtastic.__main__:main",

7
standalone_readme.txt Normal file
View File

@@ -0,0 +1,7 @@
readme.txt for single standalone executable zip files that can be
downloaded from https://github.com/meshtastic/Meshtastic-python/releases
If you do not want to install python and/or the python libraries, you can download one of these
files to run the Meshtastic command line interface (CLI) as a standalone executable.
See https://meshtastic.org/docs/software/python/python-standalone for more info.