eva-shell 0.2.36__tar.gz → 0.2.38__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eva-shell
3
- Version: 0.2.36
3
+ Version: 0.2.38
4
4
  Summary: EVA ICS v4 shell
5
5
  Home-page: https://github.com/eva-ics/eva4
6
6
  Author: Bohemia Automation / Altertech
@@ -1,3 +1,3 @@
1
- __version__ = '0.2.36'
1
+ __version__ = '0.2.38'
2
2
 
3
3
  DEFAULT_REPOSITORY_URL = 'https://pub.bma.ai/eva4'
@@ -12,12 +12,12 @@ neotermcolor.readline_always_safe = True
12
12
 
13
13
  from .sharedobj import common, current_command
14
14
  from .tools import print_tb, err, is_local_shell
15
- from .compl import ComplOID, ComplSvc, ComplNode, ComplDeployFile, ComplDobj
15
+ from .compl import ComplOID, ComplSvc, ComplNode, ComplDeployFile, ComplAnyFile, ComplDobj
16
16
  from .compl import ComplOIDtp, ComplSvcRpcMethod, ComplSvcRpcParams, ComplEdit
17
17
  from .client import call_rpc, DEFAULT_DB_SERVICE, DEFAULT_REPL_SERVICE
18
18
  from .client import DEFAULT_ACL_SERVICE, DEFAULT_AUTH_SERVICE
19
19
  from .client import DEFAULT_KIOSK_SERVICE, DEFAULT_GENERATOR_SERVICE
20
- from .client import DEFAULT_ACCOUNTING_SERVICE, DEFAULT_ALARM_SERVICE
20
+ from .client import DEFAULT_ACCOUNTING_SERVICE, DEFAULT_ALARM_SERVICE, DEFAULT_VIDEO_SERVICE
21
21
 
22
22
  ALARM_OP_CODES = [
23
23
  'TT', 'TL', 'LL', 'SS', 'SD', 'OS', 'CC', 'AA', 'US', 'RD', 'IS'
@@ -523,6 +523,12 @@ def append_svc_cli(root_sp):
523
523
  'purge', help='purge service (destroy and delete all service data)')
524
524
  p.add_argument('i', metavar='SVC').completer = ComplSvc()
525
525
 
526
+ p = sp.add_parser('flash', help='flash the service binary')
527
+ p.add_argument('i', metavar='SVC').completer = ComplSvc()
528
+ p.add_argument(
529
+ 'file', metavar='FILE',
530
+ help='service file to reflash with').completer = ComplAnyFile()
531
+
526
532
 
527
533
  def append_acl_cli(root_sp):
528
534
  ap = root_sp.add_parser('acl', help='ACL commands')
@@ -820,6 +826,12 @@ def append_item_cli(root_sp):
820
826
 
821
827
  p = sp.add_parser('create', help='create an item')
822
828
  p.add_argument('i', metavar='OID').completer = ComplOID()
829
+ p.add_argument(
830
+ '-p',
831
+ '--python',
832
+ help=
833
+ 'For Python lmacro: assign eva.controller.py as action svc and edit code after creation',
834
+ action='store_true')
823
835
 
824
836
  p = sp.add_parser('destroy', help='destroy item(s)')
825
837
  p.add_argument('i', metavar='MASK').completer = ComplOID()
@@ -832,6 +844,10 @@ def append_item_cli(root_sp):
832
844
 
833
845
  p = sp.add_parser('edit', help='edit item config')
834
846
  p.add_argument('i', metavar='OID').completer = ComplOID()
847
+ p.add_argument('-p',
848
+ '--python',
849
+ help='For Python lmacro: edit code',
850
+ action='store_true')
835
851
 
836
852
  p = sp.add_parser('set', help='set item state')
837
853
  p.add_argument('i', metavar='OID').completer = ComplOID()
@@ -1184,6 +1200,94 @@ def append_cloud_cli(root_sp):
1184
1200
  action='store_true')
