meshcore-cli 1.3.11__tar.gz → 1.3.12__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.3.11 → meshcore_cli-1.3.12}/PKG-INFO +13 -1
- {meshcore_cli-1.3.11 → meshcore_cli-1.3.12}/README.md +12 -0
- {meshcore_cli-1.3.11 → meshcore_cli-1.3.12}/flake.nix +2 -2
- {meshcore_cli-1.3.11 → meshcore_cli-1.3.12}/pyproject.toml +1 -1
- {meshcore_cli-1.3.11 → meshcore_cli-1.3.12}/src/meshcore_cli/meshcore_cli.py +36 -15
- {meshcore_cli-1.3.11 → meshcore_cli-1.3.12}/.gitignore +0 -0
- {meshcore_cli-1.3.11 → meshcore_cli-1.3.12}/LICENSE +0 -0
- {meshcore_cli-1.3.11 → meshcore_cli-1.3.12}/flake.lock +0 -0
- {meshcore_cli-1.3.11 → meshcore_cli-1.3.12}/src/meshcore_cli/__init__.py +0 -0
- {meshcore_cli-1.3.11 → meshcore_cli-1.3.12}/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.
|
|
3
|
+
Version: 1.3.12
|
|
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
|
|
@@ -21,6 +21,18 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
|
|
22
22
|
meshcore-cli : CLI interface to MeschCore companion app over BLE, TCP or Serial
|
|
23
23
|
|
|
24
|
+
## About
|
|
25
|
+
|
|
26
|
+
meshcore-cli is a tool that connects to your companion radio node (meshcore client) over BLE, TCP or Serial and lets you interact with it from a terminal using a command line interface.
|
|
27
|
+
|
|
28
|
+
You can send commands as parameters to the meshcore-cli command (from your shell) either interactively or through a script.
|
|
29
|
+
|
|
30
|
+
There is also an interactive mode (this is the default when no command is passed). In interactive mode you can enter a contact (another client a repeater, a sensor or a room) and interact with it. For clients, interaction consists in sending/receiving messages. For repeaters, rooms or sensors it will directly give you the remote cli (you can still send messages to rooms using double quote prefix or msg command).
|
|
31
|
+
|
|
32
|
+
Note that meshcore-cli only interacts with companion radios (through BLE, Serial or TCP), you can't connect to a repeater using its serial interface.
|
|
33
|
+
|
|
34
|
+
Also, most meshcore companions only have one interface compiled in at a time. So you can't connect via Serial to a node, which has been compiled as a BLE companion.
|
|
35
|
+
|
|
24
36
|
## Install
|
|
25
37
|
|
|
26
38
|
Meshcore-cli depends on the [python meshcore](https://github.com/fdlamotte/meshcore_py) package. You can install both via `pip` or `pipx` using the command:
|
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
meshcore-cli : CLI interface to MeschCore companion app over BLE, TCP or Serial
|
|
4
4
|
|
|
5
|
+
## About
|
|
6
|
+
|
|
7
|
+
meshcore-cli is a tool that connects to your companion radio node (meshcore client) over BLE, TCP or Serial and lets you interact with it from a terminal using a command line interface.
|
|
8
|
+
|
|
9
|
+
You can send commands as parameters to the meshcore-cli command (from your shell) either interactively or through a script.
|
|
10
|
+
|
|
11
|
+
There is also an interactive mode (this is the default when no command is passed). In interactive mode you can enter a contact (another client a repeater, a sensor or a room) and interact with it. For clients, interaction consists in sending/receiving messages. For repeaters, rooms or sensors it will directly give you the remote cli (you can still send messages to rooms using double quote prefix or msg command).
|
|
12
|
+
|
|
13
|
+
Note that meshcore-cli only interacts with companion radios (through BLE, Serial or TCP), you can't connect to a repeater using its serial interface.
|
|
14
|
+
|
|
15
|
+
Also, most meshcore companions only have one interface compiled in at a time. So you can't connect via Serial to a node, which has been compiled as a BLE companion.
|
|
16
|
+
|
|
5
17
|
## Install
|
|
6
18
|
|
|
7
19
|
Meshcore-cli depends on the [python meshcore](https://github.com/fdlamotte/meshcore_py) package. You can install both via `pip` or `pipx` using the command:
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
|
|
18
18
|
meshcore = python3Packages.buildPythonPackage rec {
|
|
19
19
|
pname = "meshcore";
|
|
20
|
-
version = "2.2.
|
|
20
|
+
version = "2.2.3";
|
|
21
21
|
pyproject = true;
|
|
22
22
|
|
|
23
23
|
src = python3Packages.fetchPypi {
|
|
24
24
|
inherit pname version;
|
|
25
|
-
sha256 = "sha256-
|
|
25
|
+
sha256 = "sha256-lmMflAlrNnfsc10J3CBxor9ftHK10bWyGTbjASJv82s=";
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
build-system = [ python3Packages.hatchling ];
|
|
@@ -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.12"
|
|
36
36
|
|
|
37
37
|
# default ble address is stored in a config file
|
|
38
38
|
MCCLI_CONFIG_DIR = str(Path.home()) + "/.config/meshcore/"
|
|
@@ -72,6 +72,8 @@ ANSI_LIGHT_GREEN = "\033[0;92m"
|
|
|
72
72
|
ANSI_LIGHT_YELLOW = "\033[0;93m"
|
|
73
73
|
ANSI_LIGHT_GRAY="\033[0;38;5;247m"
|
|
74
74
|
ANSI_BGRAY="\033[1;38;5;247m"
|
|
75
|
+
ANSI_GRAY_BACK="\033[48;5;247m"
|
|
76
|
+
ANSI_RESET_BACK="\033[49m"
|
|
75
77
|
ANSI_ORANGE="\033[0;38;5;214m"
|
|
76
78
|
ANSI_BORANGE="\033[1;38;5;214m"
|
|
77
79
|
#ANSI_YELLOW="\033[0;38;5;226m"
|
|
@@ -82,8 +84,9 @@ ANSI_BYELLOW = "\033[1;33m"
|
|
|
82
84
|
#Unicode chars
|
|
83
85
|
# some possible symbols for prompts 🭬🬛🬗🭬🬛🬃🬗🭬🬛🬃🬗🬏🭀🭋🭨🮋
|
|
84
86
|
ARROW_HEAD = ""
|
|
85
|
-
SLASH_END = ""
|
|
86
|
-
SLASH_START = ""
|
|
87
|
+
SLASH_END = f"{ANSI_RESET_BACK}"
|
|
88
|
+
#SLASH_START = ""
|
|
89
|
+
SLASH_START = f"{ANSI_GRAY_BACK}"
|
|
87
90
|
INVERT_SLASH = False
|
|
88
91
|
|
|
89
92
|
def escape_ansi(line):
|
|
@@ -294,7 +297,7 @@ async def handle_log_rx(event):
|
|
|
294
297
|
chan_name = channel["channel_name"]
|
|
295
298
|
aes_key = bytes.fromhex(channel["channel_secret"])
|
|
296
299
|
cipher = AES.new(aes_key, AES.MODE_ECB)
|
|
297
|
-
message = cipher.decrypt(msg)[5:].decode("utf-8").strip("\x00")
|
|
300
|
+
message = cipher.decrypt(msg)[5:].decode("utf-8", "ignore").strip("\x00")
|
|
298
301
|
|
|
299
302
|
if chan_name != "" :
|
|
300
303
|
width = os.get_terminal_size().columns
|
|
@@ -324,7 +327,7 @@ async def handle_log_rx(event):
|
|
|
324
327
|
if flags & 0x40 > 0: #has feature2
|
|
325
328
|
adv_feat2 = pk_buf.read(2).hex()
|
|
326
329
|
if flags & 0x80 > 0: #has name
|
|
327
|
-
adv_name = pk_buf.read().decode("utf-8").strip("\x00")
|
|
330
|
+
adv_name = pk_buf.read().decode("utf-8", "ignore").strip("\x00")
|
|
328
331
|
|
|
329
332
|
if adv_name is None:
|
|
330
333
|
# try to get the name from the contact
|
|
@@ -443,10 +446,16 @@ async def log_message(mc, msg):
|
|
|
443
446
|
ct = mc.get_contact_by_key_prefix(msg['pubkey_prefix'])
|
|
444
447
|
if ct is None:
|
|
445
448
|
msg["name"] = msg["pubkey_prefix"]
|
|
449
|
+
msg["sender"] = msg["pubkey_prefix"]
|
|
446
450
|
else:
|
|
447
451
|
msg["name"] = ct["adv_name"]
|
|
452
|
+
msg["sender"] = ct["adv_name"]
|
|
448
453
|
elif msg["type"] == "CHAN" :
|
|
449
|
-
|
|
454
|
+
if hasattr(mc, 'channels') :
|
|
455
|
+
msg["sender"] = mc.channels[msg['channel_idx']]["channel_name"]
|
|
456
|
+
else:
|
|
457
|
+
msg["sender"] = f"channel {msg['channel_idx']}"
|
|
458
|
+
msg["name"] = msg["sender"]
|
|
450
459
|
msg["timestamp"] = int(time.time())
|
|
451
460
|
|
|
452
461
|
with open(log_message.file, "a") as logfile:
|
|
@@ -1538,10 +1547,11 @@ async def send_cmd (mc, contact, cmd) :
|
|
|
1538
1547
|
if isinstance(contact, dict):
|
|
1539
1548
|
sent = res.payload.copy()
|
|
1540
1549
|
sent["type"] = "SENT_CMD"
|
|
1541
|
-
sent["
|
|
1550
|
+
sent["recipient"] = contact["adv_name"]
|
|
1542
1551
|
sent["text"] = cmd
|
|
1543
1552
|
sent["txt_type"] = 1
|
|
1544
|
-
sent["
|
|
1553
|
+
sent["sender"] = mc.self_info['name']
|
|
1554
|
+
sent["name"] = sent["recipient"]
|
|
1545
1555
|
await log_message(mc, sent)
|
|
1546
1556
|
return res
|
|
1547
1557
|
|
|
@@ -1551,9 +1561,16 @@ async def send_chan_msg(mc, nb, msg):
|
|
|
1551
1561
|
sent = res.payload.copy()
|
|
1552
1562
|
sent["type"] = "SENT_CHAN"
|
|
1553
1563
|
sent["channel_idx"] = nb
|
|
1564
|
+
if hasattr(mc, "channels"):
|
|
1565
|
+
chan_name = mc.channels[nb]["channel_name"]
|
|
1566
|
+
else:
|
|
1567
|
+
chan_name = f"channel {nb}"
|
|
1568
|
+
sent["chan_name"] = chan_name
|
|
1569
|
+
sent["recipient"] = chan_name
|
|
1554
1570
|
sent["text"] = msg
|
|
1555
1571
|
sent["txt_type"] = 0
|
|
1556
|
-
sent["
|
|
1572
|
+
sent["sender"] = mc.self_info['name']
|
|
1573
|
+
sent["name"] = chan_name
|
|
1557
1574
|
await log_message(mc, sent)
|
|
1558
1575
|
return res
|
|
1559
1576
|
|
|
@@ -1564,10 +1581,11 @@ async def send_msg (mc, contact, msg) :
|
|
|
1564
1581
|
if isinstance(contact, dict):
|
|
1565
1582
|
sent = res.payload.copy()
|
|
1566
1583
|
sent["type"] = "SENT_MSG"
|
|
1567
|
-
sent["
|
|
1584
|
+
sent["recipient"] = contact["adv_name"]
|
|
1568
1585
|
sent["text"] = msg
|
|
1569
1586
|
sent["txt_type"] = 0
|
|
1570
|
-
sent["
|
|
1587
|
+
sent["sender"] = mc.self_info['name']
|
|
1588
|
+
sent["name"] = sent["recipient"]
|
|
1571
1589
|
await log_message(mc, sent)
|
|
1572
1590
|
return res
|
|
1573
1591
|
|
|
@@ -1584,10 +1602,11 @@ async def msg_ack (mc, contact, msg) :
|
|
|
1584
1602
|
if isinstance(contact, dict):
|
|
1585
1603
|
sent = res.payload.copy()
|
|
1586
1604
|
sent["type"] = "SENT_MSG"
|
|
1587
|
-
sent["
|
|
1605
|
+
sent["recipient"] = contact["adv_name"]
|
|
1588
1606
|
sent["text"] = msg
|
|
1589
1607
|
sent["txt_type"] = 0
|
|
1590
|
-
sent["
|
|
1608
|
+
sent["sender"] = mc.self_info['name']
|
|
1609
|
+
sent["name"] = sent["recipient"]
|
|
1591
1610
|
await log_message(mc, sent)
|
|
1592
1611
|
return not res is None
|
|
1593
1612
|
msg_ack.max_attempts=3
|
|
@@ -2500,7 +2519,9 @@ async def next_cmd(mc, cmds, json_output=False):
|
|
|
2500
2519
|
if cmds[1].isnumeric() :
|
|
2501
2520
|
nb = int(cmds[1])
|
|
2502
2521
|
else:
|
|
2503
|
-
|
|
2522
|
+
chan = await get_channel_by_name(mc, cmds[1])
|
|
2523
|
+
print (chan)
|
|
2524
|
+
nb = chan['channel_idx']
|
|
2504
2525
|
res = await send_chan_msg(mc, nb, cmds[2])
|
|
2505
2526
|
logger.debug(res)
|
|
2506
2527
|
if res.type == EventType.ERROR:
|
|
@@ -3494,7 +3515,7 @@ def get_help_for (cmdname, context="line") :
|
|
|
3494
3515
|
json_log_rx <on/off> : logs packets incoming to device as json
|
|
3495
3516
|
channel_echoes <on/off> : print repeats for channel data
|
|
3496
3517
|
advert_echoes <on/off> : print repeats for adverts
|
|
3497
|
-
|
|
3518
|
+
echo_unk_chans <on/off> : also dump unk channels (encrypted)
|
|
3498
3519
|
color <on/off> : color off should remove ANSI codes from output
|
|
3499
3520
|
meshcore-cli behaviour:
|
|
3500
3521
|
classic_prompt <on/off> : activates less fancier prompt
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|