np-services 0.1.69__py3-none-any.whl → 0.1.71__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.
- np_services/__init__.py +8 -8
- np_services/open_ephys.py +377 -378
- np_services/protocols.py +185 -185
- np_services/proxies.py +1489 -1489
- np_services/resources/mvr_connector.py +260 -260
- np_services/resources/zro.py +325 -325
- np_services/scripts/pretest.py +412 -389
- np_services/stim_computer_theme_changer.py +41 -41
- np_services/utils.py +167 -167
- {np_services-0.1.69.dist-info → np_services-0.1.71.dist-info}/METADATA +5 -5
- np_services-0.1.71.dist-info/RECORD +15 -0
- {np_services-0.1.69.dist-info → np_services-0.1.71.dist-info}/WHEEL +2 -1
- {np_services-0.1.69.dist-info → np_services-0.1.71.dist-info}/entry_points.txt +1 -1
- np_services-0.1.71.dist-info/top_level.txt +1 -0
- np_services/.mypy_cache/.gitignore +0 -2
- np_services/.mypy_cache/3.9/@plugins_snapshot.json +0 -1
- np_services/.mypy_cache/3.9/__future__.data.json +0 -1
- np_services/.mypy_cache/3.9/__future__.meta.json +0 -1
- np_services/.mypy_cache/3.9/_ast.data.json +0 -1
- np_services/.mypy_cache/3.9/_ast.meta.json +0 -1
- np_services/.mypy_cache/3.9/_codecs.data.json +0 -1
- np_services/.mypy_cache/3.9/_codecs.meta.json +0 -1
- np_services/.mypy_cache/3.9/_collections_abc.data.json +0 -1
- np_services/.mypy_cache/3.9/_collections_abc.meta.json +0 -1
- np_services/.mypy_cache/3.9/_ctypes.data.json +0 -1
- np_services/.mypy_cache/3.9/_ctypes.meta.json +0 -1
- np_services/.mypy_cache/3.9/_decimal.data.json +0 -1
- np_services/.mypy_cache/3.9/_decimal.meta.json +0 -1
- np_services/.mypy_cache/3.9/_random.data.json +0 -1
- np_services/.mypy_cache/3.9/_random.meta.json +0 -1
- np_services/.mypy_cache/3.9/_socket.data.json +0 -1
- np_services/.mypy_cache/3.9/_socket.meta.json +0 -1
- np_services/.mypy_cache/3.9/_thread.data.json +0 -1
- np_services/.mypy_cache/3.9/_thread.meta.json +0 -1
- np_services/.mypy_cache/3.9/_typeshed/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/_typeshed/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/_warnings.data.json +0 -1
- np_services/.mypy_cache/3.9/_warnings.meta.json +0 -1
- np_services/.mypy_cache/3.9/_weakref.data.json +0 -1
- np_services/.mypy_cache/3.9/_weakref.meta.json +0 -1
- np_services/.mypy_cache/3.9/_weakrefset.data.json +0 -1
- np_services/.mypy_cache/3.9/_weakrefset.meta.json +0 -1
- np_services/.mypy_cache/3.9/_winapi.data.json +0 -1
- np_services/.mypy_cache/3.9/_winapi.meta.json +0 -1
- np_services/.mypy_cache/3.9/abc.data.json +0 -1
- np_services/.mypy_cache/3.9/abc.meta.json +0 -1
- np_services/.mypy_cache/3.9/array.data.json +0 -1
- np_services/.mypy_cache/3.9/array.meta.json +0 -1
- np_services/.mypy_cache/3.9/atexit.data.json +0 -1
- np_services/.mypy_cache/3.9/atexit.meta.json +0 -1
- np_services/.mypy_cache/3.9/builtins.data.json +0 -1
- np_services/.mypy_cache/3.9/builtins.meta.json +0 -1
- np_services/.mypy_cache/3.9/codecs.data.json +0 -1
- np_services/.mypy_cache/3.9/codecs.meta.json +0 -1
- np_services/.mypy_cache/3.9/collections/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/collections/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/collections/abc.data.json +0 -1
- np_services/.mypy_cache/3.9/collections/abc.meta.json +0 -1
- np_services/.mypy_cache/3.9/contextlib.data.json +0 -1
- np_services/.mypy_cache/3.9/contextlib.meta.json +0 -1
- np_services/.mypy_cache/3.9/ctypes/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/ctypes/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/datetime.data.json +0 -1
- np_services/.mypy_cache/3.9/datetime.meta.json +0 -1
- np_services/.mypy_cache/3.9/decimal.data.json +0 -1
- np_services/.mypy_cache/3.9/decimal.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/email/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/charset.data.json +0 -1
- np_services/.mypy_cache/3.9/email/charset.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/contentmanager.data.json +0 -1
- np_services/.mypy_cache/3.9/email/contentmanager.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/errors.data.json +0 -1
- np_services/.mypy_cache/3.9/email/errors.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/header.data.json +0 -1
- np_services/.mypy_cache/3.9/email/header.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/message.data.json +0 -1
- np_services/.mypy_cache/3.9/email/message.meta.json +0 -1
- np_services/.mypy_cache/3.9/email/policy.data.json +0 -1
- np_services/.mypy_cache/3.9/email/policy.meta.json +0 -1
- np_services/.mypy_cache/3.9/enum.data.json +0 -1
- np_services/.mypy_cache/3.9/enum.meta.json +0 -1
- np_services/.mypy_cache/3.9/errno.data.json +0 -1
- np_services/.mypy_cache/3.9/errno.meta.json +0 -1
- np_services/.mypy_cache/3.9/fractions.data.json +0 -1
- np_services/.mypy_cache/3.9/fractions.meta.json +0 -1
- np_services/.mypy_cache/3.9/genericpath.data.json +0 -1
- np_services/.mypy_cache/3.9/genericpath.meta.json +0 -1
- np_services/.mypy_cache/3.9/importlib/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/importlib/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/importlib/abc.data.json +0 -1
- np_services/.mypy_cache/3.9/importlib/abc.meta.json +0 -1
- np_services/.mypy_cache/3.9/importlib/machinery.data.json +0 -1
- np_services/.mypy_cache/3.9/importlib/machinery.meta.json +0 -1
- np_services/.mypy_cache/3.9/importlib/metadata/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/importlib/metadata/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/io.data.json +0 -1
- np_services/.mypy_cache/3.9/io.meta.json +0 -1
- np_services/.mypy_cache/3.9/json/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/json/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/json/decoder.data.json +0 -1
- np_services/.mypy_cache/3.9/json/decoder.meta.json +0 -1
- np_services/.mypy_cache/3.9/json/encoder.data.json +0 -1
- np_services/.mypy_cache/3.9/json/encoder.meta.json +0 -1
- np_services/.mypy_cache/3.9/logging/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/logging/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/math.data.json +0 -1
- np_services/.mypy_cache/3.9/math.meta.json +0 -1
- np_services/.mypy_cache/3.9/mmap.data.json +0 -1
- np_services/.mypy_cache/3.9/mmap.meta.json +0 -1
- np_services/.mypy_cache/3.9/np_services/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/np_services/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/np_services/config.data.json +0 -1
- np_services/.mypy_cache/3.9/np_services/config.meta.json +0 -1
- np_services/.mypy_cache/3.9/np_services/protocols.data.json +0 -1
- np_services/.mypy_cache/3.9/np_services/protocols.meta.json +0 -1
- np_services/.mypy_cache/3.9/np_services/zro.data.json +0 -1
- np_services/.mypy_cache/3.9/np_services/zro.meta.json +0 -1
- np_services/.mypy_cache/3.9/ntpath.data.json +0 -1
- np_services/.mypy_cache/3.9/ntpath.meta.json +0 -1
- np_services/.mypy_cache/3.9/numbers.data.json +0 -1
- np_services/.mypy_cache/3.9/numbers.meta.json +0 -1
- np_services/.mypy_cache/3.9/os/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/os/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/os/path.data.json +0 -1
- np_services/.mypy_cache/3.9/os/path.meta.json +0 -1
- np_services/.mypy_cache/3.9/pathlib.data.json +0 -1
- np_services/.mypy_cache/3.9/pathlib.meta.json +0 -1
- np_services/.mypy_cache/3.9/pickle.data.json +0 -1
- np_services/.mypy_cache/3.9/pickle.meta.json +0 -1
- np_services/.mypy_cache/3.9/platform.data.json +0 -1
- np_services/.mypy_cache/3.9/platform.meta.json +0 -1
- np_services/.mypy_cache/3.9/posixpath.data.json +0 -1
- np_services/.mypy_cache/3.9/posixpath.meta.json +0 -1
- np_services/.mypy_cache/3.9/random.data.json +0 -1
- np_services/.mypy_cache/3.9/random.meta.json +0 -1
- np_services/.mypy_cache/3.9/re.data.json +0 -1
- np_services/.mypy_cache/3.9/re.meta.json +0 -1
- np_services/.mypy_cache/3.9/shutil.data.json +0 -1
- np_services/.mypy_cache/3.9/shutil.meta.json +0 -1
- np_services/.mypy_cache/3.9/socket.data.json +0 -1
- np_services/.mypy_cache/3.9/socket.meta.json +0 -1
- np_services/.mypy_cache/3.9/sre_compile.data.json +0 -1
- np_services/.mypy_cache/3.9/sre_compile.meta.json +0 -1
- np_services/.mypy_cache/3.9/sre_constants.data.json +0 -1
- np_services/.mypy_cache/3.9/sre_constants.meta.json +0 -1
- np_services/.mypy_cache/3.9/sre_parse.data.json +0 -1
- np_services/.mypy_cache/3.9/sre_parse.meta.json +0 -1
- np_services/.mypy_cache/3.9/string.data.json +0 -1
- np_services/.mypy_cache/3.9/string.meta.json +0 -1
- np_services/.mypy_cache/3.9/subprocess.data.json +0 -1
- np_services/.mypy_cache/3.9/subprocess.meta.json +0 -1
- np_services/.mypy_cache/3.9/sys.data.json +0 -1
- np_services/.mypy_cache/3.9/sys.meta.json +0 -1
- np_services/.mypy_cache/3.9/threading.data.json +0 -1
- np_services/.mypy_cache/3.9/threading.meta.json +0 -1
- np_services/.mypy_cache/3.9/time.data.json +0 -1
- np_services/.mypy_cache/3.9/time.meta.json +0 -1
- np_services/.mypy_cache/3.9/types.data.json +0 -1
- np_services/.mypy_cache/3.9/types.meta.json +0 -1
- np_services/.mypy_cache/3.9/typing.data.json +0 -1
- np_services/.mypy_cache/3.9/typing.meta.json +0 -1
- np_services/.mypy_cache/3.9/typing_extensions.data.json +0 -1
- np_services/.mypy_cache/3.9/typing_extensions.meta.json +0 -1
- np_services/.mypy_cache/3.9/warnings.data.json +0 -1
- np_services/.mypy_cache/3.9/warnings.meta.json +0 -1
- np_services/.mypy_cache/3.9/weakref.data.json +0 -1
- np_services/.mypy_cache/3.9/weakref.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/_typing.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/_typing.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/backend/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/backend/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/backend/select.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/backend/select.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/constants.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/constants.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/error.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/error.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/attrsettr.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/attrsettr.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/context.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/context.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/frame.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/frame.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/poll.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/poll.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/socket.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/socket.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/tracker.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/tracker.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/version.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/sugar/version.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/__init__.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/__init__.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/interop.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/interop.meta.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/jsonapi.data.json +0 -1
- np_services/.mypy_cache/3.9/zmq/utils/jsonapi.meta.json +0 -1
- np_services/.mypy_cache/CACHEDIR.TAG +0 -3
- np_services/resources/black_desktop.ps1 +0 -66
- np_services/resources/grey_desktop.ps1 +0 -66
- np_services/resources/reset_desktop.ps1 +0 -66
- np_services-0.1.69.dist-info/RECORD +0 -206
|
@@ -1,260 +1,260 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
import json
|
|
3
|
-
import logging
|
|
4
|
-
import os
|
|
5
|
-
import sys
|
|
6
|
-
from pprint import pformat, pprint
|
|
7
|
-
from socket import *
|
|
8
|
-
|
|
9
|
-
import np_logging
|
|
10
|
-
|
|
11
|
-
logger = np_logging.getLogger(__name__)
|
|
12
|
-
|
|
13
|
-
R = {"mvr_request": ""}
|
|
14
|
-
encoding = "utf-8"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class ResponseBuffer:
|
|
18
|
-
def __init__(self):
|
|
19
|
-
self.read_buffer = []
|
|
20
|
-
|
|
21
|
-
def parse_buffer(self, buf):
|
|
22
|
-
if not buf:
|
|
23
|
-
return []
|
|
24
|
-
buf = buf.decode()
|
|
25
|
-
read_bracket_count = 0
|
|
26
|
-
self.read_buffer.extend(buf)
|
|
27
|
-
count = 0
|
|
28
|
-
messages = []
|
|
29
|
-
for i, c in enumerate(
|
|
30
|
-
self.read_buffer
|
|
31
|
-
): # should maintain an internal pointer so it doesn't redo the list
|
|
32
|
-
count += 1
|
|
33
|
-
# update the "bracket stack"
|
|
34
|
-
if c == "{":
|
|
35
|
-
read_bracket_count += 1
|
|
36
|
-
elif c == "}":
|
|
37
|
-
read_bracket_count -= 1
|
|
38
|
-
|
|
39
|
-
if read_bracket_count == 0: # a full JSON string is available
|
|
40
|
-
try:
|
|
41
|
-
messages.append(
|
|
42
|
-
json.loads("".join(self.read_buffer[i - count + 1 : i + 1]))
|
|
43
|
-
)
|
|
44
|
-
except TypeError:
|
|
45
|
-
logger.warning(
|
|
46
|
-
"%s | Error parsing message: %s",
|
|
47
|
-
__class__.__name__,
|
|
48
|
-
self.read_buffer,
|
|
49
|
-
)
|
|
50
|
-
count = 0
|
|
51
|
-
|
|
52
|
-
# strip prior json messages off the buffer
|
|
53
|
-
if count == 0 and read_bracket_count == 0: # There must be a better way
|
|
54
|
-
self.read_buffer = []
|
|
55
|
-
else:
|
|
56
|
-
self.read_buffer = self.read_buffer[-count:]
|
|
57
|
-
|
|
58
|
-
return messages
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class MVRConnector:
|
|
62
|
-
def __init__(self, args=None):
|
|
63
|
-
self.response_buffer = ResponseBuffer()
|
|
64
|
-
self.device_index_map = {}
|
|
65
|
-
self._errors_since_last_success: int = 0
|
|
66
|
-
self._delete_on_copy: bool = True
|
|
67
|
-
self._recording: bool = False
|
|
68
|
-
self._args = args
|
|
69
|
-
self._mvr_sock = None
|
|
70
|
-
self._host_to_camera_map = {}
|
|
71
|
-
self._mvr_connected = False
|
|
72
|
-
self.comp_ids = [] # temporary to allow for some debugging
|
|
73
|
-
self.output_dir = "c$/ProgramData/AIBS_MPE/MVR/data/"
|
|
74
|
-
try:
|
|
75
|
-
self.connect_to_mvr()
|
|
76
|
-
except Exception as err:
|
|
77
|
-
logger.error(f"failed to connect to mvr:{err}")
|
|
78
|
-
exit()
|
|
79
|
-
|
|
80
|
-
def _recv(self):
|
|
81
|
-
if not self._mvr_connected:
|
|
82
|
-
self.connect_to_mvr()
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
try:
|
|
86
|
-
ret_val = self._mvr_sock.recv(1024)
|
|
87
|
-
except ConnectionResetError as e:
|
|
88
|
-
logger.warning("%s | Connection reset error", __class__.__name__)
|
|
89
|
-
self._mvr_connected = False
|
|
90
|
-
return []
|
|
91
|
-
except:
|
|
92
|
-
return []
|
|
93
|
-
return ret_val
|
|
94
|
-
|
|
95
|
-
def read(self):
|
|
96
|
-
buf = self._recv()
|
|
97
|
-
return self.response_buffer.parse_buffer(buf)
|
|
98
|
-
|
|
99
|
-
def _send(self, msg):
|
|
100
|
-
"""
|
|
101
|
-
msg is a dictionary.
|
|
102
|
-
_send creates json from the dictionary and sends it as a byte object
|
|
103
|
-
"""
|
|
104
|
-
msg = json.dumps(msg).encode()
|
|
105
|
-
logger.debug("%s | Sending: %s", __class__.__name__, msg)
|
|
106
|
-
if not self._mvr_connected:
|
|
107
|
-
self.connect_to_mvr()
|
|
108
|
-
if not self._mvr_connected:
|
|
109
|
-
return
|
|
110
|
-
try:
|
|
111
|
-
self._mvr_sock.send(msg)
|
|
112
|
-
except (ConnectionResetError, ConnectionRefusedError):
|
|
113
|
-
self._mvr_connected = False
|
|
114
|
-
|
|
115
|
-
def connect_to_mvr(self):
|
|
116
|
-
"""
|
|
117
|
-
Creates a STREAM Socket connection to the MultiVideoRecorder
|
|
118
|
-
"""
|
|
119
|
-
self._mvr_sock = socket(AF_INET, SOCK_STREAM)
|
|
120
|
-
self._mvr_sock.settimeout(10.0)
|
|
121
|
-
if self._errors_since_last_success == 0:
|
|
122
|
-
logger.debug(
|
|
123
|
-
"%s | Connecting on %s:%s",
|
|
124
|
-
__class__.__name__,
|
|
125
|
-
self._args["host"],
|
|
126
|
-
self._args["port"],
|
|
127
|
-
)
|
|
128
|
-
try:
|
|
129
|
-
self._mvr_sock.connect((self._args["host"], self._args["port"]))
|
|
130
|
-
self._mvr_connected = True
|
|
131
|
-
except OSError:
|
|
132
|
-
if self._errors_since_last_success == 0:
|
|
133
|
-
logger.debug(
|
|
134
|
-
"%s | Connection failed, will be re-attempted on the next write.",
|
|
135
|
-
__class__.__name__,
|
|
136
|
-
)
|
|
137
|
-
self._errors_since_last_success += 1
|
|
138
|
-
else:
|
|
139
|
-
self._errors_since_last_success = 0
|
|
140
|
-
logger.debug("%s | Connection success: %s", __class__.__name__, self.read())
|
|
141
|
-
|
|
142
|
-
def get_version(self):
|
|
143
|
-
msg = {"mvr_request": "get_version"}
|
|
144
|
-
self._send(msg)
|
|
145
|
-
return self.read()
|
|
146
|
-
|
|
147
|
-
def start_display(self):
|
|
148
|
-
msg = {"mvr_request": "start_display"}
|
|
149
|
-
self._send(msg)
|
|
150
|
-
return self.read()
|
|
151
|
-
|
|
152
|
-
def stop_display(self):
|
|
153
|
-
msg = {"mvr_request": "stop_display"}
|
|
154
|
-
self._send(msg)
|
|
155
|
-
return self.read()
|
|
156
|
-
|
|
157
|
-
def start_record(self, file_name_prefix="", sub_folder=".", record_time=4800):
|
|
158
|
-
self._send(
|
|
159
|
-
{
|
|
160
|
-
"mvr_request": "start_record",
|
|
161
|
-
"sub_folder": sub_folder,
|
|
162
|
-
"file_name_prefix": file_name_prefix,
|
|
163
|
-
"recording_time": record_time,
|
|
164
|
-
}
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
def start_single_record(
|
|
168
|
-
self, host, file_name_prefix="", sub_folder=".", record_time=4800
|
|
169
|
-
):
|
|
170
|
-
print(f"start single record on {host}")
|
|
171
|
-
if host not in self._host_to_camera_map:
|
|
172
|
-
comp = self.host_to_comp["host"]
|
|
173
|
-
logger.warning(
|
|
174
|
-
f"Start Single Record: Can not find host {host} ({comp}) associated with a camera."
|
|
175
|
-
)
|
|
176
|
-
return
|
|
177
|
-
|
|
178
|
-
self._send(
|
|
179
|
-
{
|
|
180
|
-
"mvr_request": "start_record",
|
|
181
|
-
"camera_indices": [
|
|
182
|
-
{"camera_index": f"Camera {self._host_to_camera_map[host]}"}
|
|
183
|
-
],
|
|
184
|
-
"sub_folder": sub_folder,
|
|
185
|
-
"file_name_prefix": file_name_prefix,
|
|
186
|
-
"recording_time": record_time,
|
|
187
|
-
}
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
def set_automated_ui(self, state):
|
|
191
|
-
if state:
|
|
192
|
-
message = {"mvr_request": "set_automated_ui"}
|
|
193
|
-
|
|
194
|
-
else:
|
|
195
|
-
message = {"mvr_request": "set_unautomated_ui"}
|
|
196
|
-
|
|
197
|
-
self._send(message)
|
|
198
|
-
return self.read()
|
|
199
|
-
|
|
200
|
-
def stop_record(self):
|
|
201
|
-
msg = {"mvr_request": "stop_record"}
|
|
202
|
-
self._send(msg)
|
|
203
|
-
# return self.read()
|
|
204
|
-
|
|
205
|
-
def stop_single_record(self, host):
|
|
206
|
-
if host not in self._host_to_camera_map:
|
|
207
|
-
comp = self.host_to_comp["host"]
|
|
208
|
-
logger.warning(
|
|
209
|
-
f"Stop Single Record: Can not find host {host} ({comp}) associated with a camera."
|
|
210
|
-
)
|
|
211
|
-
return
|
|
212
|
-
|
|
213
|
-
cam_id = self._host_to_camera_map[host]
|
|
214
|
-
message = {
|
|
215
|
-
"mvr_request": "stop_record",
|
|
216
|
-
"camera_indices": [f"Camera {cam_id}",],
|
|
217
|
-
}
|
|
218
|
-
self._send(message)
|
|
219
|
-
|
|
220
|
-
def take_snapshot(self):
|
|
221
|
-
self._send({"mvr_request": "take_snapshot"})
|
|
222
|
-
|
|
223
|
-
def define_hosts(self, hosts):
|
|
224
|
-
self._host_to_camera_map = {}
|
|
225
|
-
for idx, host in enumerate(hosts):
|
|
226
|
-
self._host_to_camera_map[host] = idx + 1
|
|
227
|
-
|
|
228
|
-
# print(f'Host To Camera Map: {pformat(self._host_to_camera_map)}')
|
|
229
|
-
self.host_to_comp = list(zip(hosts, self.comp_ids))
|
|
230
|
-
|
|
231
|
-
def request_camera_ids(self):
|
|
232
|
-
self._send({"mvr_request": "get_camera_ids"})
|
|
233
|
-
return self.read()
|
|
234
|
-
|
|
235
|
-
def highlight_camera(self, device_name):
|
|
236
|
-
print(self.device_index_map)
|
|
237
|
-
index = self.device_index_map[device_name]
|
|
238
|
-
msg = {"mvr_request": "toggle_highlight_camera", "camera": index}
|
|
239
|
-
self._send(msg)
|
|
240
|
-
|
|
241
|
-
def unhighlight_camera(self, panel):
|
|
242
|
-
msg = {"mvr_request": "unhighlight_panel"}
|
|
243
|
-
self._send(msg)
|
|
244
|
-
return self.read()
|
|
245
|
-
|
|
246
|
-
def get_state(self):
|
|
247
|
-
if self._recording:
|
|
248
|
-
return "BUSY", "RECORDING"
|
|
249
|
-
else:
|
|
250
|
-
return "READY", ""
|
|
251
|
-
|
|
252
|
-
def shutdown(self):
|
|
253
|
-
self._rep_sock.close()
|
|
254
|
-
|
|
255
|
-
def _onclose(self):
|
|
256
|
-
self.shutdown()
|
|
257
|
-
|
|
258
|
-
@property
|
|
259
|
-
def platform_info(self):
|
|
260
|
-
return "0.1.0"
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from pprint import pformat, pprint
|
|
7
|
+
from socket import *
|
|
8
|
+
|
|
9
|
+
import np_logging
|
|
10
|
+
|
|
11
|
+
logger = np_logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
R = {"mvr_request": ""}
|
|
14
|
+
encoding = "utf-8"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ResponseBuffer:
|
|
18
|
+
def __init__(self):
|
|
19
|
+
self.read_buffer = []
|
|
20
|
+
|
|
21
|
+
def parse_buffer(self, buf):
|
|
22
|
+
if not buf:
|
|
23
|
+
return []
|
|
24
|
+
buf = buf.decode()
|
|
25
|
+
read_bracket_count = 0
|
|
26
|
+
self.read_buffer.extend(buf)
|
|
27
|
+
count = 0
|
|
28
|
+
messages = []
|
|
29
|
+
for i, c in enumerate(
|
|
30
|
+
self.read_buffer
|
|
31
|
+
): # should maintain an internal pointer so it doesn't redo the list
|
|
32
|
+
count += 1
|
|
33
|
+
# update the "bracket stack"
|
|
34
|
+
if c == "{":
|
|
35
|
+
read_bracket_count += 1
|
|
36
|
+
elif c == "}":
|
|
37
|
+
read_bracket_count -= 1
|
|
38
|
+
|
|
39
|
+
if read_bracket_count == 0: # a full JSON string is available
|
|
40
|
+
try:
|
|
41
|
+
messages.append(
|
|
42
|
+
json.loads("".join(self.read_buffer[i - count + 1 : i + 1]))
|
|
43
|
+
)
|
|
44
|
+
except TypeError:
|
|
45
|
+
logger.warning(
|
|
46
|
+
"%s | Error parsing message: %s",
|
|
47
|
+
__class__.__name__,
|
|
48
|
+
self.read_buffer,
|
|
49
|
+
)
|
|
50
|
+
count = 0
|
|
51
|
+
|
|
52
|
+
# strip prior json messages off the buffer
|
|
53
|
+
if count == 0 and read_bracket_count == 0: # There must be a better way
|
|
54
|
+
self.read_buffer = []
|
|
55
|
+
else:
|
|
56
|
+
self.read_buffer = self.read_buffer[-count:]
|
|
57
|
+
|
|
58
|
+
return messages
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class MVRConnector:
|
|
62
|
+
def __init__(self, args=None):
|
|
63
|
+
self.response_buffer = ResponseBuffer()
|
|
64
|
+
self.device_index_map = {}
|
|
65
|
+
self._errors_since_last_success: int = 0
|
|
66
|
+
self._delete_on_copy: bool = True
|
|
67
|
+
self._recording: bool = False
|
|
68
|
+
self._args = args
|
|
69
|
+
self._mvr_sock = None
|
|
70
|
+
self._host_to_camera_map = {}
|
|
71
|
+
self._mvr_connected = False
|
|
72
|
+
self.comp_ids = [] # temporary to allow for some debugging
|
|
73
|
+
self.output_dir = "c$/ProgramData/AIBS_MPE/MVR/data/"
|
|
74
|
+
try:
|
|
75
|
+
self.connect_to_mvr()
|
|
76
|
+
except Exception as err:
|
|
77
|
+
logger.error(f"failed to connect to mvr:{err}")
|
|
78
|
+
exit()
|
|
79
|
+
|
|
80
|
+
def _recv(self):
|
|
81
|
+
if not self._mvr_connected:
|
|
82
|
+
self.connect_to_mvr()
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
ret_val = self._mvr_sock.recv(1024)
|
|
87
|
+
except ConnectionResetError as e:
|
|
88
|
+
logger.warning("%s | Connection reset error", __class__.__name__)
|
|
89
|
+
self._mvr_connected = False
|
|
90
|
+
return []
|
|
91
|
+
except:
|
|
92
|
+
return []
|
|
93
|
+
return ret_val
|
|
94
|
+
|
|
95
|
+
def read(self):
|
|
96
|
+
buf = self._recv()
|
|
97
|
+
return self.response_buffer.parse_buffer(buf)
|
|
98
|
+
|
|
99
|
+
def _send(self, msg):
|
|
100
|
+
"""
|
|
101
|
+
msg is a dictionary.
|
|
102
|
+
_send creates json from the dictionary and sends it as a byte object
|
|
103
|
+
"""
|
|
104
|
+
msg = json.dumps(msg).encode()
|
|
105
|
+
logger.debug("%s | Sending: %s", __class__.__name__, msg)
|
|
106
|
+
if not self._mvr_connected:
|
|
107
|
+
self.connect_to_mvr()
|
|
108
|
+
if not self._mvr_connected:
|
|
109
|
+
return
|
|
110
|
+
try:
|
|
111
|
+
self._mvr_sock.send(msg)
|
|
112
|
+
except (ConnectionResetError, ConnectionRefusedError):
|
|
113
|
+
self._mvr_connected = False
|
|
114
|
+
|
|
115
|
+
def connect_to_mvr(self):
|
|
116
|
+
"""
|
|
117
|
+
Creates a STREAM Socket connection to the MultiVideoRecorder
|
|
118
|
+
"""
|
|
119
|
+
self._mvr_sock = socket(AF_INET, SOCK_STREAM)
|
|
120
|
+
self._mvr_sock.settimeout(10.0)
|
|
121
|
+
if self._errors_since_last_success == 0:
|
|
122
|
+
logger.debug(
|
|
123
|
+
"%s | Connecting on %s:%s",
|
|
124
|
+
__class__.__name__,
|
|
125
|
+
self._args["host"],
|
|
126
|
+
self._args["port"],
|
|
127
|
+
)
|
|
128
|
+
try:
|
|
129
|
+
self._mvr_sock.connect((self._args["host"], self._args["port"]))
|
|
130
|
+
self._mvr_connected = True
|
|
131
|
+
except OSError:
|
|
132
|
+
if self._errors_since_last_success == 0:
|
|
133
|
+
logger.debug(
|
|
134
|
+
"%s | Connection failed, will be re-attempted on the next write.",
|
|
135
|
+
__class__.__name__,
|
|
136
|
+
)
|
|
137
|
+
self._errors_since_last_success += 1
|
|
138
|
+
else:
|
|
139
|
+
self._errors_since_last_success = 0
|
|
140
|
+
logger.debug("%s | Connection success: %s", __class__.__name__, self.read())
|
|
141
|
+
|
|
142
|
+
def get_version(self):
|
|
143
|
+
msg = {"mvr_request": "get_version"}
|
|
144
|
+
self._send(msg)
|
|
145
|
+
return self.read()
|
|
146
|
+
|
|
147
|
+
def start_display(self):
|
|
148
|
+
msg = {"mvr_request": "start_display"}
|
|
149
|
+
self._send(msg)
|
|
150
|
+
return self.read()
|
|
151
|
+
|
|
152
|
+
def stop_display(self):
|
|
153
|
+
msg = {"mvr_request": "stop_display"}
|
|
154
|
+
self._send(msg)
|
|
155
|
+
return self.read()
|
|
156
|
+
|
|
157
|
+
def start_record(self, file_name_prefix="", sub_folder=".", record_time=4800):
|
|
158
|
+
self._send(
|
|
159
|
+
{
|
|
160
|
+
"mvr_request": "start_record",
|
|
161
|
+
"sub_folder": sub_folder,
|
|
162
|
+
"file_name_prefix": file_name_prefix,
|
|
163
|
+
"recording_time": record_time,
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def start_single_record(
|
|
168
|
+
self, host, file_name_prefix="", sub_folder=".", record_time=4800
|
|
169
|
+
):
|
|
170
|
+
print(f"start single record on {host}")
|
|
171
|
+
if host not in self._host_to_camera_map:
|
|
172
|
+
comp = self.host_to_comp["host"]
|
|
173
|
+
logger.warning(
|
|
174
|
+
f"Start Single Record: Can not find host {host} ({comp}) associated with a camera."
|
|
175
|
+
)
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
self._send(
|
|
179
|
+
{
|
|
180
|
+
"mvr_request": "start_record",
|
|
181
|
+
"camera_indices": [
|
|
182
|
+
{"camera_index": f"Camera {self._host_to_camera_map[host]}"}
|
|
183
|
+
],
|
|
184
|
+
"sub_folder": sub_folder,
|
|
185
|
+
"file_name_prefix": file_name_prefix,
|
|
186
|
+
"recording_time": record_time,
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
def set_automated_ui(self, state):
|
|
191
|
+
if state:
|
|
192
|
+
message = {"mvr_request": "set_automated_ui"}
|
|
193
|
+
|
|
194
|
+
else:
|
|
195
|
+
message = {"mvr_request": "set_unautomated_ui"}
|
|
196
|
+
|
|
197
|
+
self._send(message)
|
|
198
|
+
return self.read()
|
|
199
|
+
|
|
200
|
+
def stop_record(self):
|
|
201
|
+
msg = {"mvr_request": "stop_record"}
|
|
202
|
+
self._send(msg)
|
|
203
|
+
# return self.read()
|
|
204
|
+
|
|
205
|
+
def stop_single_record(self, host):
|
|
206
|
+
if host not in self._host_to_camera_map:
|
|
207
|
+
comp = self.host_to_comp["host"]
|
|
208
|
+
logger.warning(
|
|
209
|
+
f"Stop Single Record: Can not find host {host} ({comp}) associated with a camera."
|
|
210
|
+
)
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
cam_id = self._host_to_camera_map[host]
|
|
214
|
+
message = {
|
|
215
|
+
"mvr_request": "stop_record",
|
|
216
|
+
"camera_indices": [f"Camera {cam_id}",],
|
|
217
|
+
}
|
|
218
|
+
self._send(message)
|
|
219
|
+
|
|
220
|
+
def take_snapshot(self):
|
|
221
|
+
self._send({"mvr_request": "take_snapshot"})
|
|
222
|
+
|
|
223
|
+
def define_hosts(self, hosts):
|
|
224
|
+
self._host_to_camera_map = {}
|
|
225
|
+
for idx, host in enumerate(hosts):
|
|
226
|
+
self._host_to_camera_map[host] = idx + 1
|
|
227
|
+
|
|
228
|
+
# print(f'Host To Camera Map: {pformat(self._host_to_camera_map)}')
|
|
229
|
+
self.host_to_comp = list(zip(hosts, self.comp_ids))
|
|
230
|
+
|
|
231
|
+
def request_camera_ids(self):
|
|
232
|
+
self._send({"mvr_request": "get_camera_ids"})
|
|
233
|
+
return self.read()
|
|
234
|
+
|
|
235
|
+
def highlight_camera(self, device_name):
|
|
236
|
+
print(self.device_index_map)
|
|
237
|
+
index = self.device_index_map[device_name]
|
|
238
|
+
msg = {"mvr_request": "toggle_highlight_camera", "camera": index}
|
|
239
|
+
self._send(msg)
|
|
240
|
+
|
|
241
|
+
def unhighlight_camera(self, panel):
|
|
242
|
+
msg = {"mvr_request": "unhighlight_panel"}
|
|
243
|
+
self._send(msg)
|
|
244
|
+
return self.read()
|
|
245
|
+
|
|
246
|
+
def get_state(self):
|
|
247
|
+
if self._recording:
|
|
248
|
+
return "BUSY", "RECORDING"
|
|
249
|
+
else:
|
|
250
|
+
return "READY", ""
|
|
251
|
+
|
|
252
|
+
def shutdown(self):
|
|
253
|
+
self._rep_sock.close()
|
|
254
|
+
|
|
255
|
+
def _onclose(self):
|
|
256
|
+
self.shutdown()
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
def platform_info(self):
|
|
260
|
+
return "0.1.0"
|