meshcore-cli 1.2.14__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/PKG-INFO +114 -45
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/README.md +113 -44
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/flake.nix +3 -2
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/pyproject.toml +1 -1
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/src/meshcore_cli/meshcore_cli.py +171 -54
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/.gitignore +0 -0
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/LICENSE +0 -0
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/flake.lock +0 -0
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/src/meshcore_cli/__init__.py +0 -0
- {meshcore_cli-1.2.14 → meshcore_cli-1.3.0}/src/meshcore_cli/__main__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshcore-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Command line interface to meshcore companion radios
|
|
5
5
|
Project-URL: Homepage, https://github.com/fdlamotte/meshcore-cli
|
|
6
6
|
Project-URL: Issues, https://github.com/fdlamotte/meshcore-cli/issues
|
|
@@ -58,22 +58,25 @@ Init files can also be defined for a given device, meshcore-cli will look for `&
|
|
|
58
58
|
|
|
59
59
|
### Arguments
|
|
60
60
|
|
|
61
|
-
Arguments mostly deals with
|
|
61
|
+
Arguments mostly deals with connection to the node
|
|
62
62
|
|
|
63
63
|
<pre>
|
|
64
64
|
-h : prints this help
|
|
65
65
|
-v : prints version
|
|
66
66
|
-j : json output (disables init file)
|
|
67
67
|
-D : debug
|
|
68
|
-
-S :
|
|
69
|
-
-l : list available ble devices and exit
|
|
70
|
-
-T <timeout
|
|
71
|
-
-a <address
|
|
72
|
-
-d <name
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
68
|
+
-S : scan for devices and show a selector
|
|
69
|
+
-l : list available ble/serial devices and exit
|
|
70
|
+
-T <timeout> : timeout for the ble scan (-S and -l) default 2s
|
|
71
|
+
-a <address> : specifies device address (can be a name)
|
|
72
|
+
-d <name> : filter meshcore devices with name or address
|
|
73
|
+
-P : forces pairing via the OS
|
|
74
|
+
-t <hostname> : connects via tcp/ip
|
|
75
|
+
-p <port> : specifies tcp port (default 5000)
|
|
76
|
+
-s <port> : use serial port <port>
|
|
77
|
+
-b <baudrate> : specify baudrate
|
|
78
|
+
-C : toggles classic mode for prompt
|
|
79
|
+
-c <on/off> : disables most of color output if off
|
|
77
80
|
</pre>
|
|
78
81
|
|
|
79
82
|
### Available Commands
|
|
@@ -81,60 +84,70 @@ Arguments mostly deals with ble connection
|
|
|
81
84
|
Commands are given after arguments, they can be chained and some have shortcuts. Also prefixing a command with a dot `.` will force it to output json instead of synthetic result.
|
|
82
85
|
|
|
83
86
|
<pre>
|
|
87
|
+
?<cmd> may give you some more help about cmd
|
|
84
88
|
General commands
|
|
85
89
|
chat : enter the chat (interactive) mode
|
|
86
|
-
chat_to <ct
|
|
87
|
-
script <filename
|
|
90
|
+
chat_to <ct> : enter chat with contact to
|
|
91
|
+
script <filename> : execute commands in filename
|
|
88
92
|
infos : print informations about the node i
|
|
89
93
|
self_telemetry : print own telemtry t
|
|
90
94
|
card : export this node URI e
|
|
91
95
|
ver : firmware version v
|
|
92
96
|
reboot : reboots node
|
|
93
|
-
sleep <secs
|
|
94
|
-
wait_key : wait until user presses <Enter
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
sleep <secs> : sleeps for a given amount of secs s
|
|
98
|
+
wait_key : wait until user presses <Enter> wk
|
|
99
|
+
apply_to <f> <cmds> : sends cmds to contacts matching f at
|
|
100
|
+
Messaging
|
|
101
|
+
msg <name> <msg> : send message to node by name m {
|
|
97
102
|
wait_ack : wait an ack wa }
|
|
98
|
-
chan <nb
|
|
99
|
-
public <msg
|
|
103
|
+
chan <nb> <msg> : send message to channel number <nb> ch
|
|
104
|
+
public <msg> : send message to public channel (0) dch
|
|
100
105
|
recv : reads next msg r
|
|
101
106
|
wait_msg : wait for a message and read it wm
|
|
102
107
|
sync_msgs : gets all unread msgs from the node sm
|
|
103
108
|
msgs_subscribe : display msgs as they arrive ms
|
|
104
|
-
|
|
109
|
+
get_channels : prints all channel info
|
|
110
|
+
get_channel <n> : get info for channel (by number or name)
|
|
105
111
|
set_channel n nm k : set channel info (nb, name, key)
|
|
112
|
+
remove_channel <n> : remove channel (by number or name)
|
|
113
|
+
scope <s> : sets node's flood scope
|
|
106
114
|
Management
|
|
107
115
|
advert : sends advert a
|
|
108
116
|
floodadv : flood advert
|
|
109
|
-
get <param
|
|
110
|
-
set <param
|
|
111
|
-
time <epoch
|
|
117
|
+
get <param> : gets a param, \"get help\" for more
|
|
118
|
+
set <param> <value> : sets a param, \"set help\" for more
|
|
119
|
+
time <epoch> : sets time to given epoch
|
|
112
120
|
clock : get current time
|
|
113
121
|
clock sync : sync device clock st
|
|
122
|
+
node_discover <filter> : discovers nodes based on their type nd
|
|
114
123
|
Contacts
|
|
115
124
|
contacts / list : gets contact list lc
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
reload_contacts : force reloading all contacts rc
|
|
126
|
+
contact_info <ct> : prints information for contact ct ci
|
|
127
|
+
contact_timeout <ct> v : sets temp default timeout for contact
|
|
128
|
+
share_contact <ct> : share a contact with others sc
|
|
129
|
+
export_contact <ct> : get a contact's URI ec
|
|
130
|
+
import_contact <URI> : import a contact from its URI ic
|
|
131
|
+
remove_contact <ct> : removes a contact from this node
|
|
132
|
+
path <ct> : diplays path for a contact
|
|
133
|
+
disc_path <ct> : discover new path and display dp
|
|
134
|
+
reset_path <ct> : resets path to a contact to flood rp
|
|
135
|
+
change_path <ct> <pth> : change the path to a contact cp
|
|
136
|
+
change_flags <ct> <f> : change contact flags (tel_l|tel_a|star)cf
|
|
137
|
+
req_telemetry <ct> : prints telemetry data as json rt
|
|
138
|
+
req_mma <ct> : requests min/max/avg for a sensor rm
|
|
139
|
+
req_acl <ct> : requests access control list for sensor
|
|
129
140
|
pending_contacts : show pending contacts
|
|
130
|
-
add_pending <
|
|
131
|
-
flush_pending : flush pending contact
|
|
141
|
+
add_pending <pending> : manually add pending contact
|
|
142
|
+
flush_pending : flush pending contact list
|
|
132
143
|
Repeaters
|
|
133
|
-
login <name
|
|
134
|
-
logout <name
|
|
135
|
-
cmd <name
|
|
144
|
+
login <name> <pwd> : log into a node (rep) with given pwd l
|
|
145
|
+
logout <name> : log out of a repeater
|
|
146
|
+
cmd <name> <cmd> : sends a command to a repeater (no ack) c [
|
|
136
147
|
wmt8 : wait for a msg (reply) with a timeout ]
|
|
137
|
-
req_status <name
|
|
148
|
+
req_status <name> : requests status from a node rs
|
|
149
|
+
req_neighbours <name> : requests for neighbours in binary form rn
|
|
150
|
+
trace <path> : run a trace, path is comma separated
|
|
138
151
|
</pre>
|
|
139
152
|
|
|
140
153
|
### Interactive Mode
|
|
@@ -147,14 +160,70 @@ You'll get a prompt with the name of your node. From here you can type meshcore-
|
|
|
147
160
|
|
|
148
161
|
The `to` command is specific to chat mode, it lets you enter the recipient for next command. By default you're on your node but you can enter other nodes or public rooms. Here are some examples :
|
|
149
162
|
|
|
150
|
-
- `to <
|
|
163
|
+
- `to <dest>` : will enter dest (node or channel)
|
|
151
164
|
- `to /`, `to ~` : will go to the root (your node)
|
|
152
165
|
- `to ..` : will go to the last node (it will switch between the two last nodes, this is just a 1-depth history)
|
|
153
166
|
- `to !` : will switch to the node you received last message from
|
|
154
167
|
|
|
155
|
-
When you are
|
|
168
|
+
When you are in a node, the behaviour will depend on the node type, if you're on a chat node, it will send messages by default and you can chat. On a repeater or a room server, it will send commands (autocompletion has been set to comply with the CommonCli class of meshcore). To send a message through a room you'll have to prefix the message with a quote or use the send command.
|
|
156
169
|
|
|
157
|
-
|
|
170
|
+
The `/` character is used to bypass the node you have currently selected using `to`:
|
|
171
|
+
- `/<cmd>` issues cmd command on the root
|
|
172
|
+
- `/<node>/<cmd>` will send cmd to selected node
|
|
173
|
+
- `/<dest> <msg>` will send msg to dest (channel or node)
|
|
174
|
+
|
|
175
|
+
#### Flood Scope in interactive mode
|
|
176
|
+
|
|
177
|
+
Flood scope has recently been introduced in meshcore (from `v1.10.0`). It limits the scope of packets to regions, using transport codes in the frame.
|
|
178
|
+
|
|
179
|
+
When entering chat mode, scope will be reset to `*`, meaning classic flood.
|
|
180
|
+
|
|
181
|
+
You can switch scope using the `scope` command, or postfixing the `to` command with `%<scope>`.
|
|
182
|
+
|
|
183
|
+
Scope can also be applied to a command using `%` before the scope name. For instance `login%#Morbihan` will limit diffusion of the login command (which is usually sent flood to get the path to a repeater) to the `#Morbihan` region.
|
|
184
|
+
|
|
185
|
+
#### Channel echoes
|
|
186
|
+
|
|
187
|
+
It's sometimes interesting to know the path taken by a message received from a channel or which repeaters have repeated a sent message.
|
|
188
|
+
|
|
189
|
+
The app give you the information by listening `rx_log` from the device, when obtained the information is attached to the message and can be read.
|
|
190
|
+
|
|
191
|
+
In meshcore-cli I went lower-level by implementing channel echoes. When activated (with `/set channel_echoes on`), all the channel messages will be printed on the terminal along with the SNR and path taken. When sending a message, you'll have all the repeats from 0-hop repeaters as echoes, and when a message is received, you should see information about the received message, but also all the instances of the same message that might have reached you from another path.
|
|
192
|
+
|
|
193
|
+
In the example below, a msg has been sent between two repeaters, 21 and 25. 25 repeated the message and 21 the repeat and both echoes came back to the node with different SNRs.
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
f1down/#fdl|*> 8
|
|
197
|
+
#fdl f1down: 8 [25] -4.75-112
|
|
198
|
+
#fdl f1down: 8 [2521] 1.00-109
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Issuing batch commands to contacts with apply to
|
|
202
|
+
|
|
203
|
+
`apply_to <f> <cmd>` : applies cmd to contacts matching filter `<f>` it can be used to apply the same command to a pool of repeaters, or remove some contacts matching a condition.
|
|
204
|
+
|
|
205
|
+
Filter is constructed with comma separated fields :
|
|
206
|
+
|
|
207
|
+
- `u`, matches modification time `<` or `>` than a timestamp (can also be days hours or minutes ago if followed by `d`,`h` or `m`)
|
|
208
|
+
- `t`, matches the type (1: client, 2: repeater, 3: room, 4: sensor)
|
|
209
|
+
- `h`, matches number of hops
|
|
210
|
+
- `d`, direct, similar to `h>-1`
|
|
211
|
+
- `f`, flood, similar to `h<0` or `h=-1`
|
|
212
|
+
|
|
213
|
+
Commands should be written as if in interactive mode, if writing from the commandline don't forget to use commas to clearly delimit fields.
|
|
214
|
+
|
|
215
|
+
Note: Some commands like `contact_name` (aka `cn`), `reset_path` (aka `rp`), `forget_password` (aka `fp`) can be chained. There is also a `sleep` command taking an optional time parameter. The sleep will be issued after the command, it helps limiting rate through repeaters ...
|
|
216
|
+
|
|
217
|
+
#### Examples
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
# removes all clients that have not been updated in last 2 days
|
|
221
|
+
at u<2d,t=1 remove_contact
|
|
222
|
+
# gives traces to repeaters that have been updated in the last 24h and are direct
|
|
223
|
+
at t=2,u>1d,d cn trace
|
|
224
|
+
# tries to do flood login to all repeaters
|
|
225
|
+
at t=2 rp login
|
|
226
|
+
```
|
|
158
227
|
|
|
159
228
|
## Examples
|
|
160
229
|
|
|
@@ -40,22 +40,25 @@ Init files can also be defined for a given device, meshcore-cli will look for `&
|
|
|
40
40
|
|
|
41
41
|
### Arguments
|
|
42
42
|
|
|
43
|
-
Arguments mostly deals with
|
|
43
|
+
Arguments mostly deals with connection to the node
|
|
44
44
|
|
|
45
45
|
<pre>
|
|
46
46
|
-h : prints this help
|
|
47
47
|
-v : prints version
|
|
48
48
|
-j : json output (disables init file)
|
|
49
49
|
-D : debug
|
|
50
|
-
-S :
|
|
51
|
-
-l : list available ble devices and exit
|
|
52
|
-
-T <timeout
|
|
53
|
-
-a <address
|
|
54
|
-
-d <name
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
50
|
+
-S : scan for devices and show a selector
|
|
51
|
+
-l : list available ble/serial devices and exit
|
|
52
|
+
-T <timeout> : timeout for the ble scan (-S and -l) default 2s
|
|
53
|
+
-a <address> : specifies device address (can be a name)
|
|
54
|
+
-d <name> : filter meshcore devices with name or address
|
|
55
|
+
-P : forces pairing via the OS
|
|
56
|
+
-t <hostname> : connects via tcp/ip
|
|
57
|
+
-p <port> : specifies tcp port (default 5000)
|
|
58
|
+
-s <port> : use serial port <port>
|
|
59
|
+
-b <baudrate> : specify baudrate
|
|
60
|
+
-C : toggles classic mode for prompt
|
|
61
|
+
-c <on/off> : disables most of color output if off
|
|
59
62
|
</pre>
|
|
60
63
|
|
|
61
64
|
### Available Commands
|
|
@@ -63,60 +66,70 @@ Arguments mostly deals with ble connection
|
|
|
63
66
|
Commands are given after arguments, they can be chained and some have shortcuts. Also prefixing a command with a dot `.` will force it to output json instead of synthetic result.
|
|
64
67
|
|
|
65
68
|
<pre>
|
|
69
|
+
?<cmd> may give you some more help about cmd
|
|
66
70
|
General commands
|
|
67
71
|
chat : enter the chat (interactive) mode
|
|
68
|
-
chat_to <ct
|
|
69
|
-
script <filename
|
|
72
|
+
chat_to <ct> : enter chat with contact to
|
|
73
|
+
script <filename> : execute commands in filename
|
|
70
74
|
infos : print informations about the node i
|
|
71
75
|
self_telemetry : print own telemtry t
|
|
72
76
|
card : export this node URI e
|
|
73
77
|
ver : firmware version v
|
|
74
78
|
reboot : reboots node
|
|
75
|
-
sleep <secs
|
|
76
|
-
wait_key : wait until user presses <Enter
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
sleep <secs> : sleeps for a given amount of secs s
|
|
80
|
+
wait_key : wait until user presses <Enter> wk
|
|
81
|
+
apply_to <f> <cmds> : sends cmds to contacts matching f at
|
|
82
|
+
Messaging
|
|
83
|
+
msg <name> <msg> : send message to node by name m {
|
|
79
84
|
wait_ack : wait an ack wa }
|
|
80
|
-
chan <nb
|
|
81
|
-
public <msg
|
|
85
|
+
chan <nb> <msg> : send message to channel number <nb> ch
|
|
86
|
+
public <msg> : send message to public channel (0) dch
|
|
82
87
|
recv : reads next msg r
|
|
83
88
|
wait_msg : wait for a message and read it wm
|
|
84
89
|
sync_msgs : gets all unread msgs from the node sm
|
|
85
90
|
msgs_subscribe : display msgs as they arrive ms
|
|
86
|
-
|
|
91
|
+
get_channels : prints all channel info
|
|
92
|
+
get_channel <n> : get info for channel (by number or name)
|
|
87
93
|
set_channel n nm k : set channel info (nb, name, key)
|
|
94
|
+
remove_channel <n> : remove channel (by number or name)
|
|
95
|
+
scope <s> : sets node's flood scope
|
|
88
96
|
Management
|
|
89
97
|
advert : sends advert a
|
|
90
98
|
floodadv : flood advert
|
|
91
|
-
get <param
|
|
92
|
-
set <param
|
|
93
|
-
time <epoch
|
|
99
|
+
get <param> : gets a param, \"get help\" for more
|
|
100
|
+
set <param> <value> : sets a param, \"set help\" for more
|
|
101
|
+
time <epoch> : sets time to given epoch
|
|
94
102
|
clock : get current time
|
|
95
103
|
clock sync : sync device clock st
|
|
104
|
+
node_discover <filter> : discovers nodes based on their type nd
|
|
96
105
|
Contacts
|
|
97
106
|
contacts / list : gets contact list lc
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
reload_contacts : force reloading all contacts rc
|
|
108
|
+
contact_info <ct> : prints information for contact ct ci
|
|
109
|
+
contact_timeout <ct> v : sets temp default timeout for contact
|
|
110
|
+
share_contact <ct> : share a contact with others sc
|
|
111
|
+
export_contact <ct> : get a contact's URI ec
|
|
112
|
+
import_contact <URI> : import a contact from its URI ic
|
|
113
|
+
remove_contact <ct> : removes a contact from this node
|
|
114
|
+
path <ct> : diplays path for a contact
|
|
115
|
+
disc_path <ct> : discover new path and display dp
|
|
116
|
+
reset_path <ct> : resets path to a contact to flood rp
|
|
117
|
+
change_path <ct> <pth> : change the path to a contact cp
|
|
118
|
+
change_flags <ct> <f> : change contact flags (tel_l|tel_a|star)cf
|
|
119
|
+
req_telemetry <ct> : prints telemetry data as json rt
|
|
120
|
+
req_mma <ct> : requests min/max/avg for a sensor rm
|
|
121
|
+
req_acl <ct> : requests access control list for sensor
|
|
111
122
|
pending_contacts : show pending contacts
|
|
112
|
-
add_pending <
|
|
113
|
-
flush_pending : flush pending contact
|
|
123
|
+
add_pending <pending> : manually add pending contact
|
|
124
|
+
flush_pending : flush pending contact list
|
|
114
125
|
Repeaters
|
|
115
|
-
login <name
|
|
116
|
-
logout <name
|
|
117
|
-
cmd <name
|
|
126
|
+
login <name> <pwd> : log into a node (rep) with given pwd l
|
|
127
|
+
logout <name> : log out of a repeater
|
|
128
|
+
cmd <name> <cmd> : sends a command to a repeater (no ack) c [
|
|
118
129
|
wmt8 : wait for a msg (reply) with a timeout ]
|
|
119
|
-
req_status <name
|
|
130
|
+
req_status <name> : requests status from a node rs
|
|
131
|
+
req_neighbours <name> : requests for neighbours in binary form rn
|
|
132
|
+
trace <path> : run a trace, path is comma separated
|
|
120
133
|
</pre>
|
|
121
134
|
|
|
122
135
|
### Interactive Mode
|
|
@@ -129,14 +142,70 @@ You'll get a prompt with the name of your node. From here you can type meshcore-
|
|
|
129
142
|
|
|
130
143
|
The `to` command is specific to chat mode, it lets you enter the recipient for next command. By default you're on your node but you can enter other nodes or public rooms. Here are some examples :
|
|
131
144
|
|
|
132
|
-
- `to <
|
|
145
|
+
- `to <dest>` : will enter dest (node or channel)
|
|
133
146
|
- `to /`, `to ~` : will go to the root (your node)
|
|
134
147
|
- `to ..` : will go to the last node (it will switch between the two last nodes, this is just a 1-depth history)
|
|
135
148
|
- `to !` : will switch to the node you received last message from
|
|
136
149
|
|
|
137
|
-
When you are
|
|
150
|
+
When you are in a node, the behaviour will depend on the node type, if you're on a chat node, it will send messages by default and you can chat. On a repeater or a room server, it will send commands (autocompletion has been set to comply with the CommonCli class of meshcore). To send a message through a room you'll have to prefix the message with a quote or use the send command.
|
|
138
151
|
|
|
139
|
-
|
|
152
|
+
The `/` character is used to bypass the node you have currently selected using `to`:
|
|
153
|
+
- `/<cmd>` issues cmd command on the root
|
|
154
|
+
- `/<node>/<cmd>` will send cmd to selected node
|
|
155
|
+
- `/<dest> <msg>` will send msg to dest (channel or node)
|
|
156
|
+
|
|
157
|
+
#### Flood Scope in interactive mode
|
|
158
|
+
|
|
159
|
+
Flood scope has recently been introduced in meshcore (from `v1.10.0`). It limits the scope of packets to regions, using transport codes in the frame.
|
|
160
|
+
|
|
161
|
+
When entering chat mode, scope will be reset to `*`, meaning classic flood.
|
|
162
|
+
|
|
163
|
+
You can switch scope using the `scope` command, or postfixing the `to` command with `%<scope>`.
|
|
164
|
+
|
|
165
|
+
Scope can also be applied to a command using `%` before the scope name. For instance `login%#Morbihan` will limit diffusion of the login command (which is usually sent flood to get the path to a repeater) to the `#Morbihan` region.
|
|
166
|
+
|
|
167
|
+
#### Channel echoes
|
|
168
|
+
|
|
169
|
+
It's sometimes interesting to know the path taken by a message received from a channel or which repeaters have repeated a sent message.
|
|
170
|
+
|
|
171
|
+
The app give you the information by listening `rx_log` from the device, when obtained the information is attached to the message and can be read.
|
|
172
|
+
|
|
173
|
+
In meshcore-cli I went lower-level by implementing channel echoes. When activated (with `/set channel_echoes on`), all the channel messages will be printed on the terminal along with the SNR and path taken. When sending a message, you'll have all the repeats from 0-hop repeaters as echoes, and when a message is received, you should see information about the received message, but also all the instances of the same message that might have reached you from another path.
|
|
174
|
+
|
|
175
|
+
In the example below, a msg has been sent between two repeaters, 21 and 25. 25 repeated the message and 21 the repeat and both echoes came back to the node with different SNRs.
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
f1down/#fdl|*> 8
|
|
179
|
+
#fdl f1down: 8 [25] -4.75-112
|
|
180
|
+
#fdl f1down: 8 [2521] 1.00-109
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Issuing batch commands to contacts with apply to
|
|
184
|
+
|
|
185
|
+
`apply_to <f> <cmd>` : applies cmd to contacts matching filter `<f>` it can be used to apply the same command to a pool of repeaters, or remove some contacts matching a condition.
|
|
186
|
+
|
|
187
|
+
Filter is constructed with comma separated fields :
|
|
188
|
+
|
|
189
|
+
- `u`, matches modification time `<` or `>` than a timestamp (can also be days hours or minutes ago if followed by `d`,`h` or `m`)
|
|
190
|
+
- `t`, matches the type (1: client, 2: repeater, 3: room, 4: sensor)
|
|
191
|
+
- `h`, matches number of hops
|
|
192
|
+
- `d`, direct, similar to `h>-1`
|
|
193
|
+
- `f`, flood, similar to `h<0` or `h=-1`
|
|
194
|
+
|
|
195
|
+
Commands should be written as if in interactive mode, if writing from the commandline don't forget to use commas to clearly delimit fields.
|
|
196
|
+
|
|
197
|
+
Note: Some commands like `contact_name` (aka `cn`), `reset_path` (aka `rp`), `forget_password` (aka `fp`) can be chained. There is also a `sleep` command taking an optional time parameter. The sleep will be issued after the command, it helps limiting rate through repeaters ...
|
|
198
|
+
|
|
199
|
+
#### Examples
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
# removes all clients that have not been updated in last 2 days
|
|
203
|
+
at u<2d,t=1 remove_contact
|
|
204
|
+
# gives traces to repeaters that have been updated in the last 24h and are direct
|
|
205
|
+
at t=2,u>1d,d cn trace
|
|
206
|
+
# tries to do flood login to all repeaters
|
|
207
|
+
at t=2 rp login
|
|
208
|
+
```
|
|
140
209
|
|
|
141
210
|
## Examples
|
|
142
211
|
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
|
|
16
16
|
meshcore = python3Packages.buildPythonPackage rec {
|
|
17
17
|
pname = "meshcore";
|
|
18
|
-
version = "2.1.
|
|
18
|
+
version = "2.1.24";
|
|
19
19
|
pyproject = true;
|
|
20
20
|
|
|
21
21
|
src = python3Packages.fetchPypi {
|
|
22
22
|
inherit pname version;
|
|
23
|
-
sha256 = "sha256-
|
|
23
|
+
sha256 = "sha256-CTn4HsVoGPij3HmHIts9Rta/iVsR8wH+CECV1vznBjQ=";
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
build-system = [python3Packages.hatchling];
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
python3Packages.prompt_toolkit
|
|
58
58
|
python3Packages.pyserial
|
|
59
59
|
python3Packages.requests
|
|
60
|
+
python3Packages.pycryptodome
|
|
60
61
|
];
|
|
61
62
|
|
|
62
63
|
doCheck = false;
|
|
@@ -32,7 +32,7 @@ import re
|
|
|
32
32
|
from meshcore import MeshCore, EventType, logger
|
|
33
33
|
|
|
34
34
|
# Version
|
|
35
|
-
VERSION = "v1.
|
|
35
|
+
VERSION = "v1.3.0"
|
|
36
36
|
|
|
37
37
|
# default ble address is stored in a config file
|
|
38
38
|
MCCLI_CONFIG_DIR = str(Path.home()) + "/.config/meshcore/"
|
|
@@ -203,29 +203,62 @@ process_event_message.print_snr=False
|
|
|
203
203
|
process_event_message.color=True
|
|
204
204
|
process_event_message.last_node=None
|
|
205
205
|
|
|
206
|
+
PAYLOAD_TYPENAMES = ["REQ", "RESPONSE", "TEXT_MSG", "ACK", "ADVERT", "GRP_TXT", "GRP_DATA", "ANON_REQ", "PATH", "TRACE", "MULTIPART", "CONTROL"]
|
|
207
|
+
ROUTE_TYPENAMES = ["TC_FLOOD", "FLOOD", "DIRECT", "TC_DIRECT"]
|
|
208
|
+
|
|
206
209
|
async def handle_log_rx(event):
|
|
207
210
|
mc = handle_log_rx.mc
|
|
208
|
-
if handle_log_rx.json_log_rx: # json mode ... raw dump
|
|
209
|
-
msg = json.dumps(event.payload)
|
|
210
|
-
if handle_message.above:
|
|
211
|
-
print_above(msg)
|
|
212
|
-
else :
|
|
213
|
-
print(msg)
|
|
214
|
-
return
|
|
215
211
|
|
|
216
212
|
pkt = bytes().fromhex(event.payload["payload"])
|
|
217
213
|
pbuf = io.BytesIO(pkt)
|
|
218
214
|
header = pbuf.read(1)[0]
|
|
215
|
+
route_type = header & 0x03
|
|
216
|
+
payload_type = (header & 0x3c) >> 2
|
|
217
|
+
payload_ver = (header & 0xc0) >> 6
|
|
218
|
+
|
|
219
|
+
transport_code = None
|
|
220
|
+
if route_type == 0x00 or route_type == 0x03: # has transport code
|
|
221
|
+
transport_code = pbuf.read(4) # discard transport code
|
|
222
|
+
|
|
223
|
+
path_len = pbuf.read(1)[0]
|
|
224
|
+
path = pbuf.read(path_len).hex() # Beware of traces where pathes are mixed
|
|
225
|
+
|
|
226
|
+
try :
|
|
227
|
+
route_typename = ROUTE_TYPENAMES[route_type]
|
|
228
|
+
except IndexError:
|
|
229
|
+
logger.debug(f"Unknown route type {route_type}")
|
|
230
|
+
route_typename = "UNK"
|
|
219
231
|
|
|
220
|
-
|
|
232
|
+
try :
|
|
233
|
+
payload_typename = PAYLOAD_TYPENAMES[payload_type]
|
|
234
|
+
except IndexError:
|
|
235
|
+
logger.debug(f"Unknown payload type {payload_type}")
|
|
236
|
+
payload_typename = "UNK"
|
|
237
|
+
|
|
238
|
+
pkt_payload = pbuf.read()
|
|
239
|
+
|
|
240
|
+
event.payload["header"] = header
|
|
241
|
+
event.payload["route_type"] = route_type
|
|
242
|
+
event.payload["route_typename"] = route_typename
|
|
243
|
+
event.payload["payload_type"] = payload_type
|
|
244
|
+
event.payload["payload_typename"]= payload_typename
|
|
245
|
+
|
|
246
|
+
event.payload["payload_ver"] = payload_ver
|
|
247
|
+
|
|
248
|
+
if not transport_code is None:
|
|
249
|
+
event.payload["transport_code"] = transport_code.hex()
|
|
250
|
+
|
|
251
|
+
event.payload["path_len"] = path_len
|
|
252
|
+
event.payload["path"] = path
|
|
253
|
+
|
|
254
|
+
event.payload["pkt_payload"] = pkt_payload.hex()
|
|
255
|
+
|
|
256
|
+
if payload_type == 0x05: # flood msg / channel
|
|
221
257
|
if handle_log_rx.channel_echoes:
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
chan_hash = pbuf.read(1).hex()
|
|
227
|
-
cipher_mac = pbuf.read(2)
|
|
228
|
-
msg = pbuf.read() # until the end of buffer
|
|
258
|
+
pk_buf = io.BytesIO(pkt_payload)
|
|
259
|
+
chan_hash = pk_buf.read(1).hex()
|
|
260
|
+
cipher_mac = pk_buf.read(2)
|
|
261
|
+
msg = pk_buf.read() # until the end of buffer
|
|
229
262
|
|
|
230
263
|
channel = None
|
|
231
264
|
for c in await get_channels(mc):
|
|
@@ -258,6 +291,14 @@ async def handle_log_rx(event):
|
|
|
258
291
|
else:
|
|
259
292
|
print(txt)
|
|
260
293
|
|
|
294
|
+
if handle_log_rx.json_log_rx: # json mode ... raw dump
|
|
295
|
+
msg = json.dumps(event.payload)
|
|
296
|
+
if handle_message.above:
|
|
297
|
+
print_above(msg)
|
|
298
|
+
else :
|
|
299
|
+
print(msg)
|
|
300
|
+
|
|
301
|
+
|
|
261
302
|
handle_log_rx.json_log_rx = False
|
|
262
303
|
handle_log_rx.channel_echoes = False
|
|
263
304
|
handle_log_rx.mc = None
|
|
@@ -1071,6 +1112,29 @@ async def process_contact_chat_line(mc, contact, line):
|
|
|
1071
1112
|
print("")
|
|
1072
1113
|
return True
|
|
1073
1114
|
|
|
1115
|
+
if line.startswith("sleep") or line.startswith("s"):
|
|
1116
|
+
try:
|
|
1117
|
+
sleeptime = int(line.split(" ",2)[1])
|
|
1118
|
+
cmd_pos = 2
|
|
1119
|
+
except IndexError: # nothing arg after sleep
|
|
1120
|
+
sleeptime = 1
|
|
1121
|
+
cmd_pos = 0
|
|
1122
|
+
except ValueError:
|
|
1123
|
+
sleeptime = 1
|
|
1124
|
+
cmd_pos = 1
|
|
1125
|
+
|
|
1126
|
+
try:
|
|
1127
|
+
if cmd_pos > 0:
|
|
1128
|
+
secline = line.split(" ",cmd_pos)[cmd_pos]
|
|
1129
|
+
await process_contact_chat_line(mc, contact, secline)
|
|
1130
|
+
except IndexError:
|
|
1131
|
+
pass
|
|
1132
|
+
|
|
1133
|
+
# will sleep after executed command if there is a command
|
|
1134
|
+
await asyncio.sleep(sleeptime)
|
|
1135
|
+
|
|
1136
|
+
return True
|
|
1137
|
+
|
|
1074
1138
|
if line == "contact_lastmod":
|
|
1075
1139
|
timestamp = contact["lastmod"]
|
|
1076
1140
|
print(f"{contact['adv_name']} updated"
|
|
@@ -1723,19 +1787,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
1723
1787
|
match cmds[1]:
|
|
1724
1788
|
case "help" :
|
|
1725
1789
|
argnum = 1
|
|
1726
|
-
|
|
1727
|
-
pin <pin> : ble pin
|
|
1728
|
-
radio <freq,bw,sf,cr> : radio params
|
|
1729
|
-
tuning <rx_dly,af> : tuning params
|
|
1730
|
-
tx <dbm> : tx power
|
|
1731
|
-
name <name> : node name
|
|
1732
|
-
lat <lat> : latitude
|
|
1733
|
-
lon <lon> : longitude
|
|
1734
|
-
coords <lat,lon> : coordinates
|
|
1735
|
-
print_snr <on/off> : toggle snr display in messages
|
|
1736
|
-
print_adverts <on/off> : display adverts as they come
|
|
1737
|
-
print_new_contacts <on/off> : display new pending contacts when available
|
|
1738
|
-
print_path_updates <on/off> : display path updates as they come""")
|
|
1790
|
+
get_help_for("set")
|
|
1739
1791
|
case "max_flood_attempts":
|
|
1740
1792
|
msg_ack.max_flood_attempts=int(cmds[2])
|
|
1741
1793
|
case "max_attempts":
|
|
@@ -1959,21 +2011,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
1959
2011
|
argnum = 1
|
|
1960
2012
|
match cmds[1]:
|
|
1961
2013
|
case "help":
|
|
1962
|
-
|
|
1963
|
-
name : node name
|
|
1964
|
-
bat : battery level in mV
|
|
1965
|
-
fstats : fs statistics
|
|
1966
|
-
coords : adv coordinates
|
|
1967
|
-
lat : latitude
|
|
1968
|
-
lon : longitude
|
|
1969
|
-
radio : radio parameters
|
|
1970
|
-
tx : tx power
|
|
1971
|
-
print_snr : snr display in messages
|
|
1972
|
-
print_adverts : display adverts as they come
|
|
1973
|
-
print_new_contacts : display new pending contacts when available
|
|
1974
|
-
print_path_updates : display path updates as they come
|
|
1975
|
-
custom : all custom variables in json format
|
|
1976
|
-
each custom var can also be get/set directly""")
|
|
2014
|
+
get_help_for("get")
|
|
1977
2015
|
case "max_flood_attempts":
|
|
1978
2016
|
if json_output :
|
|
1979
2017
|
print(json.dumps({"max_flood_attempts" : msg_ack.max_flood_attempts}))
|
|
@@ -2340,6 +2378,7 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2340
2378
|
else :
|
|
2341
2379
|
color = process_event_message.color
|
|
2342
2380
|
classic = interactive_loop.classic or not color
|
|
2381
|
+
print(" ", end="")
|
|
2343
2382
|
for t in ev.payload["path"]:
|
|
2344
2383
|
if classic :
|
|
2345
2384
|
print("→",end="")
|
|
@@ -2610,15 +2649,30 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2610
2649
|
if json_output:
|
|
2611
2650
|
print(json.dumps(res, indent=4))
|
|
2612
2651
|
else:
|
|
2652
|
+
width = os.get_terminal_size().columns
|
|
2613
2653
|
print(f"Got {res['results_count']} neighbours out of {res['neighbours_count']} from {contact['adv_name']}:")
|
|
2614
2654
|
for n in res['neighbours']:
|
|
2615
2655
|
ct = mc.get_contact_by_key_prefix(n["pubkey"])
|
|
2616
|
-
if ct :
|
|
2656
|
+
if ct and width > 60 :
|
|
2617
2657
|
name = f"[{n['pubkey'][0:8]}] {ct['adv_name']}"
|
|
2658
|
+
name = f"{name:30}"
|
|
2659
|
+
elif ct :
|
|
2660
|
+
name = f"{ct['adv_name']}"
|
|
2661
|
+
name = f"{name:20}"
|
|
2618
2662
|
else:
|
|
2619
2663
|
name = f"[{n['pubkey']}]"
|
|
2620
2664
|
|
|
2621
|
-
|
|
2665
|
+
t_s = n['secs_ago']
|
|
2666
|
+
time_ago = f"{t_s}s"
|
|
2667
|
+
if t_s / 86400 >= 1 : # result in days
|
|
2668
|
+
time_ago = f"{int(t_s/86400)}d ago{f' ({time_ago})' if width > 62 else ''}"
|
|
2669
|
+
elif t_s / 3600 >= 1 : # result in days
|
|
2670
|
+
time_ago = f"{int(t_s/3600)}h ago{f' ({time_ago})' if width > 62 else ''}"
|
|
2671
|
+
elif t_s / 60 >= 1 : # result in min
|
|
2672
|
+
time_ago = f"{int(t_s/60)}m ago{f' ({time_ago})' if width > 62 else ''}"
|
|
2673
|
+
|
|
2674
|
+
|
|
2675
|
+
print(f" {name} {time_ago}, {n['snr']}dB{' SNR' if width > 66 else ''}")
|
|
2622
2676
|
|
|
2623
2677
|
case "req_binary" :
|
|
2624
2678
|
argnum = 2
|
|
@@ -3068,8 +3122,8 @@ def command_help():
|
|
|
3068
3122
|
reboot : reboots node
|
|
3069
3123
|
sleep <secs> : sleeps for a given amount of secs s
|
|
3070
3124
|
wait_key : wait until user presses <Enter> wk
|
|
3071
|
-
apply_to <
|
|
3072
|
-
|
|
3125
|
+
apply_to <f> <cmds> : sends cmds to contacts matching f at
|
|
3126
|
+
Messaging
|
|
3073
3127
|
msg <name> <msg> : send message to node by name m {
|
|
3074
3128
|
wait_ack : wait an ack wa }
|
|
3075
3129
|
chan <nb> <msg> : send message to channel number <nb> ch
|
|
@@ -3082,6 +3136,7 @@ def command_help():
|
|
|
3082
3136
|
get_channel <n> : get info for channel (by number or name)
|
|
3083
3137
|
set_channel n nm k : set channel info (nb, name, key)
|
|
3084
3138
|
remove_channel <n> : remove channel (by number or name)
|
|
3139
|
+
scope <s> : sets scope for flood messages
|
|
3085
3140
|
Management
|
|
3086
3141
|
advert : sends advert a
|
|
3087
3142
|
floodadv : flood advert
|
|
@@ -3133,8 +3188,6 @@ def usage () :
|
|
|
3133
3188
|
-D : debug
|
|
3134
3189
|
-S : scan for devices and show a selector
|
|
3135
3190
|
-l : list available ble/serial devices and exit
|
|
3136
|
-
-C : toggles classic mode for prompt
|
|
3137
|
-
-c <on/off> : disables most of color output if off
|
|
3138
3191
|
-T <timeout> : timeout for the ble scan (-S and -l) default 2s
|
|
3139
3192
|
-a <address> : specifies device address (can be a name)
|
|
3140
3193
|
-d <name> : filter meshcore devices with name or address
|
|
@@ -3143,14 +3196,16 @@ def usage () :
|
|
|
3143
3196
|
-p <port> : specifies tcp port (default 5000)
|
|
3144
3197
|
-s <port> : use serial port <port>
|
|
3145
3198
|
-b <baudrate> : specify baudrate
|
|
3199
|
+
-C : toggles classic mode for prompt
|
|
3200
|
+
-c <on/off> : disables most of color output if off
|
|
3146
3201
|
|
|
3147
3202
|
Available Commands and shorcuts (can be chained) :""")
|
|
3148
3203
|
command_help()
|
|
3149
3204
|
|
|
3150
3205
|
def get_help_for (cmdname, context="line") :
|
|
3151
3206
|
if cmdname == "apply_to" or cmdname == "at" :
|
|
3152
|
-
print("""apply_to <
|
|
3153
|
-
|
|
3207
|
+
print("""apply_to <f> <cmd> : applies cmd to contacts matching filter <f>
|
|
3208
|
+
Filter is constructed with comma separated fields :
|
|
3154
3209
|
- u, matches modification time < or > than a timestamp
|
|
3155
3210
|
(can also be days hours or minutes ago if followed by d,h or m)
|
|
3156
3211
|
- t, matches the type (1: client, 2: repeater, 3: room, 4: sensor)
|
|
@@ -3158,7 +3213,7 @@ def get_help_for (cmdname, context="line") :
|
|
|
3158
3213
|
- d, direct, similar to h>-1
|
|
3159
3214
|
- f, flood, similar to h<0 or h=-1
|
|
3160
3215
|
|
|
3161
|
-
Note: Some commands like contact_name (aka cn), reset_path (aka rp), forget_password (aka fp) can be chained.
|
|
3216
|
+
Note: Some commands like contact_name (aka cn), reset_path (aka rp), forget_password (aka fp) can be chained. There is also a sleep command taking an optional event. The sleep will be issued after the command, it helps limiting rate through repeaters ...
|
|
3162
3217
|
|
|
3163
3218
|
Examples:
|
|
3164
3219
|
# removes all clients that have not been updated in last 2 days
|
|
@@ -3169,7 +3224,7 @@ def get_help_for (cmdname, context="line") :
|
|
|
3169
3224
|
at t=2 rp login
|
|
3170
3225
|
""")
|
|
3171
3226
|
|
|
3172
|
-
|
|
3227
|
+
elif cmdname == "node_discover" or cmdname == "nd" :
|
|
3173
3228
|
print("""node_discover <filter> : discovers 0-hop nodes and displays signal info
|
|
3174
3229
|
|
|
3175
3230
|
filter can be "all" for all types or nodes or a comma separated list consisting of :
|
|
@@ -3181,6 +3236,68 @@ def get_help_for (cmdname, context="line") :
|
|
|
3181
3236
|
nd can be used with no filter parameter ... !!! BEWARE WITH CHAINING !!!
|
|
3182
3237
|
""")
|
|
3183
3238
|
|
|
3239
|
+
elif cmdname == "get" :
|
|
3240
|
+
print("""Gets parameters from node
|
|
3241
|
+
Please see also help for set command, which is more up to date ...
|
|
3242
|
+
name : node name
|
|
3243
|
+
bat : battery level in mV
|
|
3244
|
+
fstats : fs statistics
|
|
3245
|
+
coords : adv coordinates
|
|
3246
|
+
lat : latitude
|
|
3247
|
+
lon : longitude
|
|
3248
|
+
radio : radio parameters
|
|
3249
|
+
tx : tx power
|
|
3250
|
+
print_snr : snr display in messages
|
|
3251
|
+
print_adverts : display adverts as they come
|
|
3252
|
+
print_new_contacts : display new pending contacts when available
|
|
3253
|
+
print_path_updates : display path updates as they come
|
|
3254
|
+
custom : all custom variables in json format
|
|
3255
|
+
each custom var can also be get/set directly""")
|
|
3256
|
+
|
|
3257
|
+
elif cmdname == "set" :
|
|
3258
|
+
print("""Available parameters :
|
|
3259
|
+
device:
|
|
3260
|
+
pin <pin> : ble pin
|
|
3261
|
+
radio <freq,bw,sf,cr> : radio params
|
|
3262
|
+
tuning <rx_dly,af> : tuning params
|
|
3263
|
+
tx <dbm> : tx power
|
|
3264
|
+
name <name> : node name
|
|
3265
|
+
lat <lat> : latitude
|
|
3266
|
+
lon <lon> : longitude
|
|
3267
|
+
coords <lat,lon> : coordinates
|
|
3268
|
+
auto_update_contacts <> : automatically updates contact list
|
|
3269
|
+
multi_ack <on/off> : multi-acks feature
|
|
3270
|
+
telemetry_mode_base <mode> : set basic telemetry mode all/selected/off
|
|
3271
|
+
telemetry_mode_loc <mode> : set location telemetry mode all/selected/off
|
|
3272
|
+
telemetry_mode_env <mode> : set env telemetry mode all/selected/off
|
|
3273
|
+
advert_loc_policy <policy> : "share" means loc will be shared in adv
|
|
3274
|
+
display:
|
|
3275
|
+
print_snr <on/off> : toggle snr display in messages
|
|
3276
|
+
print_adverts <on/off> : display adverts as they come
|
|
3277
|
+
print_new_contacts <on/off> : display new pending contacts when available
|
|
3278
|
+
print_path_updates <on/off> : display path updates as they come
|
|
3279
|
+
json_log_rx <on/off> : logs packets incoming to device as json
|
|
3280
|
+
channel_echoes <on/off> : print repeats for channel data
|
|
3281
|
+
echo_unk_channels <on/off> : also dump unk channels (encrypted)
|
|
3282
|
+
color <on/off> : color off should remove ANSI codes from output
|
|
3283
|
+
prompt:
|
|
3284
|
+
classic_prompt <on/off> : activates less fancier prompt
|
|
3285
|
+
arrow_head <string> : change arrow head in prompt
|
|
3286
|
+
slash_start <string> : idem for slash start
|
|
3287
|
+
slash_end <string> : slash end
|
|
3288
|
+
invert_slash <on/off> : apply color inversion to slash """)
|
|
3289
|
+
|
|
3290
|
+
elif cmdname == "scope":
|
|
3291
|
+
print("""scope <scope> : changes flood scope of the node
|
|
3292
|
+
|
|
3293
|
+
The scope command can be used from command line or interactive mode to set the region in which flood packets will be transmitted.
|
|
3294
|
+
|
|
3295
|
+
Managing Flood Scope in interactive mode
|
|
3296
|
+
Flood scope has recently been introduced in meshcore (from v1.10.0). It limits the scope of packets to regions, using transport codes in the frame.
|
|
3297
|
+
When entering chat mode, scope will be reset to *, meaning classic flood.
|
|
3298
|
+
You can switch scope using the scope command, or postfixing the to command with %<scope>.
|
|
3299
|
+
Scope can also be applied to a command using % before the scope name. For instance login%#Morbihan will limit diffusion of the login command (which is usually sent flood to get the path to a repeater) to the #Morbihan region.""")
|
|
3300
|
+
|
|
3184
3301
|
else:
|
|
3185
3302
|
print(f"Sorry, no help yet for {cmdname}")
|
|
3186
3303
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|