Compare commits

...

281 Commits

Author SHA1 Message Date
Ben Meadors
45be828183 Merge pull request #432 from mverch67/master
Fix remote_hardware configuration
2023-03-26 14:43:41 -05:00
Ben Meadors
e0753d4745 Added new smart broadcast properties 2023-03-26 14:43:07 -05:00
Manuel
21f2e185f2 Merge branch 'master' into master 2023-03-26 20:03:19 +02:00
Manuel Verch
4bfedf6aa9 added missing audio module remote config 2023-03-26 19:59:25 +02:00
Manuel Verch
193c3faca5 Fix remote_hardware configuration 2023-03-26 16:25:59 +02:00
Manuel Verch
1f47c225b3 Fix remote_hardware configuration 2023-03-25 21:37:10 +01:00
github-actions
1b372fca8d bump version 2023-03-19 18:38:37 +00:00
Ben Meadors
5e7b6027fa Bump to 2.1.x 2023-03-19 13:36:38 -05:00
Ben Meadors
64bd5deb4b Update protos to 2.1.3 2023-03-19 13:35:13 -05:00
Ben Meadors
d0fdb9b570 Merge pull request #428 from GUVWAF/remoteAdmin
Get and set methods for remote node using one admin message
2023-03-19 13:31:49 -05:00
Garth Vander Houwen
f37755209e Merge pull request #429 from GUVWAF/configSnake
Convert sections to snake_case when configuring
2023-03-19 09:17:30 -07:00
GUVWAF
297c0dbc0e Convert sections to snake_case when configuring 2023-03-19 15:25:08 +01:00
GUVWAF
7de17f7c94 Display that '--nodes' is not supported for a remote node 2023-03-19 14:42:44 +01:00
GUVWAF
55f6494681 Wait for ACK after setting remote config 2023-03-19 14:42:12 +01:00
GUVWAF
b2cfebc5a7 '--set' works as well, also chained commands 2023-03-18 21:12:05 +01:00
GUVWAF
802768e0cc Nicer printing 2023-03-18 16:40:27 +01:00
GUVWAF
f68e4112e1 Remote get method works 2023-03-18 15:20:00 +01:00
github-actions
19b4cd65ce bump version 2023-02-10 20:53:49 +00:00
Ben Meadors
ef12125785 Update protos 2023-02-10 13:26:29 -06:00
Garth Vander Houwen
014993f058 Merge pull request #417 from tobymurray/patch-2 2023-02-09 10:01:21 -08:00
github-actions
a10da7d3ed bump version 2023-01-31 16:54:53 +00:00
Ben Meadors
786dca9d13 Protos 2023-01-31 10:53:03 -06:00
github-actions
1cfd471abc bump version 2023-01-29 23:04:27 +00:00
Ben Meadors
9ff575c388 Hack to make python compile again 2023-01-29 15:19:03 -06:00
Toby Murray
b973e39ef7 Fix link to Getting Started Guide
Previous link (https://meshtastic.org/docs/software/python/python-installation) 404's
2023-01-16 13:53:31 -05:00
github-actions
75cdc5a36b bump version 2023-01-07 21:29:31 +00:00
Thomas Göttgens
93441a473f Merge pull request #414 from meshtastic/ringtone-support
get and set RTTTL ringtone
2023-01-04 20:23:28 +01:00
Thomas Göttgens
7b8a83ade7 get and set RTTTL ringtone 2023-01-04 19:52:24 +01:00
github-actions
2cf1ce2898 Update protobuf submodule 2023-01-04 17:19:27 +00:00
Sacha Weatherstone
e4890bfff2 Update README.md 2023-01-02 16:49:27 +11:00
github-actions
5c6ba26334 Update protobuf submodule 2022-12-29 16:18:30 +00:00
Thomas Göttgens
e6e3ad121d Merge pull request #413 from GUVWAF/metrics
Display battery level, channel and Tx air util. with --nodes
2022-12-29 17:13:00 +01:00
Thomas Göttgens
7133c859d6 Merge pull request #411 from mkinney/fix_pylint_warnings
fix pylint warnings
2022-12-29 17:12:00 +01:00
GUVWAF
8acf0b849a --nodes displays battery, channel and Tx air util. 2022-12-29 17:00:35 +01:00
github-actions
42f6818a02 bump version 2022-12-28 16:41:43 +00:00
github-actions
af043ef5c0 Update protobuf submodule 2022-12-28 16:37:24 +00:00
github-actions
4f46858643 bump version 2022-12-27 21:23:16 +00:00
Thomas Göttgens
ddc47fb8de Merge pull request #412 from meshtastic/remote-hardware
tryfix remote hardware
2022-12-27 22:16:57 +01:00
Thomas Göttgens
7ee134b819 tryfix remote hardware 2022-12-27 21:32:25 +01:00
Ben Meadors
254e9f4015 Typos 2022-12-22 14:35:48 -06:00
Mike Kinney
babd1242d5 fix pylint warnings 2022-12-20 11:18:40 -08:00
mkinney
cc99ea009e Update README.md
fix codecoverage link
2022-12-20 11:00:01 -08:00
github-actions
76407e11f8 bump version 2022-12-06 14:44:31 +00:00
Thomas Göttgens
57719ddd5e Merge pull request #407 from GUVWAF/traceRoute
Traceroute option
2022-12-06 15:36:49 +01:00
GUVWAF
d0b8b9ff1b Forgot to convert into TRACEROUTE_APP 2022-12-06 14:18:30 +01:00
github-actions
c5c9723208 Update protobuf submodule 2022-12-06 13:16:28 +00:00
Ben Meadors
9bceaafd9c Merge pull request #406 from GUVWAF/hopLimit
Set hopLimit to the config of the device
2022-12-05 20:10:27 -06:00
GUVWAF
7d3a9178ea Add traceroute option 2022-12-05 20:36:34 +01:00
GUVWAF
2c76c0cafa Remove setting hopLimit to default
Instead set is to config of device
2022-12-05 20:04:38 +01:00
GUVWAF
82977e9ef2 Fix --ch-set help message 2022-12-05 20:02:53 +01:00
Sacha Weatherstone
7a9c25da8e Merge pull request #404 from ahmedkadd/fix-script-typo
Rename protobufs shell script to fix typo
2022-12-02 14:39:18 +11:00
Ahmed Kaddoura
342c48fb16 Rename protobufs shell script to fix typo 2022-11-30 07:58:56 -08:00
github-actions
6bc955a403 bump version 2022-11-27 12:10:59 +00:00
Ben Meadors
741ba378ab Merge pull request #402 from GUVWAF/wantResponse
Only set wantResponse for admin packets
2022-11-27 06:10:01 -06:00
GUVWAF
c1054caf4a Only set wantResponse for admin packets 2022-11-27 12:44:58 +01:00
Ben Meadors
24b97d9277 Merge pull request #401 from GUVWAF/setowner
Remove automatic short owner naming and increase to 4 characters
2022-11-26 07:56:34 -06:00
GUVWAF
868fb64857 Only set is_licensed if long_name is set 2022-11-26 11:08:00 +01:00
GUVWAF
8729e97e1b Remove automatic short owner naming and increase to 4 characters 2022-11-26 10:52:20 +01:00
github-actions
aaed54393e bump version 2022-11-22 17:03:56 +00:00
Ben Meadors
d12776bb5f Merge pull request #400 from meshtastic/transaction-for-config
Transactions for editing settings
2022-11-21 15:27:31 -06:00
Ben Meadors
7829f6afca Args 2022-11-20 20:01:50 -06:00
Ben Meadors
4bd10bc102 Add begin / edit transactions for setting updates 2022-11-20 19:46:43 -06:00
Ben Meadors
3821e02f09 Update protos 2022-11-20 19:11:38 -06:00
Ben Meadors
97689da0b4 Merge pull request #395 from GUVWAF/master
Change how admin packets to remote nodes are handled
2022-11-19 15:36:33 -06:00
GUVWAF
5c75e74bf9 Don't request config and channels if not needed.
Instead, wait for an (implicit) ACK or NAK.
Applies to admin packets set-owner, reboot,
shutdown, factory-reset and reset-nodedb.
2022-11-19 21:19:06 +01:00
GUVWAF
388a46abf4 Merge branch 'meshtastic:master' into master 2022-11-15 13:26:30 +01:00
github-actions
6b89fc81a1 bump version 2022-11-10 03:23:52 +00:00
Ben Meadors
c9b5d5d697 Update protos and add audio 2022-11-09 21:20:38 -06:00
Ben Meadors
f16dd0e737 Update url 2022-11-08 18:25:49 -06:00
Ben Meadors
5ed19eff73 Create cleanup_artifacts.yml 2022-11-05 06:52:28 -05:00
github-actions
0b3605141d bump version 2022-11-03 13:02:34 +00:00
GUVWAF
f1df14ca92 lastTried channel should be its index 2022-11-03 09:28:15 +01:00
Ben Meadors
83776ceec5 Fix url 2022-11-02 21:20:25 -05:00
GUVWAF
7aff5e9ee5 Unset wantAck if you set wantResponse for Admin 2022-11-02 09:49:20 +01:00
github-actions
bf6be107d3 bump version 2022-11-01 12:26:50 +00:00
Ben Meadors
c24d1fe26b Missing a comma! 2022-11-01 07:26:04 -05:00
Ben Meadors
61f5468847 Update setup.py 2022-11-01 07:24:54 -05:00
github-actions
c713ce04b6 bump version 2022-11-01 12:17:41 +00:00
Ben Meadors
fe2b36e04b Merge pull request #392 from meshtastic/licence-change-&-2.0-prep
License change & 2.0 Prep
2022-11-01 07:08:09 -05:00
Ben Meadors
a720916df5 Update version in setup.py 2022-10-31 08:00:29 -05:00
Sacha Weatherstone
b2593e4bb1 Changes 2022-10-31 19:47:42 +10:00
github-actions
6e3c759e5c bump version 2022-10-30 01:08:22 +00:00
github-actions
a41f33e0bd bump version 2022-10-28 15:06:14 +00:00
Ben Meadors
111bf8dcbf Update protos 2022-10-28 10:03:26 -05:00
Ben Meadors
f18abb2fe6 Update protos 2022-10-26 08:53:32 -05:00
github-actions
b7093e176a bump version 2022-10-21 16:58:02 +00:00
Ben Meadors
cf7d37a454 Update __main__.py 2022-10-21 11:53:58 -05:00
github-actions
2af431e2eb bump version 2022-10-21 12:38:51 +00:00
Ben Meadors
3db64f7988 Merge pull request #387 from meshtastic/fun-fun
Print available options
2022-10-21 07:37:56 -05:00
Ben Meadors
7ef64d4250 Print options 2022-10-21 07:27:55 -05:00
Ben Meadors
363aa995a2 Push it real good 2022-10-20 17:13:26 -05:00
github-actions
696fa28e6f bump version 2022-10-16 13:46:40 +00:00
Ben Meadors
a908bdfc1c Protos 2022-10-16 08:44:30 -05:00
Ben Meadors
81b64ac908 Merge pull request #385 from GUVWAF/master
Use new config for pos-fields
2022-10-16 08:43:38 -05:00
GUVWAF
d5ccdc826f Use new config for pos-fields 2022-10-16 15:38:18 +02:00
Ben Meadors
fac4faaae8 Merge pull request #383 from meshtastic/reboot-ota
add reboot to ota command for testing purposes.
2022-10-10 10:28:59 -05:00
Thomas Göttgens
cfb8769746 add reeboot to ota command for testing purposes. This is a developer only command for now :-) 2022-10-10 16:59:01 +02:00
github-actions
c1b0e4e8d0 bump version 2022-10-09 15:10:27 +00:00
Ben Meadors
5683e31f6b Update protos 2022-10-09 10:00:51 -05:00
Ben Meadors
7909ad477b Merge pull request #380 from GUVWAF/master
Remove additional print statements
2022-10-09 09:59:51 -05:00
github-actions
f94dbf05ef bump version 2022-10-08 12:19:51 +00:00
Ben Meadors
a44b769390 Merge pull request #381 from meshtastic/config
Get export-configuration and configure working again
2022-10-08 07:19:03 -05:00
Ben Meadors
2a4816a9cd Get configuration yaml working again 2022-10-08 07:16:20 -05:00
GUVWAF
674fd92690 Merge branch 'master' of https://github.com/GUVWAF/Meshtastic-python 2022-10-08 13:21:02 +02:00
GUVWAF
cc29cab99a Remove additional print statements 2022-10-08 13:20:28 +02:00
Ben Meadors
bf803bb6e9 Merge pull request #379 from GUVWAF/master
Catch RoutingApp response for Admin packet
2022-10-08 05:57:56 -05:00
Ben Meadors
3c80fd0f02 Protos 2022-10-08 05:57:10 -05:00
GUVWAF
616a3ab706 Catch RoutingApp on requestGetMetadata 2022-10-08 12:47:48 +02:00
GUVWAF
8350cc611d Catch RoutingApp on requestChannel 2022-10-08 12:47:13 +02:00
github-actions
621feb749d bump version 2022-10-02 14:40:33 +00:00
Ben Meadors
f6731a435d Proto baggins 2022-10-01 08:36:43 -05:00
Ben Meadors
dcfe5fb558 Merge pull request #377 from GUVWAF/master
Add KnownProtocol for Simulator_App
2022-10-01 07:59:26 -05:00
GUVWAF
4fa80e9652 Add KnownProtocol for Simulator_App 2022-10-01 11:46:40 +02:00
github-actions
02851b6237 bump version 2022-09-25 18:52:40 +00:00
Ben Meadors
a74ec12445 Reset nodedb command 2022-09-25 13:46:11 -05:00
github-actions
262e921a81 bump version 2022-09-20 02:05:17 +00:00
Ben Meadors
0c7b9e10f4 Update setup.py 2022-09-19 21:04:22 -05:00
github-actions
ab8b930365 bump version 2022-09-18 13:07:41 +00:00
Ben Meadors
4ae49c68aa Add factory reset 2022-09-18 08:05:50 -05:00
github-actions
733f22d927 bump version 2022-09-18 01:00:31 +00:00
Ben Meadors
791131ea27 Version bump fix 2022-09-17 19:59:08 -05:00
github-actions
f17292221c bump version 2022-09-18 00:42:08 +00:00
Ben Meadors
b60a438c9d Update setup.py 2022-09-17 19:30:56 -05:00
github-actions
3b3a610375 bump version 2022-09-18 00:20:12 +00:00
Ben Meadors
38f928bdb7 Update setup.py 2022-09-17 19:19:23 -05:00
github-actions
6272e992a4 bump version 2022-09-18 00:09:40 +00:00
Ben Meadors
3263fbca28 Increment build number instead 2022-09-17 19:08:41 -05:00
Ben Meadors
f0e7af389c Update setup.py 2022-09-17 18:52:53 -05:00
github-actions
471dfc7a29 bump version 2022-09-13 01:19:06 +00:00
Ben Meadors
2a7c21c062 Protos sync 2022-09-12 20:16:14 -05:00
github-actions
03797e3336 bump version 2022-09-11 13:03:34 +00:00
Ben Meadors
dc1be12c86 Update protos 2022-09-11 08:01:55 -05:00
github-actions
4c83a43d64 bump version 2022-09-09 16:44:46 +00:00
Ben Meadors
e083cda3d9 Merge pull request #371 from meshtastic/big-proto-refactor
Update python to use reworked protos
2022-09-09 11:43:10 -05:00
Ben Meadors
c0006f888b Add alpha back for upcoming release 2022-09-09 11:05:10 -05:00
Ben Meadors
e2d2d3a347 Refactor 2022-09-09 11:02:58 -05:00
Ben Meadors
3fd50b0e44 Update python to use reworked protos 2022-09-09 09:49:04 -05:00
github-actions
4b0e3ae923 bump version 2022-09-08 21:43:54 +00:00
Ben Meadors
37f10cc0d4 Remove alpha 2022-09-08 15:55:19 -05:00
github-actions
998df265e6 bump version 2022-09-08 12:11:11 +00:00
Ben Meadors
d852981371 Med 2022-09-08 07:09:25 -05:00
Ben Meadors
afed5bd943 Fixed med preset names 2022-09-08 07:09:13 -05:00
Ben Meadors
97b9041b76 Merge pull request #368 from ghostop14/master
Fixes #367 MedFast Enum Not Defined
2022-09-08 06:58:18 -05:00
Ben Meadors
2dc14ef466 Merge pull request #369 from rohanki/master
Fix for --setalt --setlat --setlon
2022-09-05 20:30:29 -05:00
Rohan King
8e69c32a36 Fix for --setalt --setlat --setlon
fix for --setalt --setlat and --setlon
2022-09-06 10:23:19 +10:00
github-actions
42b33bea5b bump version 2022-09-03 14:03:36 +00:00
Ben Meadors
7fd101cbf8 Update protos and fix error 2022-09-03 09:02:36 -05:00
ghostop14
92ee9889b1 Fixes #367 MedFast Enum Not Defined 2022-09-02 10:44:59 -04:00
github-actions
b6e1610abe bump version 2022-08-27 13:37:05 +00:00
Ben Meadors
bde5db9c51 Fixed ch-set command in setPref 2022-08-27 08:14:48 -05:00
github-actions
148ae49ded bump version 2022-08-25 18:25:24 +00:00
Ben Meadors
d1f8365da1 Merge pull request #363 from meshtastic/channel-url
Channel setting fixed
2022-08-25 13:24:20 -05:00
Ben Meadors
59fc294d66 Channel setting fixed 2022-08-25 13:22:05 -05:00
github-actions
7473b4e18c bump version 2022-08-17 02:49:05 +00:00
Ben Meadors
58aafcf3f1 Merge pull request #361 from Douile/dev-change-channel
Fix changing modem_preset from CLI shortcuts
2022-08-16 08:58:56 -05:00
Douile
776fc57c35 Fix changing modem_preset from CLI shortcuts
Previously the channel shortcuts (e.g. --ch-shortfast) would overrwrite
the entire lora config, this meant you lost other configured things such
as region. This patch changes that so that just modem_preset is
overwritten, and also fixes the call to write config that was missing
an argument.
2022-08-16 14:55:17 +01:00
Ben Meadors
b3f752a3c4 Merge pull request #360 from meshtastic/bt-canned
Bluetooth and canned messages changes
2022-08-15 21:01:44 -05:00
Ben Meadors
4965ec7f1d Missed some spots 2022-08-15 20:54:11 -05:00
Ben Meadors
0746acd34f Canned messages and bluetooth sections 2022-08-15 19:01:37 -05:00
github-actions
49b1c4816e bump version 2022-08-11 17:46:19 +00:00
Ben Meadors
7c6e87e161 Merge pull request #356 from meshtastic/increase-timeouts
Only write single config
2022-08-11 12:45:12 -05:00
Ben Meadors
b548700c0b Only write single config 2022-08-11 12:43:41 -05:00
github-actions
f278a30003 bump version 2022-08-11 16:53:26 +00:00
Ben Meadors
22bbe67d24 Merge pull request #355 from meshtastic/increase-timeouts
Increase delay for reliability
2022-08-11 11:51:09 -05:00
Ben Meadors
a2861a133e Increase delay for reliability 2022-08-11 11:48:57 -05:00
github-actions
03aab10786 bump version 2022-08-09 11:29:44 +00:00
Ben Meadors
95e768efd5 Merge pull request #354 from meshtastic/device-metadata
Add get device metadata admin message
2022-08-08 07:07:47 -05:00
Ben Meadors
6644e86be9 Add get device metadata admin message 2022-08-08 07:04:29 -05:00
Ben Meadors
c8363cd476 Merge pull request #352 from Douile/dev-export-valid-yaml
Replace the primative print based config generator with proper yaml serialization
2022-08-05 10:14:42 -05:00
Ben Meadors
62efe1ab7f Merge pull request #353 from Douile/dev-fix-lint-errors-2
Fix lint errors
2022-08-05 10:13:58 -05:00
Douile
01e643ad2f Fix lint errors 2022-08-05 13:48:07 +01:00
Douile
e4078e84d7 Fix linting errors caused by this PR 2022-08-05 13:34:25 +01:00
Ben Meadors
abfcbe2a90 Merge pull request #350 from Douile/dev-base64-decode
Allow setting values from base64 values
2022-07-28 17:42:08 -05:00
Douile
e06d8bbc06 Use pyyaml to generate valid configuration output
The custom yaml generator made an invalid yaml file that needed to be
fixed, by using the already included pyyaml library we can make sure the
output is valid.
2022-07-28 15:11:35 +01:00
Ben Meadors
a78cdde86f Merge pull request #349 from Douile/dev-fix-errors
Fix crash when trying to set value that doesn't exist
2022-07-27 18:53:44 -05:00
Douile
10517ac94d Allow setting values from base64 values
By prefixing a value with "base64:" e.g. ("base64:AQ==") it will now be
decoded to raw bytes. This is useful when setting psk as that is often
shown as base64.
2022-07-27 15:12:23 +01:00
Douile
a572699588 Fix crash when trying to set value that doesn't exist 2022-07-27 15:09:58 +01:00
github-actions
d11fb47734 bump version 2022-07-02 19:52:35 +00:00
Ben Meadors
92c7b2db69 Merge pull request #348 from meshtastic/moduleconfg
100ms delays to prevent overloading the serial
2022-07-02 14:43:24 -05:00
Ben Meadors
ff94ad968c 100ms delays to prevent overloading the serial 2022-07-02 14:41:09 -05:00
github-actions
c6071c57ec bump version 2022-06-30 01:17:37 +00:00
Ben Meadors
e3e3562c2c Merge pull request #347 from meshtastic/moduleconfg
Module config progress
2022-06-29 20:16:37 -05:00
Ben Meadors
06b5b8fa83 It works, I think 2022-06-29 20:01:48 -05:00
Ben Meadors
4b95b0ff30 Module config progress 2022-06-29 18:35:06 -05:00
Thomas Göttgens
42f2ed571d Merge pull request #346 from meshtastic/patch-1
small issues corrected
2022-06-21 19:38:01 +02:00
Thomas Göttgens
f3791c5c6d - make segemented config print entire name on screen
- rename wifi password to psk
2022-06-21 19:29:54 +02:00
github-actions
4cff344971 bump version 2022-06-21 16:18:33 +00:00
Ben Meadors
594b307e94 Merge pull request #344 from meshtastic/patch-1
Get and Set general attributes working.
2022-06-21 08:23:58 -05:00
Ben Meadors
8a5fd16469 Don't blow away config please 2022-06-21 08:05:15 -05:00
Ben Meadors
4fa93989fa Don't need to pass interface down 2022-06-19 15:41:21 -05:00
Ben Meadors
032072d2f3 Started on set 2022-06-19 09:55:09 -05:00
Ben Meadors
ce7b1d9916 Get preferences now working 2022-06-19 08:17:28 -05:00
Thomas Göttgens
d015da3ca1 Get and Set general attributes almost working. 2022-06-18 14:53:04 +02:00
Thomas Göttgens
a956c8068c Merge pull request #343 from meshtastic/patch-1
Untangle Modem Presets from Channels
2022-06-18 13:41:38 +02:00
Thomas Göttgens
2124e292f1 Untangle Modem Presets from Channels 2022-06-18 13:38:08 +02:00
Ben Meadors
115739a9bb Merge pull request #342 from meshtastic/nanopb-upgrade
Github action protos version
2022-06-17 08:39:00 -05:00
Ben Meadors
cc2c16b957 Github action protos version 2022-06-17 08:33:13 -05:00
Thomas Göttgens
b9245c6c1f Merge pull request #341 from meshtastic/patch-1
almost working
2022-06-17 12:40:06 +02:00
Thomas Göttgens
d21f7811fa where did that came from? 2022-06-17 12:37:50 +02:00
Thomas Göttgens
8dbd6431f7 almost working 2022-06-17 12:31:18 +02:00
Thomas Göttgens
c7b2bbf700 Merge pull request #340 from meshtastic/patch-1
remove "Request Settings" during init, team settings and deprecated settings.
2022-06-17 10:59:54 +02:00
Thomas Göttgens
682fdb7ef4 Remove test for deprecated option 2022-06-17 10:57:39 +02:00
Thomas Göttgens
9c79f9d80e Wait again, since we don't request config manually 2022-06-17 10:54:31 +02:00
Thomas Göttgens
c55b1188e8 remove "Request Settings" during init, team settings and deprecated settings. 2022-06-17 10:40:40 +02:00
github-actions
d5e4eaf2d8 bump version 2022-06-17 05:53:24 +00:00
mkinney
d49cc74828 Merge pull request #339 from mkinney/hack_13
Hack 13
2022-06-16 22:49:22 -07:00
Mike Kinney
47781fa1e0 remove unused import 2022-06-16 22:46:04 -07:00
Mike Kinney
cc98ed1084 comment yet another test 2022-06-16 22:43:42 -07:00
Mike Kinney
bec8cf2b13 change the d to an e 2022-06-16 22:40:48 -07:00
Mike Kinney
5bfebbe436 comment out code until it does not complain 2022-06-16 22:38:23 -07:00
Mike Kinney
c02a4d8138 Merge remote-tracking branch 'upstream/master' 2022-06-16 19:35:58 -07:00
mkinney
15aae34d65 Merge pull request #338 from mkinney/bump_nanopb
Bump nanopb
2022-06-16 19:30:46 -07:00
Mike Kinney
89b0426a2b fix warnings now that tests have been commented out 2022-06-16 19:26:52 -07:00
Mike Kinney
e1f1cab5a5 comment out failing tests (for now) 2022-06-16 19:22:13 -07:00
Mike Kinney
132fb4fe5f get pylint to pass 2022-06-16 19:13:18 -07:00
Mike Kinney
f1843649ba bump nanopb 2022-06-16 18:57:40 -07:00
Mike Kinney
43b7bbb5b3 Merge remote-tracking branch 'upstream/master' 2022-06-16 18:37:40 -07:00
Ben Meadors
b79b7ceb40 Correct config 2022-06-16 20:31:14 -05:00
Ben Meadors
2a546f8899 Merge master 2022-06-16 16:57:31 -05:00
Ben Meadors
a4a0740903 Regen protos 2022-06-16 16:57:05 -05:00
Ben Meadors
075ad01e46 Merge pull request #336 from meshtastic/change-default-baud
Changed baud to 115200
2022-06-15 11:46:31 -05:00
Ben Meadors
1296a1ce28 Changed baud to 115200 2022-06-15 10:58:55 -05:00
Thomas Göttgens
d510ba15c5 Trunk Protos 2022-06-09 12:20:13 +02:00
Jm Casler
decc887cb5 updating proto submodule to latest 2022-05-21 17:10:27 -07:00
Mike Kinney
163f7eeaaa update proto 2022-05-19 10:09:25 -07:00
Ben Meadors
d15667d5ce Regened new protos 2022-05-19 07:24:39 -05:00
Sacha Weatherstone
39a7869524 Update README.md 2022-05-12 21:52:04 +10:00
Sacha Weatherstone
c9464d2595 Update README.md 2022-05-12 21:28:38 +10:00
Sacha Weatherstone
717de611b9 Update ci.yml 2022-05-12 21:28:09 +10:00
Jm Casler
85869cf595 updating proto submodule to latest 2022-05-01 18:33:44 -07:00
Jm Casler
03ca28e0d2 updating proto submodule to latest 2022-05-01 08:42:04 -07:00
github-actions
a3bdf976bb bump version 2022-04-27 18:40:29 +00:00
mkinney
bf6eec626c Merge pull request #328 from mkinney/master
add nano_g1
2022-04-27 11:35:44 -07:00
Mike Kinney
cd0bdbbd9c add nano_g1 2022-04-27 11:29:05 -07:00
github-actions
e7faa85476 bump version 2022-04-27 12:33:09 +00:00
Ben Meadors
e419f95910 Merge pull request #327 from meshtastic/device-updates-release
Updated protos
2022-04-27 07:21:56 -05:00
Ben Meadors
ee613104f1 Updated protos 2022-04-27 07:19:08 -05:00
github-actions
93a8722b22 bump version 2022-04-25 07:20:32 +00:00
Thomas Göttgens
73b06248aa Update __init__.py
Device firmware requires 20300 now - change coming from android.
2022-04-25 09:15:33 +02:00
Jm Casler
82169f9d58 updating proto submodule to latest 2022-04-20 18:01:40 -07:00
github-actions
1fa71f2e2d bump version 2022-04-18 23:38:33 +00:00
mkinney
af599ab320 Merge pull request #326 from mkinney/master
update protos
2022-04-18 16:37:41 -07:00
Mike Kinney
99eed4bb5c remove send_owner_interval 2022-04-18 16:35:06 -07:00
Jm Casler
d8deb90527 updating proto submodule to latest 2022-04-18 12:29:23 -07:00
Mike Kinney
37a0010714 Merge remote-tracking branch 'upstream/master' 2022-04-18 11:53:16 -07:00
Mike Kinney
3c298df5ce update protos 2022-04-18 11:49:43 -07:00
Jm Casler
c6a8618d33 updating proto submodule to latest 2022-04-15 22:30:23 -07:00
Jm Casler
f19ddf66b8 updating proto submodule to latest 2022-04-12 21:10:46 -07:00
github-actions
203d5246eb bump version 2022-04-11 21:27:30 +00:00
mkinney
b78276e49a Merge pull request #323 from mkinney/master
fix smoke1 tests; regen protobufs
2022-04-11 14:26:00 -07:00
Mike Kinney
bd4d309d89 update codecov 2022-04-11 14:23:49 -07:00
Mike Kinney
804c09b6c5 bump to v2 of codecov 2022-04-11 14:18:38 -07:00
Mike Kinney
92202807f7 update/regen protobufs 2022-04-11 14:07:04 -07:00
Mike Kinney
0c92460163 got smoke1 tests to pass 2022-04-11 13:58:56 -07:00
Mike Kinney
8bb570d222 fix smoke1 tests 2022-04-11 13:17:39 -07:00
mkinney
f1abce9eff Merge pull request #322 from amerinoj/master
fixed set and get canned message
2022-04-11 12:48:50 -07:00
chst
1fc46a3c02 fixed set and get canned message
replacement the entries "get canned_message plugin" to get_canned_message_module_" in node.py
2022-04-10 19:21:57 +02:00
Jm Casler
1d45adfb27 Update README.md 2022-04-07 16:31:27 -07:00
mkinney
8365ad5d1b Merge pull request #316 from mkinney/master
fix tests for 1.3
2022-03-31 14:22:41 -07:00
Mike Kinney
00346ea441 fix tests for 1.3 2022-03-31 14:18:53 -07:00
github-actions
ae70d34dd6 bump version 2022-03-31 17:29:03 +00:00
mkinney
e0ef62d1b3 Merge pull request #315 from mkinney/master
detect devices only using vendor id
2022-03-31 10:28:04 -07:00
Mike Kinney
02e8467fdd detect devices only using vendor id 2022-03-31 10:24:17 -07:00
github-actions
48e7f8c755 bump version 2022-03-30 21:00:08 +00:00
mkinney
19b607b3f2 Merge pull request #314 from mkinney/master
add epaper; fix product id on 5005/4631
2022-03-30 13:59:15 -07:00
Mike Kinney
1d827ab2bf add epaper; fix product id on 5005/4631 2022-03-30 13:56:19 -07:00
github-actions
7af886cf07 bump version 2022-03-30 18:48:11 +00:00
mkinney
a76ad6c686 Merge pull request #313 from mkinney/master
regen code from latest protobufs
2022-03-30 11:36:33 -07:00
Mike Kinney
3d9a55add3 regen code from updated protobufs 2022-03-30 11:32:47 -07:00
Mike Kinney
4ceac5e847 Merge remote-tracking branch 'upstream/master' 2022-03-30 11:25:45 -07:00
Jm Casler
0939022cb4 updating proto submodule to latest 2022-03-29 21:44:51 -07:00
Jm Casler
f7afb9ff15 updating proto submodule to latest 2022-03-29 20:04:43 -07:00
Jm Casler
13fd4ba614 updating proto submodule to latest 2022-03-26 09:32:15 -07:00
Jm Casler
2f80c9866a updating proto submodule to latest 2022-03-25 22:30:43 -07:00
Jm Casler
e2bca647ae updating proto submodule to latest 2022-03-25 22:23:58 -07:00
mkinney
ec2467486c Merge pull request #302 from raldi/master
Added examples/tcp_gps_example.py
2022-03-22 15:10:25 -07:00
Mike Schiraldi
3332271a97 lint 2022-03-22 12:41:50 -07:00
github-actions
7fdfd782d8 bump version 2022-03-21 17:50:05 +00:00
Mike Kinney
af7bf7ff7f add wifi min length check 2022-03-21 10:48:27 -07:00
github-actions
b6dc4d0bd2 bump version 2022-03-16 03:26:41 +00:00
Mike Schiraldi
ef9441e7d2 Added examples/tcp_gps_example.py 2022-03-14 23:32:42 -07:00
57 changed files with 3600 additions and 6230 deletions

View File

@@ -1,4 +1,4 @@
name: Linting and Tests name: CI
on: on:
push: push:
branches: branches:
@@ -42,14 +42,14 @@ jobs:
run: | run: |
pytest --cov=meshtastic --cov-report=xml pytest --cov=meshtastic --cov-report=xml
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v2
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml files: ./coverage.xml
flags: unittests flags: unittests
name: codecov-umbrella name: codecov-umbrella
yml: ./codecov.yml
fail_ci_if_error: true fail_ci_if_error: true
verbose: true
validate: validate:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:

20
.github/workflows/cleanup_artifacts.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Remove old artifacts
on:
schedule:
# Every day at 1am
- cron: '0 1 * * *'
workflow_dispatch:
jobs:
remove-old-artifacts:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Remove old artifacts
uses: c-hive/gha-remove-artifacts@v1
with:
age: '1 month'
skip-tags: true

View File

