np-services 0.1.59__py3-none-any.whl → 0.1.73__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.
Files changed (207) hide show
  1. np_services/__init__.py +8 -8
  2. np_services/open_ephys.py +377 -378
  3. np_services/protocols.py +185 -185
  4. np_services/proxies.py +1489 -1488
  5. np_services/resources/mvr_connector.py +260 -260
  6. np_services/resources/zro.py +325 -325
  7. np_services/scripts/pretest.py +170 -73
  8. np_services/stim_computer_theme_changer.py +41 -41
  9. np_services/utils.py +167 -167
  10. {np_services-0.1.59.dist-info → np_services-0.1.73.dist-info}/METADATA +7 -8
  11. np_services-0.1.73.dist-info/RECORD +15 -0
  12. {np_services-0.1.59.dist-info → np_services-0.1.73.dist-info}/WHEEL +2 -1
  13. {np_services-0.1.59.dist-info → np_services-0.1.73.dist-info}/entry_points.txt +1 -1
  14. np_services-0.1.73.dist-info/top_level.txt +1 -0
  15. np_services/.mypy_cache/.gitignore +0 -2
  16. np_services/.mypy_cache/3.9/@plugins_snapshot.json +0 -1
  17. np_services/.mypy_cache/3.9/__future__.data.json +0 -1
  18. np_services/.mypy_cache/3.9/__future__.meta.json +0 -1
  19. np_services/.mypy_cache/3.9/_ast.data.json +0 -1
  20. np_services/.mypy_cache/3.9/_ast.meta.json +0 -1
  21. np_services/.mypy_cache/3.9/_codecs.data.json +0 -1
  22. np_services/.mypy_cache/3.9/_codecs.meta.json +0 -1
  23. np_services/.mypy_cache/3.9/_collections_abc.data.json +0 -1
  24. np_services/.mypy_cache/3.9/_collections_abc.meta.json +0 -1
  25. np_services/.mypy_cache/3.9/_ctypes.data.json +0 -1
  26. np_services/.mypy_cache/3.9/_ctypes.meta.json +0 -1
  27. np_services/.mypy_cache/3.9/_decimal.data.json +0 -1
  28. np_services/.mypy_cache/3.9/_decimal.meta.json +0 -1
  29. np_services/.mypy_cache/3.9/_random.data.json +0 -1
  30. np_services/.mypy_cache/3.9/_random.meta.json +0 -1
  31. np_services/.mypy_cache/3.9/_socket.data.json +0 -1
  32. np_services/.mypy_cache/3.9/_socket.meta.json +0 -1
  33. np_services/.mypy_cache/3.9/_thread.data.json +0 -1
  34. np_services/.mypy_cache/3.9/_thread.meta.json +0 -1
  35. np_services/.mypy_cache/3.9/_typeshed/__init__.data.json +0 -1
  36. np_services/.mypy_cache/3.9/_typeshed/__init__.meta.json +0 -1
  37. np_services/.mypy_cache/3.9/_warnings.data.json +0 -1
  38. np_services/.mypy_cache/3.9/_warnings.meta.json +0 -1
  39. np_services/.mypy_cache/3.9/_weakref.data.json +0 -1
  40. np_services/.mypy_cache/3.9/_weakref.meta.json +0 -1
  41. np_services/.mypy_cache/3.9/_weakrefset.data.json +0 -1
  42. np_services/.mypy_cache/3.9/_weakrefset.meta.json +0 -1
  43. np_services/.mypy_cache/3.9/_winapi.data.json +0 -1
  44. np_services/.mypy_cache/3.9/_winapi.meta.json +0 -1
  45. np_services/.mypy_cache/3.9/abc.data.json +0 -1
  46. np_services/.mypy_cache/3.9/abc.meta.json +0 -1
  47. np_services/.mypy_cache/3.9/array.data.json +0 -1
  48. np_services/.mypy_cache/3.9/array.meta.json +0 -1
  49. np_services/.mypy_cache/3.9/atexit.data.json +0 -1
  50. np_services/.mypy_cache/3.9/atexit.meta.json +0 -1
  51. np_services/.mypy_cache/3.9/builtins.data.json +0 -1
  52. np_services/.mypy_cache/3.9/builtins.meta.json +0 -1
  53. np_services/.mypy_cache/3.9/codecs.data.json +0 -1
  54. np_services/.mypy_cache/3.9/codecs.meta.json +0 -1
  55. np_services/.mypy_cache/3.9/collections/__init__.data.json +0 -1
  56. np_services/.mypy_cache/3.9/collections/__init__.meta.json +0 -1
  57. np_services/.mypy_cache/3.9/collections/abc.data.json +0 -1
  58. np_services/.mypy_cache/3.9/collections/abc.meta.json +0 -1
  59. np_services/.mypy_cache/3.9/contextlib.data.json +0 -1
  60. np_services/.mypy_cache/3.9/contextlib.meta.json +0 -1
  61. np_services/.mypy_cache/3.9/ctypes/__init__.data.json +0 -1
  62. np_services/.mypy_cache/3.9/ctypes/__init__.meta.json +0 -1
  63. np_services/.mypy_cache/3.9/datetime.data.json +0 -1
  64. np_services/.mypy_cache/3.9/datetime.meta.json +0 -1
  65. np_services/.mypy_cache/3.9/decimal.data.json +0 -1
  66. np_services/.mypy_cache/3.9/decimal.meta.json +0 -1
  67. np_services/.mypy_cache/3.9/email/__init__.data.json +0 -1
  68. np_services/.mypy_cache/3.9/email/__init__.meta.json +0 -1
  69. np_services/.mypy_cache/3.9/email/charset.data.json +0 -1
  70. np_services/.mypy_cache/3.9/email/charset.meta.json +0 -1
  71. np_services/.mypy_cache/3.9/email/contentmanager.data.json +0 -1
  72. np_services/.mypy_cache/3.9/email/contentmanager.meta.json +0 -1
  73. np_services/.mypy_cache/3.9/email/errors.data.json +0 -1
  74. np_services/.mypy_cache/3.9/email/errors.meta.json +0 -1
  75. np_services/.mypy_cache/3.9/email/header.data.json +0 -1
  76. np_services/.mypy_cache/3.9/email/header.meta.json +0 -1
  77. np_services/.mypy_cache/3.9/email/message.data.json +0 -1
  78. np_services/.mypy_cache/3.9/email/message.meta.json +0 -1
  79. np_services/.mypy_cache/3.9/email/policy.data.json +0 -1
  80. np_services/.mypy_cache/3.9/email/policy.meta.json +0 -1
  81. np_services/.mypy_cache/3.9/enum.data.json +0 -1
  82. np_services/.mypy_cache/3.9/enum.meta.json +0 -1
  83. np_services/.mypy_cache/3.9/errno.data.json +0 -1
  84. np_services/.mypy_cache/3.9/errno.meta.json +0 -1
  85. np_services/.mypy_cache/3.9/fractions.data.json +0 -1
  86. np_services/.mypy_cache/3.9/fractions.meta.json +0 -1
  87. np_services/.mypy_cache/3.9/genericpath.data.json +0 -1
  88. np_services/.mypy_cache/3.9/genericpath.meta.json +0 -1
  89. np_services/.mypy_cache/3.9/importlib/__init__.data.json +0 -1
  90. np_services/.mypy_cache/3.9/importlib/__init__.meta.json +0 -1
  91. np_services/.mypy_cache/3.9/importlib/abc.data.json +0 -1
  92. np_services/.mypy_cache/3.9/importlib/abc.meta.json +0 -1
  93. np_services/.mypy_cache/3.9/importlib/machinery.data.json +0 -1
  94. np_services/.mypy_cache/3.9/importlib/machinery.meta.json +0 -1
  95. np_services/.mypy_cache/3.9/importlib/metadata/__init__.data.json +0 -1
  96. np_services/.mypy_cache/3.9/importlib/metadata/__init__.meta.json +0 -1
  97. np_services/.mypy_cache/3.9/io.data.json +0 -1
  98. np_services/.mypy_cache/3.9/io.meta.json +0 -1
  99. np_services/.mypy_cache/3.9/json/__init__.data.json +0 -1
  100. np_services/.mypy_cache/3.9/json/__init__.meta.json +0 -1
  101. np_services/.mypy_cache/3.9/json/decoder.data.json +0 -1
  102. np_services/.mypy_cache/3.9/json/decoder.meta.json +0 -1
  103. np_services/.mypy_cache/3.9/json/encoder.data.json +0 -1
  104. np_services/.mypy_cache/3.9/json/encoder.meta.json +0 -1
  105. np_services/.mypy_cache/3.9/logging/__init__.data.json +0 -1
  106. np_services/.mypy_cache/3.9/logging/__init__.meta.json +0 -1
  107. np_services/.mypy_cache/3.9/math.data.json +0 -1
  108. np_services/.mypy_cache/3.9/math.meta.json +0 -1
  109. np_services/.mypy_cache/3.9/mmap.data.json +0 -1
  110. np_services/.mypy_cache/3.9/mmap.meta.json +0 -1
  111. np_services/.mypy_cache/3.9/np_services/__init__.data.json +0 -1
  112. np_services/.mypy_cache/3.9/np_services/__init__.meta.json +0 -1
  113. np_services/.mypy_cache/3.9/np_services/config.data.json +0 -1
  114. np_services/.mypy_cache/3.9/np_services/config.meta.json +0 -1
  115. np_services/.mypy_cache/3.9/np_services/protocols.data.json +0 -1
  116. np_services/.mypy_cache/3.9/np_services/protocols.meta.json +0 -1
  117. np_services/.mypy_cache/3.9/np_services/zro.data.json +0 -1
  118. np_services/.mypy_cache/3.9/np_services/zro.meta.json +0 -1
  119. np_services/.mypy_cache/3.9/ntpath.data.json +0 -1
  120. np_services/.mypy_cache/3.9/ntpath.meta.json +0 -1
  121. np_services/.mypy_cache/3.9/numbers.data.json +0 -1
  122. np_services/.mypy_cache/3.9/numbers.meta.json +0 -1
  123. np_services/.mypy_cache/3.9/os/__init__.data.json +0 -1
  124. np_services/.mypy_cache/3.9/os/__init__.meta.json +0 -1
  125. np_services/.mypy_cache/3.9/os/path.data.json +0 -1
  126. np_services/.mypy_cache/3.9/os/path.meta.json +0 -1
  127. np_services/.mypy_cache/3.9/pathlib.data.json +0 -1
  128. np_services/.mypy_cache/3.9/pathlib.meta.json +0 -1
  129. np_services/.mypy_cache/3.9/pickle.data.json +0 -1
  130. np_services/.mypy_cache/3.9/pickle.meta.json +0 -1
  131. np_services/.mypy_cache/3.9/platform.data.json +0 -1
  132. np_services/.mypy_cache/3.9/platform.meta.json +0 -1
  133. np_services/.mypy_cache/3.9/posixpath.data.json +0 -1
  134. np_services/.mypy_cache/3.9/posixpath.meta.json +0 -1
  135. np_services/.mypy_cache/3.9/random.data.json +0 -1
  136. np_services/.mypy_cache/3.9/random.meta.json +0 -1
  137. np_services/.mypy_cache/3.9/re.data.json +0 -1
  138. np_services/.mypy_cache/3.9/re.meta.json +0 -1
  139. np_services/.mypy_cache/3.9/shutil.data.json +0 -1
  140. np_services/.mypy_cache/3.9/shutil.meta.json +0 -1
  141. np_services/.mypy_cache/3.9/socket.data.json +0 -1
  142. np_services/.mypy_cache/3.9/socket.meta.json +0 -1
  143. np_services/.mypy_cache/3.9/sre_compile.data.json +0 -1
  144. np_services/.mypy_cache/3.9/sre_compile.meta.json +0 -1
  145. np_services/.mypy_cache/3.9/sre_constants.data.json +0 -1
  146. np_services/.mypy_cache/3.9/sre_constants.meta.json +0 -1
  147. np_services/.mypy_cache/3.9/sre_parse.data.json +0 -1
  148. np_services/.mypy_cache/3.9/sre_parse.meta.json +0 -1
  149. np_services/.mypy_cache/3.9/string.data.json +0 -1
  150. np_services/.mypy_cache/3.9/string.meta.json +0 -1
  151. np_services/.mypy_cache/3.9/subprocess.data.json +0 -1
  152. np_services/.mypy_cache/3.9/subprocess.meta.json +0 -1
  153. np_services/.mypy_cache/3.9/sys.data.json +0 -1
  154. np_services/.mypy_cache/3.9/sys.meta.json +0 -1
  155. np_services/.mypy_cache/3.9/threading.data.json +0 -1
  156. np_services/.mypy_cache/3.9/threading.meta.json +0 -1
  157. np_services/.mypy_cache/3.9/time.data.json +0 -1
  158. np_services/.mypy_cache/3.9/time.meta.json +0 -1
  159. np_services/.mypy_cache/3.9/types.data.json +0 -1
  160. np_services/.mypy_cache/3.9/types.meta.json +0 -1
  161. np_services/.mypy_cache/3.9/typing.data.json +0 -1
  162. np_services/.mypy_cache/3.9/typing.meta.json +0 -1
  163. np_services/.mypy_cache/3.9/typing_extensions.data.json +0 -1
  164. np_services/.mypy_cache/3.9/typing_extensions.meta.json +0 -1
  165. np_services/.mypy_cache/3.9/warnings.data.json +0 -1
  166. np_services/.mypy_cache/3.9/warnings.meta.json +0 -1
  167. np_services/.mypy_cache/3.9/weakref.data.json +0 -1
  168. np_services/.mypy_cache/3.9/weakref.meta.json +0 -1
  169. np_services/.mypy_cache/3.9/zmq/__init__.data.json +0 -1
  170. np_services/.mypy_cache/3.9/zmq/__init__.meta.json +0 -1
  171. np_services/.mypy_cache/3.9/zmq/_typing.data.json +0 -1
  172. np_services/.mypy_cache/3.9/zmq/_typing.meta.json +0 -1
  173. np_services/.mypy_cache/3.9/zmq/backend/__init__.data.json +0 -1
  174. np_services/.mypy_cache/3.9/zmq/backend/__init__.meta.json +0 -1
  175. np_services/.mypy_cache/3.9/zmq/backend/select.data.json +0 -1
  176. np_services/.mypy_cache/3.9/zmq/backend/select.meta.json +0 -1
  177. np_services/.mypy_cache/3.9/zmq/constants.data.json +0 -1
  178. np_services/.mypy_cache/3.9/zmq/constants.meta.json +0 -1
  179. np_services/.mypy_cache/3.9/zmq/error.data.json +0 -1
  180. np_services/.mypy_cache/3.9/zmq/error.meta.json +0 -1
  181. np_services/.mypy_cache/3.9/zmq/sugar/__init__.data.json +0 -1
  182. np_services/.mypy_cache/3.9/zmq/sugar/__init__.meta.json +0 -1
  183. np_services/.mypy_cache/3.9/zmq/sugar/attrsettr.data.json +0 -1
  184. np_services/.mypy_cache/3.9/zmq/sugar/attrsettr.meta.json +0 -1
  185. np_services/.mypy_cache/3.9/zmq/sugar/context.data.json +0 -1
  186. np_services/.mypy_cache/3.9/zmq/sugar/context.meta.json +0 -1
  187. np_services/.mypy_cache/3.9/zmq/sugar/frame.data.json +0 -1
  188. np_services/.mypy_cache/3.9/zmq/sugar/frame.meta.json +0 -1
  189. np_services/.mypy_cache/3.9/zmq/sugar/poll.data.json +0 -1
  190. np_services/.mypy_cache/3.9/zmq/sugar/poll.meta.json +0 -1
  191. np_services/.mypy_cache/3.9/zmq/sugar/socket.data.json +0 -1
  192. np_services/.mypy_cache/3.9/zmq/sugar/socket.meta.json +0 -1
  193. np_services/.mypy_cache/3.9/zmq/sugar/tracker.data.json +0 -1
  194. np_services/.mypy_cache/3.9/zmq/sugar/tracker.meta.json +0 -1
  195. np_services/.mypy_cache/3.9/zmq/sugar/version.data.json +0 -1
  196. np_services/.mypy_cache/3.9/zmq/sugar/version.meta.json +0 -1
  197. np_services/.mypy_cache/3.9/zmq/utils/__init__.data.json +0 -1
  198. np_services/.mypy_cache/3.9/zmq/utils/__init__.meta.json +0 -1
  199. np_services/.mypy_cache/3.9/zmq/utils/interop.data.json +0 -1
  200. np_services/.mypy_cache/3.9/zmq/utils/interop.meta.json +0 -1
  201. np_services/.mypy_cache/3.9/zmq/utils/jsonapi.data.json +0 -1
  202. np_services/.mypy_cache/3.9/zmq/utils/jsonapi.meta.json +0 -1
  203. np_services/.mypy_cache/CACHEDIR.TAG +0 -3
  204. np_services/resources/black_desktop.ps1 +0 -66
  205. np_services/resources/grey_desktop.ps1 +0 -66
  206. np_services/resources/reset_desktop.ps1 +0 -66
  207. np_services-0.1.59.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"