1185
1201
 
1186
1202
 
1203
+ def append_video_cli(root_sp):
1204
+ ap_generator = root_sp.add_parser('video', help='video commands')
1205
+ sp_generator = ap_generator.add_subparsers(dest='_subc', help='sub command')
1206
+
1207
+ ap = sp_generator.add_parser('rec', help='video recordings')
1208
+ sp = ap.add_subparsers(dest='_subc2', help='sub command')
1209
+
1210
+ p = sp.add_parser('create', help='create a video recording')
1211
+ p.add_argument('i', metavar='source')
1212
+ p.add_argument('--keep', type=float, help='Keep (seconds)')
1213
+ p.add_argument('--enabled', help='Enable recording', action='store_true')
1214
+ p.add_argument(
1215
+ '-a',
1216
+ '--video-svc',
1217
+ help=f'video service (default: {DEFAULT_VIDEO_SERVICE})',
1218
+ default=DEFAULT_VIDEO_SERVICE).completer = ComplSvc('videosrv')
1219
+
1220
+ p = sp.add_parser('list', help='list video recordings')
1221
+ p.add_argument(
1222
+ '-a',
1223
+ '--video-svc',
1224
+ help=f'video service (default: {DEFAULT_VIDEO_SERVICE})',
1225
+ default=DEFAULT_VIDEO_SERVICE).completer = ComplSvc('videosrv')
1226
+
1227
+ p = sp.add_parser('edit', help='edit a video recording config')
1228
+ p.add_argument('i', metavar='source')
1229
+ p.add_argument(
1230
+ '-a',
1231
+ '--video-svc',
1232
+ help=f'video service (default: {DEFAULT_VIDEO_SERVICE})',
1233
+ default=DEFAULT_VIDEO_SERVICE).completer = ComplSvc('videosrv')
1234
+
1235
+ p = sp.add_parser('enable', help='enable (start) a video recording')
1236
+ p.add_argument('i', metavar='source')
1237
+ p.add_argument(
1238
+ '-a',
1239
+ '--video-svc',
1240
+ help=f'video service (default: {DEFAULT_VIDEO_SERVICE})',
1241
+ default=DEFAULT_VIDEO_SERVICE).completer = ComplSvc('videosrv')
1242
+
1243
+ p = sp.add_parser('disable', help='disable (stop) a video recording')
1244
+ p.add_argument('i', metavar='source')
1245
+ p.add_argument(
1246
+ '-a',
1247
+ '--video-svc',
1248
+ help=f'video service (default: {DEFAULT_VIDEO_SERVICE})',
1249
+ default=DEFAULT_VIDEO_SERVICE).completer = ComplSvc('videosrv')
1250
+
1251
+ p = sp.add_parser('destroy', help='destroy a video recording')
1252
+ p.add_argument('i', metavar='source')
1253
+ p.add_argument(
1254
+ '-a',
1255
+ '--video-svc',
1256
+ help=f'video service (default: {DEFAULT_VIDEO_SERVICE})',
1257
+ default=DEFAULT_VIDEO_SERVICE).completer = ComplSvc('videosrv')
1258
+
1259
+ p = sp.add_parser(
1260
+ 'export', help='export video recording config(s) to a deployment file')
1261
+ p.add_argument('i', metavar='MASK')
1262
+ p.add_argument(
1263
+ '-a',
1264
+ '--video-svc',
1265
+ help=f'video service (default: {DEFAULT_VIDEO_SERVICE})',
1266
+ default=DEFAULT_VIDEO_SERVICE).completer = ComplSvc('videosrv')
1267
+ p.add_argument('-o', '--output', metavar='FILE',
1268
+ help='output file').completer = ComplDeployFile()
1269
+
1270
+ p = sp.add_parser('deploy',
1271
+ help='deploy video recording(s) from a deployment file')
1272
+ p.add_argument(
1273
+ '-a',
1274
+ '--video-svc',
1275
+ help=f'video service (default: {DEFAULT_VIDEO_SERVICE})',
1276
+ default=DEFAULT_VIDEO_SERVICE).completer = ComplSvc('generator')
1277
+ p.add_argument('-f', '--file', metavar='FILE',
1278
+ help='deployment file').completer = ComplDeployFile()
1279
+
1280
+ p = sp.add_parser(
1281
+ 'undeploy', help='undeploy video recordings(s) using a deployment file')
1282
+ p.add_argument(
1283
+ '-a',
1284
+ '--video-svc',
1285
+ help=f'video service (default: {DEFAULT_VIDEO_SERVICE})',
1286
+ default=DEFAULT_VIDEO_SERVICE).completer = ComplSvc('generator')
1287
+ p.add_argument('-f', '--file', metavar='FILE',
1288
+ help='deployment file').completer = ComplDeployFile()
1289
+
1290
+
1187
1291
  def append_generator_cli(root_sp):
