opengearwire 0.3.0__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.
- opengearwire/__init__.py +29 -0
- opengearwire/__main__.py +134 -0
- opengearwire/_protocol.py +616 -0
- opengearwire/client.py +453 -0
- opengearwire/docs/PROTOCOL.md +292 -0
- opengearwire/fixtures/dashboard-session.jsonl +3941 -0
- opengearwire/model.py +326 -0
- opengearwire/py.typed +0 -0
- opengearwire/snapshot.py +83 -0
- opengearwire/testing.py +262 -0
- opengearwire-0.3.0.dist-info/METADATA +182 -0
- opengearwire-0.3.0.dist-info/RECORD +16 -0
- opengearwire-0.3.0.dist-info/WHEEL +5 -0
- opengearwire-0.3.0.dist-info/entry_points.txt +2 -0
- opengearwire-0.3.0.dist-info/licenses/LICENSE +21 -0
- opengearwire-0.3.0.dist-info/top_level.txt +1 -0
opengearwire/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""opengearwire: read openGear frames (Ross OGX and partners) over OGP.
|
|
3
|
+
|
|
4
|
+
Read-only for now. ``Frame`` connects and reads; ``Tree`` holds what was
|
|
5
|
+
read; ``snapshot`` turns it into plain data. ``docs/PROTOCOL.md`` is the
|
|
6
|
+
wire format.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.3.0"
|
|
10
|
+
|
|
11
|
+
from ._protocol import ProtocolError, RemoteError
|
|
12
|
+
from .client import Frame, FrameBusy, FrameError
|
|
13
|
+
from .model import Change, Device, Parameter, Tree, address_of, slot_of
|
|
14
|
+
from .snapshot import snapshot
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"Change",
|
|
18
|
+
"Device",
|
|
19
|
+
"Frame",
|
|
20
|
+
"FrameBusy",
|
|
21
|
+
"FrameError",
|
|
22
|
+
"Parameter",
|
|
23
|
+
"ProtocolError",
|
|
24
|
+
"RemoteError",
|
|
25
|
+
"Tree",
|
|
26
|
+
"address_of",
|
|
27
|
+
"slot_of",
|
|
28
|
+
"snapshot",
|
|
29
|
+
]
|
opengearwire/__main__.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""opengearwire HOST COMMAND: read a frame from the command line.
|
|
3
|
+
|
|
4
|
+
opengearwire 192.0.2.10 slots occupied slots and their products
|
|
5
|
+
opengearwire 192.0.2.10 params 4 every parameter of slot 4
|
|
6
|
+
opengearwire 192.0.2.10 read 4 0x0b04 fresh value(s) by OID or name
|
|
7
|
+
opengearwire 192.0.2.10 watch 10 pushed changes for 10 s
|
|
8
|
+
opengearwire 192.0.2.10 snapshot the whole frame as JSON
|
|
9
|
+
|
|
10
|
+
Slot 0 is the frame controller. Every command opens one connection,
|
|
11
|
+
does what it says and closes; nothing is ever written to the frame.
|
|
12
|
+
The frame takes one client at a time: close DashBoard first.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import json
|
|
17
|
+
import sys
|
|
18
|
+
|
|
19
|
+
from . import _protocol as P
|
|
20
|
+
from .client import PORT, Frame, FrameError
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _fmt(v) -> str:
|
|
24
|
+
if isinstance(v, list):
|
|
25
|
+
return ", ".join(str(x) for x in v)
|
|
26
|
+
return str(v)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def main(argv=None) -> int:
|
|
30
|
+
ap = argparse.ArgumentParser(prog="opengearwire", description=__doc__.split("\n")[0])
|
|
31
|
+
ap.add_argument("host")
|
|
32
|
+
ap.add_argument("--port", type=int, default=PORT)
|
|
33
|
+
ap.add_argument(
|
|
34
|
+
"--timeout",
|
|
35
|
+
type=float,
|
|
36
|
+
default=5.0,
|
|
37
|
+
help="seconds of silence from the frame before giving up (default 5)",
|
|
38
|
+
)
|
|
39
|
+
ap.add_argument("--json", action="store_true", help="JSON output")
|
|
40
|
+
sub = ap.add_subparsers(dest="cmd", required=True)
|
|
41
|
+
sub.add_parser("slots")
|
|
42
|
+
p = sub.add_parser("params")
|
|
43
|
+
p.add_argument("slot", type=int)
|
|
44
|
+
p = sub.add_parser("read")
|
|
45
|
+
p.add_argument("slot", type=int)
|
|
46
|
+
p.add_argument("keys", nargs="+", help="OIDs (0x0b04) or exact names")
|
|
47
|
+
p = sub.add_parser("watch")
|
|
48
|
+
p.add_argument("seconds", type=float)
|
|
49
|
+
sub.add_parser("snapshot")
|
|
50
|
+
a = ap.parse_args(argv)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
with Frame(a.host, a.port, timeout=a.timeout) as f:
|
|
54
|
+
return _run(f, a)
|
|
55
|
+
except (OSError, FrameError, P.ProtocolError) as e:
|
|
56
|
+
print(f"opengearwire: {a.host}: {e}", file=sys.stderr)
|
|
57
|
+
return 1
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _run(f: Frame, a) -> int:
|
|
61
|
+
out = sys.stdout
|
|
62
|
+
if a.cmd == "slots":
|
|
63
|
+
f.discover()
|
|
64
|
+
rows = list(f.identify().items())
|
|
65
|
+
if a.json:
|
|
66
|
+
json.dump([{"slot": s, "product": p} for s, p in rows], out, indent=2)
|
|
67
|
+
out.write("\n")
|
|
68
|
+
else:
|
|
69
|
+
for s, p in rows:
|
|
70
|
+
out.write(f"{s:>3} {p}\n")
|
|
71
|
+
elif a.cmd == "params":
|
|
72
|
+
f.describe([a.slot])
|
|
73
|
+
dev = f.device(a.slot)
|
|
74
|
+
if a.json:
|
|
75
|
+
json.dump(dev.to_dict(), out, indent=2)
|
|
76
|
+
out.write("\n")
|
|
77
|
+
else:
|
|
78
|
+
for o in dev.oids:
|
|
79
|
+
p = dev.params[o]
|
|
80
|
+
d = p.descriptor
|
|
81
|
+
rw = "rw" if d and d.writable else "ro"
|
|
82
|
+
kind = d.type_name if d else "?"
|
|
83
|
+
out.write(f"0x{o:04x} {rw} {kind:9} {p.name!r:32} {_fmt(p.display)}\n")
|
|
84
|
+
elif a.cmd == "read":
|
|
85
|
+
keys = [int(k, 16) if k.lower().startswith("0x") else k for k in a.keys]
|
|
86
|
+
if all(isinstance(k, int) for k in keys):
|
|
87
|
+
f.describe_oids(a.slot, keys) # descriptors decode the values
|
|
88
|
+
else:
|
|
89
|
+
f.describe([a.slot], menus=False) # names need the whole list
|
|
90
|
+
vals = f.read(a.slot, *keys)
|
|
91
|
+
dev = f.device(a.slot)
|
|
92
|
+
rows = [(o, dev.params[o]) for o in vals]
|
|
93
|
+
if a.json:
|
|
94
|
+
json.dump([p.to_dict() for _, p in rows], out, indent=2)
|
|
95
|
+
out.write("\n")
|
|
96
|
+
else:
|
|
97
|
+
for o, p in rows:
|
|
98
|
+
out.write(f"0x{o:04x} {p.name!r}: {_fmt(p.display)}\n")
|
|
99
|
+
elif a.cmd == "watch":
|
|
100
|
+
f.discover()
|
|
101
|
+
for ch in f.watch(a.seconds):
|
|
102
|
+
if a.json:
|
|
103
|
+
out.write(
|
|
104
|
+
json.dumps(
|
|
105
|
+
{
|
|
106
|
+
"slot": ch.slot,
|
|
107
|
+
"oid": f"0x{ch.oid:04x}",
|
|
108
|
+
"name": ch.name,
|
|
109
|
+
"old": ch.old,
|
|
110
|
+
"new": ch.new,
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
+ "\n"
|
|
114
|
+
)
|
|
115
|
+
else:
|
|
116
|
+
out.write(f"slot {ch.slot} 0x{ch.oid:04x} {ch.name!r}: {ch.old!r} -> {ch.new!r}\n")
|
|
117
|
+
elif a.cmd == "snapshot":
|
|
118
|
+
f.discover()
|
|
119
|
+
f.describe()
|
|
120
|
+
json.dump(f.snapshot(), out, indent=2)
|
|
121
|
+
out.write("\n")
|
|
122
|
+
if f.unanswered:
|
|
123
|
+
print(f"opengearwire: {len(f.unanswered)} request(s) never answered", file=sys.stderr)
|
|
124
|
+
for u in f.unanswered:
|
|
125
|
+
what = u.get("oid") or ", ".join(
|
|
126
|
+
f"{k} {u[k]}" for k in ("menuset", "menu", "object", "offset") if k in u
|
|
127
|
+
)
|
|
128
|
+
name = f" {u['name']!r}" if "name" in u else ""
|
|
129
|
+
print(f" slot {u['slot']} {u['request']} {what}{name}", file=sys.stderr)
|
|
130
|
+
return 0
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
sys.exit(main())
|