meshcore-cli 1.3.7__py3-none-any.whl → 1.3.8__py3-none-any.whl
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/meshcore_cli.py +161 -15
- {meshcore_cli-1.3.7.dist-info → meshcore_cli-1.3.8.dist-info}/METADATA +1 -1
- meshcore_cli-1.3.8.dist-info/RECORD +8 -0
- {meshcore_cli-1.3.7.dist-info → meshcore_cli-1.3.8.dist-info}/WHEEL +1 -1
- meshcore_cli-1.3.7.dist-info/RECORD +0 -8
- {meshcore_cli-1.3.7.dist-info → meshcore_cli-1.3.8.dist-info}/entry_points.txt +0 -0
- {meshcore_cli-1.3.7.dist-info → meshcore_cli-1.3.8.dist-info}/licenses/LICENSE +0 -0
meshcore_cli/meshcore_cli.py
CHANGED
|
@@ -32,7 +32,7 @@ import re
|
|
|
32
32
|
from meshcore import MeshCore, EventType, logger
|
|
33
33
|
|
|
34
34
|
# Version
|
|
35
|
-
VERSION = "v1.3.
|
|
35
|
+
VERSION = "v1.3.8"
|
|
36
36
|
|
|
37
37
|
# default ble address is stored in a config file
|
|
38
38
|
MCCLI_CONFIG_DIR = str(Path.home()) + "/.config/meshcore/"
|
|
@@ -130,10 +130,23 @@ async def process_event_message(mc, ev, json_output, end="\n", above=False):
|
|
|
130
130
|
await mc.ensure_contacts()
|
|
131
131
|
data = ev.payload
|
|
132
132
|
|
|
133
|
+
path_str = ""
|
|
134
|
+
|
|
135
|
+
if process_event_message.timestamp != "" and process_event_message.timestamp != "off":
|
|
136
|
+
ts = data["sender_timestamp"]
|
|
137
|
+
if process_event_message.timestamp == "on":
|
|
138
|
+
if (abs(time.time()-ts) < 86400):
|
|
139
|
+
fmt = "%H:%S"
|
|
140
|
+
else:
|
|
141
|
+
fmt = "%y-%m-%d %H:%S"
|
|
142
|
+
else:
|
|
143
|
+
fmt = process_event_message.timestamp
|
|
144
|
+
path_str += f'{datetime.datetime.fromtimestamp(ts).strftime(fmt)},'
|
|
145
|
+
|
|
133
146
|
if data['path_len'] == 255 :
|
|
134
|
-
path_str
|
|
147
|
+
path_str += "D"
|
|
135
148
|
else :
|
|
136
|
-
path_str
|
|
149
|
+
path_str += f"{data['path_len']}"
|
|
137
150
|
if "SNR" in data and process_event_message.print_snr:
|
|
138
151
|
path_str = path_str + f",{data['SNR']}dB"
|
|
139
152
|
|
|
@@ -206,6 +219,7 @@ async def process_event_message(mc, ev, json_output, end="\n", above=False):
|
|
|
206
219
|
process_event_message.print_snr=False
|
|
207
220
|
process_event_message.color=True
|
|
208
221
|
process_event_message.last_node=None
|
|
222
|
+
process_event_message.timestamp=""
|
|
209
223
|
|
|
210
224
|
async def handle_log_rx(event):
|
|
211
225
|
mc = handle_log_rx.mc
|
|
@@ -292,6 +306,57 @@ async def handle_log_rx(event):
|
|
|
292
306
|
else:
|
|
293
307
|
print(txt)
|
|
294
308
|
|
|
309
|
+
elif payload_type == 0x04: # Advert
|
|
310
|
+
if handle_log_rx.advert_echoes:
|
|
311
|
+
pk_buf = io.BytesIO(pkt_payload)
|
|
312
|
+
adv_key = pk_buf.read(32).hex()
|
|
313
|
+
adv_timestamp = int.from_bytes(pk_buf.read(4), "little", signed=False)
|
|
314
|
+
signature = pk_buf.read(64).hex()
|
|
315
|
+
flags = pk_buf.read(1)[0]
|
|
316
|
+
adv_type = flags & 0x0F
|
|
317
|
+
adv_lat = None
|
|
318
|
+
adv_lon = None
|
|
319
|
+
if flags & 0x10 > 0: #has location
|
|
320
|
+
adv_lat = int.from_bytes(pk_buf.read(4), "little", signed=True)/1000000.0
|
|
321
|
+
adv_lon = int.from_bytes(pk_buf.read(4), "little", signed=True)/1000000.0
|
|
322
|
+
if flags & 0x20 > 0: #has feature1
|
|
323
|
+
adv_feat1 = pk_buf.read(2).hex()
|
|
324
|
+
if flags & 0x40 > 0: #has feature2
|
|
325
|
+
adv_feat2 = pk_buf.read(2).hex()
|
|
326
|
+
if flags & 0x80 > 0: #has name
|
|
327
|
+
adv_name = pk_buf.read().decode("utf-8").strip("\x00")
|
|
328
|
+
|
|
329
|
+
if adv_name is None:
|
|
330
|
+
# try to get the name from the contact
|
|
331
|
+
ct = handle_log_rx.mc.get_contact_by_key_prefix(adv_key)
|
|
332
|
+
if ct is None:
|
|
333
|
+
adv_name = adv_key[0:12]
|
|
334
|
+
else:
|
|
335
|
+
adv_name = ct["adv_name"]
|
|
336
|
+
|
|
337
|
+
ts_string = ""
|
|
338
|
+
if process_event_message.timestamp != "" and process_event_message.timestamp != "off":
|
|
339
|
+
ts = adv_timestamp
|
|
340
|
+
if process_event_message.timestamp == "on":
|
|
341
|
+
if (abs(time.time()-ts) < 86400):
|
|
342
|
+
fmt = "%H:%S"
|
|
343
|
+
else:
|
|
344
|
+
fmt = "%y-%m-%d %H:%S"
|
|
345
|
+
else:
|
|
346
|
+
fmt = process_event_message.timestamp
|
|
347
|
+
ts_str = f' at {datetime.datetime.fromtimestamp(ts).strftime(fmt)}'
|
|
348
|
+
|
|
349
|
+
txt = f"{ANSI_LIGHT_GRAY}Advert for{ANSI_END} {adv_name}{ANSI_GREEN}/{CONTACT_TYPENAMES[adv_type]}{ts_str}{ANSI_END}"
|
|
350
|
+
if not adv_lat is None:
|
|
351
|
+
txt += f" {ANSI_LIGHT_GRAY}coords: {adv_lat},{adv_lon}"
|
|
352
|
+
txt += f" {ANSI_YELLOW}path: [{path}] {ANSI_LIGHT_GRAY}snr: {event.payload['snr']:.2f}dB{ANSI_END}"
|
|
353
|
+
|
|
354
|
+
if handle_message.above:
|
|
355
|
+
print_above(txt)
|
|
356
|
+
else:
|
|
357
|
+
print(txt)
|
|
358
|
+
|
|
359
|
+
|
|
295
360
|
if handle_log_rx.json_log_rx: # json mode ... raw dump
|
|
296
361
|
msg = json.dumps(event.payload)
|
|
297
362
|
if handle_message.above:
|
|
@@ -302,6 +367,7 @@ async def handle_log_rx(event):
|
|
|
302
367
|
|
|
303
368
|
handle_log_rx.json_log_rx = False
|
|
304
369
|
handle_log_rx.channel_echoes = False
|
|
370
|
+
handle_log_rx.advert_echoes = False
|
|
305
371
|
handle_log_rx.mc = None
|
|
306
372
|
handle_log_rx.echo_unk_chans=False
|
|
307
373
|
|
|
@@ -518,6 +584,7 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
|
|
|
518
584
|
"self_telemetry" : None,
|
|
519
585
|
"get_channel": None,
|
|
520
586
|
"set_channel": None,
|
|
587
|
+
"add_channel": None,
|
|
521
588
|
"get_channels": None,
|
|
522
589
|
"remove_channel": None,
|
|
523
590
|
"apply_to": None,
|
|
@@ -533,11 +600,13 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
|
|
|
533
600
|
"lon" : None,
|
|
534
601
|
"coords" : None,
|
|
535
602
|
"print_snr" : {"on":None, "off": None},
|
|
603
|
+
"print_timestamp" : {"on":None, "off": None, "%Y:%M":None},
|
|
536
604
|
"json_msgs" : {"on":None, "off": None},
|
|
537
605
|
"color" : {"on":None, "off":None},
|
|
538
606
|
"print_adverts" : {"on":None, "off":None},
|
|
539
607
|
"json_log_rx" : {"on":None, "off":None},
|
|
540
608
|
"channel_echoes" : {"on":None, "off":None},
|
|
609
|
+
"advert_echoes" : {"on":None, "off":None},
|
|
541
610
|
"echo_unk_chans" : {"on":None, "off":None},
|
|
542
611
|
"print_new_contacts" : {"on": None, "off":None},
|
|
543
612
|
"print_path_updates" : {"on":None,"off":None},
|
|
@@ -562,11 +631,13 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
|
|
|
562
631
|
"lat":None,
|
|
563
632
|
"lon":None,
|
|
564
633
|
"print_snr":None,
|
|
634
|
+
"print_timestamp":None,
|
|
565
635
|
"json_msgs":None,
|
|
566
636
|
"color":None,
|
|
567
637
|
"print_adverts":None,
|
|
568
638
|
"json_log_rx":None,
|
|
569
639
|
"channel_echoes":None,
|
|
640
|
+
"advert_echoes":None,
|
|
570
641
|
"echo_unk_chans":None,
|
|
571
642
|
"print_path_updates":None,
|
|
572
643
|
"print_new_contacts":None,
|
|
@@ -594,6 +665,12 @@ def make_completion_dict(contacts, pending={}, to=None, channels=None):
|
|
|
594
665
|
"?pending_contacts":None,
|
|
595
666
|
"?add_pending":None,
|
|
596
667
|
"?flush_pending":None,
|
|
668
|
+
"?get_channels":None,
|
|
669
|
+
"?set_channel":None,
|
|
670
|
+
"?get_channel":None,
|
|
671
|
+
"?set_channel":None,
|
|
672
|
+
"?add_channel":None,
|
|
673
|
+
"?remove_channel":None,
|
|
597
674
|
}
|
|
598
675
|
|
|
599
676
|
contact_completion_list = {
|
|
@@ -1556,13 +1633,18 @@ async def get_channel (mc, chan) :
|
|
|
1556
1633
|
|
|
1557
1634
|
async def set_channel (mc, chan, name, key=None):
|
|
1558
1635
|
|
|
1559
|
-
if chan
|
|
1560
|
-
|
|
1636
|
+
if isinstance(chan, str):
|
|
1637
|
+
if chan.isnumeric():
|
|
1638
|
+
nb = int(chan)
|
|
1639
|
+
else:
|
|
1640
|
+
c = await get_channel_by_name(mc, chan)
|
|
1641
|
+
if c is None:
|
|
1642
|
+
return None
|
|
1643
|
+
nb = c['channel_idx']
|
|
1644
|
+
elif isinstance(chan, int):
|
|
1645
|
+
nb = chan
|
|
1561
1646
|
else:
|
|
1562
|
-
|
|
1563
|
-
if c is None:
|
|
1564
|
-
return None
|
|
1565
|
-
nb = c['channel_idx']
|
|
1647
|
+
return None
|
|
1566
1648
|
|
|
1567
1649
|
res = await mc.commands.set_channel(nb, name, key)
|
|
1568
1650
|
|
|
@@ -1874,6 +1956,10 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
1874
1956
|
process_event_message.color = (cmds[2] == "on")
|
|
1875
1957
|
if json_output :
|
|
1876
1958
|
print(json.dumps({"cmd" : cmds[1], "param" : cmds[2]}))
|
|
1959
|
+
case "print_timestamp" :
|
|
1960
|
+
process_event_message.timestamp = cmds[2]
|
|
1961
|
+
if json_output :
|
|
1962
|
+
print(json.dumps({"cmd" : cmds[1], "param" : cmds[2]}))
|
|
1877
1963
|
case "print_snr" :
|
|
1878
1964
|
process_event_message.print_snr = (cmds[2] == "on")
|
|
1879
1965
|
if json_output :
|
|
@@ -1886,6 +1972,10 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
1886
1972
|
handle_log_rx.channel_echoes = (cmds[2] == "on")
|
|
1887
1973
|
if json_output :
|
|
1888
1974
|
print(json.dumps({"cmd" : cmds[1], "param" : cmds[2]}))
|
|
1975
|
+
case "advert_echoes" :
|
|
1976
|
+
handle_log_rx.advert_echoes = (cmds[2] == "on")
|
|
1977
|
+
if json_output :
|
|
1978
|
+
print(json.dumps({"cmd" : cmds[1], "param" : cmds[2]}))
|
|
1889
1979
|
case "echo_unk_chans" :
|
|
1890
1980
|
handle_log_rx.echo_unk_chans = (cmds[2] == "on")
|
|
1891
1981
|
if json_output :
|
|
@@ -2101,6 +2191,11 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2101
2191
|
print(json.dumps({"color" : process_event_message.color}))
|
|
2102
2192
|
else:
|
|
2103
2193
|
print(f"{'on' if process_event_message.color else 'off'}")
|
|
2194
|
+
case "print_timestamp":
|
|
2195
|
+
if json_output :
|
|
2196
|
+
print(json.dumps({"timestamp" : process_event_message.timestamp}))
|
|
2197
|
+
else:
|
|
2198
|
+
print(f"{process_event_message.timestamp}")
|
|
2104
2199
|
case "json_log_rx":
|
|
2105
2200
|
if json_output :
|
|
2106
2201
|
print(json.dumps({"json_log_rx" : handle_log_rx.json_log_rx}))
|
|
@@ -2111,6 +2206,11 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2111
2206
|
print(json.dumps({"channel_echoes" : handle_log_rx.channel_echoes}))
|
|
2112
2207
|
else:
|
|
2113
2208
|
print(f"{'on' if handle_log_rx.channel_echoes else 'off'}")
|
|
2209
|
+
case "advert_echoes":
|
|
2210
|
+
if json_output :
|
|
2211
|
+
print(json.dumps({"advert_echoes" : handle_log_rx.channel_echoes}))
|
|
2212
|
+
else:
|
|
2213
|
+
print(f"{'on' if handle_log_rx.advert_echoes else 'off'}")
|
|
2114
2214
|
case "echo_unk_chans":
|
|
2115
2215
|
if json_output :
|
|
2116
2216
|
print(json.dumps({"echo_unk_chans" : handle_log_rx.echo_unk_chans}))
|
|
@@ -2313,11 +2413,17 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2313
2413
|
if res is None:
|
|
2314
2414
|
print("Error setting channel")
|
|
2315
2415
|
|
|
2316
|
-
case "
|
|
2317
|
-
argnum =
|
|
2318
|
-
|
|
2416
|
+
case "add_channel":
|
|
2417
|
+
argnum = 2
|
|
2418
|
+
if cmds[1].startswith("#") or len(cmds) == 2:
|
|
2419
|
+
argnum = 1
|
|
2420
|
+
res = await set_channel(mc, "", cmds[1])
|
|
2421
|
+
elif len(cmds[2]) != 32:
|
|
2422
|
+
res = None
|
|
2423
|
+
else:
|
|
2424
|
+
res = await set_channel(mc, "", cmds[1], bytes.fromhex(cmds[3]))
|
|
2319
2425
|
if res is None:
|
|
2320
|
-
print(
|
|
2426
|
+
print("Error adding channel")
|
|
2321
2427
|
|
|
2322
2428
|
case "remove_channel":
|
|
2323
2429
|
argnum = 1
|
|
@@ -2325,6 +2431,12 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2325
2431
|
if res is None:
|
|
2326
2432
|
print("Error deleting channel")
|
|
2327
2433
|
|
|
2434
|
+
case "scope":
|
|
2435
|
+
argnum = 1
|
|
2436
|
+
res = await set_scope(mc, cmds[1])
|
|
2437
|
+
if res is None:
|
|
2438
|
+
print(f"Error while setting scope")
|
|
2439
|
+
|
|
2328
2440
|
case "reboot" :
|
|
2329
2441
|
res = await mc.commands.reboot()
|
|
2330
2442
|
logger.debug(res)
|
|
@@ -3202,7 +3314,8 @@ def command_help():
|
|
|
3202
3314
|
msgs_subscribe : display msgs as they arrive ms
|
|
3203
3315
|
get_channels : prints all channel info
|
|
3204
3316
|
get_channel <n> : get info for channel (by number or name)
|
|
3205
|
-
set_channel n nm k
|
|
3317
|
+
set_channel n nm [k] : set channel info (nb, name, key)
|
|
3318
|
+
add_channel name [key] : add new channel with optional key
|
|
3206
3319
|
remove_channel <n> : remove channel (by number or name)
|
|
3207
3320
|
scope <s> : sets scope for flood messages
|
|
3208
3321
|
Management
|
|
@@ -3347,12 +3460,14 @@ def get_help_for (cmdname, context="line") :
|
|
|
3347
3460
|
- when on contacts must be added manually using add_pending
|
|
3348
3461
|
(pending contacts list is built by meshcli from adverts while connected)
|
|
3349
3462
|
display:
|
|
3463
|
+
print_timestamp <on/off/fmt>: toggle printing of timestamp, can be strftime format
|
|
3350
3464
|
print_snr <on/off> : toggle snr display in messages
|
|
3351
3465
|
print_adverts <on/off> : display adverts as they come
|
|
3352
3466
|
print_new_contacts <on/off> : display new pending contacts when available
|
|
3353
3467
|
print_path_updates <on/off> : display path updates as they come
|
|
3354
3468
|
json_log_rx <on/off> : logs packets incoming to device as json
|
|
3355
3469
|
channel_echoes <on/off> : print repeats for channel data
|
|
3470
|
+
advert_echoes <on/off> : print repeats for adverts
|
|
3356
3471
|
echo_unk_channels <on/off> : also dump unk channels (encrypted)
|
|
3357
3472
|
color <on/off> : color off should remove ANSI codes from output
|
|
3358
3473
|
meshcore-cli behaviour:
|
|
@@ -3397,6 +3512,30 @@ With growing number of users, it becomes necessary to manage contact list and on
|
|
|
3397
3512
|
This feature only really works in interactive mode.
|
|
3398
3513
|
|
|
3399
3514
|
Note: There is also an auto_update_contacts setting that has nothing to do with adding contacts, it permits to automatically sync contact lists between device and meshcore-cli (when there is an update in name, location or path).
|
|
3515
|
+
""")
|
|
3516
|
+
|
|
3517
|
+
elif "channel" in cmdname:
|
|
3518
|
+
print("""Channel management
|
|
3519
|
+
|
|
3520
|
+
Channels are used to send messages to a group of people. This group of people share a common key, used to encrypt, identify and decrypt the messages that are sent flood over the network (possibly with a scope).
|
|
3521
|
+
|
|
3522
|
+
Channel commands are the following:
|
|
3523
|
+
- get_channels
|
|
3524
|
+
- get_channel chan
|
|
3525
|
+
- add_channel name [key]
|
|
3526
|
+
- set_channel chan name [key]
|
|
3527
|
+
- remove_channel chan
|
|
3528
|
+
|
|
3529
|
+
There is a fixed number of slots on companions to store channel messages, each channel has a number, a name and a key, the get_channels command lists theses slots.
|
|
3530
|
+
|
|
3531
|
+
You can also call get_channel (with number or name) to get information about one channel.
|
|
3532
|
+
|
|
3533
|
+
Adding a channel can be done using the set_channel command, taking as parameters the channel number, the name and the key. Key is optional, if not provided, it will be computed from the name.
|
|
3534
|
+
The add_channel command won't take a number as it will use first available slot.
|
|
3535
|
+
|
|
3536
|
+
There is a special case for auto channels, which starts with a #, these have always their key computed from the name (note that mccli does not lowercase and strip characters so you should be carefull when sharing when users of the android app or ripple).
|
|
3537
|
+
|
|
3538
|
+
To remove a channel, use remove_channel, either with channel name or number.
|
|
3400
3539
|
""")
|
|
3401
3540
|
|
|
3402
3541
|
else:
|
|
@@ -3537,7 +3676,14 @@ async def main(argv):
|
|
|
3537
3676
|
logger.info(f"Searching first MC BLE device")
|
|
3538
3677
|
else:
|
|
3539
3678
|
logger.info(f"Scanning BLE for device matching {address}")
|
|
3540
|
-
|
|
3679
|
+
try:
|
|
3680
|
+
devices = await BleakScanner.discover(timeout=timeout)
|
|
3681
|
+
except (BleakError, BleakDBusError):
|
|
3682
|
+
print("BLE connection asked (default behaviour), but no BLE HW found")
|
|
3683
|
+
print("Call meshcore-cli with -h for some more help (on commands)")
|
|
3684
|
+
command_usage()
|
|
3685
|
+
return
|
|
3686
|
+
|
|
3541
3687
|
found = False
|
|
3542
3688
|
for d in devices:
|
|
3543
3689
|
if not d.name is None and d.name.startswith("MeshCore-") and\
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshcore-cli
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.8
|
|
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
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
meshcore_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
meshcore_cli/__main__.py,sha256=PfYgibmu2LEtC-OV7L1UgmvV3swJ5rQ4bbXHlwUFlgE,83
|
|
3
|
+
meshcore_cli/meshcore_cli.py,sha256=lBuixjTPVJm6ijXuB8RojArSjSDu6k8xCTOtpPAAgs4,158679
|
|
4
|
+
meshcore_cli-1.3.8.dist-info/METADATA,sha256=PTtqAGUv5-37BMScJY5ErRy4gLFs9jIoBNbxnzSvgME,17137
|
|
5
|
+
meshcore_cli-1.3.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
6
|
+
meshcore_cli-1.3.8.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
|
|
7
|
+
meshcore_cli-1.3.8.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
|
|
8
|
+
meshcore_cli-1.3.8.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
meshcore_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
meshcore_cli/__main__.py,sha256=PfYgibmu2LEtC-OV7L1UgmvV3swJ5rQ4bbXHlwUFlgE,83
|
|
3
|
-
meshcore_cli/meshcore_cli.py,sha256=iRrICDi9pCAngyuY6_Jc6teubgi4gomJ8l_NHXYNFrE,151869
|
|
4
|
-
meshcore_cli-1.3.7.dist-info/METADATA,sha256=0o6ju0KlttNIOFoy3_0-rUEIlVwSymgsHDLkkr-So5w,17137
|
|
5
|
-
meshcore_cli-1.3.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
6
|
-
meshcore_cli-1.3.7.dist-info/entry_points.txt,sha256=77V29Pyth11GteDk7tneBN3MMk8JI7bTlS-BGSmxCmI,103
|
|
7
|
-
meshcore_cli-1.3.7.dist-info/licenses/LICENSE,sha256=F9s987VtS0AKxW7LdB2EkLMkrdeERI7ICdLJR60A9M4,1066
|
|
8
|
-
meshcore_cli-1.3.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|