@@ -15,22 +15,22 @@ jobs:
run: | run: |
git pull --recurse-submodules git pull --recurse-submodules
git submodule update --remote --recursive git submodule update --remote --recursive
- name: Download nanopb - name: Download nanopb
run: | run: |
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.4-linux-x86.tar.gz wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.6-linux-x86.tar.gz
tar xvzf nanopb-0.4.4-linux-x86.tar.gz tar xvzf nanopb-0.4.6-linux-x86.tar.gz
mv nanopb-0.4.4-linux-x86 nanopb-0.4.4 mv nanopb-0.4.6-linux-x86 nanopb-0.4.6
- name: Re-generate protocol buffers - name: Re-generate protocol buffers
run: | run: |
./bin/regen-protos.sh ./bin/regen-protobufs.sh
- name: Commit update - name: Commit update
run: | run: |
git config --global user.name 'github-actions' git config --global user.name 'github-actions'
git config --global user.email 'bot@noreply.github.com' 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 remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
git add proto git add protobufs
git add meshtastic git add meshtastic
git commit -m "Update protobuf submodule" && git push || echo "No changes to commit" git commit -m "Update protobuf submodule" && git push || echo "No changes to commit"

3
.gitignore vendored
View File

@@ -5,8 +5,7 @@ dist
*.egg-info *.egg-info
log_* log_*
.eggs .eggs
nanopb-0.4.4 nanopb-*
nanopb-0.4.5
.*swp .*swp
.coverage .coverage
*.py-E *.py-E

6
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "proto"] [submodule "protobufs"]
path = proto path = protobufs
url = https://github.com/meshtastic/Meshtastic-protobufs.git url = http://github.com/meshtastic/protobufs

View File

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

93
.vscode/launch.json vendored
View File