1188
1292
  source_types = [
1189
1293
  'random', 'random_float', 'counter', 'time', 'wave', 'udp_float'
@@ -1589,6 +1693,7 @@ def init_ap():
1589
1693
  'lvar': [],
1590
1694
  'mirror': [],
1591
1695
  'node': [],
1696
+ 'video': [],
1592
1697
  'server': [],
1593
1698
  'spoint': [],
1594
1699
  'system': [],
@@ -1627,6 +1732,7 @@ def init_ap():
1627
1732
  if is_local_shell():
1628
1733
  append_mirror_cli(sp)
1629
1734
  append_node_cli(sp)
1735
+ append_video_cli(sp)
1630
1736
  if is_local_shell():
1631
1737
  append_server_cli(sp)
1632
1738
  append_spoint_cli(sp)
@@ -13,13 +13,11 @@ from rapidtables import format_table, FORMAT_GENERATOR, FORMAT_GENERATOR_COLS
13
13
  from .tools import print_result, ok
14
14
  from .tools import edit_config, edit_remote_file, read_file, write_file
15
15
  from .tools import print_action_result, format_value, prepare_time, err, warn
16
- from .tools import get_node_svc_info, edit_file, get_term_size, exec_cmd, xc
16
+ from .tools import get_node_svc_info, get_term_size, exec_cmd, xc
17
17
  from .tools import get_my_ip, check_local_shell
18
18
  from .client import call_rpc, DEFAULT_REPL_SERVICE, connect
19
19
  from .sharedobj import common, current_command
20
20
 
21
- from . import DEFAULT_REPOSITORY_URL
22
-
23
21
 
24
22
  def eva_control_c(c, pfx=''):
25
23
  check_local_shell()
@@ -27,6 +25,12 @@ def eva_control_c(c, pfx=''):
27
25
  os.system(cmd)
28
26
 
29
27
 
28
+ def format_python_fname(i):
29
+ short_id = i.rsplit('/', 1)[-1].rsplit(':', 1)[-1]
30
+ fname = f'xc/py/{short_id}.py'
31
+ return fname
32
+
33
+
30
34
  class CLI:
31
35
 
32
36
  def __init__(self, *args, **kwargs):
@@ -661,6 +665,11 @@ class CLI:
661
665
  call_rpc('svc.restart', dict(i=i))
662
666
  ok()
663
667
 
668
+ def svc_flash(self, i, file):
669
+ binary = open(file, 'rb').read()
670
+ call_rpc('svc.flash', dict(i=i, binary=binary))
671
+ ok()
672
+
664
673
  def svc_destroy(self, i):
665
674
  call_rpc('svc.undeploy', dict(svcs=[i]))
666
675
  ok()
@@ -1134,8 +1143,13 @@ class CLI:
1134
1143
  print(f'{len(items)} item(s) undeployed')
1135
1144
  print()
1136
1145
 
1137
- def item_create(self, i):
1138
- call_rpc('item.create', dict(i=i))
1146
+ def item_create(self, i, python=False):
1147
+ if python:
1148
+ cfg = {'oid': i, 'action': {'svc': 'eva.controller.py'}}
1149
+ call_rpc('item.deploy', dict(items=[cfg]))
1150
+ return self.edit(format_python_fname(i), 'eva.filemgr.main')
1151
+ else:
1152
+ call_rpc('item.create', dict(i=i))
1139
1153
  ok()
1140
1154
 
1141
1155
  def item_destroy(self, i):
@@ -1146,7 +1160,10 @@ class CLI:
1146
1160
  call_rpc('item.enable', dict(i=i))
1147
1161
  ok()
1148
1162
 
1149
- def item_edit(self, i):
1163
+ def item_edit(self, i, python=False):
1164
+
1165
+ if python:
1166
+ return self.edit(format_python_fname(i), 'eva.filemgr.main')
1150
1167
 
1151
1168
  def deploy_edited_item(cfg, i):
1152
1169
  call_rpc('item.deploy', dict(items=[cfg]))
@@ -1707,6 +1724,99 @@ class CLI:
1707
1724
  call_rpc('kiosk.dev_close', dict(i=i), target=kiosk_svc)
1708
1725
  ok()
1709
1726
 
1727
+ def video_rec_list(self, video_svc):
1728
+ data = call_rpc('rec.list', target=video_svc)
1729
+ print_result(data, cols=['oid', 'keep', 'enabled'])
1730
+
1731
+ def video_rec_create(self, i, keep, enabled, video_svc):
1732
+ payload = {
1733
+ 'oid': i,
1734
+ }
1735
+ if keep:
1736
+ payload['keep'] = keep
1737
+ if enabled:
1738
+ payload['enabled'] = enabled
1739
+ call_rpc('rec.deploy',
1740
+ dict(video_recordings=[payload]),
1741
+ target=video_svc)
1742
+ ok()
1743
+
1744
+ def video_rec_destroy(self, i, video_svc):
1745
+ payload = {
1746
+ 'oid': i,
1747
+ }
1748
+ call_rpc('rec.undeploy',
1749
+ dict(video_recordings=[payload]),
1750
+ target=video_svc)
1751
+ ok()
1752
+
1753
+ def video_rec_enable(self, i, video_svc):
1754
+ call_rpc('rec.enable', dict(i=i), target=video_svc)
1755
+ ok()
1756
+
1757
+ def video_rec_disable(self, i, video_svc):
1758
+ call_rpc('rec.disable', dict(i=i), target=video_svc)
1759
+ ok()
1760
+
1761
+ def video_rec_edit(self, i, video_svc):
1762
+
1763
+ def deploy(cfg, i):
1764
+ call_rpc('rec.deploy',
1765
+ dict(video_recordings=[cfg]),
1766
+ target=video_svc)
1767
+ print(f'video recording config re-deployed: {i}')
1768
+ print()
1769
+
1770
+ config = call_rpc('rec.get_config', dict(i=i), target=video_svc)
1771
+ edit_config(config,
1772
+ f'video.rec|{i}|config',
1773
+ deploy_fn=partial(deploy, i=i))
1774
+
1775
+ def video_rec_export(self, i, video_svc, output=None):
1776
+ c = 0
1777
+ configs = []
1778
+ for source in call_rpc('rec.list', target=video_svc):
1779
+ oid = source['oid']
1780
+ if (i.startswith('*') and oid.endswith(i[1:])) or \
1781
+ (i.endswith('*') and oid.startswith(i[:-1])) or \
1782
+ (i.startswith('*') and i.endswith('*') and i[1:-1] in oid) or \
1783
+ i == oid:
1784
+ c += 1
1785
+ config = call_rpc('rec.get_config',
1786
+ dict(i=oid),
1787
+ target=video_svc)
1788
+ configs.append(config)
1789
+ result = dict(video_recordings=configs)
1790
+ if current_command.json:
1791
+ print_result(result)
1792
+ else:
1793
+ import yaml
1794
+ dump = yaml.dump(result, default_flow_style=False)
1795
+ if output is None:
1796
+ print(dump)
1797
+ else:
1798
+ write_file(output, dump)
1799
+ print(f'{c} video recording configuration(s) exported')
1800
+ print()
1801
+
1802
+ def video_rec_deploy(self, video_svc, file=None):
1803
+ import yaml
1804
+ sources = yaml.safe_load(
1805
+ read_file(file).decode()).pop('video_recordings')
1806
+ call_rpc('rec.deploy', dict(video_recordings=sources), target=video_svc)
1807
+ print(f'{len(sources)} video recording configuration(s) deployed')
1808
+ print()
1809
+
1810
+ def video_rec_undeploy(self, video_svc, file=None):
1811
+ import yaml
1812
+ sources = yaml.safe_load(
1813
+ read_file(file).decode()).pop('video_recordings')
1814
+ call_rpc('rec.undeploy',
1815
+ dict(video_recordings=sources),
1816
+ target=video_svc)
1817
+ print(f'{len(sources)} video recording configuration(s) undeployed')
1818
+ print()
1819
+
1710
1820
  def generator_source_list(self, generator_svc):
1711
1821
  data = call_rpc('source.list', target=generator_svc)
1712
1822
  print_result(data, cols=['name', 'kind', 'active'])
@@ -16,6 +16,7 @@ DEFAULT_ACL_SERVICE = 'eva.aaa.acl'
16
16
  DEFAULT_AUTH_SERVICE = 'eva.aaa.localauth'
17
17
  DEFAULT_KIOSK_SERVICE = 'eva.kioskman.default'
18
18
  DEFAULT_GENERATOR_SERVICE = 'eva.generator.default'
19
+ DEFAULT_VIDEO_SERVICE = 'eva.videosrv.default'
19
20
  DEFAULT_ACCOUNTING_SERVICE = 'eva.aaa.accounting'
20
21
  DEFAULT_ALARM_SERVICE = 'eva.alarm.default'
21
22
 
@@ -96,6 +96,38 @@ class ComplSvcRpcParams:
96
96
  if p.startswith(prefix) and not p in pp:
97
97
  yield f'{p}='
98
98
 
99
+ class ComplAnyFile:
100
+
101
+ def __call__(self, prefix, **kwargs):
102
+ import glob
103
+ expanded = None
104
+
105
+ def expand_user(pfx):
106
+ nonlocal expanded
107
+ if pfx.startswith('~'):
108
+ expanded = os.path.expanduser('~')
109
+ return expanded + pfx[1:]
110
+ else:
111
+ return pfx
112
+
113
+ def contract_user(pfx):
114
+ nonlocal expanded
115
+ if expanded is None:
116
+ return pfx
117
+ else:
118
+ return '~' + pfx[len(expanded):]
119
+
120
+ if not prefix:
121
+ masks = ['*']
122
+ else:
123
+ prefix = expand_user(prefix)
124
+ masks = [f'{prefix}*']
125
+ for mask in masks:
126
+ for f in glob.glob(mask):
127
+ yield contract_user(f)
128
+ for f in glob.glob(f'{prefix}*'):
129
+ if os.path.isdir(f):
130
+ yield contract_user(f'{f}/')
99
131
 
100
132
  class ComplDeployFile:
101
133
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eva-shell
3
- Version: 0.2.36
3
+ Version: 0.2.38
4
4
  Summary: EVA ICS v4 shell
5
5
  Home-page: https://github.com/eva-ics/eva4
6
6
  Author: Bohemia Automation / Altertech
@@ -1,4 +1,4 @@
1
- __version__ = '0.2.36'
1
+ __version__ = '0.2.38'
2
2
 
3
3
  import setuptools
4
4
 
File without changes
File without changes
File without changes
File without changes