@@ -42,7 +42,87 @@
"request": "launch", "request": "launch",
"module": "meshtastic", "module": "meshtastic",
"justMyCode": true, "justMyCode": true,
"args": ["--debug" ] "args": ["--debug"]
},
{
"name": "meshtastic debug getPref",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--get", "power.is_power_saving"]
},
{
"name": "meshtastic debug getPref telemetry",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--get", "telemetry.environment_update_interval"]
},
{
"name": "meshtastic debug info",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--info"]
},
{
"name": "meshtastic debug set region",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--set", "lora.region", "TW"]
},
{
"name": "meshtastic debug set bluetooth fixed pin",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--set", "bluetooth.fixed_pin", "555555"]
},
{
"name": "meshtastic debug get bluetooth fixed pin",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--get", "bluetooth.fixed_pin"]
},
{
"name": "meshtastic debug setPref",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--set", "power.is_power_saving", "1"]
},
{
"name": "meshtastic debug setPref telemetry.environment_measurement_enabled",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--set", "telemetry.environment_measurement_enabled", "1"]
},
{
"name": "meshtastic debug setPref telemetry.environment_screen_enabled",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--set", "telemetry.environment_screen_enabled", "1"]
},
{
"name": "meshtastic debug setPref telemetry",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--set", "telemetry.environment_measurement_enabled", "1"]
}, },
{ {
"name": "meshtastic setpref", "name": "meshtastic setpref",
@@ -52,6 +132,15 @@
"justMyCode": true, "justMyCode": true,
"args": ["--debug", "--setchan", "psk", ""] "args": ["--debug", "--setchan", "psk", ""]
}, },
{
"name": "meshtastic --ch-set",
"type": "python",
"request": "launch",
"module": "meshtastic",
"justMyCode": true,
"args": ["--debug", "--ch-set", "channel_num", "0", "--ch-index", "0"]
},
{ {
"name": "meshtastic seturl", "name": "meshtastic seturl",
"type": "python", "type": "python",
@@ -92,7 +181,7 @@
"module": "meshtastic", "module": "meshtastic",
"justMyCode": true, "justMyCode": true,
"args": ["--debug", "--sendtext", "pytest"] "args": ["--debug", "--sendtext", "pytest"]
} },
{ {
"name": "meshtastic showNodes", "name": "meshtastic showNodes",
"type": "python", "type": "python",

View File

@@ -6,6 +6,10 @@ test:
virt: virt:
pytest -m smokevirt pytest -m smokevirt
# run the smoke1 test (after doing a factory reset and unplugging/replugging in device)
smoke1:
pytest -m smoke1 -s -vv
# local install # local install
install: install:
pip install . pip install .
@@ -22,11 +26,11 @@ lint:
slow: slow:
pytest -m unit --durations=5 pytest -m unit --durations=5
proto: FORCE protobufs: FORCE
git submodule update --init --recursive git submodule update --init --recursive
git pull --rebase git pull --rebase
git submodule update --remote --merge git submodule update --remote --merge
./bin/regen-protos.sh ./bin/regen-protobufs.sh
# run the coverage report and open results in a browser # run the coverage report and open results in a browser
cov: cov:

View File

@@ -1,15 +1,23 @@
# Meshtastic-python # Meshtastic Python
[![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) [![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) ![PyPI - Downloads](https://img.shields.io/pypi/dm/meshtastic)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/python/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/python/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/python)](https://cla-assistant.io/meshtastic/python)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
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. ## Overview
Full documentation including examples [here](https://meshtastic.org/docs/software/python/python-installation). A Python client for use with Meshtastic 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.
The library api is documented [here](https://meshtastic-python.vercel.app/meshtastic/index.html) **[Getting Started Guide](https://meshtastic.org/docs/software/python/cli/installation)**
**[Documentation/API Reference](https://python.meshtastic.org/)**
[![Powered by Vercel](https://raw.githubusercontent.com/abumalick/powered-by-vercel/master/powered-by-vercel.svg)](https://vercel.com?utm_source=meshtastic&utm_campaign=oss) ## Stats
![Alt](https://repobeats.axiom.co/api/embed/c71ee8fc4a79690402e5d2807a41eec5e96d9039.svg "Repobeats analytics image")

View File

@@ -34,7 +34,7 @@ Basic functionality is complete now.
- DONE add fromId and toId to received messages dictionaries - DONE add fromId and toId to received messages dictionaries
- make command line options for displaying/changing config - make command line options for displaying/changing config
- update nodedb as nodes change - update nodedb as nodes change
- radioConfig - getter/setter syntax: https://www.python-course.eu/python3_properties.php - localConfig - getter/setter syntax: https://www.python-course.eu/python3_properties.php
- let user change radio params via commandline options - let user change radio params via commandline options
- keep nodedb up-to-date based on received MeshPackets - keep nodedb up-to-date based on received MeshPackets
- handle radio reboots and redownload db when that happens. Look for a special FromRadio.rebooted packet - handle radio reboots and redownload db when that happens. Look for a special FromRadio.rebooted packet

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
"""Bump the version number""" """Bump the version number"""
import re
version_filename = "setup.py" version_filename = "setup.py"
@@ -19,7 +20,9 @@ with open(version_filename, 'w', encoding='utf-8') as f:
words = line.split("=") words = line.split("=")
# split the version into parts (by period) # split the version into parts (by period)
v = words[1].split(".") v = words[1].split(".")
ver = f'{v[0]}.{v[1]}.{int(v[2]) + 1}' build_num = re.findall(r"\d+", v[2])[0]
new_build_num = str(int(build_num)+1)
ver = f'{v[0]}.{v[1]}.{v[2].replace(build_num, new_build_num)}'.replace('\n', '')
f.write(f' version="{ver}",\n') f.write(f' version="{ver}",\n')
else: else:
f.write(line) f.write(line)

View File

@@ -1,15 +1,19 @@
#!/bin/bash #!/bin/bash
./nanopb-0.4.5/generator-bin/protoc -I=proto --python_out meshtastic `ls proto/*.proto` #Uncomment to run hack
#gsed -i 's/import "\//import ".\//g' ./protobufs/meshtastic/*
#gsed -i 's/package meshtastic;//g' ./protobufs/meshtastic/*
./nanopb-0.4.6/generator-bin/protoc -I=protobufs --python_out ./ ./protobufs/meshtastic/*.proto
# workaround for import bug in protoc https://github.com/protocolbuffers/protobuf/issues/1491#issuecomment-690618628 # workaround for import bug in protoc https://github.com/protocolbuffers/protobuf/issues/1491#issuecomment-690618628
if [[ $OSTYPE == 'darwin'* ]]; then 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) # automate the current workaround (may be related to Meshtastic-protobufs issue #27 https://github.com/meshtastic/protobufs/issues/27)
sed -i '' -E "s/^None = 0/globals()['None'] = 0/" meshtastic/mesh_pb2.py sed -i '' -E "s/^None = 0/globals()['None'] = 0/" meshtastic/mesh_pb2.py
else 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) # automate the current workaround (may be related to Meshtastic-protobufs issue #27 https://github.com/meshtastic/protobufs/issues/27)
sed -i -e "s/^None = 0/globals()['None'] = 0/" meshtastic/mesh_pb2.py sed -i -e "s/^None = 0/globals()['None'] = 0/" meshtastic/mesh_pb2.py
fi fi

View File

@@ -12,6 +12,5 @@ location:
userPrefs: userPrefs:
region: 1 region: 1
isAlwaysPowered: 'true' isAlwaysPowered: 'true'
sendOwnerInterval: 2
screenOnSecs: 31536000 screenOnSecs: 31536000
waitBluetoothSecs: 31536000 waitBluetoothSecs: 31536000

View File

@@ -2,17 +2,42 @@
owner: Bob TBeam owner: Bob TBeam
owner_short: BOB owner_short: BOB
channel_url: https://www.meshtastic.org/d/#CgUYAyIBAQ channel_url: https://www.meshtastic.org/e/#CgMSAQESCDgBQANIAVAe
location: location:
lat: 35.88888 lat: 35.88888
lon: -93.88888 lon: -93.88888
alt: 304 alt: 304
user_prefs: config:
region: 1 bluetooth:
is_always_powered: 'true' enabled: true
send_owner_interval: 2 fixedPin: 123456
screen_on_secs: 31536000 device:
wait_bluetooth_secs: 31536000 serialEnabled: true
location_share: 'LocEnabled' display:
screenOnSecs: 600
lora:
region: US
hopLimit: 3
txEnabled: true
txPower: 30
network:
ntpServer: 0.pool.ntp.org
position:
gpsAttemptTime: 900
gpsEnabled: true
gpsUpdateInterval: 120
positionBroadcastSecs: 900
positionBroadcastSmartEnabled: true
positionFlags: 3
power:
lsSecs: 300
meshSdsTimeoutSecs: 7200
minWakeSecs: 10
sdsSecs: 4294967295
module_config:
telemetry:
deviceUpdateInterval: 900
environmentUpdateInterval: 900

View File

@@ -0,0 +1,14 @@
"""Demonstration of how to look up a radio's location via its LAN connection.
Before running, connect your machine to the same WiFi network as the radio.
"""
import meshtastic
import meshtastic.tcp_interface
radio_hostname = "meshtastic.local" # Can also be an IP
iface = meshtastic.tcp_interface.TCPInterface(radio_hostname)
my_node_num = iface.myInfo.my_node_num
pos = iface.nodesByNum[my_node_num]["position"]
print (pos)
iface.close()

30
info/mac/nano_g1.txt Normal file
View File

@@ -0,0 +1,30 @@
meshtastic detected port: /dev/cu.wchusbserial53820208781
ioreg -p IOUSB
shows this:
| +-o USB Single Serial@14300000 <class AppleUSBDevice, id 0x1000407a5, registered, matched, active, busy 0 (18 ms), retain 14>
system_profiler SPUSBDataType > /tmp/a
with device plugged in
system_profiler SPUSBDataType > /tmp/b
with device not plugged in
diff /tmp/a /tmp/b
< USB Single Serial:
<
< Product ID: 0x55d4
< Vendor ID: 0x1a86
< Version: 4.43
< Serial Number: 5382020878
< Speed: Up to 12 Mb/s
< Location ID: 0x14300000 / 63
< Current Available (mA): 500
< Current Required (mA): 134
< Extra Operating Current (mA): 0

91
info/ubuntu/nano_g1.txt Normal file
View File

@@ -0,0 +1,91 @@
lsusb -d 1a86: -v
Bus 001 Device 013: 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 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

39
info/windows/nano_g1.txt Normal file
View File

@@ -0,0 +1,39 @@
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 (COM9) =>
Description : USB-Enhanced-SERIAL CH9102 =>
Name : USB-Enhanced-SERIAL CH9102 (COM9) =>
DeviceID : USB\VID_1A86&PID_55D4\5382020745 =>
PNPDeviceID : USB\VID_1A86&PID_55D4\5382020745 =>
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 (COM9) =>
InstanceId : USB\VID_1A86&PID_55D4\5382020745 =>
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 : =>
=>

View File

@@ -3,11 +3,11 @@
Primary class: SerialInterface Primary class: SerialInterface
Install with pip: "[pip3 install meshtastic](https://pypi.org/project/meshtastic/)" Install with pip: "[pip3 install meshtastic](https://pypi.org/project/meshtastic/)"
Source code on [github](https://github.com/meshtastic/Meshtastic-python) Source code on [github](https://github.com/meshtastic/python)
properties of SerialInterface: properties of SerialInterface:
- radioConfig - Current radio configuration and device settings, if you write to this the new settings will be applied to - localConfig - Current radio configuration and device settings, if you write to this the new settings will be applied to
the device. the device.
- nodes - The database of received nodes. Includes always up-to-date location and username information for each - nodes - The database of received nodes. Includes always up-to-date location and username information for each
node in the mesh. This is a read-only datastructure. node in the mesh. This is a read-only datastructure.
@@ -80,7 +80,7 @@ from meshtastic.util import fixme, catchAndIgnore, stripnl, DeferredExecution, T
from meshtastic.node import Node from meshtastic.node import Node
from meshtastic import (mesh_pb2, portnums_pb2, apponly_pb2, admin_pb2, from meshtastic import (mesh_pb2, portnums_pb2, apponly_pb2, admin_pb2,
telemetry_pb2, remote_hardware_pb2, telemetry_pb2, remote_hardware_pb2,
channel_pb2, radioconfig_pb2, util) channel_pb2, config_pb2, util)
# Note: To follow PEP224, comments should be after the module variable. # Note: To follow PEP224, comments should be after the module variable.
@@ -94,7 +94,7 @@ BROADCAST_NUM = 0xffffffff
BROADCAST_ADDR = "^all" BROADCAST_ADDR = "^all"
"""A special ID that means broadcast""" """A special ID that means broadcast"""
OUR_APP_VERSION = 20200 OUR_APP_VERSION = 20300
"""The numeric buildnumber (shared with android apps) specifying the """The numeric buildnumber (shared with android apps) specifying the
level of device code we are guaranteed to understand level of device code we are guaranteed to understand
@@ -182,5 +182,7 @@ protocols = {
portnums_pb2.PortNum.ADMIN_APP: KnownProtocol("admin", admin_pb2.AdminMessage), portnums_pb2.PortNum.ADMIN_APP: KnownProtocol("admin", admin_pb2.AdminMessage),
portnums_pb2.PortNum.ROUTING_APP: KnownProtocol("routing", mesh_pb2.Routing), portnums_pb2.PortNum.ROUTING_APP: KnownProtocol("routing", mesh_pb2.Routing),
portnums_pb2.PortNum.TELEMETRY_APP: KnownProtocol("telemetry", telemetry_pb2.Telemetry), portnums_pb2.PortNum.TELEMETRY_APP: KnownProtocol("telemetry", telemetry_pb2.Telemetry),
portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol("remotehw", remote_hardware_pb2.HardwareMessage) portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol("remotehw", remote_hardware_pb2.HardwareMessage),
portnums_pb2.PortNum.SIMULATOR_APP: KnownProtocol("simulator", mesh_pb2.Compressed),
portnums_pb2.PortNum.TRACEROUTE_APP: KnownProtocol("traceroute", mesh_pb2.RouteDiscovery)
} }

View File

@@ -12,11 +12,12 @@ import yaml
from pubsub import pub from pubsub import pub
import pyqrcode import pyqrcode
import pkg_resources import pkg_resources
from google.protobuf.json_format import MessageToDict
import meshtastic.util import meshtastic.util
import meshtastic.test import meshtastic.test
from meshtastic import remote_hardware from meshtastic import remote_hardware
from meshtastic.ble_interface import BLEInterface from meshtastic.ble_interface import BLEInterface
from meshtastic import portnums_pb2, channel_pb2, radioconfig_pb2 from meshtastic import portnums_pb2, channel_pb2, config_pb2
from meshtastic.globals import Globals from meshtastic.globals import Globals
from meshtastic.__init__ import BROADCAST_ADDR from meshtastic.__init__ import BROADCAST_ADDR
@@ -52,74 +53,101 @@ def onConnection(interface, topic=pub.AUTO_TOPIC): # pylint: disable=W0613
print(f"Connection changed: {topic.getName()}") print(f"Connection changed: {topic.getName()}")
def getPref(attributes, name): def getPref(node, comp_name):
"""Get a channel or preferences value""" """Get a channel or preferences value"""
camel_name = meshtastic.util.snake_to_camel(name) name = splitCompoundName(comp_name)
wholeField = name[0] == name[1] # We want the whole field
camel_name = meshtastic.util.snake_to_camel(name[1])
# Note: protobufs has the keys in snake_case, so snake internally # Note: protobufs has the keys in snake_case, so snake internally
snake_name = meshtastic.util.camel_to_snake(name) snake_name = meshtastic.util.camel_to_snake(name[1])
logging.debug(f'snake_name:{snake_name} camel_name:{camel_name}') logging.debug(f'snake_name:{snake_name} camel_name:{camel_name}')
logging.debug(f'use camel:{Globals.getInstance().get_camel_case()}') logging.debug(f'use camel:{Globals.getInstance().get_camel_case()}')
objDesc = attributes.DESCRIPTOR # First validate the input
field = objDesc.fields_by_name.get(snake_name) localConfig = node.localConfig
if not field: moduleConfig = node.moduleConfig
found = False
for config in [localConfig, moduleConfig]:
objDesc = config.DESCRIPTOR
config_type = objDesc.fields_by_name.get(name[0])
pref = False
if config_type:
pref = config_type.message_type.fields_by_name.get(snake_name)
if pref or wholeField:
found = True
break
if not found:
if Globals.getInstance().get_camel_case(): if Globals.getInstance().get_camel_case():
print(f"{attributes.__class__.__name__} does not have an attribute called {camel_name}, so you can not get it.") print(f"{localConfig.__class__.__name__} and {moduleConfig.__class__.__name__} do not have an attribute {snake_name}.")
else: else:
print(f"{attributes.__class__.__name__} does not have an attribute called {snake_name}, so you can not get it.") print(f"{localConfig.__class__.__name__} and {moduleConfig.__class__.__name__} do not have attribute {snake_name}.")
print(f"Choices in sorted order are:") print("Choices are...")
names = [] printConfig(localConfig)
for f in objDesc.fields: printConfig(moduleConfig)
tmp_name = f'{f.name}' return False
# Check if we need to request the config
if len(config.ListFields()) != 0:
# read the value
config_values = getattr(config, config_type.name)
if not wholeField:
pref_value = getattr(config_values, pref.name)
if Globals.getInstance().get_camel_case(): if Globals.getInstance().get_camel_case():
tmp_name = meshtastic.util.snake_to_camel(tmp_name) print(f"{str(config_type.name)}.{camel_name}: {str(pref_value)}")
names.append(tmp_name) logging.debug(f"{str(config_type.name)}.{camel_name}: {str(pref_value)}")
for temp_name in sorted(names): else:
print(f" {temp_name}") print(f"{str(config_type.name)}.{snake_name}: {str(pref_value)}")
return logging.debug(f"{str(config_type.name)}.{snake_name}: {str(pref_value)}")
else:
print(f"{str(config_type.name)}:\n{str(config_values)}")
logging.debug(f"{str(config_type.name)}: {str(config_values)}")
else:
# Always show whole field for remote node
node.requestConfig(config_type)
return True
# read the value def splitCompoundName(comp_name):
val = getattr(attributes, snake_name) """Split compound (dot separated) preference name into parts"""
name = comp_name.split(".",1)
if len(name) != 2:
name[0]=comp_name
name.append(comp_name)
return name
if Globals.getInstance().get_camel_case(): def setPref(config, comp_name, valStr):
print(f"{camel_name}: {str(val)}")
logging.debug(f"{camel_name}: {str(val)}")
else:
print(f"{snake_name}: {str(val)}")
logging.debug(f"{snake_name}: {str(val)}")
def setPref(attributes, name, valStr):
"""Set a channel or preferences value""" """Set a channel or preferences value"""
snake_name = meshtastic.util.camel_to_snake(name) name = splitCompoundName(comp_name)
camel_name = meshtastic.util.snake_to_camel(name)
snake_name = meshtastic.util.camel_to_snake(name[1])
camel_name = meshtastic.util.snake_to_camel(name[1])
logging.debug(f'snake_name:{snake_name}') logging.debug(f'snake_name:{snake_name}')
logging.debug(f'camel_name:{camel_name}') logging.debug(f'camel_name:{camel_name}')
objDesc = attributes.DESCRIPTOR objDesc = config.DESCRIPTOR
field = objDesc.fields_by_name.get(snake_name) config_type = objDesc.fields_by_name.get(name[0])
if not field: pref = False
if Globals.getInstance().get_camel_case(): if config_type and config_type.message_type is not None:
print(f"{attributes.__class__.__name__} does not have an attribute called {camel_name}, so you can not set it.") pref = config_type.message_type.fields_by_name.get(snake_name)
else: # Others like ChannelSettings are standalone
print(f"{attributes.__class__.__name__} does not have an attribute called {snake_name}, so you can not set it.") elif config_type:
print(f"Choices in sorted order are:") pref = config_type
names = []
for f in objDesc.fields: if (not pref) or (not config_type):
tmp_name = f'{f.name}' return False
if Globals.getInstance().get_camel_case():
tmp_name = meshtastic.util.snake_to_camel(tmp_name)
names.append(tmp_name)
for temp_name in sorted(names):
print(f" {temp_name}")
return
val = meshtastic.util.fromStr(valStr) val = meshtastic.util.fromStr(valStr)
logging.debug(f'valStr:{valStr} val:{val}') logging.debug(f'valStr:{valStr} val:{val}')
enumType = field.enum_type if snake_name == 'psk' and len(valStr) < 8:
print(f"Warning: wifi.psk must be 8 or more characters.")
return False
enumType = pref.enum_type
# pylint: disable=C0123 # pylint: disable=C0123
if enumType and type(val) == str: if enumType and type(val) == str:
# We've failed so far to convert this string into an enum, try to find it by reflection # We've failed so far to convert this string into an enum, try to find it by reflection
@@ -128,9 +156,9 @@ def setPref(attributes, name, valStr):
val = e.number val = e.number
else: else:
if Globals.getInstance().get_camel_case(): if Globals.getInstance().get_camel_case():
print(f"{camel_name} does not have an enum called {val}, so you can not set it.") print(f"{name[0]}.{camel_name} does not have an enum called {val}, so you can not set it.")
else: else:
print(f"{snake_name} does not have an enum called {val}, so you can not set it.") print(f"{name[0]}.{snake_name} does not have an enum called {val}, so you can not set it.")
print(f"Choices in sorted order are:") print(f"Choices in sorted order are:")
names = [] names = []
for f in enumType.values: for f in enumType.values:
@@ -138,33 +166,42 @@ def setPref(attributes, name, valStr):
names.append(f'{f.name}') names.append(f'{f.name}')
for temp_name in sorted(names): for temp_name in sorted(names):
print(f" {temp_name}") print(f" {temp_name}")
return return False
# note: 'ignore_incoming' is a repeating field # note: 'ignore_incoming' is a repeating field
if snake_name != 'ignore_incoming': if snake_name != 'ignore_incoming':
try: try:
setattr(attributes, snake_name, val) if config_type.message_type is not None:
config_values = getattr(config, config_type.name)
setattr(config_values, pref.name, val)
else:
setattr(config, snake_name, val)
except TypeError: except TypeError:
# The setter didn't like our arg type guess try again as a string # The setter didn't like our arg type guess try again as a string
setattr(attributes, snake_name, valStr) config_values = getattr(config, config_type.name)
setattr(config_values, pref.name, valStr)
else: else:
if val == 0: if val == 0:
# clear values # clear values
print("Clearing ignore_incoming list") print("Clearing ignore_incoming list")
del attributes.ignore_incoming[:] del config_type.message_type.ignore_incoming[:]
else: else:
print(f"Adding '{val}' to the ignore_incoming list") print(f"Adding '{val}' to the ignore_incoming list")
attributes.ignore_incoming.extend([val]) config_type.message_type.ignore_incoming.extend([val])
prefix = f"{name[0]}." if config_type.message_type is not None else ""
if Globals.getInstance().get_camel_case(): if Globals.getInstance().get_camel_case():
print(f"Set {camel_name} to {valStr}") print(f"Set {prefix}{camel_name} to {valStr}")
else: else:
print(f"Set {snake_name} to {valStr}") print(f"Set {prefix}{snake_name} to {valStr}")
return True
def onConnected(interface): def onConnected(interface):
"""Callback invoked when we connect to a radio""" """Callback invoked when we connect to a radio"""
closeNow = False # Should we drop the connection after we finish? closeNow = False # Should we drop the connection after we finish?
waitForAckNak = False # Should we wait for an acknowledgment if we send to a remote node?
try: try:
our_globals = Globals.getInstance() our_globals = Globals.getInstance()
args = our_globals.get_args() args = our_globals.get_args()
@@ -179,90 +216,88 @@ def onConnected(interface):
alt = 0 alt = 0
lat = 0.0 lat = 0.0
lon = 0.0 lon = 0.0
prefs = interface.localNode.radioConfig.preferences # TODO: use getNode(args.dest) to be able to set it for a remote node
localConfig = interface.localNode.localConfig
if args.setalt: if args.setalt:
alt = int(args.setalt) alt = int(args.setalt)
prefs.fixed_position = True localConfig.position.fixed_position = True
print(f"Fixing altitude at {alt} meters") print(f"Fixing altitude at {alt} meters")
if args.setlat: if args.setlat:
lat = float(args.setlat) lat = float(args.setlat)
prefs.fixed_position = True localConfig.position.fixed_position = True
print(f"Fixing latitude at {lat} degrees") print(f"Fixing latitude at {lat} degrees")
if args.setlon: if args.setlon:
lon = float(args.setlon) lon = float(args.setlon)
prefs.fixed_position = True localConfig.position.fixed_position = True
print(f"Fixing longitude at {lon} degrees") print(f"Fixing longitude at {lon} degrees")
print("Setting device position") print("Setting device position")
# can include lat/long/alt etc: latitude = 37.5, longitude = -122.1 # can include lat/long/alt etc: latitude = 37.5, longitude = -122.1
interface.sendPosition(lat, lon, alt) interface.sendPosition(lat, lon, alt)
interface.localNode.writeConfig() interface.localNode.writeConfig('position')
elif not args.no_time: elif not args.no_time:
# We normally provide a current time to the mesh when we connect # We normally provide a current time to the mesh when we connect
interface.sendPosition() interface.sendPosition()
if args.set_owner: if args.set_owner:
closeNow = True closeNow = True
waitForAckNak = True
print(f"Setting device owner to {args.set_owner}") print(f"Setting device owner to {args.set_owner}")
interface.getNode(args.dest).setOwner(args.set_owner) interface.getNode(args.dest, False).setOwner(args.set_owner)
if args.set_owner_short: if args.set_owner_short:
closeNow = True closeNow = True
waitForAckNak = True
print(f"Setting device owner short to {args.set_owner_short}") 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) interface.getNode(args.dest, False).setOwner(long_name=None, short_name=args.set_owner_short)
# TODO: add to export-config and configure # TODO: add to export-config and configure
if args.set_canned_message: if args.set_canned_message:
closeNow = True closeNow = True
waitForAckNak = True
print(f"Setting canned plugin message to {args.set_canned_message}") print(f"Setting canned plugin message to {args.set_canned_message}")
interface.getNode(args.dest).set_canned_message(args.set_canned_message) interface.getNode(args.dest, False).set_canned_message(args.set_canned_message)
# TODO: add to export-config and configure
if args.set_ringtone:
closeNow = True
waitForAckNak = True
print(f"Setting ringtone to {args.set_ringtone}")
interface.getNode(args.dest, False).set_ringtone(args.set_ringtone)
if args.pos_fields: if args.pos_fields:
# If --pos-fields invoked with args, set position fields # If --pos-fields invoked with args, set position fields
closeNow = True closeNow = True
prefs = interface.getNode(args.dest).radioConfig.preferences positionConfig = interface.getNode(args.dest).localConfig.position
allFields = 0 allFields = 0
try: try:
for field in args.pos_fields: for field in args.pos_fields:
v_field = radioconfig_pb2.PositionFlags.Value(field) v_field = positionConfig.PositionFlags.Value(field)
allFields |= v_field allFields |= v_field
except ValueError: except ValueError:
print("ERROR: supported position fields are:") print("ERROR: supported position fields are:")
print(radioconfig_pb2.PositionFlags.keys()) print(positionConfig.PositionFlags.keys())
print("If no fields are specified, will read and display current value.") print("If no fields are specified, will read and display current value.")
else: else:
print(f"Setting position fields to {allFields}") print(f"Setting position fields to {allFields}")
setPref(prefs, 'position_flags', f'{allFields:d}') setPref(positionConfig, 'position_flags', f'{allFields:d}')
print("Writing modified preferences to device") print("Writing modified preferences to device")
interface.getNode(args.dest).writeConfig() interface.getNode(args.dest).writeConfig('position')
elif args.pos_fields is not None: elif args.pos_fields is not None:
# If --pos-fields invoked without args, read and display current value # If --pos-fields invoked without args, read and display current value
closeNow = True closeNow = True
prefs = interface.getNode(args.dest).radioConfig.preferences positionConfig = interface.getNode(args.dest).localConfig.position
fieldNames = [] fieldNames = []
for bit in radioconfig_pb2.PositionFlags.values(): for bit in positionConfig.PositionFlags.values():
if prefs.position_flags & bit: if positionConfig.position_flags & bit:
fieldNames.append(radioconfig_pb2.PositionFlags.Name(bit)) fieldNames.append(positionConfig.PositionFlags.Name(bit))
print(' '.join(fieldNames)) print(' '.join(fieldNames))
if args.set_team:
closeNow = True
try:
v_team = meshtastic.mesh_pb2.Team.Value(args.set_team.upper())
except ValueError:
v_team = 0
print(f"ERROR: Team \'{args.set_team}\' not found.")
print("Try a team name from the sorted list below, or use 'CLEAR' for unaffiliated:")
print(sorted(meshtastic.mesh_pb2.Team.keys()))
else:
print(f"Setting team to {meshtastic.mesh_pb2.Team.Name(v_team)}")
interface.getNode(args.dest).setOwner(team=v_team)
if args.set_ham: if args.set_ham:
closeNow = True closeNow = True
print(f"Setting Ham ID to {args.set_ham} and turning off encryption") print(f"Setting Ham ID to {args.set_ham} and turning off encryption")
@@ -272,11 +307,40 @@ def onConnected(interface):
if args.reboot: if args.reboot:
closeNow = True closeNow = True
interface.getNode(args.dest).reboot() waitForAckNak = True
interface.getNode(args.dest, False).reboot()
if args.reboot_ota:
closeNow = True
waitForAckNak = True
interface.getNode(args.dest, False).rebootOTA()
if args.shutdown: if args.shutdown:
closeNow = True closeNow = True
interface.getNode(args.dest).shutdown() waitForAckNak = True
interface.getNode(args.dest, False).shutdown()
if args.device_metadata:
closeNow = True
interface.getNode(args.dest, False).getMetadata()
if args.begin_edit:
closeNow = True
interface.getNode(args.dest, False).beginSettingsTransaction()
if args.commit_edit:
closeNow = True
interface.getNode(args.dest, False).commitSettingsTransaction()
if args.factory_reset:
closeNow = True
waitForAckNak = True
interface.getNode(args.dest, False).factoryReset()
if args.reset_nodedb:
closeNow = True
waitForAckNak = True
interface.getNode(args.dest, False).resetNodeDb()
if args.sendtext: if args.sendtext:
closeNow = True closeNow = True
@@ -297,6 +361,13 @@ def onConnected(interface):
interface.sendData(payload, args.dest, portNum=portnums_pb2.PortNum.REPLY_APP, interface.sendData(payload, args.dest, portNum=portnums_pb2.PortNum.REPLY_APP,
wantAck=True, wantResponse=True) wantAck=True, wantResponse=True)
if args.traceroute:
loraConfig = getattr(interface.localNode.localConfig, 'lora')
hopLimit = getattr(loraConfig, 'hop_limit')
dest = str(args.traceroute)
print(f"Sending traceroute request to {dest} (this could take a while)")
interface.sendTraceRoute(dest, hopLimit)
if args.gpio_wrb or args.gpio_rd or args.gpio_watch: if args.gpio_wrb or args.gpio_rd or args.gpio_watch:
if args.dest == BROADCAST_ADDR: if args.dest == BROADCAST_ADDR:
meshtastic.util.our_exit("Warning: Must use a destination node ID.") meshtastic.util.our_exit("Warning: Must use a destination node ID.")
@@ -335,31 +406,56 @@ def onConnected(interface):
# handle settings # handle settings
if args.set: if args.set:
closeNow = True closeNow = True
prefs = interface.getNode(args.dest).radioConfig.preferences waitForAckNak = True
node = interface.getNode(args.dest, False)
# Handle the int/float/bool arguments # Handle the int/float/bool arguments
pref = None
for pref in args.set: for pref in args.set:
setPref(prefs, pref[0], pref[1]) found = False
field = splitCompoundName(pref[0].lower())[0]
for config in [node.localConfig, node.moduleConfig]:
config_type = config.DESCRIPTOR.fields_by_name.get(field)
if config_type:
if len(config.ListFields()) == 0:
node.requestConfig(config.DESCRIPTOR.fields_by_name.get(field))
found = setPref(config, pref[0], pref[1])
if found:
break
print("Writing modified preferences to device") if found:
interface.getNode(args.dest).writeConfig() print("Writing modified preferences to device")
node.writeConfig(field)
else:
if Globals.getInstance().get_camel_case():
print(f"{node.localConfig.__class__.__name__} and {node.moduleConfig.__class__.__name__} do not have an attribute {pref[0]}.")
else:
print(f"{node.localConfig.__class__.__name__} and {node.moduleConfig.__class__.__name__} do not have attribute {pref[0]}.")
print("Choices are...")
printConfig(node.localConfig)
printConfig(node.moduleConfig)
if args.configure: if args.configure:
with open(args.configure[0], encoding='utf8') as file: with open(args.configure[0], encoding='utf8') as file:
configuration = yaml.safe_load(file) configuration = yaml.safe_load(file)
closeNow = True closeNow = True
interface.getNode(args.dest, False).beginSettingsTransaction()
if 'owner' in configuration: if 'owner' in configuration:
print(f"Setting device owner to {configuration['owner']}") print(f"Setting device owner to {configuration['owner']}")
interface.getNode(args.dest).setOwner(configuration['owner']) waitForAckNak = True
interface.getNode(args.dest, False).setOwner(configuration['owner'])
if 'owner_short' in configuration: if 'owner_short' in configuration:
print(f"Setting device owner short to {configuration['owner_short']}") print(f"Setting device owner short to {configuration['owner_short']}")
interface.getNode(args.dest).setOwner(long_name=None, short_name=configuration['owner_short']) waitForAckNak = True
interface.getNode(args.dest, False).setOwner(long_name=None, short_name=configuration['owner_short'])
if 'ownerShort' in configuration: if 'ownerShort' in configuration:
print(f"Setting device owner short to {configuration['ownerShort']}") print(f"Setting device owner short to {configuration['ownerShort']}")
interface.getNode(args.dest).setOwner(long_name=None, short_name=configuration['ownerShort']) waitForAckNak = True
interface.getNode(args.dest, False).setOwner(long_name=None, short_name=configuration['ownerShort'])
if 'channel_url' in configuration: if 'channel_url' in configuration:
print("Setting channel url to", configuration['channel_url']) print("Setting channel url to", configuration['channel_url'])
@@ -373,37 +469,40 @@ def onConnected(interface):
alt = 0 alt = 0
lat = 0.0 lat = 0.0
lon = 0.0 lon = 0.0
prefs = interface.localNode.radioConfig.preferences localConfig = interface.localNode.localConfig
if 'alt' in configuration['location']: if 'alt' in configuration['location']:
alt = int(configuration['location']['alt']) alt = int(configuration['location']['alt'])
prefs.fixed_position = True localConfig.position.fixed_position = True
print(f"Fixing altitude at {alt} meters") print(f"Fixing altitude at {alt} meters")
if 'lat' in configuration['location']: if 'lat' in configuration['location']:
lat = float(configuration['location']['lat']) lat = float(configuration['location']['lat'])
prefs.fixed_position = True localConfig.position.fixed_position = True
print(f"Fixing latitude at {lat} degrees") print(f"Fixing latitude at {lat} degrees")
if 'lon' in configuration['location']: if 'lon' in configuration['location']:
lon = float(configuration['location']['lon']) lon = float(configuration['location']['lon'])
prefs.fixed_position = True localConfig.position.fixed_position = True
print(f"Fixing longitude at {lon} degrees") print(f"Fixing longitude at {lon} degrees")
print("Setting device position") print("Setting device position")
interface.sendPosition(lat, lon, alt) interface.sendPosition(lat, lon, alt)
interface.localNode.writeConfig() interface.localNode.writeConfig('position')
if 'user_prefs' in configuration: if 'config' in configuration:
prefs = interface.getNode(args.dest).radioConfig.preferences localConfig = interface.getNode(args.dest).localConfig
for pref in configuration['user_prefs']: for section in configuration['config']:
setPref(prefs, pref, str(configuration['user_prefs'][pref])) for pref in configuration['config'][section]:
print("Writing modified preferences to device") setPref(localConfig, f"{meshtastic.util.camel_to_snake(section)}.{pref}", str(configuration['config'][section][pref]))
interface.getNode(args.dest).writeConfig() interface.getNode(args.dest).writeConfig(meshtastic.util.camel_to_snake(section))
if 'userPrefs' in configuration: if 'module_config' in configuration:
prefs = interface.getNode(args.dest).radioConfig.preferences moduleConfig = interface.getNode(args.dest).moduleConfig
for pref in configuration['userPrefs']: for section in configuration['module_config']:
setPref(prefs, pref, str(configuration['userPrefs'][pref])) for pref in configuration['module_config'][section]:
print("Writing modified preferences to device") setPref(moduleConfig, f"{meshtastic.util.camel_to_snake(section)}.{pref}", str(configuration['module_config'][section][pref]))
interface.getNode(args.dest).writeConfig() interface.getNode(args.dest).writeConfig(meshtastic.util.camel_to_snake(section))
interface.getNode(args.dest, False).commitSettingsTransaction()
print("Writing modified configuration to device")
if args.export_config: if args.export_config:
# export the configuration (the opposite of '--configure') # export the configuration (the opposite of '--configure')
@@ -450,69 +549,54 @@ def onConnected(interface):
print(f"Deleting channel {channelIndex}") print(f"Deleting channel {channelIndex}")
ch = interface.getNode(args.dest).deleteChannel(channelIndex) ch = interface.getNode(args.dest).deleteChannel(channelIndex)
ch_changes = [args.ch_vlongslow, args.ch_longslow, args.ch_longfast, def setSimpleConfig(modem_preset):
args.ch_midslow, args.ch_midfast, """Set one of the simple modem_config"""
args.ch_shortslow, args.ch_shortfast] # Overwrite modem_preset
any_primary_channel_changes = any(x for x in ch_changes) prefs = interface.getNode(args.dest).localConfig
if args.ch_set or any_primary_channel_changes or args.ch_enable or args.ch_disable: prefs.lora.modem_preset = modem_preset
interface.getNode(args.dest).writeConfig('lora')
# handle the simple radio set commands
if args.ch_vlongslow:
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.VERY_LONG_SLOW)
if args.ch_longslow:
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.LONG_SLOW)
if args.ch_longfast:
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.LONG_FAST)
if args.ch_medslow:
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.MEDIUM_SLOW)
if args.ch_medfast:
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.MEDIUM_FAST)
if args.ch_shortslow:
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.SHORT_SLOW)
if args.ch_shortfast:
setSimpleConfig(config_pb2.Config.LoRaConfig.ModemPreset.SHORT_FAST)
if args.ch_set or args.ch_enable or args.ch_disable:
closeNow = True closeNow = True
channelIndex = our_globals.get_channel_index() channelIndex = our_globals.get_channel_index()
if channelIndex is None: if channelIndex is None:
if any_primary_channel_changes: meshtastic.util.our_exit("Warning: Need to specify '--ch-index'.", 1)
# we assume that they want the primary channel if they're setting range values
channelIndex = 0
else:
meshtastic.util.our_exit("Warning: Need to specify '--ch-index'.", 1)
ch = interface.getNode(args.dest).channels[channelIndex] ch = interface.getNode(args.dest).channels[channelIndex]
if any_primary_channel_changes or args.ch_enable or args.ch_disable: if args.ch_enable or args.ch_disable:
if channelIndex == 0 and not any_primary_channel_changes: if channelIndex == 0:
meshtastic.util.our_exit("Warning: Cannot enable/disable PRIMARY channel.") meshtastic.util.our_exit("Warning: Cannot enable/disable PRIMARY channel.")
if channelIndex != 0:
if any_primary_channel_changes:
meshtastic.util.our_exit("Warning: Standard channel settings can only be applied to the PRIMARY channel")
enable = True # default to enable enable = True # default to enable
if args.ch_enable: if args.ch_enable:
enable = True enable = True
if args.ch_disable: if args.ch_disable:
enable = False enable = False
def setSimpleChannel(modem_config):
"""Set one of the simple modem_config only based channels"""
# Completely new channel settings
chs = channel_pb2.ChannelSettings()
chs.modem_config = modem_config
chs.psk = bytes([1]) # Use default channel psk 1
ch.settings.CopyFrom(chs)
# handle the simple channel set commands
if args.ch_vlongslow:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.VLongSlow)
if args.ch_longslow:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.LongSlow)
if args.ch_longfast:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.LongFast)
if args.ch_midslow:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.MidSlow)
if args.ch_midfast:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.MidFast)
if args.ch_shortslow:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.ShortSlow)
if args.ch_shortfast:
setSimpleChannel(channel_pb2.ChannelSettings.ModemConfig.ShortFast)
# Handle the channel settings # Handle the channel settings
for pref in (args.ch_set or []): for pref in (args.ch_set or []):
if pref[0] == "psk": if pref[0] == "psk":
@@ -535,29 +619,38 @@ def onConnected(interface):
print("") print("")
interface.getNode(args.dest).get_canned_message() interface.getNode(args.dest).get_canned_message()
if args.get_ringtone:
closeNow = True
print("")
interface.getNode(args.dest).get_ringtone()
if args.info: if args.info:
print("") print("")
# If we aren't trying to talk to our local node, don't show it # If we aren't trying to talk to our local node, don't show it
if args.dest == BROADCAST_ADDR: if args.dest == BROADCAST_ADDR:
interface.showInfo() interface.showInfo()
print("")
print("") interface.getNode(args.dest).showInfo()
interface.getNode(args.dest).showInfo() closeNow = True
closeNow = True # FIXME, for now we leave the link up while talking to remote nodes print("")
print("") else:
print("Showing info of remote node is not supported.")
print("Use the '--get' command for a specific configuration (e.g. 'lora') instead.")
if args.get: if args.get:
closeNow = True closeNow = True
prefs = interface.getNode(args.dest).radioConfig.preferences node = interface.getNode(args.dest, False)
# Handle the int/float/bool arguments
for pref in args.get: for pref in args.get:
getPref(prefs, pref[0]) found = getPref(node, pref[0])
print("Completed getting preferences") if found:
print("Completed getting preferences")
if args.nodes: if args.nodes:
closeNow = True closeNow = True
if args.dest != BROADCAST_ADDR:
print("Showing node list of a remote node is not supported.")
return
interface.showNodes() interface.showNodes()
if args.qr: if args.qr:
@@ -578,6 +671,10 @@ def onConnected(interface):
else: else:
tunnel.Tunnel(interface, subnet=args.tunnel_net) tunnel.Tunnel(interface, subnet=args.tunnel_net)
if args.dest != BROADCAST_ADDR and waitForAckNak:
print(f"Waiting for an acknowledgment from remote node (this could take a while)")
interface.getNode(args.dest, False).iface.waitForAckNak()
# if the user didn't ask for serial debugging output, we might want to exit after we've done our operation # if the user didn't ask for serial debugging output, we might want to exit after we've done our operation
if (not args.seriallog) and closeNow: if (not args.seriallog) and closeNow:
interface.close() # after running command then exit interface.close() # after running command then exit
@@ -586,6 +683,21 @@ def onConnected(interface):
print(f"Aborting due to: {ex}") print(f"Aborting due to: {ex}")
interface.close() # close the connection now, so that our app exits interface.close() # close the connection now, so that our app exits
def printConfig(config):
"""print configuration"""
objDesc = config.DESCRIPTOR
for config_section in objDesc.fields:
if config_section.name != "version":
config = objDesc.fields_by_name.get(config_section.name)
print(f"{config_section.name}:")
names = []
for field in config.message_type.fields:
tmp_name = f'{config_section.name}.{field.name}'
if Globals.getInstance().get_camel_case():
tmp_name = meshtastic.util.snake_to_camel(tmp_name)
names.append(tmp_name)
for temp_name in sorted(names):
print(f" {temp_name}")
def onNode(node): def onNode(node):
"""Callback invoked when the node DB changes""" """Callback invoked when the node DB changes"""
@@ -605,6 +717,8 @@ def subscribe():
def export_config(interface): def export_config(interface):
"""used in--export-config""" """used in--export-config"""
configObj = {}
owner = interface.getLongName() owner = interface.getLongName()
owner_short = interface.getShortName() owner_short = interface.getShortName()
channel_url = interface.localNode.getURL() channel_url = interface.localNode.getURL()
@@ -618,38 +732,46 @@ def export_config(interface):
lon = pos.get('longitude') lon = pos.get('longitude')
alt = pos.get('altitude') alt = pos.get('altitude')
config = "# start of Meshtastic configure yaml\n"
if owner: if owner:
config += f"owner: {owner}\n\n" configObj["owner"] = owner
if owner_short: if owner_short:
config += f"owner_short: {owner_short}\n\n" configObj["owner_short"] = owner_short
if channel_url: if channel_url:
if Globals.getInstance().get_camel_case(): if Globals.getInstance().get_camel_case():
config += f"channelUrl: {channel_url}\n\n" configObj["channelUrl"] = channel_url
else: else:
config += f"channel_url: {channel_url}\n\n" configObj["channel_url"] = channel_url
if lat or lon or alt: if lat or lon or alt:
config += "location:\n" configObj["location"] = { "lat": lat, "lon": lon, "alt": alt }
if lat:
config += f" lat: {lat}\n" config = MessageToDict(interface.localNode.localConfig)
if lon: if config:
config += f" lon: {lon}\n" # Convert inner keys to correct snake/camelCase
if alt: prefs = {}
config += f" alt: {alt}\n" for pref in config:
config += "\n"
preferences = f'{interface.localNode.radioConfig.preferences}'
prefs = preferences.splitlines()
if prefs:
if Globals.getInstance().get_camel_case():
config += "userPrefs:\n"
else:
config += "user_prefs:\n"
for pref in prefs:
if Globals.getInstance().get_camel_case(): if Globals.getInstance().get_camel_case():
# Note: This may not work if the value has '_' prefs[meshtastic.util.snake_to_camel(pref)] = config[pref]
config += f" {meshtastic.util.snake_to_camel(meshtastic.util.quoteBooleans(pref))}\n"
else: else:
config += f" {meshtastic.util.quoteBooleans(pref)}\n" prefs[pref] = config[pref]
if Globals.getInstance().get_camel_case():
configObj["config"] = config
else:
configObj["config"] = config
module_config = MessageToDict(interface.localNode.moduleConfig)
if module_config:
# Convert inner keys to correct snake/camelCase
prefs = {}
for pref in module_config:
if len(module_config[pref]) > 0:
prefs[pref] = module_config[pref]
if Globals.getInstance().get_camel_case():
configObj["module_config"] = prefs
else:
configObj["module_config"] = prefs
config = "# start of Meshtastic configure yaml\n"
config += yaml.dump(configObj)
print(config) print(config)
return config return config
@@ -774,6 +896,9 @@ def initParser():
parser.add_argument("--get-canned-message", help="Show the canned message plugin message", parser.add_argument("--get-canned-message", help="Show the canned message plugin message",
action="store_true") action="store_true")
parser.add_argument("--get-ringtone", help="Show the stored ringtone",
action="store_true")
parser.add_argument("--nodes", help="Print Node List in a pretty formatted table", parser.add_argument("--nodes", help="Print Node List in a pretty formatted table",
action="store_true") action="store_true")
@@ -811,7 +936,7 @@ def initParser():
"--ch-set", help=("Set a channel parameter. To see channel settings available:'--ch-set all all --ch-index 0'. " "--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'. " "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 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 " "To set encryption back to the default:'--ch-set psk default --ch-index 0'. To set encryption with your "
"own key: '--ch-set psk 0x1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b --ch-index 0'."), "own key: '--ch-set psk 0x1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b --ch-index 0'."),
nargs=2, action='append') nargs=2, action='append')
@@ -825,10 +950,10 @@ def initParser():
"--ch-longfast", help="Change to the long-range and fast channel", action='store_true') "--ch-longfast", help="Change to the long-range and fast channel", action='store_true')
parser.add_argument( parser.add_argument(
"--ch-midslow", help="Change to the mid-range and slow channel", action='store_true') "--ch-medslow", help="Change to the med-range and slow channel", action='store_true')
parser.add_argument( parser.add_argument(
"--ch-midfast", help="Change to the mid-range and fast channel", action='store_true') "--ch-medfast", help="Change to the med-range and fast channel", action='store_true')
parser.add_argument( parser.add_argument(
"--ch-shortslow", help="Change to the short-range and slow channel", action='store_true') "--ch-shortslow", help="Change to the short-range and slow channel", action='store_true')
@@ -840,14 +965,14 @@ def initParser():
"--set-owner", help="Set device owner name", action="store") "--set-owner", help="Set device owner name", action="store")
parser.add_argument( parser.add_argument(
"--set-canned-message", help="Set the canned messages plugin message (up to 1000 characters).", action="store") "--set-canned-message", help="Set the canned messages plugin message (up to 200 characters).", action="store")
parser.add_argument(
"--set-ringtone", help="Set the Notification Ringtone (up to 230 characters).", action="store")
parser.add_argument( parser.add_argument(
"--set-owner-short", help="Set device owner short name", action="store") "--set-owner-short", help="Set device owner short name", action="store")
parser.add_argument(
"--set-team", help="Set team affiliation (an invalid team will list valid values)", action="store")
parser.add_argument( parser.add_argument(
"--set-ham", help="Set licensed Ham ID and turn off encryption", action="store") "--set-ham", help="Set licensed Ham ID and turn off encryption", action="store")
@@ -860,12 +985,36 @@ def initParser():
parser.add_argument( parser.add_argument(
"--sendping", help="Send a ping message (which requests a reply)", action="store_true") "--sendping", help="Send a ping message (which requests a reply)", action="store_true")
parser.add_argument(
"--traceroute", help="Traceroute from connected node to a destination. " \
"You need pass the destination ID as argument, like " \
"this: '--traceroute !ba4bf9d0' " \
"Only nodes that have the encryption key can be traced.")
parser.add_argument( parser.add_argument(
"--reboot", help="Tell the destination node to reboot", action="store_true") "--reboot", help="Tell the destination node to reboot", action="store_true")
parser.add_argument(
"--reboot-ota", help="Tell the destination node to reboot into factory firmware", action="store_true")
parser.add_argument( parser.add_argument(
"--shutdown", help="Tell the destination node to shutdown", action="store_true") "--shutdown", help="Tell the destination node to shutdown", action="store_true")
parser.add_argument(
"--device-metadata", help="Get the device metadata from the node", action="store_true")
parser.add_argument(
"--begin-edit", help="Tell the node to open a transaction to edit settings", action="store_true")
parser.add_argument(
"--commit-edit", help="Tell the node to commit open settings transaction", action="store_true")
parser.add_argument(
"--factory-reset", help="Tell the destination node to install the default config", action="store_true")
parser.add_argument(
"--reset-nodedb", help="Tell the destination node clear its list of nodes", action="store_true")
parser.add_argument( parser.add_argument(
"--reply", help="Reply to received messages", "--reply", help="Reply to received messages",
action="store_true") action="store_true")
@@ -909,13 +1058,6 @@ def initParser():
parser.add_argument("--noproto", help="Don't start the API, just function as a dumb serial terminal.", parser.add_argument("--noproto", help="Don't start the API, just function as a dumb serial terminal.",
action="store_true") action="store_true")
parser.add_argument('--setchan', dest='deprecated', nargs=2, action='append',
help='Deprecated, use "--ch-set param value" instead')
parser.add_argument('--set-router', dest='deprecated',
action='store_true', help='Deprecated, use "--set is_router true" instead')
parser.add_argument('--unset-router', dest='deprecated',
action='store_false', help='Deprecated, use "--set is_router false" instead')
have_tunnel = platform.system() == 'Linux' have_tunnel = platform.system() == 'Linux'
if have_tunnel: if have_tunnel:
parser.add_argument('--tunnel', action='store_true', parser.add_argument('--tunnel', action='store_true',

View File

@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: admin.proto # source: meshtastic/admin.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -11,325 +12,45 @@ from google.protobuf import symbol_database as _symbol_database
_sym_db = _symbol_database.Default() _sym_db = _symbol_database.Default()
from . import channel_pb2 as channel__pb2 from meshtastic import channel_pb2 as meshtastic_dot_channel__pb2
from . import mesh_pb2 as mesh__pb2 from meshtastic import config_pb2 as meshtastic_dot_config__pb2
from . import radioconfig_pb2 as radioconfig__pb2 from meshtastic import mesh_pb2 as meshtastic_dot_mesh__pb2
from meshtastic import module_config_pb2 as meshtastic_dot_module__config__pb2
from meshtastic import connection_status_pb2 as meshtastic_dot_connection__status__pb2
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16meshtastic/admin.proto\x1a\x18meshtastic/channel.proto\x1a\x17meshtastic/config.proto\x1a\x15meshtastic/mesh.proto\x1a\x1emeshtastic/module_config.proto\x1a\"meshtastic/connection_status.proto\"\xd8\x0c\n\x0c\x41\x64minMessage\x12\x1d\n\x13get_channel_request\x18\x01 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x02 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_owner_request\x18\x03 \x01(\x08H\x00\x12#\n\x12get_owner_response\x18\x04 \x01(\x0b\x32\x05.UserH\x00\x12\x36\n\x12get_config_request\x18\x05 \x01(\x0e\x32\x18.AdminMessage.ConfigTypeH\x00\x12&\n\x13get_config_response\x18\x06 \x01(\x0b\x32\x07.ConfigH\x00\x12\x43\n\x19get_module_config_request\x18\x07 \x01(\x0e\x32\x1e.AdminMessage.ModuleConfigTypeH\x00\x12\x33\n\x1aget_module_config_response\x18\x08 \x01(\x0b\x32\r.ModuleConfigH\x00\x12\x34\n*get_canned_message_module_messages_request\x18\n \x01(\x08H\x00\x12\x35\n+get_canned_message_module_messages_response\x18\x0b \x01(\tH\x00\x12%\n\x1bget_device_metadata_request\x18\x0c \x01(\x08H\x00\x12\x37\n\x1cget_device_metadata_response\x18\r \x01(\x0b\x32\x0f.DeviceMetadataH\x00\x12\x1e\n\x14get_ringtone_request\x18\x0e \x01(\x08H\x00\x12\x1f\n\x15get_ringtone_response\x18\x0f \x01(\tH\x00\x12.\n$get_device_connection_status_request\x18\x10 \x01(\x08H\x00\x12H\n%get_device_connection_status_response\x18\x11 \x01(\x0b\x32\x17.DeviceConnectionStatusH\x00\x12&\n\x0cset_ham_mode\x18\x12 \x01(\x0b\x32\x0e.HamParametersH\x00\x12\x1a\n\tset_owner\x18 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18! \x01(\x0b\x32\x08.ChannelH\x00\x12\x1d\n\nset_config\x18\" \x01(\x0b\x32\x07.ConfigH\x00\x12*\n\x11set_module_config\x18# \x01(\x0b\x32\r.ModuleConfigH\x00\x12,\n\"set_canned_message_module_messages\x18$ \x01(\tH\x00\x12\x1e\n\x14set_ringtone_message\x18% \x01(\tH\x00\x12\x1d\n\x13\x62\x65gin_edit_settings\x18@ \x01(\x08H\x00\x12\x1e\n\x14\x63ommit_edit_settings\x18\x41 \x01(\x08H\x00\x12\x1c\n\x12reboot_ota_seconds\x18_ \x01(\x05H\x00\x12\x18\n\x0e\x65xit_simulator\x18` \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18\x61 \x01(\x05H\x00\x12\x1a\n\x10shutdown_seconds\x18\x62 \x01(\x05H\x00\x12\x17\n\rfactory_reset\x18\x63 \x01(\x05H\x00\x12\x16\n\x0cnodedb_reset\x18\x64 \x01(\x05H\x00\"\x95\x01\n\nConfigType\x12\x11\n\rDEVICE_CONFIG\x10\x00\x12\x13\n\x0fPOSITION_CONFIG\x10\x01\x12\x10\n\x0cPOWER_CONFIG\x10\x02\x12\x12\n\x0eNETWORK_CONFIG\x10\x03\x12\x12\n\x0e\x44ISPLAY_CONFIG\x10\x04\x12\x0f\n\x0bLORA_CONFIG\x10\x05\x12\x14\n\x10\x42LUETOOTH_CONFIG\x10\x06\"\xd3\x01\n\x10ModuleConfigType\x12\x0f\n\x0bMQTT_CONFIG\x10\x00\x12\x11\n\rSERIAL_CONFIG\x10\x01\x12\x13\n\x0f\x45XTNOTIF_CONFIG\x10\x02\x12\x17\n\x13STOREFORWARD_CONFIG\x10\x03\x12\x14\n\x10RANGETEST_CONFIG\x10\x04\x12\x14\n\x10TELEMETRY_CONFIG\x10\x05\x12\x14\n\x10\x43\x41NNEDMSG_CONFIG\x10\x06\x12\x10\n\x0c\x41UDIO_CONFIG\x10\x07\x12\x19\n\x15REMOTEHARDWARE_CONFIG\x10\x08\x42\x11\n\x0fpayload_variant\"[\n\rHamParameters\x12\x11\n\tcall_sign\x18\x01 \x01(\t\x12\x10\n\x08tx_power\x18\x02 \x01(\x05\x12\x11\n\tfrequency\x18\x03 \x01(\x02\x12\x12\n\nshort_name\x18\x04 \x01(\tB`\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
name='admin.proto',
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\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,mesh__pb2.DESCRIPTOR,radioconfig__pb2.DESCRIPTOR,])
_ADMINMESSAGE = DESCRIPTOR.message_types_by_name['AdminMessage']
_ADMINMESSAGE = _descriptor.Descriptor( _HAMPARAMETERS = DESCRIPTOR.message_types_by_name['HamParameters']
name='AdminMessage', _ADMINMESSAGE_CONFIGTYPE = _ADMINMESSAGE.enum_types_by_name['ConfigType']
full_name='AdminMessage', _ADMINMESSAGE_MODULECONFIGTYPE = _ADMINMESSAGE.enum_types_by_name['ModuleConfigType']
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='set_radio', full_name='AdminMessage.set_radio', 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='set_owner', full_name='AdminMessage.set_owner', index=1,
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='set_channel', full_name='AdminMessage.set_channel', index=2,
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='get_radio_request', full_name='AdminMessage.get_radio_request', index=3,
number=4, 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_radio_response', full_name='AdminMessage.get_radio_response', index=4,
number=5, 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='get_channel_request', full_name='AdminMessage.get_channel_request', index=5,
number=6, 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='get_channel_response', full_name='AdminMessage.get_channel_response', index=6,
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='get_owner_request', full_name='AdminMessage.get_owner_request', index=7,
number=8, 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_owner_response', full_name='AdminMessage.get_owner_response', index=8,
number=9, 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='confirm_set_channel', full_name='AdminMessage.confirm_set_channel', index=9,
number=32, 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='confirm_set_radio', full_name='AdminMessage.confirm_set_radio', index=10,
number=33, 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='exit_simulator', full_name='AdminMessage.exit_simulator', index=11,
number=34, 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='reboot_seconds', full_name='AdminMessage.reboot_seconds', index=12,
number=35, 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),
_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=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
_descriptor.OneofDescriptor(
name='variant', full_name='AdminMessage.variant',
index=0, containing_type=None, fields=[]),
],
serialized_start=62,
serialized_end=1119,
)
_ADMINMESSAGE.fields_by_name['set_radio'].message_type = radioconfig__pb2._RADIOCONFIG
_ADMINMESSAGE.fields_by_name['set_owner'].message_type = mesh__pb2._USER
_ADMINMESSAGE.fields_by_name['set_channel'].message_type = channel__pb2._CHANNEL
_ADMINMESSAGE.fields_by_name['get_radio_response'].message_type = radioconfig__pb2._RADIOCONFIG
_ADMINMESSAGE.fields_by_name['get_channel_response'].message_type = channel__pb2._CHANNEL
_ADMINMESSAGE.fields_by_name['get_owner_response'].message_type = mesh__pb2._USER
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['set_radio'])
_ADMINMESSAGE.fields_by_name['set_radio'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['set_owner'])
_ADMINMESSAGE.fields_by_name['set_owner'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['set_channel'])
_ADMINMESSAGE.fields_by_name['set_channel'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_radio_request'])
_ADMINMESSAGE.fields_by_name['get_radio_request'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_radio_response'])
_ADMINMESSAGE.fields_by_name['get_radio_response'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_channel_request'])
_ADMINMESSAGE.fields_by_name['get_channel_request'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_channel_response'])
_ADMINMESSAGE.fields_by_name['get_channel_response'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_owner_request'])
_ADMINMESSAGE.fields_by_name['get_owner_request'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['get_owner_response'])
_ADMINMESSAGE.fields_by_name['get_owner_response'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['confirm_set_channel'])
_ADMINMESSAGE.fields_by_name['confirm_set_channel'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['confirm_set_radio'])
_ADMINMESSAGE.fields_by_name['confirm_set_radio'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
_ADMINMESSAGE.fields_by_name['exit_simulator'])
_ADMINMESSAGE.fields_by_name['exit_simulator'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
_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)
AdminMessage = _reflection.GeneratedProtocolMessageType('AdminMessage', (_message.Message,), { AdminMessage = _reflection.GeneratedProtocolMessageType('AdminMessage', (_message.Message,), {
'DESCRIPTOR' : _ADMINMESSAGE, 'DESCRIPTOR' : _ADMINMESSAGE,
'__module__' : 'admin_pb2' '__module__' : 'meshtastic.admin_pb2'
# @@protoc_insertion_point(class_scope:AdminMessage) # @@protoc_insertion_point(class_scope:AdminMessage)
}) })
_sym_db.RegisterMessage(AdminMessage) _sym_db.RegisterMessage(AdminMessage)
HamParameters = _reflection.GeneratedProtocolMessageType('HamParameters', (_message.Message,), {
'DESCRIPTOR' : _HAMPARAMETERS,
'__module__' : 'meshtastic.admin_pb2'
# @@protoc_insertion_point(class_scope:HamParameters)
})
_sym_db.RegisterMessage(HamParameters)
DESCRIPTOR._options = None if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\013AdminProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_ADMINMESSAGE._serialized_start=169
_ADMINMESSAGE._serialized_end=1793
_ADMINMESSAGE_CONFIGTYPE._serialized_start=1411
_ADMINMESSAGE_CONFIGTYPE._serialized_end=1560
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_start=1563
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_end=1774
_HAMPARAMETERS._serialized_start=1795
_HAMPARAMETERS._serialized_end=1886
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: apponly.proto # source: meshtastic/apponly.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -11,62 +12,26 @@ from google.protobuf import symbol_database as _symbol_database
_sym_db = _symbol_database.Default() _sym_db = _symbol_database.Default()
from . import channel_pb2 as channel__pb2 from meshtastic import channel_pb2 as meshtastic_dot_channel__pb2
from meshtastic import config_pb2 as meshtastic_dot_config__pb2
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18meshtastic/apponly.proto\x1a\x18meshtastic/channel.proto\x1a\x17meshtastic/config.proto\"Y\n\nChannelSet\x12\"\n\x08settings\x18\x01 \x03(\x0b\x32\x10.ChannelSettings\x12\'\n\x0blora_config\x18\x02 \x01(\x0b\x32\x12.Config.LoRaConfigBb\n\x13\x63om.geeksville.meshB\rAppOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
name='apponly.proto',
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\rAppOnlyProtosH\003Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\rapponly.proto\x1a\rchannel.proto\"0\n\nChannelSet\x12\"\n\x08settings\x18\x01 \x03(\x0b\x32\x10.ChannelSettingsBI\n\x13\x63om.geeksville.meshB\rAppOnlyProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
,
dependencies=[channel__pb2.DESCRIPTOR,])
_CHANNELSET = DESCRIPTOR.message_types_by_name['ChannelSet']
_CHANNELSET = _descriptor.Descriptor(
name='ChannelSet',
full_name='ChannelSet',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='settings', full_name='ChannelSet.settings', index=0,
number=1, 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),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=32,
serialized_end=80,
)
_CHANNELSET.fields_by_name['settings'].message_type = channel__pb2._CHANNELSETTINGS
DESCRIPTOR.message_types_by_name['ChannelSet'] = _CHANNELSET
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
ChannelSet = _reflection.GeneratedProtocolMessageType('ChannelSet', (_message.Message,), { ChannelSet = _reflection.GeneratedProtocolMessageType('ChannelSet', (_message.Message,), {
'DESCRIPTOR' : _CHANNELSET, 'DESCRIPTOR' : _CHANNELSET,
'__module__' : 'apponly_pb2' '__module__' : 'meshtastic.apponly_pb2'
# @@protoc_insertion_point(class_scope:ChannelSet) # @@protoc_insertion_point(class_scope:ChannelSet)
}) })
_sym_db.RegisterMessage(ChannelSet) _sym_db.RegisterMessage(ChannelSet)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\rAppOnlyProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_CHANNELSET._serialized_start=79
_CHANNELSET._serialized_end=168
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: cannedmessages.proto # source: meshtastic/cannedmessages.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -13,78 +14,22 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1fmeshtastic/cannedmessages.proto\"-\n\x19\x43\x61nnedMessageModuleConfig\x12\x10\n\x08messages\x18\x01 \x01(\tBn\n\x13\x63om.geeksville.meshB\x19\x43\x61nnedMessageConfigProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
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.message_types_by_name['CannedMessageModuleConfig']
_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,), { CannedMessageModuleConfig = _reflection.GeneratedProtocolMessageType('CannedMessageModuleConfig', (_message.Message,), {
'DESCRIPTOR' : _CANNEDMESSAGEMODULECONFIG, 'DESCRIPTOR' : _CANNEDMESSAGEMODULECONFIG,
'__module__' : 'cannedmessages_pb2' '__module__' : 'meshtastic.cannedmessages_pb2'
# @@protoc_insertion_point(class_scope:CannedMessageModuleConfig) # @@protoc_insertion_point(class_scope:CannedMessageModuleConfig)
}) })
_sym_db.RegisterMessage(CannedMessageModuleConfig) _sym_db.RegisterMessage(CannedMessageModuleConfig)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\031CannedMessageConfigProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_CANNEDMESSAGEMODULECONFIG._serialized_start=35
_CANNEDMESSAGEMODULECONFIG._serialized_end=80
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: channel.proto # source: meshtastic/channel.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -13,255 +14,37 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18meshtastic/channel.proto\"\x83\x01\n\x0f\x43hannelSettings\x12\x17\n\x0b\x63hannel_num\x18\x01 \x01(\rB\x02\x18\x01\x12\x0b\n\x03psk\x18\x02 \x01(\x0c\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\n\n\x02id\x18\x04 \x01(\x07\x12\x16\n\x0euplink_enabled\x18\x05 \x01(\x08\x12\x18\n\x10\x64ownlink_enabled\x18\x06 \x01(\x08\"\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\x42\x62\n\x13\x63om.geeksville.meshB\rChannelProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
name='channel.proto',
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\rChannelProtosH\003Z!github.com/meshtastic/gomeshproto',
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'
)
_CHANNELSETTINGS_MODEMCONFIG = _descriptor.EnumDescriptor( _CHANNELSETTINGS = DESCRIPTOR.message_types_by_name['ChannelSettings']
name='ModemConfig', _CHANNEL = DESCRIPTOR.message_types_by_name['Channel']
full_name='ChannelSettings.ModemConfig', _CHANNEL_ROLE = _CHANNEL.enum_types_by_name['Role']
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='VLongSlow', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='LongSlow', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='LongFast', index=2, number=2,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='MidSlow', index=3, number=3,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='MidFast', index=4, number=4,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
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=280,
serialized_end=392,
)
_sym_db.RegisterEnumDescriptor(_CHANNELSETTINGS_MODEMCONFIG)
_CHANNEL_ROLE = _descriptor.EnumDescriptor(
name='Role',
full_name='Channel.Role',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='DISABLED', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='PRIMARY', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='SECONDARY', index=2, number=2,
serialized_options=None,
type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=486,
serialized_end=534,
)
_sym_db.RegisterEnumDescriptor(_CHANNEL_ROLE)
_CHANNELSETTINGS = _descriptor.Descriptor(
name='ChannelSettings',
full_name='ChannelSettings',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='tx_power', full_name='ChannelSettings.tx_power', index=0,
number=1, 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),
_descriptor.FieldDescriptor(
name='modem_config', full_name='ChannelSettings.modem_config', index=1,
number=3, 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),
_descriptor.FieldDescriptor(
name='bandwidth', full_name='ChannelSettings.bandwidth', index=2,
number=6, 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='spread_factor', full_name='ChannelSettings.spread_factor', index=3,
number=7, 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='coding_rate', full_name='ChannelSettings.coding_rate', 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='channel_num', full_name='ChannelSettings.channel_num', index=5,
number=9, 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='psk', full_name='ChannelSettings.psk', index=6,
number=4, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=b"",
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='name', full_name='ChannelSettings.name', index=7,
number=5, 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='id', full_name='ChannelSettings.id', index=8,
number=10, type=7, 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='uplink_enabled', full_name='ChannelSettings.uplink_enabled', index=9,
number=16, 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='downlink_enabled', full_name='ChannelSettings.downlink_enabled', index=10,
number=17, 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),
],
extensions=[
],
nested_types=[],
enum_types=[
_CHANNELSETTINGS_MODEMCONFIG,
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=18,
serialized_end=392,
)
_CHANNEL = _descriptor.Descriptor(
name='Channel',
full_name='Channel',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='index', full_name='Channel.index', index=0,
number=1, 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),
_descriptor.FieldDescriptor(
name='settings', full_name='Channel.settings', index=1,
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='role', full_name='Channel.role', index=2,
number=3, 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=[
_CHANNEL_ROLE,
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=395,
serialized_end=534,
)
_CHANNELSETTINGS.fields_by_name['modem_config'].enum_type = _CHANNELSETTINGS_MODEMCONFIG
_CHANNELSETTINGS_MODEMCONFIG.containing_type = _CHANNELSETTINGS
_CHANNEL.fields_by_name['settings'].message_type = _CHANNELSETTINGS
_CHANNEL.fields_by_name['role'].enum_type = _CHANNEL_ROLE
_CHANNEL_ROLE.containing_type = _CHANNEL
DESCRIPTOR.message_types_by_name['ChannelSettings'] = _CHANNELSETTINGS
DESCRIPTOR.message_types_by_name['Channel'] = _CHANNEL
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
ChannelSettings = _reflection.GeneratedProtocolMessageType('ChannelSettings', (_message.Message,), { ChannelSettings = _reflection.GeneratedProtocolMessageType('ChannelSettings', (_message.Message,), {
'DESCRIPTOR' : _CHANNELSETTINGS, 'DESCRIPTOR' : _CHANNELSETTINGS,
'__module__' : 'channel_pb2' '__module__' : 'meshtastic.channel_pb2'
# @@protoc_insertion_point(class_scope:ChannelSettings) # @@protoc_insertion_point(class_scope:ChannelSettings)
}) })
_sym_db.RegisterMessage(ChannelSettings) _sym_db.RegisterMessage(ChannelSettings)
Channel = _reflection.GeneratedProtocolMessageType('Channel', (_message.Message,), { Channel = _reflection.GeneratedProtocolMessageType('Channel', (_message.Message,), {
'DESCRIPTOR' : _CHANNEL, 'DESCRIPTOR' : _CHANNEL,
'__module__' : 'channel_pb2' '__module__' : 'meshtastic.channel_pb2'
# @@protoc_insertion_point(class_scope:Channel) # @@protoc_insertion_point(class_scope:Channel)
}) })
_sym_db.RegisterMessage(Channel) _sym_db.RegisterMessage(Channel)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\rChannelProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_CHANNELSETTINGS.fields_by_name['channel_num']._options = None
_CHANNELSETTINGS.fields_by_name['channel_num']._serialized_options = b'\030\001'
_CHANNELSETTINGS._serialized_start=29
_CHANNELSETTINGS._serialized_end=160
_CHANNEL._serialized_start=163
_CHANNEL._serialized_end=302
_CHANNEL_ROLE._serialized_start=254
_CHANNEL_ROLE._serialized_end=302
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

156
meshtastic/config_pb2.py Normal file
View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/connection_status.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
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_pool.Default().AddSerializedFile(b'\n\"meshtastic/connection_status.proto\"\x85\x02\n\x16\x44\x65viceConnectionStatus\x12(\n\x04wifi\x18\x01 \x01(\x0b\x32\x15.WifiConnectionStatusH\x00\x88\x01\x01\x12\x30\n\x08\x65thernet\x18\x02 \x01(\x0b\x32\x19.EthernetConnectionStatusH\x01\x88\x01\x01\x12\x32\n\tbluetooth\x18\x03 \x01(\x0b\x32\x1a.BluetoothConnectionStatusH\x02\x88\x01\x01\x12,\n\x06serial\x18\x04 \x01(\x0b\x32\x17.SerialConnectionStatusH\x03\x88\x01\x01\x42\x07\n\x05_wifiB\x0b\n\t_ethernetB\x0c\n\n_bluetoothB\t\n\x07_serial\"\\\n\x14WifiConnectionStatus\x12(\n\x06status\x18\x01 \x01(\x0b\x32\x18.NetworkConnectionStatus\x12\x0c\n\x04ssid\x18\x02 \x01(\t\x12\x0c\n\x04rssi\x18\x03 \x01(\x05\"D\n\x18\x45thernetConnectionStatus\x12(\n\x06status\x18\x01 \x01(\x0b\x32\x18.NetworkConnectionStatus\"{\n\x17NetworkConnectionStatus\x12\x12\n\nip_address\x18\x01 \x01(\x07\x12\x14\n\x0cis_connected\x18\x02 \x01(\x08\x12\x19\n\x11is_mqtt_connected\x18\x03 \x01(\x08\x12\x1b\n\x13is_syslog_connected\x18\x04 \x01(\x08\"L\n\x19\x42luetoothConnectionStatus\x12\x0b\n\x03pin\x18\x01 \x01(\r\x12\x0c\n\x04rssi\x18\x02 \x01(\x05\x12\x14\n\x0cis_connected\x18\x03 \x01(\x08\"<\n\x16SerialConnectionStatus\x12\x0c\n\x04\x62\x61ud\x18\x01 \x01(\r\x12\x14\n\x0cis_connected\x18\x02 \x01(\x08\x42\x65\n\x13\x63om.geeksville.meshB\x10\x43onnStatusProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_DEVICECONNECTIONSTATUS = DESCRIPTOR.message_types_by_name['DeviceConnectionStatus']
_WIFICONNECTIONSTATUS = DESCRIPTOR.message_types_by_name['WifiConnectionStatus']
_ETHERNETCONNECTIONSTATUS = DESCRIPTOR.message_types_by_name['EthernetConnectionStatus']
_NETWORKCONNECTIONSTATUS = DESCRIPTOR.message_types_by_name['NetworkConnectionStatus']
_BLUETOOTHCONNECTIONSTATUS = DESCRIPTOR.message_types_by_name['BluetoothConnectionStatus']
_SERIALCONNECTIONSTATUS = DESCRIPTOR.message_types_by_name['SerialConnectionStatus']
DeviceConnectionStatus = _reflection.GeneratedProtocolMessageType('DeviceConnectionStatus', (_message.Message,), {
'DESCRIPTOR' : _DEVICECONNECTIONSTATUS,
'__module__' : 'meshtastic.connection_status_pb2'
# @@protoc_insertion_point(class_scope:DeviceConnectionStatus)
})
_sym_db.RegisterMessage(DeviceConnectionStatus)
WifiConnectionStatus = _reflection.GeneratedProtocolMessageType('WifiConnectionStatus', (_message.Message,), {
'DESCRIPTOR' : _WIFICONNECTIONSTATUS,
'__module__' : 'meshtastic.connection_status_pb2'
# @@protoc_insertion_point(class_scope:WifiConnectionStatus)
})
_sym_db.RegisterMessage(WifiConnectionStatus)
EthernetConnectionStatus = _reflection.GeneratedProtocolMessageType('EthernetConnectionStatus', (_message.Message,), {
'DESCRIPTOR' : _ETHERNETCONNECTIONSTATUS,
'__module__' : 'meshtastic.connection_status_pb2'
# @@protoc_insertion_point(class_scope:EthernetConnectionStatus)
})
_sym_db.RegisterMessage(EthernetConnectionStatus)
NetworkConnectionStatus = _reflection.GeneratedProtocolMessageType('NetworkConnectionStatus', (_message.Message,), {
'DESCRIPTOR' : _NETWORKCONNECTIONSTATUS,
'__module__' : 'meshtastic.connection_status_pb2'
# @@protoc_insertion_point(class_scope:NetworkConnectionStatus)
})
_sym_db.RegisterMessage(NetworkConnectionStatus)
BluetoothConnectionStatus = _reflection.GeneratedProtocolMessageType('BluetoothConnectionStatus', (_message.Message,), {
'DESCRIPTOR' : _BLUETOOTHCONNECTIONSTATUS,
'__module__' : 'meshtastic.connection_status_pb2'
# @@protoc_insertion_point(class_scope:BluetoothConnectionStatus)
})
_sym_db.RegisterMessage(BluetoothConnectionStatus)
SerialConnectionStatus = _reflection.GeneratedProtocolMessageType('SerialConnectionStatus', (_message.Message,), {
'DESCRIPTOR' : _SERIALCONNECTIONSTATUS,
'__module__' : 'meshtastic.connection_status_pb2'
# @@protoc_insertion_point(class_scope:SerialConnectionStatus)
})
_sym_db.RegisterMessage(SerialConnectionStatus)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\020ConnStatusProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_DEVICECONNECTIONSTATUS._serialized_start=39
_DEVICECONNECTIONSTATUS._serialized_end=300
_WIFICONNECTIONSTATUS._serialized_start=302
_WIFICONNECTIONSTATUS._serialized_end=394
_ETHERNETCONNECTIONSTATUS._serialized_start=396
_ETHERNETCONNECTIONSTATUS._serialized_end=464
_NETWORKCONNECTIONSTATUS._serialized_start=466
_NETWORKCONNECTIONSTATUS._serialized_end=589
_BLUETOOTHCONNECTIONSTATUS._serialized_start=591
_BLUETOOTHCONNECTIONSTATUS._serialized_end=667
_SERIALCONNECTIONSTATUS._serialized_start=669
_SERIALCONNECTIONSTATUS._serialized_end=729
# @@protoc_insertion_point(module_scope)

View File

@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/device_metadata.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
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()
from meshtastic import config_pb2 as meshtastic_dot_config__pb2
from meshtastic import mesh_pb2 as meshtastic_dot_mesh__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n meshtastic/device_metadata.proto\x1a\x17meshtastic/config.proto\x1a\x15meshtastic/mesh.proto\"\xfc\x01\n\x0e\x44\x65viceMetadata\x12\x18\n\x10\x66irmware_version\x18\x01 \x01(\t\x12\x1c\n\x14\x64\x65vice_state_version\x18\x02 \x01(\r\x12\x13\n\x0b\x63\x61nShutdown\x18\x03 \x01(\x08\x12\x0f\n\x07hasWifi\x18\x04 \x01(\x08\x12\x14\n\x0chasBluetooth\x18\x05 \x01(\x08\x12\x13\n\x0bhasEthernet\x18\x06 \x01(\x08\x12\'\n\x04role\x18\x07 \x01(\x0e\x32\x19.Config.DeviceConfig.Role\x12\x16\n\x0eposition_flags\x18\x08 \x01(\r\x12 \n\x08hw_model\x18\t \x01(\x0e\x32\x0e.HardwareModelBi\n\x13\x63om.geeksville.meshB\x14\x44\x65viceMetadataProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_DEVICEMETADATA = DESCRIPTOR.message_types_by_name['DeviceMetadata']
DeviceMetadata = _reflection.GeneratedProtocolMessageType('DeviceMetadata', (_message.Message,), {
'DESCRIPTOR' : _DEVICEMETADATA,
'__module__' : 'meshtastic.device_metadata_pb2'
# @@protoc_insertion_point(class_scope:DeviceMetadata)
})
_sym_db.RegisterMessage(DeviceMetadata)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\024DeviceMetadataProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_DEVICEMETADATA._serialized_start=85
_DEVICEMETADATA._serialized_end=337
# @@protoc_insertion_point(module_scope)

View File

@@ -1,8 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: deviceonly.proto # source: meshtastic/deviceonly.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -11,156 +13,54 @@ from google.protobuf import symbol_database as _symbol_database
_sym_db = _symbol_database.Default() _sym_db = _symbol_database.Default()
from . import channel_pb2 as channel__pb2 from meshtastic import channel_pb2 as meshtastic_dot_channel__pb2
from . import mesh_pb2 as mesh__pb2 from meshtastic import localonly_pb2 as meshtastic_dot_localonly__pb2
from meshtastic import mesh_pb2 as meshtastic_dot_mesh__pb2
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bmeshtastic/deviceonly.proto\x1a\x18meshtastic/channel.proto\x1a\x1ameshtastic/localonly.proto\x1a\x15meshtastic/mesh.proto\"\xe0\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(\x08\":\n\x0b\x43hannelFile\x12\x1a\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x08.Channel\x12\x0f\n\x07version\x18\x02 \x01(\r\"\xf6\x01\n\x08OEMStore\x12\x16\n\x0eoem_icon_width\x18\x01 \x01(\r\x12\x17\n\x0foem_icon_height\x18\x02 \x01(\r\x12\x15\n\roem_icon_bits\x18\x03 \x01(\x0c\x12\x1e\n\x08oem_font\x18\x04 \x01(\x0e\x32\x0c.ScreenFonts\x12\x10\n\x08oem_text\x18\x05 \x01(\t\x12\x13\n\x0boem_aes_key\x18\x06 \x01(\x0c\x12&\n\x10oem_local_config\x18\x07 \x01(\x0b\x32\x0c.LocalConfig\x12\x33\n\x17oem_local_module_config\x18\x08 \x01(\x0b\x32\x12.LocalModuleConfig*>\n\x0bScreenFonts\x12\x0e\n\nFONT_SMALL\x10\x00\x12\x0f\n\x0b\x46ONT_MEDIUM\x10\x01\x12\x0e\n\nFONT_LARGE\x10\x02\x42_\n\x13\x63om.geeksville.meshB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
name='deviceonly.proto',
package='', _SCREENFONTS = DESCRIPTOR.enum_types_by_name['ScreenFonts']
syntax='proto3', ScreenFonts = enum_type_wrapper.EnumTypeWrapper(_SCREENFONTS)
serialized_options=b'\n\023com.geeksville.meshB\nDeviceOnlyH\003Z!github.com/meshtastic/gomeshproto', FONT_SMALL = 0
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' FONT_MEDIUM = 1
, FONT_LARGE = 2
dependencies=[channel__pb2.DESCRIPTOR,mesh__pb2.DESCRIPTOR,])
_DEVICESTATE = DESCRIPTOR.message_types_by_name['DeviceState']
_CHANNELFILE = DESCRIPTOR.message_types_by_name['ChannelFile']
_DEVICESTATE = _descriptor.Descriptor( _OEMSTORE = DESCRIPTOR.message_types_by_name['OEMStore']
name='DeviceState',
full_name='DeviceState',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
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=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=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=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=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=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=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=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,
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=48,
serialized_end=278,
)
_CHANNELFILE = _descriptor.Descriptor(
name='ChannelFile',
full_name='ChannelFile',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='channels', full_name='ChannelFile.channels', index=0,
number=1, 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),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=280,
serialized_end=321,
)
_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['DeviceState'] = _DEVICESTATE
DESCRIPTOR.message_types_by_name['ChannelFile'] = _CHANNELFILE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
DeviceState = _reflection.GeneratedProtocolMessageType('DeviceState', (_message.Message,), { DeviceState = _reflection.GeneratedProtocolMessageType('DeviceState', (_message.Message,), {
'DESCRIPTOR' : _DEVICESTATE, 'DESCRIPTOR' : _DEVICESTATE,
'__module__' : 'deviceonly_pb2' '__module__' : 'meshtastic.deviceonly_pb2'
# @@protoc_insertion_point(class_scope:DeviceState) # @@protoc_insertion_point(class_scope:DeviceState)
}) })
_sym_db.RegisterMessage(DeviceState) _sym_db.RegisterMessage(DeviceState)
ChannelFile = _reflection.GeneratedProtocolMessageType('ChannelFile', (_message.Message,), { ChannelFile = _reflection.GeneratedProtocolMessageType('ChannelFile', (_message.Message,), {
'DESCRIPTOR' : _CHANNELFILE, 'DESCRIPTOR' : _CHANNELFILE,
'__module__' : 'deviceonly_pb2' '__module__' : 'meshtastic.deviceonly_pb2'
# @@protoc_insertion_point(class_scope:ChannelFile) # @@protoc_insertion_point(class_scope:ChannelFile)
}) })
_sym_db.RegisterMessage(ChannelFile) _sym_db.RegisterMessage(ChannelFile)
OEMStore = _reflection.GeneratedProtocolMessageType('OEMStore', (_message.Message,), {
'DESCRIPTOR' : _OEMSTORE,
'__module__' : 'meshtastic.deviceonly_pb2'
# @@protoc_insertion_point(class_scope:OEMStore)
})
_sym_db.RegisterMessage(OEMStore)
DESCRIPTOR._options = None if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_SCREENFONTS._serialized_start=644
_SCREENFONTS._serialized_end=706
_DEVICESTATE._serialized_start=109
_DEVICESTATE._serialized_end=333
_CHANNELFILE._serialized_start=335
_CHANNELFILE._serialized_end=393
_OEMSTORE._serialized_start=396
_OEMSTORE._serialized_end=642
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/localonly.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
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()
from meshtastic import config_pb2 as meshtastic_dot_config__pb2
from meshtastic import module_config_pb2 as meshtastic_dot_module__config__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1ameshtastic/localonly.proto\x1a\x17meshtastic/config.proto\x1a\x1emeshtastic/module_config.proto\"\xb0\x02\n\x0bLocalConfig\x12$\n\x06\x64\x65vice\x18\x01 \x01(\x0b\x32\x14.Config.DeviceConfig\x12(\n\x08position\x18\x02 \x01(\x0b\x32\x16.Config.PositionConfig\x12\"\n\x05power\x18\x03 \x01(\x0b\x32\x13.Config.PowerConfig\x12&\n\x07network\x18\x04 \x01(\x0b\x32\x15.Config.NetworkConfig\x12&\n\x07\x64isplay\x18\x05 \x01(\x0b\x32\x15.Config.DisplayConfig\x12 \n\x04lora\x18\x06 \x01(\x0b\x32\x12.Config.LoRaConfig\x12*\n\tbluetooth\x18\x07 \x01(\x0b\x32\x17.Config.BluetoothConfig\x12\x0f\n\x07version\x18\x08 \x01(\r\"\x81\x04\n\x11LocalModuleConfig\x12&\n\x04mqtt\x18\x01 \x01(\x0b\x32\x18.ModuleConfig.MQTTConfig\x12*\n\x06serial\x18\x02 \x01(\x0b\x32\x1a.ModuleConfig.SerialConfig\x12G\n\x15\x65xternal_notification\x18\x03 \x01(\x0b\x32(.ModuleConfig.ExternalNotificationConfig\x12\x37\n\rstore_forward\x18\x04 \x01(\x0b\x32 .ModuleConfig.StoreForwardConfig\x12\x31\n\nrange_test\x18\x05 \x01(\x0b\x32\x1d.ModuleConfig.RangeTestConfig\x12\x30\n\ttelemetry\x18\x06 \x01(\x0b\x32\x1d.ModuleConfig.TelemetryConfig\x12\x39\n\x0e\x63\x61nned_message\x18\x07 \x01(\x0b\x32!.ModuleConfig.CannedMessageConfig\x12(\n\x05\x61udio\x18\t \x01(\x0b\x32\x19.ModuleConfig.AudioConfig\x12;\n\x0fremote_hardware\x18\n \x01(\x0b\x32\".ModuleConfig.RemoteHardwareConfig\x12\x0f\n\x07version\x18\x08 \x01(\rBd\n\x13\x63om.geeksville.meshB\x0fLocalOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_LOCALCONFIG = DESCRIPTOR.message_types_by_name['LocalConfig']
_LOCALMODULECONFIG = DESCRIPTOR.message_types_by_name['LocalModuleConfig']
LocalConfig = _reflection.GeneratedProtocolMessageType('LocalConfig', (_message.Message,), {
'DESCRIPTOR' : _LOCALCONFIG,
'__module__' : 'meshtastic.localonly_pb2'
# @@protoc_insertion_point(class_scope:LocalConfig)
})
_sym_db.RegisterMessage(LocalConfig)
LocalModuleConfig = _reflection.GeneratedProtocolMessageType('LocalModuleConfig', (_message.Message,), {
'DESCRIPTOR' : _LOCALMODULECONFIG,
'__module__' : 'meshtastic.localonly_pb2'
# @@protoc_insertion_point(class_scope:LocalModuleConfig)
})
_sym_db.RegisterMessage(LocalModuleConfig)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\017LocalOnlyProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_LOCALCONFIG._serialized_start=88
_LOCALCONFIG._serialized_end=392
_LOCALMODULECONFIG._serialized_start=395
_LOCALMODULECONFIG._serialized_end=908
# @@protoc_insertion_point(module_scope)

View File

@@ -18,7 +18,7 @@ from google.protobuf.json_format import MessageToJson
import meshtastic.node import meshtastic.node
from meshtastic import portnums_pb2, mesh_pb2 from meshtastic import portnums_pb2, mesh_pb2
from meshtastic.util import stripnl, Timeout, our_exit, remove_keys_from_dict, convert_mac_addr from meshtastic.util import stripnl, Timeout, Acknowledgment, our_exit, remove_keys_from_dict, convert_mac_addr
from meshtastic.__init__ import LOCAL_ADDR, BROADCAST_NUM, BROADCAST_ADDR, ResponseHandler, publishingThread, OUR_APP_VERSION, protocols from meshtastic.__init__ import LOCAL_ADDR, BROADCAST_NUM, BROADCAST_ADDR, ResponseHandler, publishingThread, OUR_APP_VERSION, protocols
class MeshInterface: class MeshInterface:
@@ -47,12 +47,12 @@ class MeshInterface:
self.responseHandlers = {} # A map from request ID to the handler self.responseHandlers = {} # A map from request ID to the handler
self.failure = None # If we've encountered a fatal exception it will be kept here self.failure = None # If we've encountered a fatal exception it will be kept here
self._timeout = Timeout() self._timeout = Timeout()
self._acknowledgment = Acknowledgment()
self.heartbeatTimer = None self.heartbeatTimer = None
random.seed() # FIXME, we should not clobber the random seedval here, instead tell user they must call it random.seed() # FIXME, we should not clobber the random seedval here, instead tell user they must call it
self.currentPacketId = random.randint(0, 0xffffffff) self.currentPacketId = random.randint(0, 0xffffffff)
self.nodesByNum = None self.nodesByNum = None
self.configId = None self.configId = None
self.defaultHopLimit = 3
self.gotResponse = False # used in gpio read self.gotResponse = False # used in gpio read
self.mask = None # used in gpio read and gpio watch self.mask = None # used in gpio read and gpio watch
@@ -137,7 +137,20 @@ class MeshInterface:
"Latitude": formatFloat(pos.get("latitude"), 4, "°"), "Latitude": formatFloat(pos.get("latitude"), 4, "°"),
"Longitude": formatFloat(pos.get("longitude"), 4, "°"), "Longitude": formatFloat(pos.get("longitude"), 4, "°"),
"Altitude": formatFloat(pos.get("altitude"), 0, " m"), "Altitude": formatFloat(pos.get("altitude"), 0, " m"),
"Battery": formatFloat(pos.get("batteryLevel"), 2, "%"), })
metrics = node.get('deviceMetrics')
if metrics:
batteryLevel = metrics.get('batteryLevel')
if batteryLevel is not None:
if batteryLevel == 0:
batteryString = "Powered"
else:
batteryString = str(batteryLevel)+"%"
row.update({"Battery": batteryString})
row.update({
"Channel util.": formatFloat(metrics.get('channelUtilization'), 2, "%"),
"Tx air util.": formatFloat(metrics.get('airUtilTx'), 2, "%"),
}) })
row.update({ row.update({
@@ -157,23 +170,24 @@ class MeshInterface:
return table return table
def getNode(self, nodeId): def getNode(self, nodeId, requestChannels=True):
"""Return a node object which contains device settings and channel info""" """Return a node object which contains device settings and channel info"""
if nodeId in (LOCAL_ADDR, BROADCAST_ADDR): if nodeId in (LOCAL_ADDR, BROADCAST_ADDR):
return self.localNode return self.localNode
else: else:
n = meshtastic.node.Node(self, nodeId) n = meshtastic.node.Node(self, nodeId)
logging.debug("About to requestConfig") # Only request device settings and channel info when necessary
n.requestConfig() if requestChannels:
if not n.waitForConfig(): logging.debug("About to requestChannels")
our_exit("Error: Timed out waiting for node config") n.requestChannels()
if not n.waitForConfig():
our_exit("Error: Timed out waiting for channels")
return n return n
def sendText(self, text: AnyStr, def sendText(self, text: AnyStr,
destinationId=BROADCAST_ADDR, destinationId=BROADCAST_ADDR,
wantAck=False, wantAck=False,
wantResponse=False, wantResponse=False,
hopLimit=None,
onResponse=None, onResponse=None,
channelIndex=0): channelIndex=0):
"""Send a utf8 string to some other node, if the node has a display it """Send a utf8 string to some other node, if the node has a display it
@@ -195,21 +209,17 @@ class MeshInterface:
Returns the sent packet. The id field will be populated in this packet Returns the sent packet. The id field will be populated in this packet
and can be used to track future message acks/naks. and can be used to track future message acks/naks.
""" """
if hopLimit is None:
hopLimit = self.defaultHopLimit
return self.sendData(text.encode("utf-8"), destinationId, return self.sendData(text.encode("utf-8"), destinationId,
portNum=portnums_pb2.PortNum.TEXT_MESSAGE_APP, portNum=portnums_pb2.PortNum.TEXT_MESSAGE_APP,
wantAck=wantAck, wantAck=wantAck,
wantResponse=wantResponse, wantResponse=wantResponse,
hopLimit=hopLimit,
onResponse=onResponse, onResponse=onResponse,
channelIndex=channelIndex) channelIndex=channelIndex)
def sendData(self, data, destinationId=BROADCAST_ADDR, def sendData(self, data, destinationId=BROADCAST_ADDR,
portNum=portnums_pb2.PortNum.PRIVATE_APP, wantAck=False, portNum=portnums_pb2.PortNum.PRIVATE_APP, wantAck=False,
wantResponse=False, wantResponse=False,
hopLimit=None,
onResponse=None, onResponse=None,
channelIndex=0): channelIndex=0):
"""Send a data packet to some other node """Send a data packet to some other node
@@ -234,8 +244,6 @@ class MeshInterface:
Returns the sent packet. The id field will be populated in this packet Returns the sent packet. The id field will be populated in this packet
and can be used to track future message acks/naks. and can be used to track future message acks/naks.
""" """
if hopLimit is None:
hopLimit = self.defaultHopLimit
if getattr(data, "SerializeToString", None): if getattr(data, "SerializeToString", None):
logging.debug(f"Serializing protobuf as data: {stripnl(data)}") logging.debug(f"Serializing protobuf as data: {stripnl(data)}")
@@ -258,8 +266,7 @@ class MeshInterface:
if onResponse is not None: if onResponse is not None:
self._addResponseHandler(meshPacket.id, onResponse) self._addResponseHandler(meshPacket.id, onResponse)
p = self._sendPacket(meshPacket, destinationId, p = self._sendPacket(meshPacket, destinationId, wantAck=wantAck)
wantAck=wantAck, hopLimit=hopLimit)
return p return p
def sendPosition(self, latitude=0.0, longitude=0.0, altitude=0, timeSec=0, def sendPosition(self, latitude=0.0, longitude=0.0, altitude=0, timeSec=0,
@@ -298,20 +305,43 @@ class MeshInterface:
wantAck=wantAck, wantAck=wantAck,
wantResponse=wantResponse) wantResponse=wantResponse)
def sendTraceRoute(self, dest, hopLimit):
"""Send the trace route"""
r = mesh_pb2.RouteDiscovery()
self.sendData(r, destinationId=dest, portNum=portnums_pb2.PortNum.TRACEROUTE_APP,
wantResponse=True, onResponse=self.onResponseTraceRoute)
# extend timeout based on number of nodes, limit by configured hopLimit
waitFactor = min(len(self.nodes)-1, hopLimit)
self.waitForTraceRoute(waitFactor)
def onResponseTraceRoute(self, p):
"""on response for trace route"""
routeDiscovery = mesh_pb2.RouteDiscovery()
routeDiscovery.ParseFromString(p["decoded"]["payload"])
asDict = google.protobuf.json_format.MessageToDict(routeDiscovery)
print("Route traced:")
routeStr = self._nodeNumToId(p["to"])
if "route" in asDict:
for nodeNum in asDict["route"]:
routeStr += " --> " + self._nodeNumToId(nodeNum)
routeStr += " --> " + self._nodeNumToId(p["from"])
print(routeStr)
self._acknowledgment.receivedTraceRoute = True
def _addResponseHandler(self, requestId, callback): def _addResponseHandler(self, requestId, callback):
self.responseHandlers[requestId] = ResponseHandler(callback) self.responseHandlers[requestId] = ResponseHandler(callback)
def _sendPacket(self, meshPacket, def _sendPacket(self, meshPacket,
destinationId=BROADCAST_ADDR, destinationId=BROADCAST_ADDR,
wantAck=False, hopLimit=None): wantAck=False):
"""Send a MeshPacket to the specified node (or if unspecified, broadcast). """Send a MeshPacket to the specified node (or if unspecified, broadcast).
You probably don't want this - use sendData instead. You probably don't want this - use sendData instead.
Returns the sent packet. The id field will be populated in this packet and Returns the sent packet. The id field will be populated in this packet and
can be used to track future message acks/naks. can be used to track future message acks/naks.
""" """
if hopLimit is None:
hopLimit = self.defaultHopLimit
# We allow users to talk to the local node before we've completed the full connection flow... # We allow users to talk to the local node before we've completed the full connection flow...
if(self.myInfo is not None and destinationId != self.myInfo.my_node_num): if(self.myInfo is not None and destinationId != self.myInfo.my_node_num):
@@ -345,6 +375,8 @@ class MeshInterface:
meshPacket.to = nodeNum meshPacket.to = nodeNum
meshPacket.want_ack = wantAck meshPacket.want_ack = wantAck
loraConfig = getattr(self.localNode.localConfig, 'lora')
hopLimit = getattr(loraConfig, 'hop_limit')
meshPacket.hop_limit = hopLimit meshPacket.hop_limit = hopLimit
# if the user hasn't set an ID for this packet (likely and recommended), # if the user hasn't set an ID for this packet (likely and recommended),
@@ -366,6 +398,18 @@ class MeshInterface:
if not success: if not success:
raise Exception("Timed out waiting for interface config") raise Exception("Timed out waiting for interface config")
def waitForAckNak(self):
"""Wait for the ack/nak"""
success = self._timeout.waitForAckNak(self._acknowledgment)
if not success:
raise Exception("Timed out waiting for an acknowledgment")
def waitForTraceRoute(self, waitFactor):
"""Wait for trace route"""
success = self._timeout.waitForTraceRoute(waitFactor, self._acknowledgment)
if not success:
raise Exception("Timed out waiting for traceroute")
def getMyNodeInfo(self): def getMyNodeInfo(self):
"""Get info about my node.""" """Get info about my node."""
if self.myInfo is None: if self.myInfo is None:
@@ -422,8 +466,8 @@ class MeshInterface:
"""We need to send a heartbeat message to the device every X seconds""" """We need to send a heartbeat message to the device every X seconds"""
def callback(): def callback():
self.heartbeatTimer = None self.heartbeatTimer = None
prefs = self.localNode.radioConfig.preferences prefs = self.localNode.localConfig
i = prefs.phone_timeout_secs / 2 i = prefs.power.ls_secs / 2
logging.debug(f"Sending heartbeat, interval {i}") logging.debug(f"Sending heartbeat, interval {i}")
if i != 0: if i != 0:
self.heartbeatTimer = threading.Timer(i, callback) self.heartbeatTimer = threading.Timer(i, callback)
@@ -478,7 +522,7 @@ class MeshInterface:
Done with initial config messages, now send regular MeshPackets Done with initial config messages, now send regular MeshPackets
to ask for settings and channels to ask for settings and channels
""" """
self.localNode.requestConfig() self.localNode.requestChannels()
def _handleFromRadio(self, fromRadioBytes): def _handleFromRadio(self, fromRadioBytes):
""" """
@@ -532,14 +576,50 @@ class MeshInterface:
# stream API fromRadio.config_complete_id # stream API fromRadio.config_complete_id
logging.debug(f"Config complete ID {self.configId}") logging.debug(f"Config complete ID {self.configId}")
self._handleConfigComplete() self._handleConfigComplete()
elif fromRadio.HasField("packet"): elif fromRadio.HasField("packet"):
self._handlePacketFromRadio(fromRadio.packet) self._handlePacketFromRadio(fromRadio.packet)
elif fromRadio.rebooted: elif fromRadio.rebooted:
# Tell clients the device went away. Careful not to call the overridden # Tell clients the device went away. Careful not to call the overridden
# subclass version that closes the serial port # subclass version that closes the serial port
MeshInterface._disconnected(self) MeshInterface._disconnected(self)
self._startConfig() # redownload the node db etc... self._startConfig() # redownload the node db etc...
elif fromRadio.config or fromRadio.moduleConfig:
if fromRadio.config.HasField("device"):
self.localNode.localConfig.device.CopyFrom(fromRadio.config.device)
elif fromRadio.config.HasField("position"):
self.localNode.localConfig.position.CopyFrom(fromRadio.config.position)
elif fromRadio.config.HasField("power"):
self.localNode.localConfig.power.CopyFrom(fromRadio.config.power)
elif fromRadio.config.HasField("network"):
self.localNode.localConfig.network.CopyFrom(fromRadio.config.network)
elif fromRadio.config.HasField("display"):
self.localNode.localConfig.display.CopyFrom(fromRadio.config.display)
elif fromRadio.config.HasField("lora"):
self.localNode.localConfig.lora.CopyFrom(fromRadio.config.lora)
elif fromRadio.config.HasField("bluetooth"):
self.localNode.localConfig.bluetooth.CopyFrom(fromRadio.config.bluetooth)
elif fromRadio.moduleConfig.HasField("mqtt"):
self.localNode.moduleConfig.mqtt.CopyFrom(fromRadio.moduleConfig.mqtt)
elif fromRadio.moduleConfig.HasField("serial"):
self.localNode.moduleConfig.serial.CopyFrom(fromRadio.moduleConfig.serial)
elif fromRadio.moduleConfig.HasField("external_notification"):
self.localNode.moduleConfig.external_notification.CopyFrom(fromRadio.moduleConfig.external_notification)
elif fromRadio.moduleConfig.HasField("range_test"):
self.localNode.moduleConfig.range_test.CopyFrom(fromRadio.moduleConfig.range_test)
elif fromRadio.moduleConfig.HasField("telemetry"):
self.localNode.moduleConfig.telemetry.CopyFrom(fromRadio.moduleConfig.telemetry)
elif fromRadio.moduleConfig.HasField("canned_message"):
self.localNode.moduleConfig.canned_message.CopyFrom(fromRadio.moduleConfig.canned_message)
elif fromRadio.moduleConfig.HasField("audio"):
self.localNode.moduleConfig.audio.CopyFrom(fromRadio.moduleConfig.audio)
elif fromRadio.moduleConfig.HasField("remote_hardware"):
self.localNode.moduleConfig.remote_hardware.CopyFrom(fromRadio.moduleConfig.remote_hardware)
else: else:
logging.debug("Unexpected FromRadio payload") logging.debug("Unexpected FromRadio payload")
@@ -643,7 +723,7 @@ class MeshInterface:
# UNKNOWN_APP is the default protobuf portnum value, and therefore if not # 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 # set it will not be populated at all to make API usage easier, set
# it to prevent confusion # it to prevent confusion
if "portnum" not in decoded: if decoded and "portnum" not in decoded:
new_portnum = portnums_pb2.PortNum.Name(portnums_pb2.PortNum.UNKNOWN_APP) new_portnum = portnums_pb2.PortNum.Name(portnums_pb2.PortNum.UNKNOWN_APP)
decoded["portnum"] = new_portnum decoded["portnum"] = new_portnum
logging.warning(f"portnum was not in decoded. Setting to:{new_portnum}") logging.warning(f"portnum was not in decoded. Setting to:{new_portnum}")
@@ -685,7 +765,8 @@ class MeshInterface:
# we keep the responseHandler in dict until we get a non ack # we keep the responseHandler in dict until we get a non ack
handler = self.responseHandlers.pop(requestId, None) handler = self.responseHandlers.pop(requestId, None)
if handler is not None: if handler is not None:
handler.callback(asDict) if not isAck or (isAck and handler.__name__ == "onAckNak"):
handler.callback(asDict)
logging.debug(f"Publishing {topic}: packet={stripnl(asDict)} ") logging.debug(f"Publishing {topic}: packet={stripnl(asDict)} ")
publishingThread.queueWork(lambda: pub.sendMessage( publishingThread.queueWork(lambda: pub.sendMessage(

View File

File diff suppressed because one or more lines are too long

View File

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: mqtt.proto # source: meshtastic/mqtt.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -11,76 +12,25 @@ from google.protobuf import symbol_database as _symbol_database
_sym_db = _symbol_database.Default() _sym_db = _symbol_database.Default()
from . import mesh_pb2 as mesh__pb2 from meshtastic import mesh_pb2 as meshtastic_dot_mesh__pb2
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15meshtastic/mqtt.proto\x1a\x15meshtastic/mesh.proto\"V\n\x0fServiceEnvelope\x12\x1b\n\x06packet\x18\x01 \x01(\x0b\x32\x0b.MeshPacket\x12\x12\n\nchannel_id\x18\x02 \x01(\t\x12\x12\n\ngateway_id\x18\x03 \x01(\tB_\n\x13\x63om.geeksville.meshB\nMQTTProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
name='mqtt.proto',
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\nMQTTProtosH\003Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\nmqtt.proto\x1a\nmesh.proto\"V\n\x0fServiceEnvelope\x12\x1b\n\x06packet\x18\x01 \x01(\x0b\x32\x0b.MeshPacket\x12\x12\n\nchannel_id\x18\x02 \x01(\t\x12\x12\n\ngateway_id\x18\x03 \x01(\tBF\n\x13\x63om.geeksville.meshB\nMQTTProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
,
dependencies=[mesh__pb2.DESCRIPTOR,])
_SERVICEENVELOPE = DESCRIPTOR.message_types_by_name['ServiceEnvelope']
_SERVICEENVELOPE = _descriptor.Descriptor(
name='ServiceEnvelope',
full_name='ServiceEnvelope',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='packet', full_name='ServiceEnvelope.packet', 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='channel_id', full_name='ServiceEnvelope.channel_id', index=1,
number=2, 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='gateway_id', full_name='ServiceEnvelope.gateway_id', index=2,
number=3, 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=26,
serialized_end=112,
)
_SERVICEENVELOPE.fields_by_name['packet'].message_type = mesh__pb2._MESHPACKET
DESCRIPTOR.message_types_by_name['ServiceEnvelope'] = _SERVICEENVELOPE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
ServiceEnvelope = _reflection.GeneratedProtocolMessageType('ServiceEnvelope', (_message.Message,), { ServiceEnvelope = _reflection.GeneratedProtocolMessageType('ServiceEnvelope', (_message.Message,), {
'DESCRIPTOR' : _SERVICEENVELOPE, 'DESCRIPTOR' : _SERVICEENVELOPE,
'__module__' : 'mqtt_pb2' '__module__' : 'meshtastic.mqtt_pb2'
# @@protoc_insertion_point(class_scope:ServiceEnvelope) # @@protoc_insertion_point(class_scope:ServiceEnvelope)
}) })
_sym_db.RegisterMessage(ServiceEnvelope) _sym_db.RegisterMessage(ServiceEnvelope)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\nMQTTProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_SERVICEENVELOPE._serialized_start=48
_SERVICEENVELOPE._serialized_end=134
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@@ -5,32 +5,30 @@ import logging
import base64 import base64
import time import time
from google.protobuf.json_format import MessageToJson from google.protobuf.json_format import MessageToJson
from meshtastic import portnums_pb2, apponly_pb2, admin_pb2, channel_pb2 from meshtastic import portnums_pb2, apponly_pb2, admin_pb2, channel_pb2, localonly_pb2
from meshtastic.util import pskToString, stripnl, Timeout, our_exit, fromPSK from meshtastic.util import pskToString, stripnl, Timeout, our_exit, fromPSK, camel_to_snake
class Node: class Node:
"""A model of a (local or remote) node in the mesh """A model of a (local or remote) node in the mesh
Includes methods for radioConfig and channels Includes methods for localConfig, moduleConfig and channels
""" """
def __init__(self, iface, nodeNum, noProto=False): def __init__(self, iface, nodeNum, noProto=False):
"""Constructor""" """Constructor"""
self.iface = iface self.iface = iface
self.nodeNum = nodeNum self.nodeNum = nodeNum
self.radioConfig = None self.localConfig = localonly_pb2.LocalConfig()
self.moduleConfig = localonly_pb2.LocalModuleConfig()
self.channels = None self.channels = None
self._timeout = Timeout(maxSecs=300) self._timeout = Timeout(maxSecs=300)
self.partialChannels = None self.partialChannels = None
self.noProto = noProto self.noProto = noProto
self.cannedPluginMessage = None self.cannedPluginMessage = None
self.cannedPluginMessageMessages = None
self.cannedPluginMessagePart1 = None self.ringtone = None
self.cannedPluginMessagePart2 = None self.ringtonePart = None
self.cannedPluginMessagePart3 = None
self.cannedPluginMessagePart4 = None
self.gotResponse = None self.gotResponse = None
@@ -54,27 +52,69 @@ class Node:
def showInfo(self): def showInfo(self):
"""Show human readable description of our node""" """Show human readable description of our node"""
prefs = "" prefs = ""
if self.radioConfig and self.radioConfig.preferences: if self.localConfig:
prefs = stripnl(MessageToJson(self.radioConfig.preferences)) prefs = stripnl(MessageToJson(self.localConfig))
print(f"Preferences: {prefs}\n") print(f"Preferences: {prefs}\n")
prefs = ""
if self.moduleConfig:
prefs = stripnl(MessageToJson(self.moduleConfig))
print(f"Module preferences: {prefs}\n")
self.showChannels() self.showChannels()
def requestConfig(self): def requestChannels(self):
"""Send regular MeshPackets to ask for settings and channels.""" """Send regular MeshPackets to ask channels."""
logging.debug(f"requestConfig for nodeNum:{self.nodeNum}") logging.debug(f"requestChannels for nodeNum:{self.nodeNum}")
self.radioConfig = None
self.channels = None self.channels = None
self.partialChannels = [] # We keep our channels in a temp array until finished 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._requestChannel(0)
self.cannedPluginMessage = None
def onResponseRequestSettings(self, p):
"""Handle the response packets for requesting settings _requestSettings()"""
logging.debug(f'onResponseRequestSetting() p:{p}')
if "routing" in p["decoded"]:
if p["decoded"]["routing"]["errorReason"] != "NONE":
print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}')
self.iface._acknowledgment.receivedNak = True
else:
self.iface._acknowledgment.receivedAck = True
print("")
adminMessage = p["decoded"]["admin"]
if "getConfigResponse" in adminMessage:
resp = adminMessage["getConfigResponse"]
field = list(resp.keys())[0]
config_type = self.localConfig.DESCRIPTOR.fields_by_name.get(camel_to_snake(field))
config_values = getattr(self.localConfig, config_type.name)
elif "getModuleConfigResponse" in adminMessage:
resp = adminMessage["getModuleConfigResponse"]
field = list(resp.keys())[0]
config_type = self.moduleConfig.DESCRIPTOR.fields_by_name.get(camel_to_snake(field))
config_values = getattr(self.moduleConfig, config_type.name)
else:
print("Did not receive a valid response. Make sure to have a shared channel named 'admin'.")
return
for key, value in resp[field].items():
setattr(config_values, camel_to_snake(key), value)
print(f"{str(camel_to_snake(field))}:\n{str(config_values)}")
self.cannedPluginMessagePart1 = None def requestConfig(self, configType):
self.cannedPluginMessagePart2 = None if self == self.iface.localNode:
self.cannedPluginMessagePart3 = None onResponse = None
self.cannedPluginMessagePart4 = None else:
onResponse = self.onResponseRequestSettings
print("Requesting current config from remote node (this can take a while).")
self._requestSettings() msgIndex = configType.index
if configType.containing_type.full_name == "LocalConfig":
p = admin_pb2.AdminMessage()
p.get_config_request = msgIndex
self._sendAdmin(p, wantResponse=True, onResponse=onResponse)
else:
p = admin_pb2.AdminMessage()
p.get_module_config_request = msgIndex
self._sendAdmin(p, wantResponse=True, onResponse=onResponse)
if onResponse:
self.iface.waitForAckNak()
def turnOffEncryptionOnPrimaryChannel(self): def turnOffEncryptionOnPrimaryChannel(self):
"""Turn off encryption on primary channel.""" """Turn off encryption on primary channel."""
@@ -84,25 +124,179 @@ class Node:
def waitForConfig(self, attribute='channels'): def waitForConfig(self, attribute='channels'):
"""Block until radio config is received. Returns True if config has been received.""" """Block until radio config is received. Returns True if config has been received."""
return self._timeout.waitForSet(self, attrs=('radioConfig', attribute)) return self._timeout.waitForSet(self, attrs=('localConfig', attribute))
def writeConfig(self): def writeConfig(self):
"""Write the current (edited) radioConfig to the device""" """Write the current (edited) localConfig to the device"""
if self.radioConfig is None: if self.localConfig is None:
our_exit("Error: No RadioConfig has been read") our_exit("Error: No localConfig has been read")
if self.localConfig.device:
p = admin_pb2.AdminMessage()
p.set_config.device.CopyFrom(self.localConfig.device)
self._sendAdmin(p)
logging.debug("Wrote device")
time.sleep(0.3)
if self.localConfig.position:
p = admin_pb2.AdminMessage()
p.set_config.position.CopyFrom(self.localConfig.position)
self._sendAdmin(p)
logging.debug("Wrote position")
time.sleep(0.3)
if self.localConfig.power:
p = admin_pb2.AdminMessage()
p.set_config.power.CopyFrom(self.localConfig.power)
self._sendAdmin(p)
logging.debug("Wrote power")
time.sleep(0.3)
if self.localConfig.network:
p = admin_pb2.AdminMessage()
p.set_config.network.CopyFrom(self.localConfig.network)
self._sendAdmin(p)
logging.debug("Wrote network")
time.sleep(0.3)
if self.localConfig.display:
p = admin_pb2.AdminMessage()
p.set_config.display.CopyFrom(self.localConfig.display)
self._sendAdmin(p)
logging.debug("Wrote display")
time.sleep(0.3)
if self.localConfig.lora:
p = admin_pb2.AdminMessage()
p.set_config.lora.CopyFrom(self.localConfig.lora)
self._sendAdmin(p)
logging.debug("Wrote lora")
time.sleep(0.3)
if self.localConfig.bluetooth:
p = admin_pb2.AdminMessage()
p.set_config.bluetooth.CopyFrom(self.localConfig.bluetooth)
self._sendAdmin(p)
logging.debug("Wrote bluetooth")
time.sleep(0.3)
if self.moduleConfig.mqtt:
p = admin_pb2.AdminMessage()
p.set_module_config.mqtt.CopyFrom(self.moduleConfig.mqtt)
self._sendAdmin(p)
logging.debug("Wrote module: mqtt")
time.sleep(0.3)
if self.moduleConfig.serial:
p = admin_pb2.AdminMessage()
p.set_module_config.serial.CopyFrom(self.moduleConfig.serial)
self._sendAdmin(p)
logging.debug("Wrote module: serial")
time.sleep(0.3)
if self.moduleConfig.external_notification:
p = admin_pb2.AdminMessage()
p.set_module_config.external_notification.CopyFrom(self.moduleConfig.external_notification)
self._sendAdmin(p)
logging.debug("Wrote module: external_notification")
time.sleep(0.3)
if self.moduleConfig.store_forward:
p = admin_pb2.AdminMessage()
p.set_module_config.store_forward.CopyFrom(self.moduleConfig.store_forward)
self._sendAdmin(p)
logging.debug("Wrote module: store_forward")
time.sleep(0.3)
if self.moduleConfig.range_test:
p = admin_pb2.AdminMessage()
p.set_module_config.range_test.CopyFrom(self.moduleConfig.range_test)
self._sendAdmin(p)
logging.debug("Wrote module: range_test")
time.sleep(0.3)
if self.moduleConfig.telemetry:
p = admin_pb2.AdminMessage()
p.set_module_config.telemetry.CopyFrom(self.moduleConfig.telemetry)
self._sendAdmin(p)
logging.debug("Wrote module: telemetry")
time.sleep(0.3)
if self.moduleConfig.canned_message:
p = admin_pb2.AdminMessage()
p.set_module_config.canned_message.CopyFrom(self.moduleConfig.canned_message)
self._sendAdmin(p)
logging.debug("Wrote module: canned_message")
time.sleep(0.3)
if self.moduleConfig.audio:
p = admin_pb2.AdminMessage()
p.set_module_config.audio.CopyFrom(self.moduleConfig.audio)
self._sendAdmin(p)
logging.debug("Wrote module: audio")
time.sleep(0.3)
if self.moduleConfig.remote_hardware:
p = admin_pb2.AdminMessage()
p.set_module_config.remote_hardware.CopyFrom(self.moduleConfig.remote_hardware)
self._sendAdmin(p)
logging.debug("Wrote module: remote_hardware")
time.sleep(0.3)
def writeConfig(self, config_name):
"""Write the current (edited) localConfig to the device"""
if self.localConfig is None:
our_exit("Error: No localConfig has been read")
p = admin_pb2.AdminMessage() p = admin_pb2.AdminMessage()
p.set_radio.CopyFrom(self.radioConfig)
self._sendAdmin(p) if config_name == 'device':
logging.debug("Wrote config") p.set_config.device.CopyFrom(self.localConfig.device)
elif config_name == 'position':
p.set_config.position.CopyFrom(self.localConfig.position)
elif config_name == 'power':
p.set_config.power.CopyFrom(self.localConfig.power)
elif config_name == 'network':
p.set_config.network.CopyFrom(self.localConfig.network)
elif config_name == 'display':
p.set_config.display.CopyFrom(self.localConfig.display)
elif config_name == 'lora':
p.set_config.lora.CopyFrom(self.localConfig.lora)
elif config_name == 'bluetooth':
p.set_config.bluetooth.CopyFrom(self.localConfig.bluetooth)
elif config_name == 'mqtt':
p.set_module_config.mqtt.CopyFrom(self.moduleConfig.mqtt)
elif config_name == 'serial':
p.set_module_config.serial.CopyFrom(self.moduleConfig.serial)
elif config_name == 'external_notification':
p.set_module_config.external_notification.CopyFrom(self.moduleConfig.external_notification)
elif config_name == 'store_forward':
p.set_module_config.store_forward.CopyFrom(self.moduleConfig.store_forward)
elif config_name == 'range_test':
p.set_module_config.range_test.CopyFrom(self.moduleConfig.range_test)
elif config_name == 'telemetry':
p.set_module_config.telemetry.CopyFrom(self.moduleConfig.telemetry)
elif config_name == 'canned_message':
p.set_module_config.canned_message.CopyFrom(self.moduleConfig.canned_message)
elif config_name == 'audio':
p.set_module_config.audio.CopyFrom(self.moduleConfig.audio)
elif config_name == 'remote_hardware':
p.set_module_config.remote_hardware.CopyFrom(self.moduleConfig.remote_hardware)
else:
our_exit(f"Error: No valid config with name {config_name}")
logging.debug(f"Wrote: {config_name}")
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
self._sendAdmin(p, onResponse=onResponse)
def writeChannel(self, channelIndex, adminIndex=0): def writeChannel(self, channelIndex, adminIndex=0):
"""Write the current (edited) channel to the device""" """Write the current (edited) channel to the device"""
p = admin_pb2.AdminMessage() p = admin_pb2.AdminMessage()
p.set_channel.CopyFrom(self.channels[channelIndex]) p.set_channel.CopyFrom(self.channels[channelIndex])
self._sendAdmin(p, adminIndex=adminIndex) self._sendAdmin(p, adminIndex=adminIndex)
logging.debug(f"Wrote channel {channelIndex}") logging.debug(f"Wrote channel {channelIndex}")
@@ -163,44 +357,33 @@ class Node:
else: else:
return 0 return 0
def setOwner(self, long_name=None, short_name=None, is_licensed=False, team=None): def setOwner(self, long_name=None, short_name=None, is_licensed=False):
"""Set device owner name""" """Set device owner name"""
logging.debug(f"in setOwner nodeNum:{self.nodeNum}") logging.debug(f"in setOwner nodeNum:{self.nodeNum}")
nChars = 3
minChars = 2
if long_name is not None:
long_name = long_name.strip()
if short_name is None:
words = long_name.split()
if len(long_name) <= nChars:
short_name = long_name
elif len(words) >= minChars:
short_name = ''.join(map(lambda word: word[0], words))
else:
trans = str.maketrans(dict.fromkeys('aeiouAEIOU'))
short_name = long_name[0] + long_name[1:].translate(trans)
if len(short_name) < nChars:
short_name = long_name[:nChars]
p = admin_pb2.AdminMessage() p = admin_pb2.AdminMessage()
nChars = 4
if long_name is not None: if long_name is not None:
long_name = long_name.strip()
p.set_owner.long_name = long_name p.set_owner.long_name = long_name
p.set_owner.is_licensed = is_licensed
if short_name is not None: if short_name is not None:
short_name = short_name.strip() short_name = short_name.strip()
if len(short_name) > nChars: if len(short_name) > nChars:
short_name = short_name[:nChars] short_name = short_name[:nChars]
print(f"Maximum is 4 characters, truncated to {short_name}")
p.set_owner.short_name = short_name p.set_owner.short_name = short_name
p.set_owner.is_licensed = is_licensed
if team is not None:
p.set_owner.team = team
# Note: These debug lines are used in unit tests # Note: These debug lines are used in unit tests
logging.debug(f'p.set_owner.long_name:{p.set_owner.long_name}:') logging.debug(f'p.set_owner.long_name:{p.set_owner.long_name}:')
logging.debug(f'p.set_owner.short_name:{p.set_owner.short_name}:') logging.debug(f'p.set_owner.short_name:{p.set_owner.short_name}:')
logging.debug(f'p.set_owner.is_licensed:{p.set_owner.is_licensed}') logging.debug(f'p.set_owner.is_licensed:{p.set_owner.is_licensed}')
logging.debug(f'p.set_owner.team:{p.set_owner.team}') # If sending to a remote node, wait for ACK/NAK
return self._sendAdmin(p) if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def getURL(self, includeAll: bool = True): def getURL(self, includeAll: bool = True):
"""The sharable URL that describes the current channel""" """The sharable URL that describes the current channel"""
@@ -210,16 +393,19 @@ class Node:
for c in self.channels: for c in self.channels:
if c.role == channel_pb2.Channel.Role.PRIMARY or (includeAll and c.role == channel_pb2.Channel.Role.SECONDARY): if c.role == channel_pb2.Channel.Role.PRIMARY or (includeAll and c.role == channel_pb2.Channel.Role.SECONDARY):
channelSet.settings.append(c.settings) channelSet.settings.append(c.settings)
channelSet.lora_config.CopyFrom(self.localConfig.lora)
some_bytes = channelSet.SerializeToString() some_bytes = channelSet.SerializeToString()
s = base64.urlsafe_b64encode(some_bytes).decode('ascii') s = base64.urlsafe_b64encode(some_bytes).decode('ascii')
return f"https://www.meshtastic.org/d/#{s}".replace("=", "") s = s.replace("=", "").replace("+", "-").replace("/", "_")
return f"https://meshtastic.org/e/#{s}"
def setURL(self, url): def setURL(self, url):
"""Set mesh network URL""" """Set mesh network URL"""
if self.radioConfig is None: if self.localConfig is None:
our_exit("Warning: No RadioConfig has been read") our_exit("Warning: No Config has been read")
# URLs are of the form https://www.meshtastic.org/d/#{base64_channel_set} # URLs are of the form https://meshtastic.org/d/#{base64_channel_set}
# Split on '/#' to find the base64 encoded channel settings # Split on '/#' to find the base64 encoded channel settings
splitURL = url.split("/#") splitURL = url.split("/#")
b64 = splitURL[-1] b64 = splitURL[-1]
@@ -250,45 +436,80 @@ class Node:
self.writeChannel(ch.index) self.writeChannel(ch.index)
i = i + 1 i = i + 1
def onResponseRequestSettings(self, p):
"""Handle the response packet for requesting settings _requestSettings()"""
logging.debug(f'onResponseRequestSetting() p:{p}')
errorFound = False
if "routing" in p["decoded"]:
if p["decoded"]["routing"]["errorReason"] != "NONE":
errorFound = True
print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}')
if errorFound is False:
self.radioConfig = p["decoded"]["admin"]["raw"].get_radio_response
logging.debug(f'self.radioConfig:{self.radioConfig}')
logging.debug("Received radio config, now fetching channels...")
self._timeout.reset() # We made foreward progress
self._requestChannel(0) # now start fetching channels
def _requestSettings(self):
"""Done with initial config messages, now send regular
MeshPackets to ask for settings."""
p = admin_pb2.AdminMessage() p = admin_pb2.AdminMessage()
p.get_radio_request = True p.set_config.lora.CopyFrom(channelSet.lora_config)
self._sendAdmin(p)
# TODO: should we check that localNode has an 'admin' channel? def onResponseRequestRingtone(self, p):
# Show progress message for super slow operations """Handle the response packet for requesting ringtone part 1"""
if self != self.iface.localNode: logging.debug(f'onResponseRequestRingtone() p:{p}')
print("Requesting preferences from remote node.") errorFound = False
print("Be sure:") if "routing" in p["decoded"]:
print(" 1. There is a SECONDARY channel named 'admin'.") if p["decoded"]["routing"]["errorReason"] != "NONE":
print(" 2. The '--seturl' was used to configure.") errorFound = True
print(" 3. All devices have the same modem config. (i.e., '--ch-longfast')") print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}')
print(" 4. All devices have been rebooted after all of the above. (optional, but recommended)") if errorFound is False:
print("Note: This could take a while (it requests remote channel configs, then writes config)") if "decoded" in p:
if "admin" in p["decoded"]:
if "raw" in p["decoded"]["admin"]:
self.ringtonePart = p["decoded"]["admin"]["raw"].get_ringtone_response
logging.debug(f'self.ringtonePart:{self.ringtonePart}')
self.gotResponse = True
return self._sendAdmin(p, wantResponse=True, onResponse=self.onResponseRequestSettings) def get_ringtone(self):
"""Get the ringtone. Concatenate all pieces together and return a single string."""
logging.debug(f'in get_ringtone()')
if not self.ringtone:
def onResponseRequestCannedMessagePluginMessagePart1(self, p): p1 = admin_pb2.AdminMessage()
p1.get_ringtone_request = True
self.gotResponse = False
self._sendAdmin(p1, wantResponse=True, onResponse=self.onResponseRequestRingtone)
while self.gotResponse is False:
time.sleep(0.1)
logging.debug(f'self.ringtone:{self.ringtone}')
self.ringtone = ""
if self.ringtonePart:
self.ringtone += self.ringtonePart
print(f'ringtone:{self.ringtone}')
logging.debug(f'ringtone:{self.ringtone}')
return self.ringtone
def set_ringtone(self, ringtone):
"""Set the ringtone. The ringtone length must be less than 230 character."""
if len(ringtone) > 230:
our_exit("Warning: The ringtone must be less than 230 characters.")
# split into chunks
chunks = []
chunks_size = 230
for i in range(0, len(ringtone), chunks_size):
chunks.append(ringtone[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_ringtone_message = chunk
logging.debug(f"Setting ringtone '{chunk}' part {i+1}")
# If sending to a remote node, wait for ACK/NAK
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def onResponseRequestCannedMessagePluginMessageMessages(self, p):
"""Handle the response packet for requesting canned message plugin message part 1""" """Handle the response packet for requesting canned message plugin message part 1"""
logging.debug(f'onResponseRequestCannedMessagePluginMessagePart1() p:{p}') logging.debug(f'onResponseRequestCannedMessagePluginMessageMessages() p:{p}')
errorFound = False errorFound = False
if "routing" in p["decoded"]: if "routing" in p["decoded"]:
if p["decoded"]["routing"]["errorReason"] != "NONE": if p["decoded"]["routing"]["errorReason"] != "NONE":
@@ -298,57 +519,10 @@ class Node:
if "decoded" in p: if "decoded" in p:
if "admin" in p["decoded"]: if "admin" in p["decoded"]:
if "raw" in p["decoded"]["admin"]: if "raw" in p["decoded"]["admin"]:
self.cannedPluginMessagePart1 = p["decoded"]["admin"]["raw"].get_canned_message_plugin_part1_response self.cannedPluginMessageMessages = p["decoded"]["admin"]["raw"].get_canned_message_module_messages_response
logging.debug(f'self.cannedPluginMessagePart1:{self.cannedPluginMessagePart1}') logging.debug(f'self.cannedPluginMessageMessages:{self.cannedPluginMessageMessages}')
self.gotResponse = True 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): def get_canned_message(self):
"""Get the canned message string. Concatenate all pieces together and return a single string.""" """Get the canned message string. Concatenate all pieces together and return a single string."""
@@ -356,61 +530,27 @@ class Node:
if not self.cannedPluginMessage: if not self.cannedPluginMessage:
p1 = admin_pb2.AdminMessage() p1 = admin_pb2.AdminMessage()
p1.get_canned_message_plugin_part1_request = True p1.get_canned_message_module_messages_request = True
self.gotResponse = False self.gotResponse = False
self._sendAdmin(p1, wantResponse=True, onResponse=self.onResponseRequestCannedMessagePluginMessagePart1) self._sendAdmin(p1, wantResponse=True, onResponse=self.onResponseRequestCannedMessagePluginMessageMessages)
while self.gotResponse is False: while self.gotResponse is False:
time.sleep(0.1) time.sleep(0.1)
p2 = admin_pb2.AdminMessage() logging.debug(f'self.cannedPluginMessageMessages:{self.cannedPluginMessageMessages}')
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 = "" self.cannedPluginMessage = ""
if self.cannedPluginMessagePart1: if self.cannedPluginMessageMessages:
self.cannedPluginMessage += self.cannedPluginMessagePart1 self.cannedPluginMessage += self.cannedPluginMessageMessages
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}') print(f'canned_plugin_message:{self.cannedPluginMessage}')
logging.debug(f'canned_plugin_message:{self.cannedPluginMessage}') logging.debug(f'canned_plugin_message:{self.cannedPluginMessage}')
return self.cannedPluginMessage return self.cannedPluginMessage
def set_canned_message(self, message): def set_canned_message(self, message):
"""Set the canned message. Split into parts of 200 chars each.""" """Set the canned message. The canned messages length must be less than 200 character."""
if len(message) > 800: if len(message) > 200:
our_exit("Warning: The canned message must be less than 800 characters.") our_exit("Warning: The canned message must be less than 200 characters.")
# split into chunks # split into chunks
chunks = [] chunks = []
@@ -425,16 +565,15 @@ class Node:
# TODO: should be a way to improve this # TODO: should be a way to improve this
if i == 0: if i == 0:
p.set_canned_message_plugin_part1 = chunk p.set_canned_message_module_messages = 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}") logging.debug(f"Setting canned message '{chunk}' part {i+1}")
self._sendAdmin(p) # If sending to a remote node, wait for ACK/NAK
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def exitSimulator(self): def exitSimulator(self):
"""Tell a simulator node to exit (this message """Tell a simulator node to exit (this message
@@ -451,7 +590,51 @@ class Node:
p.reboot_seconds = secs p.reboot_seconds = secs
logging.info(f"Telling node to reboot in {secs} seconds") logging.info(f"Telling node to reboot in {secs} seconds")
return self._sendAdmin(p) # If sending to a remote node, wait for ACK/NAK
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def beginSettingsTransaction(self):
"""Tell the node to open a transaction to edit settings."""
p = admin_pb2.AdminMessage()
p.begin_edit_settings = True
logging.info(f"Telling open a transaction to edit settings")
# If sending to a remote node, wait for ACK/NAK
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def commitSettingsTransaction(self):
"""Tell the node to commit the open transaction for editing settings."""
p = admin_pb2.AdminMessage()
p.commit_edit_settings = True
logging.info(f"Telling node to commit open transaction for editing settings")
# If sending to a remote node, wait for ACK/NAK
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def rebootOTA(self, secs: int = 10):
"""Tell the node to reboot into factory firmware."""
p = admin_pb2.AdminMessage()
p.reboot_ota_seconds = secs
logging.info(f"Telling node to reboot to OTA in {secs} seconds")
# If sending to a remote node, wait for ACK/NAK
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def shutdown(self, secs: int = 10): def shutdown(self, secs: int = 10):
"""Tell the node to shutdown.""" """Tell the node to shutdown."""
@@ -459,7 +642,46 @@ class Node:
p.shutdown_seconds = secs p.shutdown_seconds = secs
logging.info(f"Telling node to shutdown in {secs} seconds") logging.info(f"Telling node to shutdown in {secs} seconds")
return self._sendAdmin(p) # If sending to a remote node, wait for ACK/NAK
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def getMetadata(self):
"""Get the node's metadata."""
p = admin_pb2.AdminMessage()
p.get_device_metadata_request = True
logging.info(f"Requesting device metadata")
return self._sendAdmin(p, wantResponse=True, onResponse=self.onRequestGetMetadata)
def factoryReset(self):
"""Tell the node to factory reset."""
p = admin_pb2.AdminMessage()
p.factory_reset = True
logging.info(f"Telling node to factory reset")
# If sending to a remote node, wait for ACK/NAK
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def resetNodeDb(self):
"""Tell the node to reset its list of nodes."""
p = admin_pb2.AdminMessage()
p.nodedb_reset = True
logging.info(f"Telling node to reset the NodeDB")
# If sending to a remote node, wait for ACK/NAK
if self == self.iface.localNode:
onResponse = None
else:
onResponse = self.onAckNak
return self._sendAdmin(p, onResponse=onResponse)
def _fixupChannels(self): def _fixupChannels(self):
"""Fixup indexes and add disabled channels as needed""" """Fixup indexes and add disabled channels as needed"""
@@ -484,9 +706,41 @@ class Node:
index += 1 index += 1
def onRequestGetMetadata(self, p):
"""Handle the response packet for requesting device metadata getMetadata()"""
logging.debug(f'onRequestGetMetadata() p:{p}')
if p["decoded"]["portnum"] == portnums_pb2.PortNum.Name(portnums_pb2.PortNum.ROUTING_APP):
if p["decoded"]["routing"]["errorReason"] != "NONE":
logging.warning(f'Metadata request failed, error reason: {p["decoded"]["routing"]["errorReason"]}')
self._timeout.expireTime = time.time() # Do not wait any longer
return # Don't try to parse this routing message
logging.debug(f"Retrying metadata request.")
self.getMetadata()
return
c = p["decoded"]["admin"]["raw"].get_device_metadata_response
self._timeout.reset() # We made foreward progress
logging.debug(f"Received metadata {stripnl(c)}")
print(f"\nfirmware_version: {c.firmware_version}")
print(f"device_state_version: {c.device_state_version}")
def onResponseRequestChannel(self, p): def onResponseRequestChannel(self, p):
"""Handle the response packet for requesting a channel _requestChannel()""" """Handle the response packet for requesting a channel _requestChannel()"""
logging.debug(f'onResponseRequestChannel() p:{p}') logging.debug(f'onResponseRequestChannel() p:{p}')
if p["decoded"]["portnum"] == portnums_pb2.PortNum.Name(portnums_pb2.PortNum.ROUTING_APP):
if p["decoded"]["routing"]["errorReason"] != "NONE":
logging.warning(f'Channel request failed, error reason: {p["decoded"]["routing"]["errorReason"]}')
self._timeout.expireTime = time.time() # Do not wait any longer
return # Don't try to parse this routing message
lastTried = 0
if len(self.partialChannels) > 0:
lastTried = self.partialChannels[-1].index
logging.debug(f"Retrying previous channel request.")
self._requestChannel(lastTried)
return
c = p["decoded"]["admin"]["raw"].get_channel_response c = p["decoded"]["admin"]["raw"].get_channel_response
self.partialChannels.append(c) self.partialChannels.append(c)
self._timeout.reset() # We made foreward progress self._timeout.reset() # We made foreward progress
@@ -511,6 +765,18 @@ class Node:
else: else:
self._requestChannel(index + 1) self._requestChannel(index + 1)
def onAckNak(self, p):
if p["decoded"]["routing"]["errorReason"] != "NONE":
print(f'Received a NAK, error reason: {p["decoded"]["routing"]["errorReason"]}')
self.iface._acknowledgment.receivedNak = True
else:
if int(p["from"]) == self.iface.localNode.nodeNum:
print(f'Received an implicit ACK. Packet will likely arrive, but cannot be guaranteed.')
self.iface._acknowledgment.receivedImplAck = True
else:
print(f'Received an ACK.')
self.iface._acknowledgment.receivedAck = True
def _requestChannel(self, channelNum: int): def _requestChannel(self, channelNum: int):
"""Done with initial config messages, now send regular """Done with initial config messages, now send regular
MeshPackets to ask for settings""" MeshPackets to ask for settings"""
@@ -528,7 +794,7 @@ class Node:
# pylint: disable=R1710 # pylint: disable=R1710
def _sendAdmin(self, p: admin_pb2.AdminMessage, wantResponse=False, def _sendAdmin(self, p: admin_pb2.AdminMessage, wantResponse=True,
onResponse=None, adminIndex=0): onResponse=None, adminIndex=0):
"""Send an admin message to the specified node (or the local node if destNodeNum is zero)""" """Send an admin message to the specified node (or the local node if destNodeNum is zero)"""
@@ -538,10 +804,10 @@ class Node:
if adminIndex == 0: # unless a special channel index was used, we want to use the admin index if adminIndex == 0: # unless a special channel index was used, we want to use the admin index
adminIndex = self.iface.localNode._getAdminChannelIndex() adminIndex = self.iface.localNode._getAdminChannelIndex()
logging.debug(f'adminIndex:{adminIndex}') logging.debug(f'adminIndex:{adminIndex}')
return self.iface.sendData(p, self.nodeNum, return self.iface.sendData(p, self.nodeNum,
portNum=portnums_pb2.PortNum.ADMIN_APP, portNum=portnums_pb2.PortNum.ADMIN_APP,
wantAck=True, wantAck=False,
wantResponse=wantResponse, wantResponse=wantResponse,
onResponse=onResponse, onResponse=onResponse,
channelIndex=adminIndex) channelIndex=adminIndex)

View File

@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: portnums.proto # source: meshtastic/portnums.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import enum_type_wrapper from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -14,96 +15,9 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19meshtastic/portnums.proto*\xa4\x03\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\x1f\n\x1bTEXT_MESSAGE_COMPRESSED_APP\x10\x07\x12\x10\n\x0cWAYPOINT_APP\x10\x08\x12\r\n\tAUDIO_APP\x10\t\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\x11\n\rSIMULATOR_APP\x10\x45\x12\x12\n\x0eTRACEROUTE_APP\x10\x46\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]\n\x13\x63om.geeksville.meshB\x08PortnumsZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
name='portnums.proto',
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\010PortnumsH\003Z!github.com/meshtastic/gomeshproto',
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(
name='PortNum',
full_name='PortNum',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='UNKNOWN_APP', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TEXT_MESSAGE_APP', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='REMOTE_HARDWARE_APP', index=2, number=2,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='POSITION_APP', index=3, number=3,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='NODEINFO_APP', index=4, number=4,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ROUTING_APP', index=5, number=5,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ADMIN_APP', index=6, number=6,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='REPLY_APP', index=7, number=32,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='IP_TUNNEL_APP', index=8, number=33,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='SERIAL_APP', index=9, number=64,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='STORE_FORWARD_APP', index=10, number=65,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='RANGE_TEST_APP', index=11, number=66,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TELEMETRY_APP', index=12, number=67,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ZPS_APP', index=13, number=68,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='PRIVATE_APP', index=14, number=256,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ATAK_FORWARDER', index=15, number=257,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='MAX', index=16, number=511,
serialized_options=None,
type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=19,
serialized_end=334,
)
_sym_db.RegisterEnumDescriptor(_PORTNUM)
_PORTNUM = DESCRIPTOR.enum_types_by_name['PortNum']
PortNum = enum_type_wrapper.EnumTypeWrapper(_PORTNUM) PortNum = enum_type_wrapper.EnumTypeWrapper(_PORTNUM)
UNKNOWN_APP = 0 UNKNOWN_APP = 0
TEXT_MESSAGE_APP = 1 TEXT_MESSAGE_APP = 1
@@ -112,6 +26,9 @@ POSITION_APP = 3
NODEINFO_APP = 4 NODEINFO_APP = 4
ROUTING_APP = 5 ROUTING_APP = 5
ADMIN_APP = 6 ADMIN_APP = 6
TEXT_MESSAGE_COMPRESSED_APP = 7
WAYPOINT_APP = 8
AUDIO_APP = 9
REPLY_APP = 32 REPLY_APP = 32
IP_TUNNEL_APP = 33 IP_TUNNEL_APP = 33
SERIAL_APP = 64 SERIAL_APP = 64
@@ -119,14 +36,17 @@ STORE_FORWARD_APP = 65
RANGE_TEST_APP = 66 RANGE_TEST_APP = 66
TELEMETRY_APP = 67 TELEMETRY_APP = 67
ZPS_APP = 68 ZPS_APP = 68
SIMULATOR_APP = 69
TRACEROUTE_APP = 70
PRIVATE_APP = 256 PRIVATE_APP = 256
ATAK_FORWARDER = 257 ATAK_FORWARDER = 257
MAX = 511 MAX = 511
DESCRIPTOR.enum_types_by_name['PortNum'] = _PORTNUM if _descriptor._USE_C_DESCRIPTORS == False:
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
DESCRIPTOR._options = None
DESCRIPTOR._options = None DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\010PortnumsZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_PORTNUM._serialized_start=30
_PORTNUM._serialized_end=450
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

File diff suppressed because one or more lines are too long

View File

@@ -23,7 +23,7 @@ def onGPIOreceive(packet, interface):
#print(f'mask:{interface.mask}') #print(f'mask:{interface.mask}')
value = int(gpioValue) & int(interface.mask) value = int(gpioValue) & int(interface.mask)
print(f'Received RemoteHardware typ={hw["typ"]}, gpio_value={gpioValue} value={value}') print(f'Received RemoteHardware type={hw["type"]}, gpio_value={gpioValue} value={value}')
interface.gotResponse = True interface.gotResponse = True
@@ -66,7 +66,7 @@ class RemoteHardwareClient:
""" """
logging.debug(f'writeGPIOs nodeid:{nodeid} mask:{mask} vals:{vals}') logging.debug(f'writeGPIOs nodeid:{nodeid} mask:{mask} vals:{vals}')
r = remote_hardware_pb2.HardwareMessage() r = remote_hardware_pb2.HardwareMessage()
r.typ = remote_hardware_pb2.HardwareMessage.Type.WRITE_GPIOS r.type = remote_hardware_pb2.HardwareMessage.Type.WRITE_GPIOS
r.gpio_mask = mask r.gpio_mask = mask
r.gpio_value = vals r.gpio_value = vals
return self._sendHardware(nodeid, r) return self._sendHardware(nodeid, r)
@@ -75,7 +75,7 @@ class RemoteHardwareClient:
"""Read the specified bits from GPIO inputs on the device""" """Read the specified bits from GPIO inputs on the device"""
logging.debug(f'readGPIOs nodeid:{nodeid} mask:{mask}') logging.debug(f'readGPIOs nodeid:{nodeid} mask:{mask}')
r = remote_hardware_pb2.HardwareMessage() r = remote_hardware_pb2.HardwareMessage()
r.typ = remote_hardware_pb2.HardwareMessage.Type.READ_GPIOS r.type = remote_hardware_pb2.HardwareMessage.Type.READ_GPIOS
r.gpio_mask = mask r.gpio_mask = mask
return self._sendHardware(nodeid, r, wantResponse=True, onResponse=onResponse) return self._sendHardware(nodeid, r, wantResponse=True, onResponse=onResponse)
@@ -83,7 +83,7 @@ class RemoteHardwareClient:
"""Watch the specified bits from GPIO inputs on the device for changes""" """Watch the specified bits from GPIO inputs on the device for changes"""
logging.debug(f'watchGPIOs nodeid:{nodeid} mask:{mask}') logging.debug(f'watchGPIOs nodeid:{nodeid} mask:{mask}')
r = remote_hardware_pb2.HardwareMessage() r = remote_hardware_pb2.HardwareMessage()
r.typ = remote_hardware_pb2.HardwareMessage.Type.WATCH_GPIOS r.type = remote_hardware_pb2.HardwareMessage.Type.WATCH_GPIOS
r.gpio_mask = mask r.gpio_mask = mask
self.iface.mask = mask self.iface.mask = mask
return self._sendHardware(nodeid, r) return self._sendHardware(nodeid, r)

View File

@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: remote_hardware.proto # source: meshtastic/remote_hardware.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -13,112 +14,25 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n meshtastic/remote_hardware.proto\"\xcb\x01\n\x0fHardwareMessage\x12#\n\x04type\x18\x01 \x01(\x0e\x32\x15.HardwareMessage.Type\x12\x11\n\tgpio_mask\x18\x02 \x01(\x04\x12\x12\n\ngpio_value\x18\x03 \x01(\x04\"l\n\x04Type\x12\t\n\x05UNSET\x10\x00\x12\x0f\n\x0bWRITE_GPIOS\x10\x01\x12\x0f\n\x0bWATCH_GPIOS\x10\x02\x12\x11\n\rGPIOS_CHANGED\x10\x03\x12\x0e\n\nREAD_GPIOS\x10\x04\x12\x14\n\x10READ_GPIOS_REPLY\x10\x05\x42\x63\n\x13\x63om.geeksville.meshB\x0eRemoteHardwareZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
name='remote_hardware.proto',
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\016RemoteHardwareH\003Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\x15remote_hardware.proto\"\xca\x01\n\x0fHardwareMessage\x12\"\n\x03typ\x18\x01 \x01(\x0e\x32\x15.HardwareMessage.Type\x12\x11\n\tgpio_mask\x18\x02 \x01(\x04\x12\x12\n\ngpio_value\x18\x03 \x01(\x04\"l\n\x04Type\x12\t\n\x05UNSET\x10\x00\x12\x0f\n\x0bWRITE_GPIOS\x10\x01\x12\x0f\n\x0bWATCH_GPIOS\x10\x02\x12\x11\n\rGPIOS_CHANGED\x10\x03\x12\x0e\n\nREAD_GPIOS\x10\x04\x12\x14\n\x10READ_GPIOS_REPLY\x10\x05\x42J\n\x13\x63om.geeksville.meshB\x0eRemoteHardwareH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
)
_HARDWAREMESSAGE_TYPE = _descriptor.EnumDescriptor( _HARDWAREMESSAGE = DESCRIPTOR.message_types_by_name['HardwareMessage']
name='Type', _HARDWAREMESSAGE_TYPE = _HARDWAREMESSAGE.enum_types_by_name['Type']
full_name='HardwareMessage.Type',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='UNSET', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='WRITE_GPIOS', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='WATCH_GPIOS', index=2, number=2,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='GPIOS_CHANGED', index=3, number=3,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='READ_GPIOS', index=4, number=4,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='READ_GPIOS_REPLY', index=5, number=5,
serialized_options=None,
type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=120,
serialized_end=228,
)
_sym_db.RegisterEnumDescriptor(_HARDWAREMESSAGE_TYPE)
_HARDWAREMESSAGE = _descriptor.Descriptor(
name='HardwareMessage',
full_name='HardwareMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='typ', full_name='HardwareMessage.typ', index=0,
number=1, 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),
_descriptor.FieldDescriptor(
name='gpio_mask', full_name='HardwareMessage.gpio_mask', index=1,
number=2, type=4, cpp_type=4, 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='gpio_value', full_name='HardwareMessage.gpio_value', index=2,
number=3, type=4, cpp_type=4, 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=[
_HARDWAREMESSAGE_TYPE,
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=26,
serialized_end=228,
)
_HARDWAREMESSAGE.fields_by_name['typ'].enum_type = _HARDWAREMESSAGE_TYPE
_HARDWAREMESSAGE_TYPE.containing_type = _HARDWAREMESSAGE
DESCRIPTOR.message_types_by_name['HardwareMessage'] = _HARDWAREMESSAGE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
HardwareMessage = _reflection.GeneratedProtocolMessageType('HardwareMessage', (_message.Message,), { HardwareMessage = _reflection.GeneratedProtocolMessageType('HardwareMessage', (_message.Message,), {
'DESCRIPTOR' : _HARDWAREMESSAGE, 'DESCRIPTOR' : _HARDWAREMESSAGE,
'__module__' : 'remote_hardware_pb2' '__module__' : 'meshtastic.remote_hardware_pb2'
# @@protoc_insertion_point(class_scope:HardwareMessage) # @@protoc_insertion_point(class_scope:HardwareMessage)
}) })
_sym_db.RegisterMessage(HardwareMessage) _sym_db.RegisterMessage(HardwareMessage)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\016RemoteHardwareZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_HARDWAREMESSAGE._serialized_start=37
_HARDWAREMESSAGE._serialized_end=240
_HARDWAREMESSAGE_TYPE._serialized_start=132
_HARDWAREMESSAGE_TYPE._serialized_end=240
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

35
meshtastic/rtttl_pb2.py Normal file
View File

@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/rtttl.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
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_pool.Default().AddSerializedFile(b'\n\x16meshtastic/rtttl.proto\"\x1f\n\x0bRTTTLConfig\x12\x10\n\x08ringtone\x18\x01 \x01(\tBf\n\x13\x63om.geeksville.meshB\x11RTTTLConfigProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_RTTTLCONFIG = DESCRIPTOR.message_types_by_name['RTTTLConfig']
RTTTLConfig = _reflection.GeneratedProtocolMessageType('RTTTLConfig', (_message.Message,), {
'DESCRIPTOR' : _RTTTLCONFIG,
'__module__' : 'meshtastic.rtttl_pb2'
# @@protoc_insertion_point(class_scope:RTTTLConfig)
})
_sym_db.RegisterMessage(RTTTLConfig)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\021RTTTLConfigProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_RTTTLCONFIG._serialized_start=26
_RTTTLCONFIG._serialized_end=57
# @@protoc_insertion_point(module_scope)

View File

@@ -50,7 +50,7 @@ class SerialInterface(StreamInterface):
f.close() f.close()
time.sleep(0.1) time.sleep(0.1)
self.stream = serial.Serial(self.devPath, 921600, exclusive=True, timeout=0.5, write_timeout=0) self.stream = serial.Serial(self.devPath, 115200, exclusive=True, timeout=0.5, write_timeout=0)
self.stream.flush() self.stream.flush()
time.sleep(0.1) time.sleep(0.1)

View File

@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: storeforward.proto # source: meshtastic/storeforward.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -13,337 +14,39 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dmeshtastic/storeforward.proto\"\xbe\x06\n\x0fStoreAndForward\x12,\n\x02rr\x18\x01 \x01(\x0e\x32 .StoreAndForward.RequestResponse\x12,\n\x05stats\x18\x02 \x01(\x0b\x32\x1b.StoreAndForward.StatisticsH\x00\x12+\n\x07history\x18\x03 \x01(\x0b\x32\x18.StoreAndForward.HistoryH\x00\x12/\n\theartbeat\x18\x04 \x01(\x0b\x32\x1a.StoreAndForward.HeartbeatH\x00\x12\x0f\n\x05\x65mpty\x18\x05 \x01(\x08H\x00\x1a\xcd\x01\n\nStatistics\x12\x16\n\x0emessages_total\x18\x01 \x01(\r\x12\x16\n\x0emessages_saved\x18\x02 \x01(\r\x12\x14\n\x0cmessages_max\x18\x03 \x01(\r\x12\x0f\n\x07up_time\x18\x04 \x01(\r\x12\x10\n\x08requests\x18\x05 \x01(\r\x12\x18\n\x10requests_history\x18\x06 \x01(\r\x12\x11\n\theartbeat\x18\x07 \x01(\x08\x12\x12\n\nreturn_max\x18\x08 \x01(\r\x12\x15\n\rreturn_window\x18\t \x01(\r\x1aI\n\x07History\x12\x18\n\x10history_messages\x18\x01 \x01(\r\x12\x0e\n\x06window\x18\x02 \x01(\r\x12\x14\n\x0clast_request\x18\x03 \x01(\r\x1a.\n\tHeartbeat\x12\x0e\n\x06period\x18\x01 \x01(\r\x12\x11\n\tsecondary\x18\x02 \x01(\r\"\x89\x02\n\x0fRequestResponse\x12\t\n\x05UNSET\x10\x00\x12\x10\n\x0cROUTER_ERROR\x10\x01\x12\x14\n\x10ROUTER_HEARTBEAT\x10\x02\x12\x0f\n\x0bROUTER_PING\x10\x03\x12\x0f\n\x0bROUTER_PONG\x10\x04\x12\x0f\n\x0bROUTER_BUSY\x10\x05\x12\x12\n\x0eROUTER_HISTORY\x10\x06\x12\x10\n\x0cROUTER_STATS\x10\x07\x12\x10\n\x0c\x43LIENT_ERROR\x10@\x12\x12\n\x0e\x43LIENT_HISTORY\x10\x41\x12\x10\n\x0c\x43LIENT_STATS\x10\x42\x12\x0f\n\x0b\x43LIENT_PING\x10\x43\x12\x0f\n\x0b\x43LIENT_PONG\x10\x44\x12\x10\n\x0c\x43LIENT_ABORT\x10jB\t\n\x07variantBj\n\x13\x63om.geeksville.meshB\x15StoreAndForwardProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
name='storeforward.proto',
package='',
syntax='proto3',
serialized_options=b'\n\023com.geeksville.meshB\025StoreAndForwardProtosH\003Z!github.com/meshtastic/gomeshproto',
serialized_pb=b'\n\x12storeforward.proto\"\x8a\x06\n\x0fStoreAndForward\x12,\n\x02rr\x18\x01 \x01(\x0e\x32 .StoreAndForward.RequestResponse\x12*\n\x05stats\x18\x02 \x01(\x0b\x32\x1b.StoreAndForward.Statistics\x12)\n\x07history\x18\x03 \x01(\x0b\x32\x18.StoreAndForward.History\x12-\n\theartbeat\x18\x04 \x01(\x0b\x32\x1a.StoreAndForward.Heartbeat\x1a\xcd\x01\n\nStatistics\x12\x16\n\x0emessages_total\x18\x01 \x01(\r\x12\x16\n\x0emessages_saved\x18\x02 \x01(\r\x12\x14\n\x0cmessages_max\x18\x03 \x01(\r\x12\x0f\n\x07up_time\x18\x04 \x01(\r\x12\x10\n\x08requests\x18\x05 \x01(\r\x12\x18\n\x10requests_history\x18\x06 \x01(\r\x12\x11\n\theartbeat\x18\x07 \x01(\x08\x12\x12\n\nreturn_max\x18\x08 \x01(\r\x12\x15\n\rreturn_window\x18\t \x01(\r\x1aI\n\x07History\x12\x18\n\x10history_messages\x18\x01 \x01(\r\x12\x0e\n\x06window\x18\x02 \x01(\r\x12\x14\n\x0clast_request\x18\x03 \x01(\r\x1a.\n\tHeartbeat\x12\x0e\n\x06period\x18\x01 \x01(\r\x12\x11\n\tsecondary\x18\x02 \x01(\r\"\xf7\x01\n\x0fRequestResponse\x12\t\n\x05UNSET\x10\x00\x12\x10\n\x0cROUTER_ERROR\x10\x01\x12\x14\n\x10ROUTER_HEARTBEAT\x10\x02\x12\x0f\n\x0bROUTER_PING\x10\x03\x12\x0f\n\x0bROUTER_PONG\x10\x04\x12\x0f\n\x0bROUTER_BUSY\x10\x05\x12\x12\n\x0eROUTER_HISTORY\x10\x06\x12\x10\n\x0c\x43LIENT_ERROR\x10\x65\x12\x12\n\x0e\x43LIENT_HISTORY\x10\x66\x12\x10\n\x0c\x43LIENT_STATS\x10g\x12\x0f\n\x0b\x43LIENT_PING\x10h\x12\x0f\n\x0b\x43LIENT_PONG\x10i\x12\x10\n\x0c\x43LIENT_ABORT\x10jBQ\n\x13\x63om.geeksville.meshB\x15StoreAndForwardProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
)
_STOREANDFORWARD_REQUESTRESPONSE = _descriptor.EnumDescriptor( _STOREANDFORWARD = DESCRIPTOR.message_types_by_name['StoreAndForward']
name='RequestResponse', _STOREANDFORWARD_STATISTICS = _STOREANDFORWARD.nested_types_by_name['Statistics']
full_name='StoreAndForward.RequestResponse', _STOREANDFORWARD_HISTORY = _STOREANDFORWARD.nested_types_by_name['History']
filename=None, _STOREANDFORWARD_HEARTBEAT = _STOREANDFORWARD.nested_types_by_name['Heartbeat']
file=DESCRIPTOR, _STOREANDFORWARD_REQUESTRESPONSE = _STOREANDFORWARD.enum_types_by_name['RequestResponse']
values=[
_descriptor.EnumValueDescriptor(
name='UNSET', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ROUTER_ERROR', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ROUTER_HEARTBEAT', index=2, number=2,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ROUTER_PING', index=3, number=3,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ROUTER_PONG', index=4, number=4,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ROUTER_BUSY', index=5, number=5,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ROUTER_HISTORY', index=6, number=6,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='CLIENT_ERROR', index=7, number=101,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='CLIENT_HISTORY', index=8, number=102,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='CLIENT_STATS', index=9, number=103,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='CLIENT_PING', index=10, number=104,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='CLIENT_PONG', index=11, number=105,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='CLIENT_ABORT', index=12, number=106,
serialized_options=None,
type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=554,
serialized_end=801,
)
_sym_db.RegisterEnumDescriptor(_STOREANDFORWARD_REQUESTRESPONSE)
_STOREANDFORWARD_STATISTICS = _descriptor.Descriptor(
name='Statistics',
full_name='StoreAndForward.Statistics',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='messages_total', full_name='StoreAndForward.Statistics.messages_total', index=0,
number=1, 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='messages_saved', full_name='StoreAndForward.Statistics.messages_saved', index=1,
number=2, 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='messages_max', full_name='StoreAndForward.Statistics.messages_max', index=2,
number=3, 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='up_time', full_name='StoreAndForward.Statistics.up_time', index=3,
number=4, 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='requests', full_name='StoreAndForward.Statistics.requests', index=4,
number=5, 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='requests_history', full_name='StoreAndForward.Statistics.requests_history', index=5,
number=6, 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='heartbeat', full_name='StoreAndForward.Statistics.heartbeat', index=6,
number=7, 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='return_max', full_name='StoreAndForward.Statistics.return_max', index=7,
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='return_window', full_name='StoreAndForward.Statistics.return_window', index=8,
number=9, 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),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=223,
serialized_end=428,
)
_STOREANDFORWARD_HISTORY = _descriptor.Descriptor(
name='History',
full_name='StoreAndForward.History',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='history_messages', full_name='StoreAndForward.History.history_messages', index=0,
number=1, 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='window', full_name='StoreAndForward.History.window', index=1,
number=2, 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='last_request', full_name='StoreAndForward.History.last_request', index=2,
number=3, 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),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=430,
serialized_end=503,
)
_STOREANDFORWARD_HEARTBEAT = _descriptor.Descriptor(
name='Heartbeat',
full_name='StoreAndForward.Heartbeat',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='period', full_name='StoreAndForward.Heartbeat.period', index=0,
number=1, 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='secondary', full_name='StoreAndForward.Heartbeat.secondary', index=1,
number=2, 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),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=505,
serialized_end=551,
)
_STOREANDFORWARD = _descriptor.Descriptor(
name='StoreAndForward',
full_name='StoreAndForward',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='rr', full_name='StoreAndForward.rr', index=0,
number=1, 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),
_descriptor.FieldDescriptor(
name='stats', full_name='StoreAndForward.stats', index=1,
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='history', full_name='StoreAndForward.history', index=2,
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='heartbeat', full_name='StoreAndForward.heartbeat', index=3,
number=4, 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=[_STOREANDFORWARD_STATISTICS, _STOREANDFORWARD_HISTORY, _STOREANDFORWARD_HEARTBEAT, ],
enum_types=[
_STOREANDFORWARD_REQUESTRESPONSE,
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=23,
serialized_end=801,
)
_STOREANDFORWARD_STATISTICS.containing_type = _STOREANDFORWARD
_STOREANDFORWARD_HISTORY.containing_type = _STOREANDFORWARD
_STOREANDFORWARD_HEARTBEAT.containing_type = _STOREANDFORWARD
_STOREANDFORWARD.fields_by_name['rr'].enum_type = _STOREANDFORWARD_REQUESTRESPONSE
_STOREANDFORWARD.fields_by_name['stats'].message_type = _STOREANDFORWARD_STATISTICS
_STOREANDFORWARD.fields_by_name['history'].message_type = _STOREANDFORWARD_HISTORY
_STOREANDFORWARD.fields_by_name['heartbeat'].message_type = _STOREANDFORWARD_HEARTBEAT
_STOREANDFORWARD_REQUESTRESPONSE.containing_type = _STOREANDFORWARD
DESCRIPTOR.message_types_by_name['StoreAndForward'] = _STOREANDFORWARD
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
StoreAndForward = _reflection.GeneratedProtocolMessageType('StoreAndForward', (_message.Message,), { StoreAndForward = _reflection.GeneratedProtocolMessageType('StoreAndForward', (_message.Message,), {
'Statistics' : _reflection.GeneratedProtocolMessageType('Statistics', (_message.Message,), { 'Statistics' : _reflection.GeneratedProtocolMessageType('Statistics', (_message.Message,), {
'DESCRIPTOR' : _STOREANDFORWARD_STATISTICS, 'DESCRIPTOR' : _STOREANDFORWARD_STATISTICS,
'__module__' : 'storeforward_pb2' '__module__' : 'meshtastic.storeforward_pb2'
# @@protoc_insertion_point(class_scope:StoreAndForward.Statistics) # @@protoc_insertion_point(class_scope:StoreAndForward.Statistics)
}) })
, ,
'History' : _reflection.GeneratedProtocolMessageType('History', (_message.Message,), { 'History' : _reflection.GeneratedProtocolMessageType('History', (_message.Message,), {
'DESCRIPTOR' : _STOREANDFORWARD_HISTORY, 'DESCRIPTOR' : _STOREANDFORWARD_HISTORY,
'__module__' : 'storeforward_pb2' '__module__' : 'meshtastic.storeforward_pb2'
# @@protoc_insertion_point(class_scope:StoreAndForward.History) # @@protoc_insertion_point(class_scope:StoreAndForward.History)
}) })
, ,
'Heartbeat' : _reflection.GeneratedProtocolMessageType('Heartbeat', (_message.Message,), { 'Heartbeat' : _reflection.GeneratedProtocolMessageType('Heartbeat', (_message.Message,), {
'DESCRIPTOR' : _STOREANDFORWARD_HEARTBEAT, 'DESCRIPTOR' : _STOREANDFORWARD_HEARTBEAT,
'__module__' : 'storeforward_pb2' '__module__' : 'meshtastic.storeforward_pb2'
# @@protoc_insertion_point(class_scope:StoreAndForward.Heartbeat) # @@protoc_insertion_point(class_scope:StoreAndForward.Heartbeat)
}) })
, ,
'DESCRIPTOR' : _STOREANDFORWARD, 'DESCRIPTOR' : _STOREANDFORWARD,
'__module__' : 'storeforward_pb2' '__module__' : 'meshtastic.storeforward_pb2'
# @@protoc_insertion_point(class_scope:StoreAndForward) # @@protoc_insertion_point(class_scope:StoreAndForward)
}) })
_sym_db.RegisterMessage(StoreAndForward) _sym_db.RegisterMessage(StoreAndForward)
@@ -351,6 +54,18 @@ _sym_db.RegisterMessage(StoreAndForward.Statistics)
_sym_db.RegisterMessage(StoreAndForward.History) _sym_db.RegisterMessage(StoreAndForward.History)
_sym_db.RegisterMessage(StoreAndForward.Heartbeat) _sym_db.RegisterMessage(StoreAndForward.Heartbeat)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\025StoreAndForwardProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_STOREANDFORWARD._serialized_start=34
_STOREANDFORWARD._serialized_end=864
_STOREANDFORWARD_STATISTICS._serialized_start=257
_STOREANDFORWARD_STATISTICS._serialized_end=462
_STOREANDFORWARD_HISTORY._serialized_start=464
_STOREANDFORWARD_HISTORY._serialized_end=537
_STOREANDFORWARD_HEARTBEAT._serialized_start=539
_STOREANDFORWARD_HEARTBEAT._serialized_end=585
_STOREANDFORWARD_REQUESTRESPONSE._serialized_start=588
_STOREANDFORWARD_REQUESTRESPONSE._serialized_end=853
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@@ -131,9 +131,9 @@ class StreamInterface(MeshInterface):
try: try:
while not self._wantExit: while not self._wantExit:
logging.debug("reading character") #logging.debug("reading character")
b = self._readBytes(1) b = self._readBytes(1)
logging.debug("In reader loop") #logging.debug("In reader loop")
#logging.debug(f"read returned {b}") #logging.debug(f"read returned {b}")
if len(b) > 0: if len(b) > 0:
c = b[0] c = b[0]

View File

@@ -73,14 +73,21 @@ rak4631_5005 = SupportedDevice(name="RAK 4631 5005", version="", for_firmware="r
device_class="nrf52", device_class="nrf52",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem", baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="239a", usb_product_id_in_hex="0029") usb_vendor_id_in_hex="239a", usb_product_id_in_hex="0029")
rak4631_5005_epaper = SupportedDevice(name="RAK 4631 5005 14000 epaper", version="", for_firmware="rak4631_5005_epaper",
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 # Note: The 19003 reports same product id as 5005 in boot mode
rak4631_19003 = SupportedDevice(name="RAK 4631 19003", version="", for_firmware="rak4631_19003", rak4631_19003 = SupportedDevice(name="RAK 4631 19003", version="", for_firmware="rak4631_19003",
device_class="nrf52", device_class="nrf52",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem", baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="239a", usb_product_id_in_hex="8029") usb_vendor_id_in_hex="239a", usb_product_id_in_hex="8029")
nano_g1 = SupportedDevice(name="Nano G1", version="", for_firmware="nano-g1",
baseport_on_linux="ttyACM", baseport_on_mac="cu.usbmodem",
usb_vendor_id_in_hex="1a86", usb_product_id_in_hex="55d4")
supported_devices = [tbeam_v0_7, tbeam_v1_1, tbeam_M8N, tbeam_M8N_SX1262, supported_devices = [tbeam_v0_7, tbeam_v1_1, tbeam_M8N, tbeam_M8N_SX1262,
tlora_v1, tlora_v1_3, tlora_v2, tlora_v2_1_1_6, tlora_v1, tlora_v1_3, tlora_v2, tlora_v2_1_1_6,
heltec_v1, heltec_v2_0, heltec_v2_1, heltec_v1, heltec_v2_0, heltec_v2_1,
meshtastic_diy_v1, techo_1, rak4631_5005, rak4631_19003, meshtastic_diy_v1, techo_1, rak4631_5005, rak4631_5005_epaper, rak4631_19003,
rak11200] rak11200, nano_g1]

View File

@@ -1,8 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# source: telemetry.proto # source: meshtastic/telemetry.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message from google.protobuf import message as _message
from google.protobuf import reflection as _reflection from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database from google.protobuf import symbol_database as _symbol_database
@@ -13,92 +15,70 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor( DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1ameshtastic/telemetry.proto\"i\n\rDeviceMetrics\x12\x15\n\rbattery_level\x18\x01 \x01(\r\x12\x0f\n\x07voltage\x18\x02 \x01(\x02\x12\x1b\n\x13\x63hannel_utilization\x18\x03 \x01(\x02\x12\x13\n\x0b\x61ir_util_tx\x18\x04 \x01(\x02\"\x9b\x01\n\x12\x45nvironmentMetrics\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\"\xbf\x02\n\x11\x41irQualityMetrics\x12\x15\n\rpm10_standard\x18\x01 \x01(\r\x12\x15\n\rpm25_standard\x18\x02 \x01(\r\x12\x16\n\x0epm100_standard\x18\x03 \x01(\r\x12\x1a\n\x12pm10_environmental\x18\x04 \x01(\r\x12\x1a\n\x12pm25_environmental\x18\x05 \x01(\r\x12\x1b\n\x13pm100_environmental\x18\x06 \x01(\r\x12\x16\n\x0eparticles_03um\x18\x07 \x01(\r\x12\x16\n\x0eparticles_05um\x18\x08 \x01(\r\x12\x16\n\x0eparticles_10um\x18\t \x01(\r\x12\x16\n\x0eparticles_25um\x18\n \x01(\r\x12\x16\n\x0eparticles_50um\x18\x0b \x01(\r\x12\x17\n\x0fparticles_100um\x18\x0c \x01(\r\"\xb5\x01\n\tTelemetry\x12\x0c\n\x04time\x18\x01 \x01(\x07\x12(\n\x0e\x64\x65vice_metrics\x18\x02 \x01(\x0b\x32\x0e.DeviceMetricsH\x00\x12\x32\n\x13\x65nvironment_metrics\x18\x03 \x01(\x0b\x32\x13.EnvironmentMetricsH\x00\x12\x31\n\x13\x61ir_quality_metrics\x18\x04 \x01(\x0b\x32\x12.AirQualityMetricsH\x00\x42\t\n\x07variant*\xc7\x01\n\x13TelemetrySensorType\x12\x10\n\x0cSENSOR_UNSET\x10\x00\x12\n\n\x06\x42ME280\x10\x01\x12\n\n\x06\x42ME680\x10\x02\x12\x0b\n\x07MCP9808\x10\x03\x12\n\n\x06INA260\x10\x04\x12\n\n\x06INA219\x10\x05\x12\n\n\x06\x42MP280\x10\x06\x12\t\n\x05SHTC3\x10\x07\x12\t\n\x05LPS22\x10\x08\x12\x0b\n\x07QMC6310\x10\t\x12\x0b\n\x07QMI8658\x10\n\x12\x0c\n\x08QMC5883L\x10\x0b\x12\t\n\x05SHT31\x10\x0c\x12\x0c\n\x08PMSA003I\x10\rBd\n\x13\x63om.geeksville.meshB\x0fTelemetryProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
name='telemetry.proto',
package='', _TELEMETRYSENSORTYPE = DESCRIPTOR.enum_types_by_name['TelemetrySensorType']
syntax='proto3', TelemetrySensorType = enum_type_wrapper.EnumTypeWrapper(_TELEMETRYSENSORTYPE)
serialized_options=b'Z!github.com/meshtastic/gomeshproto', SENSOR_UNSET = 0
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' BME280 = 1
) BME680 = 2
MCP9808 = 3
INA260 = 4
INA219 = 5
BMP280 = 6
SHTC3 = 7
LPS22 = 8
QMC6310 = 9
QMI8658 = 10
QMC5883L = 11
SHT31 = 12
PMSA003I = 13
_DEVICEMETRICS = DESCRIPTOR.message_types_by_name['DeviceMetrics']
_ENVIRONMENTMETRICS = DESCRIPTOR.message_types_by_name['EnvironmentMetrics']
_AIRQUALITYMETRICS = DESCRIPTOR.message_types_by_name['AirQualityMetrics']
_TELEMETRY = DESCRIPTOR.message_types_by_name['Telemetry']
DeviceMetrics = _reflection.GeneratedProtocolMessageType('DeviceMetrics', (_message.Message,), {
'DESCRIPTOR' : _DEVICEMETRICS,
'__module__' : 'meshtastic.telemetry_pb2'
# @@protoc_insertion_point(class_scope:DeviceMetrics)
})
_sym_db.RegisterMessage(DeviceMetrics)
EnvironmentMetrics = _reflection.GeneratedProtocolMessageType('EnvironmentMetrics', (_message.Message,), {
'DESCRIPTOR' : _ENVIRONMENTMETRICS,
'__module__' : 'meshtastic.telemetry_pb2'
# @@protoc_insertion_point(class_scope:EnvironmentMetrics)
})
_sym_db.RegisterMessage(EnvironmentMetrics)
_TELEMETRY = _descriptor.Descriptor( AirQualityMetrics = _reflection.GeneratedProtocolMessageType('AirQualityMetrics', (_message.Message,), {
name='Telemetry', 'DESCRIPTOR' : _AIRQUALITYMETRICS,
full_name='Telemetry', '__module__' : 'meshtastic.telemetry_pb2'
filename=None, # @@protoc_insertion_point(class_scope:AirQualityMetrics)
file=DESCRIPTOR, })
containing_type=None, _sym_db.RegisterMessage(AirQualityMetrics)
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,), { Telemetry = _reflection.GeneratedProtocolMessageType('Telemetry', (_message.Message,), {
'DESCRIPTOR' : _TELEMETRY, 'DESCRIPTOR' : _TELEMETRY,
'__module__' : 'telemetry_pb2' '__module__' : 'meshtastic.telemetry_pb2'
# @@protoc_insertion_point(class_scope:Telemetry) # @@protoc_insertion_point(class_scope:Telemetry)
}) })
_sym_db.RegisterMessage(Telemetry) _sym_db.RegisterMessage(Telemetry)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\017TelemetryProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_TELEMETRYSENSORTYPE._serialized_start=802
_TELEMETRYSENSORTYPE._serialized_end=1001
_DEVICEMETRICS._serialized_start=30
_DEVICEMETRICS._serialized_end=135
_ENVIRONMENTMETRICS._serialized_start=138
_ENVIRONMENTMETRICS._serialized_end=293
_AIRQUALITYMETRICS._serialized_start=296
_AIRQUALITYMETRICS._serialized_end=615
_TELEMETRY._serialized_start=618
_TELEMETRY._serialized_end=799
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@@ -12,14 +12,14 @@ import pytest
from meshtastic.__main__ import initParser, main, Globals, onReceive, onConnection, export_config, getPref, setPref, onNode, tunnelMain from meshtastic.__main__ import initParser, main, Globals, onReceive, onConnection, export_config, getPref, setPref, onNode, tunnelMain
#from ..radioconfig_pb2 import UserPreferences #from ..radioconfig_pb2 import UserPreferences
import meshtastic.radioconfig_pb2 #import meshtastic.config_pb2
from ..serial_interface import SerialInterface from ..serial_interface import SerialInterface
from ..tcp_interface import TCPInterface from ..tcp_interface import TCPInterface
#from ..ble_interface import BLEInterface #from ..ble_interface import BLEInterface
from ..node import Node from ..node import Node
from ..channel_pb2 import Channel from ..channel_pb2 import Channel
from ..remote_hardware import onGPIOreceive #from ..remote_hardware import onGPIOreceive
from ..radioconfig_pb2 import RadioConfig #from ..config_pb2 import Config
@pytest.mark.unit @pytest.mark.unit
@@ -789,61 +789,6 @@ def test_main_setalt(capsys):
assert err == '' assert err == ''
mo.assert_called() mo.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_team_valid(capsys):
"""Test --set-team"""
sys.argv = ['', '--set-team', 'CYAN']
Globals.getInstance().set_args(sys.argv)
mocked_node = MagicMock(autospec=Node)
def mock_setOwner(team):
print('inside mocked setOwner')
print(f'{team}')
mocked_node.setOwner.side_effect = mock_setOwner
iface = MagicMock(autospec=SerialInterface)
iface.localNode.return_value = mocked_node
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
with patch('meshtastic.mesh_pb2.Team') as mm:
mm.Name.return_value = 'FAKENAME'
mm.Value.return_value = 'FAKEVAL'
main()
out, err = capsys.readouterr()
assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'Setting team to', out, re.MULTILINE)
assert err == ''
mo.assert_called()
mm.Name.assert_called()
mm.Value.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_team_invalid(capsys):
"""Test --set-team using an invalid team name"""
sys.argv = ['', '--set-team', 'NOTCYAN']
Globals.getInstance().set_args(sys.argv)
iface = MagicMock(autospec=SerialInterface)
def throw_an_exception(exc):
raise ValueError("Fake exception.")
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
with patch('meshtastic.mesh_pb2.Team') as mm:
mm.Value.side_effect = throw_an_exception
main()
out, err = capsys.readouterr()
assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'ERROR: Team', out, re.MULTILINE)
assert err == ''
mo.assert_called()
mm.Value.assert_called()
@pytest.mark.unit @pytest.mark.unit
@pytest.mark.usefixtures("reset_globals") @pytest.mark.usefixtures("reset_globals")
def test_main_seturl(capsys): def test_main_seturl(capsys):
@@ -902,6 +847,27 @@ def test_main_set_valid_wifi_passwd(capsys):
mo.assert_called() mo.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_set_invalid_wifi_passwd(capsys):
"""Test --set with an invalid value (password must be 8 or more characters)"""
sys.argv = ['', '--set', 'wifi_password', '1234567']
Globals.getInstance().set_args(sys.argv)
mocked_node = MagicMock(autospec=Node)
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 not re.search(r'Set wifi_password to 1234567', out, re.MULTILINE)
assert re.search(r'Warning: wifi_password must be 8 or more characters.', out, re.MULTILINE)
assert err == ''
mo.assert_called()
@pytest.mark.unit @pytest.mark.unit
@pytest.mark.usefixtures("reset_globals") @pytest.mark.usefixtures("reset_globals")
def test_main_set_valid_camel_case(capsys): def test_main_set_valid_camel_case(capsys):
@@ -1281,28 +1247,29 @@ def test_main_ch_enable_primary_channel(capsys):
mo.assert_called() mo.assert_called()
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_ch_range_options(capsys): #@pytest.mark.usefixtures("reset_globals")
"""Test changing the various range options.""" #def test_main_ch_range_options(capsys):
range_options = ['--ch-vlongslow', '--ch-longslow', '--ch-longfast', '--ch-midslow', # """Test changing the various range options."""
'--ch-midfast', '--ch-shortslow', '--ch-shortfast'] # range_options = ['--ch-vlongslow', '--ch-longslow', '--ch-longfast', '--ch-midslow',
for range_option in range_options: # '--ch-midfast', '--ch-shortslow', '--ch-shortfast']
sys.argv = ['', f"{range_option}" ] # for range_option in range_options:
Globals.getInstance().set_args(sys.argv) # sys.argv = ['', f"{range_option}" ]
# Globals.getInstance().set_args(sys.argv)
mocked_node = MagicMock(autospec=Node) #
# mocked_node = MagicMock(autospec=Node)
iface = MagicMock(autospec=SerialInterface) #
iface.getNode.return_value = mocked_node # iface = MagicMock(autospec=SerialInterface)
# iface.getNode.return_value = mocked_node
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo: #
main() # with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
out, err = capsys.readouterr() # main()
assert re.search(r'Connected to radio', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'Writing modified channels', out, re.MULTILINE) # assert re.search(r'Connected to radio', out, re.MULTILINE)
assert err == '' # assert re.search(r'Writing modified channels', out, re.MULTILINE)
mo.assert_called() # assert err == ''
# mo.assert_called()
@pytest.mark.unit @pytest.mark.unit
@@ -1343,121 +1310,125 @@ def test_main_ch_longsfast_on_non_primary_channel(capsys):
# POS_SEQ_NOS 128 # POS_SEQ_NOS 128
# POS_TIMESTAMP 256 # POS_TIMESTAMP 256
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_pos_fields_no_args(capsys): #@pytest.mark.usefixtures("reset_globals")
"""Test --pos-fields no args (which shows settings)""" #def test_main_pos_fields_no_args(capsys):
sys.argv = ['', '--pos-fields'] # """Test --pos-fields no args (which shows settings)"""
Globals.getInstance().set_args(sys.argv) # sys.argv = ['', '--pos-fields']
# Globals.getInstance().set_args(sys.argv)
pos_flags = MagicMock(autospec=meshtastic.radioconfig_pb2.PositionFlags) #
# pos_flags = MagicMock(autospec=meshtastic.radioconfig_pb2.PositionFlags)
with patch('meshtastic.serial_interface.SerialInterface') as mo: #
mo().getNode().radioConfig.preferences.position_flags = 35 # with patch('meshtastic.serial_interface.SerialInterface') as mo:
with patch('meshtastic.radioconfig_pb2.PositionFlags', return_value=pos_flags) as mrc: # mo().getNode().radioConfig.preferences.position_flags = 35
# with patch('meshtastic.radioconfig_pb2.PositionFlags', return_value=pos_flags) as mrc:
mrc.values.return_value = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256] #
# Note: When you use side_effect and a list, each call will use a value from the front of the list then # mrc.values.return_value = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256]
# remove that value from the list. If there are three values in the list, we expect it to be called # # Note: When you use side_effect and a list, each call will use a value from the front of the list then
# three times. # # remove that value from the list. If there are three values in the list, we expect it to be called
mrc.Name.side_effect = ['POS_ALTITUDE', 'POS_ALT_MSL', 'POS_BATTERY'] # # three times.
# mrc.Name.side_effect = ['POS_ALTITUDE', 'POS_ALT_MSL', 'POS_BATTERY']
main() #
# main()
mrc.Name.assert_called() #
mrc.values.assert_called() # mrc.Name.assert_called()
mo.assert_called() # mrc.values.assert_called()
# mo.assert_called()
out, err = capsys.readouterr() #
assert re.search(r'Connected to radio', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'POS_ALTITUDE POS_ALT_MSL POS_BATTERY', out, re.MULTILINE) # assert re.search(r'Connected to radio', out, re.MULTILINE)
assert err == '' # assert re.search(r'POS_ALTITUDE POS_ALT_MSL POS_BATTERY', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_pos_fields_arg_of_zero(capsys): #@pytest.mark.usefixtures("reset_globals")
"""Test --pos-fields an arg of 0 (which shows list)""" #def test_main_pos_fields_arg_of_zero(capsys):
sys.argv = ['', '--pos-fields', '0'] # """Test --pos-fields an arg of 0 (which shows list)"""
Globals.getInstance().set_args(sys.argv) # sys.argv = ['', '--pos-fields', '0']
# Globals.getInstance().set_args(sys.argv)
pos_flags = MagicMock(autospec=meshtastic.radioconfig_pb2.PositionFlags) #
# pos_flags = MagicMock(autospec=meshtastic.radioconfig_pb2.PositionFlags)
with patch('meshtastic.serial_interface.SerialInterface') as mo: #
with patch('meshtastic.radioconfig_pb2.PositionFlags', return_value=pos_flags) as mrc: # with patch('meshtastic.serial_interface.SerialInterface') as mo:
# with patch('meshtastic.radioconfig_pb2.PositionFlags', return_value=pos_flags) as mrc:
def throw_value_error_exception(exc): #
raise ValueError() # def throw_value_error_exception(exc):
mrc.Value.side_effect = throw_value_error_exception # raise ValueError()
mrc.keys.return_value = [ 'POS_UNDEFINED', 'POS_ALTITUDE', 'POS_ALT_MSL', # mrc.Value.side_effect = throw_value_error_exception
'POS_GEO_SEP', 'POS_DOP', 'POS_HVDOP', 'POS_BATTERY', # mrc.keys.return_value = [ 'POS_UNDEFINED', 'POS_ALTITUDE', 'POS_ALT_MSL',
'POS_SATINVIEW', 'POS_SEQ_NOS', 'POS_TIMESTAMP'] # 'POS_GEO_SEP', 'POS_DOP', 'POS_HVDOP', 'POS_BATTERY',
# 'POS_SATINVIEW', 'POS_SEQ_NOS', 'POS_TIMESTAMP']
main() #
# main()
mrc.Value.assert_called() #
mrc.keys.assert_called() # mrc.Value.assert_called()
mo.assert_called() # mrc.keys.assert_called()
# mo.assert_called()
out, err = capsys.readouterr() #
assert re.search(r'Connected to radio', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'ERROR: supported position fields are:', out, re.MULTILINE) # assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r"['POS_UNDEFINED', 'POS_ALTITUDE', 'POS_ALT_MSL', 'POS_GEO_SEP',"\ # assert re.search(r'ERROR: supported position fields are:', out, re.MULTILINE)
"'POS_DOP', 'POS_HVDOP', 'POS_BATTERY', 'POS_SATINVIEW', 'POS_SEQ_NOS',"\ # assert re.search(r"['POS_UNDEFINED', 'POS_ALTITUDE', 'POS_ALT_MSL', 'POS_GEO_SEP',"\
"'POS_TIMESTAMP']", out, re.MULTILINE) # "'POS_DOP', 'POS_HVDOP', 'POS_BATTERY', 'POS_SATINVIEW', 'POS_SEQ_NOS',"\
assert err == '' # "'POS_TIMESTAMP']", out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_pos_fields_valid_values(capsys): #@pytest.mark.usefixtures("reset_globals")
"""Test --pos-fields with valid values""" #def test_main_pos_fields_valid_values(capsys):
sys.argv = ['', '--pos-fields', 'POS_GEO_SEP', 'POS_ALT_MSL'] # """Test --pos-fields with valid values"""
Globals.getInstance().set_args(sys.argv) # sys.argv = ['', '--pos-fields', 'POS_GEO_SEP', 'POS_ALT_MSL']
# Globals.getInstance().set_args(sys.argv)
pos_flags = MagicMock(autospec=meshtastic.radioconfig_pb2.PositionFlags) #
# pos_flags = MagicMock(autospec=meshtastic.radioconfig_pb2.PositionFlags)
with patch('meshtastic.serial_interface.SerialInterface') as mo: #
with patch('meshtastic.radioconfig_pb2.PositionFlags', return_value=pos_flags) as mrc: # with patch('meshtastic.serial_interface.SerialInterface') as mo:
# with patch('meshtastic.radioconfig_pb2.PositionFlags', return_value=pos_flags) as mrc:
mrc.Value.side_effect = [ 4, 2 ] #
# mrc.Value.side_effect = [ 4, 2 ]
main() #
# main()
mrc.Value.assert_called() #
mo.assert_called() # mrc.Value.assert_called()
# mo.assert_called()
out, err = capsys.readouterr() #
assert re.search(r'Connected to radio', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'Setting position fields to 6', out, re.MULTILINE) # assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'Set position_flags to 6', out, re.MULTILINE) # assert re.search(r'Setting position fields to 6', out, re.MULTILINE)
assert re.search(r'Writing modified preferences to device', out, re.MULTILINE) # assert re.search(r'Set position_flags to 6', out, re.MULTILINE)
assert err == '' # assert re.search(r'Writing modified preferences to device', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_get_with_valid_values(capsys): #@pytest.mark.usefixtures("reset_globals")
"""Test --get with valid values (with string, number, boolean)""" #def test_main_get_with_valid_values(capsys):
sys.argv = ['', '--get', 'ls_secs', '--get', 'wifi_ssid', '--get', 'fixed_position'] # """Test --get with valid values (with string, number, boolean)"""
Globals.getInstance().set_args(sys.argv) # sys.argv = ['', '--get', 'ls_secs', '--get', 'wifi_ssid', '--get', 'fixed_position']
# Globals.getInstance().set_args(sys.argv)
with patch('meshtastic.serial_interface.SerialInterface') as mo: #
# with patch('meshtastic.serial_interface.SerialInterface') as mo:
mo().getNode().radioConfig.preferences.wifi_ssid = 'foo' #
mo().getNode().radioConfig.preferences.ls_secs = 300 # mo().getNode().radioConfig.preferences.wifi_ssid = 'foo'
mo().getNode().radioConfig.preferences.fixed_position = False # mo().getNode().radioConfig.preferences.ls_secs = 300
# mo().getNode().radioConfig.preferences.fixed_position = False
main() #
# main()
mo.assert_called() #
# mo.assert_called()
out, err = capsys.readouterr() #
assert re.search(r'Connected to radio', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'ls_secs: 300', out, re.MULTILINE) # assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'wifi_ssid: foo', out, re.MULTILINE) # assert re.search(r'ls_secs: 300', out, re.MULTILINE)
assert re.search(r'fixed_position: False', out, re.MULTILINE) # assert re.search(r'wifi_ssid: foo', out, re.MULTILINE)
assert err == '' # assert re.search(r'fixed_position: False', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit @pytest.mark.unit
@@ -1513,24 +1484,6 @@ def test_main_get_with_invalid(capsys):
mo.assert_called() mo.assert_called()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_globals")
def test_main_setchan(capsys):
"""Test --setchan (deprecated)"""
sys.argv = ['', '--setchan', 'a', 'b']
Globals.getInstance().set_args(sys.argv)
iface = MagicMock(autospec=SerialInterface)
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface):
with pytest.raises(SystemExit) as pytest_wrapped_e:
main()
assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 1
_, err = capsys.readouterr()
assert re.search(r'usage:', err, re.MULTILINE)
@pytest.mark.unit @pytest.mark.unit
@pytest.mark.usefixtures("reset_globals") @pytest.mark.usefixtures("reset_globals")
def test_main_onReceive_empty(caplog, capsys): def test_main_onReceive_empty(caplog, capsys):
@@ -1790,207 +1743,212 @@ def test_main_gpio_rd_no_dest(capsys):
assert err == '' assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
@patch('time.sleep') #@pytest.mark.usefixtures("reset_globals")
def test_main_gpio_rd(caplog, capsys): #@patch('time.sleep')
"""Test --gpio_rd with a named gpio channel""" #def test_main_gpio_rd(caplog, capsys):
# Note: On the Heltec v2.1, there is a GPIO pin GPIO 13 that does not have a # """Test --gpio_rd with a named gpio channel"""
# red arrow (meaning ok to use for our purposes) # # Note: On the Heltec v2.1, there is a GPIO pin GPIO 13 that does not have a
# See https://resource.heltec.cn/download/WiFi_LoRa_32/WIFI_LoRa_32_V2.pdf # # red arrow (meaning ok to use for our purposes)
# To find out the mask for GPIO 13, let us assign n as 13. # # See https://resource.heltec.cn/download/WiFi_LoRa_32/WIFI_LoRa_32_V2.pdf
# 1. Find the 2^n or 2^13 (8192) # # To find out the mask for GPIO 13, let us assign n as 13.
# 2. Convert 8192 decimal to hex (0x2000) # # 1. Find the 2^n or 2^13 (8192)
# You can use python: # # 2. Convert 8192 decimal to hex (0x2000)
# >>> print(hex(2**13)) # # You can use python:
# 0x2000 # # >>> print(hex(2**13))
sys.argv = ['', '--gpio-rd', '0x1000', '--dest', '!1234'] # # 0x2000
Globals.getInstance().set_args(sys.argv) # 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 = Channel(index=1, role=1)
channel.settings.psk = b'\x01' # channel.settings.modem_config = 3
# channel.settings.psk = b'\x01'
packet = { #
# packet = {
'from': 682968668, #
'to': 682968612, # 'from': 682968668,
'channel': 1, # 'to': 682968612,
'decoded': { # 'channel': 1,
'portnum': 'REMOTE_HARDWARE_APP', # 'decoded': {
'payload': b'\x08\x05\x18\x80 ', # 'portnum': 'REMOTE_HARDWARE_APP',
'requestId': 1629980484, # 'payload': b'\x08\x05\x18\x80 ',
'remotehw': { # 'requestId': 1629980484,
'typ': 'READ_GPIOS_REPLY', # 'remotehw': {
'gpioValue': '4096', # 'typ': 'READ_GPIOS_REPLY',
'raw': 'faked', # 'gpioValue': '4096',
'id': 1693085229, # 'raw': 'faked',
'rxTime': 1640294262, # 'id': 1693085229,
'rxSnr': 4.75, # 'rxTime': 1640294262,
'hopLimit': 3, # 'rxSnr': 4.75,
'wantAck': True, # 'hopLimit': 3,
} # 'wantAck': True,
} # }
} # }
# }
iface = MagicMock(autospec=SerialInterface) #
iface.localNode.getChannelByName.return_value = channel # iface = MagicMock(autospec=SerialInterface)
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo: # iface.localNode.getChannelByName.return_value = channel
with caplog.at_level(logging.DEBUG): # with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
main() # with caplog.at_level(logging.DEBUG):
onGPIOreceive(packet, mo) # main()
out, err = capsys.readouterr() # onGPIOreceive(packet, mo)
assert re.search(r'Connected to radio', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'Reading GPIO mask 0x1000 ', out, re.MULTILINE) # assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=4096', out, re.MULTILINE) # assert re.search(r'Reading GPIO mask 0x1000 ', out, re.MULTILINE)
assert err == '' # assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=4096', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
@patch('time.sleep') #@pytest.mark.usefixtures("reset_globals")
def test_main_gpio_rd_with_no_gpioMask(caplog, capsys): #@patch('time.sleep')
"""Test --gpio_rd with a named gpio channel""" #def test_main_gpio_rd_with_no_gpioMask(caplog, capsys):
sys.argv = ['', '--gpio-rd', '0x1000', '--dest', '!1234'] # """Test --gpio_rd with a named gpio channel"""
Globals.getInstance().set_args(sys.argv) # 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 = Channel(index=1, role=1)
channel.settings.psk = b'\x01' # channel.settings.modem_config = 3
# channel.settings.psk = b'\x01'
# Note: Intentionally do not have gpioValue in response as that is the #
# default value # # Note: Intentionally do not have gpioValue in response as that is the
packet = { # # default value
'from': 682968668, # packet = {
'to': 682968612, # 'from': 682968668,
'channel': 1, # 'to': 682968612,
'decoded': { # 'channel': 1,
'portnum': 'REMOTE_HARDWARE_APP', # 'decoded': {
'payload': b'\x08\x05\x18\x80 ', # 'portnum': 'REMOTE_HARDWARE_APP',
'requestId': 1629980484, # 'payload': b'\x08\x05\x18\x80 ',
'remotehw': { # 'requestId': 1629980484,
'typ': 'READ_GPIOS_REPLY', # 'remotehw': {
'raw': 'faked', # 'typ': 'READ_GPIOS_REPLY',
'id': 1693085229, # 'raw': 'faked',
'rxTime': 1640294262, # 'id': 1693085229,
'rxSnr': 4.75, # 'rxTime': 1640294262,
'hopLimit': 3, # 'rxSnr': 4.75,
'wantAck': True, # 'hopLimit': 3,
} # 'wantAck': True,
} # }
} # }
# }
iface = MagicMock(autospec=SerialInterface) #
iface.localNode.getChannelByName.return_value = channel # iface = MagicMock(autospec=SerialInterface)
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo: # iface.localNode.getChannelByName.return_value = channel
with caplog.at_level(logging.DEBUG): # with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
main() # with caplog.at_level(logging.DEBUG):
onGPIOreceive(packet, mo) # main()
out, err = capsys.readouterr() # onGPIOreceive(packet, mo)
assert re.search(r'Connected to radio', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'Reading GPIO mask 0x1000 ', out, re.MULTILINE) # assert re.search(r'Connected to radio', out, re.MULTILINE)
assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=0', out, re.MULTILINE) # assert re.search(r'Reading GPIO mask 0x1000 ', out, re.MULTILINE)
assert err == '' # assert re.search(r'Received RemoteHardware typ=READ_GPIOS_REPLY, gpio_value=0', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_gpio_watch(caplog, capsys): #@pytest.mark.usefixtures("reset_globals")
"""Test --gpio_watch with a named gpio channel""" #def test_main_gpio_watch(caplog, capsys):
sys.argv = ['', '--gpio-watch', '0x1000', '--dest', '!1234'] # """Test --gpio_watch with a named gpio channel"""
Globals.getInstance().set_args(sys.argv) # sys.argv = ['', '--gpio-watch', '0x1000', '--dest', '!1234']
# Globals.getInstance().set_args(sys.argv)
def my_sleep(amount): #
print(f'{amount}') # def my_sleep(amount):
sys.exit(3) # print(f'{amount}')
# sys.exit(3)
channel = Channel(index=1, role=1) #
channel.settings.modem_config = 3 # channel = Channel(index=1, role=1)
channel.settings.psk = b'\x01' # channel.settings.modem_config = 3
# channel.settings.psk = b'\x01'
packet = { #
# packet = {
'from': 682968668, #
'to': 682968612, # 'from': 682968668,
'channel': 1, # 'to': 682968612,
'decoded': { # 'channel': 1,
'portnum': 'REMOTE_HARDWARE_APP', # 'decoded': {
'payload': b'\x08\x05\x18\x80 ', # 'portnum': 'REMOTE_HARDWARE_APP',
'requestId': 1629980484, # 'payload': b'\x08\x05\x18\x80 ',
'remotehw': { # 'requestId': 1629980484,
'typ': 'READ_GPIOS_REPLY', # 'remotehw': {
'gpioValue': '4096', # 'typ': 'READ_GPIOS_REPLY',
'raw': 'faked', # 'gpioValue': '4096',
'id': 1693085229, # 'raw': 'faked',
'rxTime': 1640294262, # 'id': 1693085229,
'rxSnr': 4.75, # 'rxTime': 1640294262,
'hopLimit': 3, # 'rxSnr': 4.75,
'wantAck': True, # 'hopLimit': 3,
} # 'wantAck': True,
} # }
} # }
# }
with patch('time.sleep', side_effect=my_sleep): #
with pytest.raises(SystemExit) as pytest_wrapped_e: # with patch('time.sleep', side_effect=my_sleep):
iface = MagicMock(autospec=SerialInterface) # with pytest.raises(SystemExit) as pytest_wrapped_e:
iface.localNode.getChannelByName.return_value = channel # iface = MagicMock(autospec=SerialInterface)
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo: # iface.localNode.getChannelByName.return_value = channel
with caplog.at_level(logging.DEBUG): # with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
main() # with caplog.at_level(logging.DEBUG):
onGPIOreceive(packet, mo) # main()
assert pytest_wrapped_e.type == SystemExit # onGPIOreceive(packet, mo)
assert pytest_wrapped_e.value.code == 3 # assert pytest_wrapped_e.type == SystemExit
out, err = capsys.readouterr() # assert pytest_wrapped_e.value.code == 3
assert re.search(r'Connected to radio', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'Watching GPIO mask 0x1000 ', out, re.MULTILINE) # assert re.search(r'Connected to radio', out, re.MULTILINE)
assert err == '' # assert re.search(r'Watching GPIO mask 0x1000 ', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_gpio_wrb(caplog, capsys): #@pytest.mark.usefixtures("reset_globals")
"""Test --gpio_wrb with a named gpio channel""" #def test_main_gpio_wrb(caplog, capsys):
sys.argv = ['', '--gpio-wrb', '4', '1', '--dest', '!1234'] # """Test --gpio_wrb with a named gpio channel"""
Globals.getInstance().set_args(sys.argv) # 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 == ''
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.unit
@pytest.mark.usefixtures("reset_globals") @pytest.mark.usefixtures("reset_globals")
@@ -2178,93 +2136,98 @@ def test_main_setPref_valid_field_int_as_string(capsys):
assert err == '' assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_setPref_valid_field_invalid_enum(capsys, caplog): #@pytest.mark.usefixtures("reset_globals")
"""Test setPref() with a valid field but invalid enum value""" #def test_main_setPref_valid_field_invalid_enum(capsys, caplog):
# """Test setPref() with a valid field but invalid enum value"""
radioConfig = RadioConfig() #
prefs = radioConfig.preferences # radioConfig = RadioConfig()
# prefs = radioConfig.preferences
with caplog.at_level(logging.DEBUG): #
setPref(prefs, 'charge_current', 'foo') # with caplog.at_level(logging.DEBUG):
out, err = capsys.readouterr() # setPref(prefs, 'charge_current', 'foo')
assert re.search(r'charge_current does not have an enum called foo', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'Choices in sorted order are', out, re.MULTILINE) # assert re.search(r'charge_current does not have an enum called foo', out, re.MULTILINE)
assert re.search(r'MA100', out, re.MULTILINE) # assert re.search(r'Choices in sorted order are', out, re.MULTILINE)
assert re.search(r'MA280', out, re.MULTILINE) # assert re.search(r'MA100', out, re.MULTILINE)
assert err == '' # assert re.search(r'MA280', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_setPref_valid_field_invalid_enum_where_enums_are_camel_cased_values(capsys, caplog): #@pytest.mark.usefixtures("reset_globals")
"""Test setPref() with a valid field but invalid enum value""" #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 # radioConfig = RadioConfig()
# prefs = radioConfig.preferences
with caplog.at_level(logging.DEBUG): #
setPref(prefs, 'location_share', 'foo') # with caplog.at_level(logging.DEBUG):
out, err = capsys.readouterr() # setPref(prefs, 'region', 'foo')
assert re.search(r'location_share does not have an enum called foo', out, re.MULTILINE) # out, err = capsys.readouterr()
assert re.search(r'Choices in sorted order are', out, re.MULTILINE) # assert re.search(r'region does not have an enum called foo', out, re.MULTILINE)
assert re.search(r'LocDisabled', out, re.MULTILINE) # assert re.search(r'Choices in sorted order are', out, re.MULTILINE)
assert re.search(r'LocEnabled', out, re.MULTILINE) # assert re.search(r'ANZ', out, re.MULTILINE)
assert err == '' # assert re.search(r'CN', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_setPref_valid_field_invalid_enum_camel(capsys, caplog): #@pytest.mark.usefixtures("reset_globals")
"""Test setPref() with a valid field but invalid enum value""" #def test_main_setPref_valid_field_invalid_enum_camel(capsys, caplog):
Globals.getInstance().set_camel_case() # """Test setPref() with a valid field but invalid enum value"""
# Globals.getInstance().set_camel_case()
radioConfig = RadioConfig() #
prefs = radioConfig.preferences # radioConfig = RadioConfig()
# prefs = radioConfig.preferences
with caplog.at_level(logging.DEBUG): #
setPref(prefs, 'charge_current', 'foo') # with caplog.at_level(logging.DEBUG):
out, err = capsys.readouterr() # setPref(prefs, 'charge_current', 'foo')
assert re.search(r'chargeCurrent does not have an enum called foo', out, re.MULTILINE) # out, err = capsys.readouterr()
assert err == '' # assert re.search(r'chargeCurrent does not have an enum called foo', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_setPref_valid_field_valid_enum(capsys, caplog): #@pytest.mark.usefixtures("reset_globals")
"""Test setPref() with a valid field and valid enum value""" #def test_main_setPref_valid_field_valid_enum(capsys, caplog):
# """Test setPref() with a valid field and valid enum value"""
# charge_current #
# some valid values: MA100 MA1000 MA1080 # # charge_current
# # some valid values: MA100 MA1000 MA1080
radioConfig = RadioConfig() #
prefs = radioConfig.preferences # radioConfig = RadioConfig()
# prefs = radioConfig.preferences
with caplog.at_level(logging.DEBUG): #
setPref(prefs, 'charge_current', 'MA100') # with caplog.at_level(logging.DEBUG):
out, err = capsys.readouterr() # setPref(prefs, 'charge_current', 'MA100')
assert re.search(r'Set charge_current to MA100', out, re.MULTILINE) # out, err = capsys.readouterr()
assert err == '' # assert re.search(r'Set charge_current to MA100', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_main_setPref_valid_field_valid_enum_camel(capsys, caplog): #@pytest.mark.usefixtures("reset_globals")
"""Test setPref() with a valid field and valid enum value""" #def test_main_setPref_valid_field_valid_enum_camel(capsys, caplog):
Globals.getInstance().set_camel_case() # """Test setPref() with a valid field and valid enum value"""
# Globals.getInstance().set_camel_case()
# charge_current #
# some valid values: MA100 MA1000 MA1080 # # charge_current
# # some valid values: MA100 MA1000 MA1080
radioConfig = RadioConfig() #
prefs = radioConfig.preferences # radioConfig = RadioConfig()
# prefs = radioConfig.preferences
with caplog.at_level(logging.DEBUG): #
setPref(prefs, 'charge_current', 'MA100') # with caplog.at_level(logging.DEBUG):
out, err = capsys.readouterr() # setPref(prefs, 'charge_current', 'MA100')
assert re.search(r'Set chargeCurrent to MA100', out, re.MULTILINE) # out, err = capsys.readouterr()
assert err == '' # assert re.search(r'Set chargeCurrent to MA100', out, re.MULTILINE)
# assert err == ''
@pytest.mark.unit @pytest.mark.unit

View File

@@ -10,7 +10,8 @@ from ..mesh_interface import MeshInterface
from ..node import Node from ..node import Node
from .. import mesh_pb2 from .. import mesh_pb2
from ..__init__ import LOCAL_ADDR, BROADCAST_ADDR from ..__init__ import LOCAL_ADDR, BROADCAST_ADDR
from ..radioconfig_pb2 import RadioConfig # TODO
#from ..config import Config
from ..util import Timeout from ..util import Timeout
@@ -177,32 +178,34 @@ def test_sendPosition(caplog):
assert re.search(r'p.time:', caplog.text, re.MULTILINE) assert re.search(r'p.time:', caplog.text, re.MULTILINE)
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_close_with_heartbeatTimer(caplog): #@pytest.mark.usefixtures("reset_globals")
"""Test close() with heartbeatTimer""" #def test_close_with_heartbeatTimer(caplog):
iface = MeshInterface(noProto=True) # """Test close() with heartbeatTimer"""
anode = Node('foo', 'bar') # iface = MeshInterface(noProto=True)
radioConfig = RadioConfig() # anode = Node('foo', 'bar')
radioConfig.preferences.phone_timeout_secs = 10 # aconfig = Config()
anode.radioConfig = radioConfig # aonfig.preferences.phone_timeout_secs = 10
iface.localNode = anode # anode.config = aconfig
assert iface.heartbeatTimer is None # iface.localNode = anode
with caplog.at_level(logging.DEBUG): # assert iface.heartbeatTimer is None
iface._startHeartbeat() # with caplog.at_level(logging.DEBUG):
assert iface.heartbeatTimer is not None # iface._startHeartbeat()
iface.close() # assert iface.heartbeatTimer is not None
# iface.close()
@pytest.mark.unit # TODO
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unit
def test_handleFromRadio_empty_payload(caplog): #@pytest.mark.usefixtures("reset_globals")
"""Test _handleFromRadio""" #def test_handleFromRadio_empty_payload(caplog):
iface = MeshInterface(noProto=True) # """Test _handleFromRadio"""
with caplog.at_level(logging.DEBUG): # iface = MeshInterface(noProto=True)
iface._handleFromRadio(b'') # with caplog.at_level(logging.DEBUG):
iface.close() # iface._handleFromRadio(b'')
assert re.search(r'Unexpected FromRadio payload', caplog.text, re.MULTILINE) # iface.close()
# assert re.search(r'Unexpected FromRadio payload', caplog.text, re.MULTILINE)
@pytest.mark.unit @pytest.mark.unit
@@ -604,11 +607,12 @@ def test_getOrCreateByNum(iface_with_nodes):
assert tmp['num'] == 2475227164 assert tmp['num'] == 2475227164
@pytest.mark.unit # TODO
def test_enter(): #@pytest.mark.unit
"""Test __enter__()""" #def test_enter():
iface = MeshInterface(noProto=True) # """Test __enter__()"""
assert iface == iface.__enter__() # iface = MeshInterface(noProto=True)
# assert iface == iface.__enter__()
@pytest.mark.unit @pytest.mark.unit

View File

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@ def test_RemoteHardwareClient():
def test_onGPIOreceive(capsys): def test_onGPIOreceive(capsys):
"""Test onGPIOreceive""" """Test onGPIOreceive"""
iface = MagicMock(autospec=SerialInterface) iface = MagicMock(autospec=SerialInterface)
packet = {'decoded': {'remotehw': {'typ': 'foo', 'gpioValue': '4096' }}} packet = {'decoded': {'remotehw': {'type': 'foo', 'gpioValue': '4096' }}}
onGPIOreceive(packet, iface) onGPIOreceive(packet, iface)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert re.search(r'Received RemoteHardware', out) assert re.search(r'Received RemoteHardware', out)

View File

@@ -170,20 +170,6 @@ def test_smoke1_port():
assert return_value == 0 assert return_value == 0
@pytest.mark.smoke1
def test_smoke1_set_is_router_true():
"""Test --set is_router true"""
return_value, out = subprocess.getstatusoutput('meshtastic --set is_router true')
assert re.match(r'Connected to radio', out)
assert re.search(r'^Set is_router to true', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --get is_router')
assert re.search(r'^is_router: True', out, re.MULTILINE)
assert return_value == 0
@pytest.mark.smoke1 @pytest.mark.smoke1
def test_smoke1_set_location_info(): def test_smoke1_set_location_info():
"""Test --setlat, --setlon and --setalt """ """Test --setlat, --setlon and --setalt """
@@ -202,20 +188,6 @@ def test_smoke1_set_location_info():
assert return_value == 0 assert return_value == 0
@pytest.mark.smoke1
def test_smoke1_set_is_router_false():
"""Test --set is_router false"""
return_value, out = subprocess.getstatusoutput('meshtastic --set is_router false')
assert re.match(r'Connected to radio', out)
assert re.search(r'^Set is_router to false', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --get is_router')
assert re.search(r'^is_router: False', out, re.MULTILINE)
assert return_value == 0
@pytest.mark.smoke1 @pytest.mark.smoke1
def test_smoke1_set_owner(): def test_smoke1_set_owner():
"""Test --set-owner name""" """Test --set-owner name"""
@@ -243,38 +215,42 @@ def test_smoke1_set_owner():
@pytest.mark.smoke1 @pytest.mark.smoke1
def test_smoke1_set_team(): def test_smoke1_ch_set_modem_config():
"""Test --set-team """ """Test --ch-set modem_config"""
# unset the team return_value, out = subprocess.getstatusoutput('meshtastic --ch-set modem_config MedFast')
return_value, out = subprocess.getstatusoutput('meshtastic --set-team CLEAR') assert re.search(r'Warning: Need to specify', out, re.MULTILINE)
assert re.match(r'Connected to radio', out) assert return_value == 1
assert re.search(r'^Setting team to CLEAR', out, re.MULTILINE) # pause for the radio
time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --info')
assert not re.search(r'MedFast', out, re.MULTILINE)
assert return_value == 0 assert return_value == 0
# pause for the radio # pause for the radio
time.sleep(PAUSE_AFTER_REBOOT) time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --set-team CYAN') return_value, out = subprocess.getstatusoutput('meshtastic --ch-set modem_config MedFast --ch-index 0')
assert re.search(r'Setting team to CYAN', out, re.MULTILINE) assert re.match(r'Connected to radio', out)
assert re.search(r'^Set modem_config to MedFast', out, re.MULTILINE)
assert return_value == 0 assert return_value == 0
# pause for the radio # pause for the radio
time.sleep(PAUSE_AFTER_REBOOT) time.sleep(PAUSE_AFTER_REBOOT)
return_value, out = subprocess.getstatusoutput('meshtastic --info') return_value, out = subprocess.getstatusoutput('meshtastic --info')
assert re.search(r'CYAN', out, re.MULTILINE) assert re.search(r'MedFast', out, re.MULTILINE)
assert return_value == 0 assert return_value == 0
@pytest.mark.smoke1 @pytest.mark.smoke1
def test_smoke1_ch_values(): def test_smoke1_ch_values():
"""Test --ch-longslow, --ch-longfast, --ch-mediumslow, --ch-mediumsfast, """Test --ch-vlongslow --ch-longslow, --ch-longfast, --ch-mediumslow, --ch-mediumsfast,
--ch-shortslow, and --ch-shortfast arguments --ch-shortslow, and --ch-shortfast arguments
""" """
exp = { exp = {
'--ch-longslow': 'Bw125Cr48Sf4096', '--ch-vlongslow': '{ "psk": "AQ==" }',
'--ch-longfast': 'Bw31_25Cr48Sf512', '--ch-longslow': 'LongSlow',
'--ch-mediumslow': 'Bw250Cr46Sf2048', '--ch-longfast': 'LongFast',
'--ch-mediumfast': 'Bw250Cr47Sf1024', '--ch-medslow': 'MedSlow',
# for some reason, this value does not show any modemConfig '--ch-medfast': 'MedFast',
'--ch-shortslow': '{ "psk', '--ch-shortslow': 'ShortSlow',
'--ch-shortfast': 'Bw500Cr45Sf128' '--ch-shortfast': 'ShortFast'
} }
for key, val in exp.items(): for key, val in exp.items():
@@ -578,30 +554,6 @@ def test_smoke1_ensure_ch_del_third_of_three_channels():
time.sleep(PAUSE_AFTER_COMMAND) time.sleep(PAUSE_AFTER_COMMAND)
@pytest.mark.smoke1
def test_smoke1_ch_set_modem_config():
"""Test --ch-set modem_config"""
return_value, out = subprocess.getstatusoutput('meshtastic --ch-set modem_config Bw31_25Cr48Sf512')
assert re.search(r'Warning: Need to specify', out, re.MULTILINE)
assert return_value == 1
# pause for the radio
time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --info')
assert not re.search(r'Bw31_25Cr48Sf512', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --ch-set modem_config Bw31_25Cr48Sf512 --ch-index 0')
assert re.match(r'Connected to radio', out)
assert re.search(r'^Set modem_config to Bw31_25Cr48Sf512', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --info')
assert re.search(r'Bw31_25Cr48Sf512', out, re.MULTILINE)
assert return_value == 0
@pytest.mark.smoke1 @pytest.mark.smoke1
def test_smoke1_seturl_default(): def test_smoke1_seturl_default():
"""Test --seturl with default value""" """Test --seturl with default value"""
@@ -650,7 +602,6 @@ def test_smoke1_configure():
assert re.search('^Setting device position', out, re.MULTILINE) assert re.search('^Setting device position', out, re.MULTILINE)
assert re.search('^Set region to 1', out, re.MULTILINE) assert re.search('^Set region to 1', out, re.MULTILINE)
assert re.search('^Set is_always_powered to true', out, re.MULTILINE) assert re.search('^Set is_always_powered to true', out, re.MULTILINE)
assert re.search('^Set send_owner_interval to 2', out, re.MULTILINE)
assert re.search('^Set screen_on_secs to 31536000', out, re.MULTILINE) assert re.search('^Set screen_on_secs to 31536000', out, re.MULTILINE)
assert re.search('^Set wait_bluetooth_secs to 31536000', out, re.MULTILINE) assert re.search('^Set wait_bluetooth_secs to 31536000', out, re.MULTILINE)
assert re.search('^Writing modified preferences to device', out, re.MULTILINE) assert re.search('^Writing modified preferences to device', out, re.MULTILINE)

View File

@@ -175,20 +175,6 @@ def test_smokevirt_port():
assert len(ports) == 0 assert len(ports) == 0
@pytest.mark.smokevirt
def test_smokevirt_set_is_router_true():
"""Test --set is_router true"""
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --set is_router true')
assert re.match(r'Connected to radio', out)
assert re.search(r'^Set is_router to true', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --get is_router')
assert re.search(r'^is_router: True', out, re.MULTILINE)
assert return_value == 0
@pytest.mark.smokevirt @pytest.mark.smokevirt
def test_smokevirt_set_location_info(): def test_smokevirt_set_location_info():
"""Test --setlat, --setlon and --setalt """ """Test --setlat, --setlon and --setalt """
@@ -207,20 +193,6 @@ def test_smokevirt_set_location_info():
assert return_value == 0 assert return_value == 0
@pytest.mark.smokevirt
def test_smokevirt_set_is_router_false():
"""Test --set is_router false"""
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --set is_router false')
assert re.match(r'Connected to radio', out)
assert re.search(r'^Set is_router to false', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --get is_router')
assert re.search(r'^is_router: False', out, re.MULTILINE)
assert return_value == 0
@pytest.mark.smokevirt @pytest.mark.smokevirt
def test_smokevirt_set_owner(): def test_smokevirt_set_owner():
"""Test --set-owner name""" """Test --set-owner name"""
@@ -247,38 +219,18 @@ def test_smokevirt_set_owner():
assert return_value == 0 assert return_value == 0
@pytest.mark.smokevirt
def test_smokevirt_set_team():
"""Test --set-team """
# unset the team
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --set-team CLEAR')
assert re.match(r'Connected to radio', out)
assert re.search(r'^Setting team to CLEAR', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_REBOOT)
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --set-team CYAN')
assert re.search(r'Setting team to CYAN', out, re.MULTILINE)
assert return_value == 0
# pause for the radio
time.sleep(PAUSE_AFTER_REBOOT)
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --info')
assert re.search(r'CYAN', out, re.MULTILINE)
assert return_value == 0
@pytest.mark.smokevirt @pytest.mark.smokevirt
def test_smokevirt_ch_values(): def test_smokevirt_ch_values():
"""Test --ch-longslow, --ch-longfast, --ch-mediumslow, --ch-mediumsfast, """Test --ch-longslow, --ch-longfast, --ch-mediumslow, --ch-mediumsfast,
--ch-shortslow, and --ch-shortfast arguments --ch-shortslow, and --ch-shortfast arguments
""" """
exp = { exp = {
'--ch-longslow': 'Bw125Cr48Sf4096', '--ch-longslow': 'LongSlow',
'--ch-longfast': 'Bw31_25Cr48Sf512', '--ch-longfast': 'LongFast',
'--ch-mediumslow': 'Bw250Cr46Sf2048', '--ch-medslow': 'MedSlow',
'--ch-mediumfast': 'Bw250Cr47Sf1024', '--ch-medfast': 'MedFast',
'--ch-shortslow': '{ "psk', '--ch-shortslow': 'ShortSlow',
'--ch-shortfast': 'Bw500Cr45Sf128' '--ch-shortfast': 'ShortFast'
} }
for key, val in exp.items(): for key, val in exp.items():
@@ -611,14 +563,14 @@ def test_smokevirt_ch_set_modem_config():
assert return_value == 0 assert return_value == 0
# pause for the radio # pause for the radio
time.sleep(PAUSE_AFTER_COMMAND) time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --ch-set modem_config Bw31_25Cr48Sf512 --ch-index 0') return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --ch-set modem_config MidSlow --ch-index 0')
assert re.match(r'Connected to radio', out) assert re.match(r'Connected to radio', out)
assert re.search(r'^Set modem_config to Bw31_25Cr48Sf512', out, re.MULTILINE) assert re.search(r'^Set modem_config to MidSlow', out, re.MULTILINE)
assert return_value == 0 assert return_value == 0
# pause for the radio # pause for the radio
time.sleep(PAUSE_AFTER_COMMAND) time.sleep(PAUSE_AFTER_COMMAND)
return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --info') return_value, out = subprocess.getstatusoutput('meshtastic --host localhost --info')
assert re.search(r'Bw31_25Cr48Sf512', out, re.MULTILINE) assert re.search(r'MidSlow', out, re.MULTILINE)
assert return_value == 0 assert return_value == 0

View File

@@ -1,7 +1,7 @@
"""Meshtastic unit tests for stream_interface.py""" """Meshtastic unit tests for stream_interface.py"""
import logging import logging
import re #import re
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest import pytest
@@ -35,48 +35,49 @@ def test_StreamInterface_with_noProto(caplog):
assert data == test_data assert data == test_data
## Note: This takes a bit, so moving from unit to slow # TODO
## Tip: If you want to see the print output, run with '-s' flag: ### Note: This takes a bit, so moving from unit to slow
## pytest -s meshtastic/tests/test_stream_interface.py::test_sendToRadioImpl ### Tip: If you want to see the print output, run with '-s' flag:
@pytest.mark.unitslow ### pytest -s meshtastic/tests/test_stream_interface.py::test_sendToRadioImpl
@pytest.mark.usefixtures("reset_globals") #@pytest.mark.unitslow
def test_sendToRadioImpl(caplog): #@pytest.mark.usefixtures("reset_globals")
"""Test _sendToRadioImpl()""" #def test_sendToRadioImpl(caplog):
# """Test _sendToRadioImpl()"""
# def add_header(b): #
# """Add header stuffs for radio""" ## def add_header(b):
# bufLen = len(b) ## """Add header stuffs for radio"""
# header = bytes([START1, START2, (bufLen >> 8) & 0xff, bufLen & 0xff]) ## bufLen = len(b)
# return header + b ## header = bytes([START1, START2, (bufLen >> 8) & 0xff, bufLen & 0xff])
## return header + b
# captured raw bytes of a Heltec2.1 radio with 2 channels (primary and a secondary channel named "gpio") #
raw_1_my_info = b'\x1a,\x08\xdc\x8c\xd5\xc5\x02\x18\r2\x0e1.2.49.5354c49P\x15]\xe1%\x17Eh\xe0\xa7\x12p\xe8\x9d\x01x\x08\x90\x01\x01' # # captured raw bytes of a Heltec2.1 radio with 2 channels (primary and a secondary channel named "gpio")
raw_2_node_info = b'"9\x08\xdc\x8c\xd5\xc5\x02\x12(\n\t!28b5465c\x12\x0cUnknown 465c\x1a\x03?5C"\x06$o(\xb5F\\0\n\x1a\x02 1%M<\xc6a' # raw_1_my_info = b'\x1a,\x08\xdc\x8c\xd5\xc5\x02\x18\r2\x0e1.2.49.5354c49P\x15]\xe1%\x17Eh\xe0\xa7\x12p\xe8\x9d\x01x\x08\x90\x01\x01'
# pylint: disable=C0301 # raw_2_node_info = b'"9\x08\xdc\x8c\xd5\xc5\x02\x12(\n\t!28b5465c\x12\x0cUnknown 465c\x1a\x03?5C"\x06$o(\xb5F\\0\n\x1a\x02 1%M<\xc6a'
raw_3_node_info = b'"C\x08\xa4\x8c\xd5\xc5\x02\x12(\n\t!28b54624\x12\x0cUnknown 4624\x1a\x03?24"\x06$o(\xb5F$0\n\x1a\x07 5MH<\xc6a%G<\xc6a=\x00\x00\xc0@' # # pylint: disable=C0301
raw_4_complete = b'@\xcf\xe5\xd1\x8c\x0e' # raw_3_node_info = b'"C\x08\xa4\x8c\xd5\xc5\x02\x12(\n\t!28b54624\x12\x0cUnknown 4624\x1a\x03?24"\x06$o(\xb5F$0\n\x1a\x07 5MH<\xc6a%G<\xc6a=\x00\x00\xc0@'
# pylint: disable=C0301 # raw_4_complete = b'@\xcf\xe5\xd1\x8c\x0e'
raw_5_prefs = b'Z6\r\\F\xb5(\x15\\F\xb5("\x1c\x08\x06\x12\x13*\x11\n\x0f0\x84\x07P\xac\x02\x88\x01\x01\xb0\t#\xb8\t\x015]$\xddk5\xd5\x7f!b=M<\xc6aP\x03`F' # # pylint: disable=C0301
# pylint: disable=C0301 # raw_5_prefs = b'Z6\r\\F\xb5(\x15\\F\xb5("\x1c\x08\x06\x12\x13*\x11\n\x0f0\x84\x07P\xac\x02\x88\x01\x01\xb0\t#\xb8\t\x015]$\xddk5\xd5\x7f!b=M<\xc6aP\x03`F'
raw_6_channel0 = b'Z.\r\\F\xb5(\x15\\F\xb5("\x14\x08\x06\x12\x0b:\t\x12\x05\x18\x01"\x01\x01\x18\x015^$\xddk5\xd6\x7f!b=M<\xc6aP\x03`F' # # pylint: disable=C0301
# pylint: disable=C0301 # raw_6_channel0 = b'Z.\r\\F\xb5(\x15\\F\xb5("\x14\x08\x06\x12\x0b:\t\x12\x05\x18\x01"\x01\x01\x18\x015^$\xddk5\xd6\x7f!b=M<\xc6aP\x03`F'
raw_7_channel1 = b'ZS\r\\F\xb5(\x15\\F\xb5("9\x08\x06\x120:.\x08\x01\x12(" \xb4&\xb3\xc7\x06\xd8\xe39%\xba\xa5\xee\x8eH\x06\xf6\xf4H\xe8\xd5\xc1[ao\xb5Y\\\xb4"\xafmi*\x04gpio\x18\x025_$\xddk5\xd7\x7f!b=M<\xc6aP\x03`F' # # pylint: disable=C0301
raw_8_channel2 = b'Z)\r\\F\xb5(\x15\\F\xb5("\x0f\x08\x06\x12\x06:\x04\x08\x02\x12\x005`$\xddk5\xd8\x7f!b=M<\xc6aP\x03`F' # raw_7_channel1 = b'ZS\r\\F\xb5(\x15\\F\xb5("9\x08\x06\x120:.\x08\x01\x12(" \xb4&\xb3\xc7\x06\xd8\xe39%\xba\xa5\xee\x8eH\x06\xf6\xf4H\xe8\xd5\xc1[ao\xb5Y\\\xb4"\xafmi*\x04gpio\x18\x025_$\xddk5\xd7\x7f!b=M<\xc6aP\x03`F'
raw_blank = b'' # raw_8_channel2 = b'Z)\r\\F\xb5(\x15\\F\xb5("\x0f\x08\x06\x12\x06:\x04\x08\x02\x12\x005`$\xddk5\xd8\x7f!b=M<\xc6aP\x03`F'
# raw_blank = b''
test_data = b'hello' #
stream = MagicMock() # test_data = b'hello'
#stream.read.return_value = add_header(test_data) # stream = MagicMock()
stream.read.side_effect = [ raw_1_my_info, raw_2_node_info, raw_3_node_info, raw_4_complete, # #stream.read.return_value = add_header(test_data)
raw_5_prefs, raw_6_channel0, raw_7_channel1, raw_8_channel2, # stream.read.side_effect = [ raw_1_my_info, raw_2_node_info, raw_3_node_info, raw_4_complete,
raw_blank, raw_blank] # raw_5_prefs, raw_6_channel0, raw_7_channel1, raw_8_channel2,
toRadio = MagicMock() # raw_blank, raw_blank]
toRadio.SerializeToString.return_value = test_data # toRadio = MagicMock()
with caplog.at_level(logging.DEBUG): # toRadio.SerializeToString.return_value = test_data
iface = StreamInterface(noProto=True, connectNow=False) # with caplog.at_level(logging.DEBUG):
iface.stream = stream # iface = StreamInterface(noProto=True, connectNow=False)
iface.connect() # iface.stream = stream
iface._sendToRadioImpl(toRadio) # iface.connect()
assert re.search(r'Sending: ', caplog.text, re.MULTILINE) # iface._sendToRadioImpl(toRadio)
assert re.search(r'reading character', caplog.text, re.MULTILINE) # assert re.search(r'Sending: ', caplog.text, re.MULTILINE)
assert re.search(r'In reader loop', caplog.text, re.MULTILINE) # assert re.search(r'reading character', caplog.text, re.MULTILINE)
# assert re.search(r'In reader loop', caplog.text, re.MULTILINE)

View File

@@ -64,6 +64,8 @@ def fromStr(valstr):
elif valstr.startswith('0x'): elif valstr.startswith('0x'):
# if needed convert to string with asBytes.decode('utf-8') # if needed convert to string with asBytes.decode('utf-8')
val = bytes.fromhex(valstr[2:]) val = bytes.fromhex(valstr[2:])
elif valstr.startswith('base64:'):
val = base64.b64decode(valstr[7:])
elif valstr.lower() in {"t", "true", "yes"}: elif valstr.lower() in {"t", "true", "yes"}:
val = True val = True
elif valstr.lower() in {"f", "false", "no"}: elif valstr.lower() in {"f", "false", "no"}:
@@ -157,6 +159,42 @@ class Timeout:
time.sleep(self.sleepInterval) time.sleep(self.sleepInterval)
return False return False
def waitForAckNak(self, acknowledgment, attrs=('receivedAck', 'receivedNak', 'receivedImplAck')):
"""Block until an ACK or NAK has been received. Returns True if ACK or NAK has been received."""
self.reset()
while time.time() < self.expireTime:
if any(map(lambda a: getattr(acknowledgment, a, None), attrs)):
acknowledgment.reset()
return True
time.sleep(self.sleepInterval)
return False
def waitForTraceRoute(self, waitFactor, acknowledgment, attr='receivedTraceRoute'):
"""Block until traceroute response is received. Returns True if traceroute response has been received."""
self.expireTimeout *= waitFactor
self.reset()
while time.time() < self.expireTime:
if getattr(acknowledgment, attr, None):
acknowledgment.reset()
return True
time.sleep(self.sleepInterval)
return False
class Acknowledgment:
"A class that records which type of acknowledgment was just received, if any."
def __init__(self):
"""initialize"""
self.receivedAck = False
self.receivedNak = False
self.receivedImplAck = False
self.receivedTraceRoute = False
def reset(self):
"""reset"""
self.receivedAck = False
self.receivedNak = False
self.receivedImplAck = False
self.receivedTraceRoute = False
class DeferredExecution(): class DeferredExecution():
"""A thread that accepts closures to run, and runs them as they are received""" """A thread that accepts closures to run, and runs them as they are received"""
@@ -194,7 +232,7 @@ def support_info():
print('') print('')
print('If having issues with meshtastic cli or python library') print('If having issues with meshtastic cli or python library')
print('or wish to make feature requests, visit:') print('or wish to make feature requests, visit:')
print('https://github.com/meshtastic/Meshtastic-python/issues') print('https://github.com/meshtastic/python/issues')
print('When adding an issue, be sure to include the following info:') print('When adding an issue, be sure to include the following info:')
print(f' System: {platform.system()}') print(f' System: {platform.system()}')
print(f' Platform: {platform.platform()}') print(f' Platform: {platform.platform()}')
@@ -266,7 +304,7 @@ def camel_to_snake(a_string):
def detect_supported_devices(): def detect_supported_devices():
"""detect supported devices""" """detect supported devices based on vendor id"""
system = platform.system() system = platform.system()
#print(f'system:{system}') #print(f'system:{system}')
@@ -285,19 +323,8 @@ def detect_supported_devices():
if re.search(search, lsusb_output, re.MULTILINE): if re.search(search, lsusb_output, re.MULTILINE):
#print(f'Found vendor id that matches') #print(f'Found vendor id that matches')
devices = get_devices_with_vendor_id(vid) devices = get_devices_with_vendor_id(vid)
# check device id
for device in devices: for device in devices:
#print(f'device:{device} device.usb_product_id_in_hex:{device.usb_product_id_in_hex}') possible_devices.add(device)
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": elif system == "Windows":
# if windows, run Get-PnpDevice # if windows, run Get-PnpDevice
@@ -313,22 +340,8 @@ def detect_supported_devices():
if re.search(search, sp_output, re.MULTILINE): if re.search(search, sp_output, re.MULTILINE):
#print(f'Found vendor id that matches') #print(f'Found vendor id that matches')
devices = get_devices_with_vendor_id(vid) devices = get_devices_with_vendor_id(vid)
# check device id
for device in devices: for device in devices:
#print(f'device:{device} device.usb_product_id_in_hex:{device.usb_product_id_in_hex}') possible_devices.add(device)
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": elif system == "Darwin":
# run: system_profiler SPUSBDataType # run: system_profiler SPUSBDataType
@@ -343,19 +356,8 @@ def detect_supported_devices():
if re.search(search, sp_output, re.MULTILINE): if re.search(search, sp_output, re.MULTILINE):
#print(f'Found vendor id that matches') #print(f'Found vendor id that matches')
devices = get_devices_with_vendor_id(vid) devices = get_devices_with_vendor_id(vid)
# check device id
for device in devices: for device in devices:
#print(f'device:{device} device.usb_product_id_in_hex:{device.usb_product_id_in_hex}') possible_devices.add(device)
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 return possible_devices

38
meshtastic/xmodem_pb2.py Normal file
View File

@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/xmodem.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
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_pool.Default().AddSerializedFile(b'\n\x17meshtastic/xmodem.proto\"\xab\x01\n\x06XModem\x12 \n\x07\x63ontrol\x18\x01 \x01(\x0e\x32\x0f.XModem.Control\x12\x0b\n\x03seq\x18\x02 \x01(\r\x12\r\n\x05\x63rc16\x18\x03 \x01(\r\x12\x0e\n\x06\x62uffer\x18\x04 \x01(\x0c\"S\n\x07\x43ontrol\x12\x07\n\x03NUL\x10\x00\x12\x07\n\x03SOH\x10\x01\x12\x07\n\x03STX\x10\x02\x12\x07\n\x03\x45OT\x10\x04\x12\x07\n\x03\x41\x43K\x10\x06\x12\x07\n\x03NAK\x10\x15\x12\x07\n\x03\x43\x41N\x10\x18\x12\t\n\x05\x43TRLZ\x10\x1a\x42\x61\n\x13\x63om.geeksville.meshB\x0cXmodemProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_XMODEM = DESCRIPTOR.message_types_by_name['XModem']
_XMODEM_CONTROL = _XMODEM.enum_types_by_name['Control']
XModem = _reflection.GeneratedProtocolMessageType('XModem', (_message.Message,), {
'DESCRIPTOR' : _XMODEM,
'__module__' : 'meshtastic.xmodem_pb2'
# @@protoc_insertion_point(class_scope:XModem)
})
_sym_db.RegisterMessage(XModem)
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\014XmodemProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_XMODEM._serialized_start=28
_XMODEM._serialized_end=199
_XMODEM_CONTROL._serialized_start=116
_XMODEM_CONTROL._serialized_end=199
# @@protoc_insertion_point(module_scope)

1
proto

Submodule proto deleted from 441303d531

1
protobufs Submodule

Submodule protobufs added at 8aa371de2d

View File

@@ -12,16 +12,16 @@ with open("README.md", "r") as fh:
# This call to setup() does all the work # This call to setup() does all the work
setup( setup(
name="meshtastic", name="meshtastic",
version="1.3alpha.6", version="2.1.1",
description="Python API & client shell for talking to Meshtastic devices", description="Python API & client shell for talking to Meshtastic devices",
long_description=long_description, long_description=long_description,
long_description_content_type="text/markdown", long_description_content_type="text/markdown",
url="https://github.com/meshtastic/Meshtastic-python", url="https://github.com/meshtastic/python",
author="Kevin Hester", author="Meshtastic Developers",
author_email="kevinh@geeksville.com", author_email="contact@meshtastic.org",
license="MIT", license="GPL-3.0-only",
classifiers=[ classifiers=[
"License :: OSI Approved :: MIT License", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Development Status :: 4 - Beta", "Development Status :: 4 - Beta",
"Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.8",

View File

@@ -1,5 +1,5 @@
readme.txt for single standalone executable zip files that can be readme.txt for single standalone executable zip files that can be
downloaded from https://github.com/meshtastic/Meshtastic-python/releases downloaded from https://github.com/meshtastic/python/releases
If you do not want to install python and/or the python libraries, you can download one of these 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. files to run the Meshtastic command line interface (CLI) as a standalone executable.