MultiPyVu 3.5.4__tar.gz → 3.8.0__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.
Files changed (72) hide show
  1. {multipyvu-3.5.4 → multipyvu-3.8.0}/LICENSE +20 -20
  2. {multipyvu-3.5.4/src/MultiPyVu.egg-info → multipyvu-3.8.0}/PKG-INFO +39 -38
  3. {multipyvu-3.5.4 → multipyvu-3.8.0}/README.md +36 -12
  4. {multipyvu-3.5.4 → multipyvu-3.8.0}/pyproject.toml +11 -4
  5. multipyvu-3.8.0/setup.py +27 -0
  6. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/CommandChamber.py +35 -32
  7. multipyvu-3.5.4/src/MultiPyVu/Command_factory.py → multipyvu-3.8.0/src/MultiPyVu/CommandFactory.py +103 -3
  8. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/CommandField.py +175 -94
  9. multipyvu-3.8.0/src/MultiPyVu/CommandFieldSetPoints.py +398 -0
  10. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/CommandMultiVu.py +27 -0
  11. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/CommandRotator.py +42 -36
  12. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/CommandSdo.py +18 -5
  13. multipyvu-3.8.0/src/MultiPyVu/CommandTempSetPoints.py +257 -0
  14. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/CommandTemperature.py +130 -58
  15. multipyvu-3.8.0/src/MultiPyVu/CommandVectorMagnet.py +780 -0
  16. multipyvu-3.8.0/src/MultiPyVu/CommandWaitFor.py +851 -0
  17. multipyvu-3.8.0/src/MultiPyVu/ICommand.py +522 -0
  18. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/IEventManager.py +42 -42
  19. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/IServer.py +68 -68
  20. multipyvu-3.8.0/src/MultiPyVu/MultiVuClient.py +849 -0
  21. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/MultiVuClient_base.py +562 -521
  22. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/MultiVuDataFile/MultiVuDataFile.py +4 -0
  23. multipyvu-3.8.0/src/MultiPyVu/MultiVuDataFile/__version.py +2 -0
  24. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/MultiVuDataFile/is_pathname_valid.py +3 -3
  25. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/MultiVuServer.py +405 -388
  26. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/ParseInputs.py +14 -14
  27. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/SocketMessage.py +16 -2
  28. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/SocketMessageClient.py +526 -503
  29. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/SocketMessageServer.py +912 -867
  30. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/__init__.py +1 -1
  31. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/__main__.py +3 -4
  32. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/__version.py +1 -1
  33. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/exceptions.py +1 -3
  34. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/generate_sdo_objects.py +6 -2
  35. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/gui/Controller.py +208 -246
  36. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/gui/IController.py +132 -132
  37. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/gui/IView.py +97 -83
  38. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/gui/ViewFactory.py +26 -26
  39. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/gui/ViewTk.py +687 -532
  40. multipyvu-3.8.0/src/MultiPyVu/gui/font_loader.py +204 -0
  41. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/instrument.py +62 -6
  42. multipyvu-3.8.0/src/MultiPyVu/logging_config.py +111 -0
  43. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/project_vars.py +13 -4
  44. multipyvu-3.8.0/src/MultiPyVu/scripts/helper_scripts.py +28 -0
  45. multipyvu-3.8.0/src/MultiPyVu/scripts/helper_scripts_client.py +54 -0
  46. {multipyvu-3.5.4 → multipyvu-3.8.0/src/MultiPyVu.egg-info}/PKG-INFO +39 -38
  47. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu.egg-info/SOURCES.txt +6 -2
  48. multipyvu-3.5.4/setup.py +0 -61
  49. multipyvu-3.5.4/src/MultiPyVu/CommandWaitFor.py +0 -507
  50. multipyvu-3.5.4/src/MultiPyVu/ICommand.py +0 -322
  51. multipyvu-3.5.4/src/MultiPyVu/MultiVuClient.py +0 -513
  52. multipyvu-3.5.4/src/MultiPyVu/MultiVuDataFile/__version.py +0 -2
  53. multipyvu-3.5.4/src/MultiPyVu/logging_config.py +0 -76
  54. multipyvu-3.5.4/src/MultiPyVu/scripts/helper_scripts.py +0 -118
  55. multipyvu-3.5.4/src/MultiPyVu/scripts/whats_my_ip_address.cmd +0 -21
  56. {multipyvu-3.5.4 → multipyvu-3.8.0}/setup.cfg +0 -0
  57. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/BRT.py +0 -0
  58. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/MultiVuDataFile/__init__.py +0 -0
  59. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/check_windows_esc.py +0 -0
  60. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/font/Play-Bold.ttf +0 -0
  61. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/font/Play-Regular.ttf +0 -0
  62. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/font/__init__.py +0 -0
  63. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/gui/__init__.py +0 -0
  64. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/images/Q.png +0 -0
  65. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/images/QD_logo.jpg +0 -0
  66. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/images/__init__.py +0 -0
  67. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/logging_config.yaml +0 -0
  68. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/scripts/__init__.py +0 -0
  69. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu/sdo_object.py +0 -0
  70. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu.egg-info/dependency_links.txt +0 -0
  71. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu.egg-info/requires.txt +0 -0
  72. {multipyvu-3.5.4 → multipyvu-3.8.0}/src/MultiPyVu.egg-info/top_level.txt +0 -0
@@ -1,21 +1,21 @@
1
- MIT License (MIT)
2
-
3
- Copyright (c) 2023 Quantum Design, Inc
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1
+ MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Quantum Design, Inc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  SOFTWARE.
@@ -1,41 +1,20 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MultiPyVu
3
- Version: 3.5.4
3
+ Version: 3.8.0
4
4
  Summary: Control MultiVu using Python
5
5
  Author-email: Damon D Jackson <djackson@qdusa.com>
6
6
  Maintainer-email: "Quantum Design, Inc." <apps@qdusa.com>
7
- License: MIT License (MIT)
8
-
9
- Copyright (c) 2023 Quantum Design, Inc
10
-
11
- Permission is hereby granted, free of charge, to any person obtaining a copy
12
- of this software and associated documentation files (the "Software"), to deal
13
- in the Software without restriction, including without limitation the rights
14
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
- copies of the Software, and to permit persons to whom the Software is
16
- furnished to do so, subject to the following conditions:
17
-
18
- The above copyright notice and this permission notice shall be included in all
19
- copies or substantial portions of the Software.
20
-
21
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
- SOFTWARE.
7
+ License-Expression: MIT
28
8
  Project-URL: Quantum Design, https://qdusa.com
29
9
  Project-URL: Pharos, https://www.qdusa.com/register/account/login
30
10
  Keywords: Quantum Design,QD,MultiVu,PPMS,DynaCool,MPMS3,VersaLab,OptiCool
31
11
  Classifier: Programming Language :: Python :: 3
32
- Classifier: License :: OSI Approved :: MIT License
33
12
  Classifier: Operating System :: OS Independent
34
13
  Classifier: Intended Audience :: Science/Research
35
14
  Classifier: Topic :: Scientific/Engineering :: Physics
36
15
  Classifier: Topic :: Scientific/Engineering :: Chemistry
37
16
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
38
- Requires-Python: >=3.9
17
+ Requires-Python: >=3.7
39
18
  Description-Content-Type: text/markdown
40
19
  License-File: LICENSE
41
20
  Requires-Dist: pandas
@@ -43,9 +22,7 @@ Requires-Dist: pywin32>=300; platform_system == "Windows"
43
22
  Requires-Dist: pillow
44
23
  Requires-Dist: pyyaml
45
24
  Dynamic: license-file
46
- Dynamic: requires-dist
47
25
  Dynamic: requires-python
48
- Dynamic: summary
49
26
 
50
27
  ![qd_logo](https://qdusa.com/images/QD_logo.png)
51
28
  # MultiPyVu
@@ -82,13 +59,13 @@ The components of MultiPyVu enable access to the set and read the temperature, f
82
59
 
83
60
  ### Module Requirements<a class="anchor" id="requirements"></a>
84
61
  MultiPyVu uses the following modules:
85
- - python version 3.10 or higher
62
+ - python version 3.7 or higher
86
63
  - pywin32 - version 300 or higher.
87
64
  - pandas - data read back from a *.dat* file is a Pandas Dataframe
88
65
  - pillow - supports server gui
89
66
  - pyyaml - supports logging
90
67
 
91
- For the Python 3 distribution Quantum Design recommends [Anaconda](https://www.anaconda.com/products/individual) as it includes most modules needed for this server and other packages useful for scientific computing. This code was built and tested using Python 3.8. If you are not sure which version of Python you are using, from a command prompt type:
68
+ To find which version of Python is used on the local computer, from a command prompt type:
92
69
  ```
93
70
  python --version
94
71
  ```
@@ -109,13 +86,13 @@ Remote Connection\example_MVDataFile_VISA.py | Simple example showing how to rou
109
86
  Data Processing\example_save_open_dat.py | Script showing how to save and read a MultiVu *.dat* file into a Pandas DataFrame, then plot with matplotlib.
110
87
  Measuring\example_stabilize.py | Measures the temperature while stabilizing at each temperature.
111
88
  Measuring\example_sweep.py | Measures the temperature while sweeping the temperature.
112
- Options\example_aux_therm.py | Gets the temperature of the auxilary thermometer from the OptiCool.
89
+ Measuring\example_get_setpoints.py | Shows how to get the temperature and magnetic field setpoints.
90
+ Options\example_aux_therm.py | Gets the temperature of the auxiliary thermometer from the OptiCool.
113
91
  Options\example_resistivity_option.py | Demonstrates how to set up the BRT module bridges for resistivity measurements and how to save the data.
114
92
  Options\example_horizontal_rotator.py | Demonstrates how to move the horizontal rotator to a new position.
115
- UsefulBatchFiles\whats_my_ip_address.cmd | This batch file script prints out the IP address for the computer, providing an easy way to get the server IP address needed for remote operation. Alternatively, the gui can be used to get the IP address by calling ```python -m MultiPyVu```.
116
- UsefulBatchFiles\show_process_with_port.cmd | Shows that active processes are running and what port is being used. By default, this looks for processes running on port 5000. To query a different port number, append it to the command line arguments. ```$ show_processes_with_port.cmd 4567```
93
+ UsefulBatchFiles\show_processes_with_port.cmd | Shows that active processes are running and what port is being used. By default, this looks for processes running on port 27183. To query a different port number, append it to the command line arguments. ```$ show_processes_with_port.cmd 45678```
117
94
  UsefulBatchFiles\RunServer.cmd | This runs the server GUI.
118
- UsefulBatchFiles\kill_process.cmd | This ends the processes with the specified PID (which can be identified using show_process_with_port.cmd). Run using ```$ kill_process.cmd 13579```
95
+ UsefulBatchFiles\kill_process.cmd | This ends the processes with the specified PID (which can be identified using show_processes_with_port.cmd). Run using ```$ kill_process.cmd 13579```
119
96
 
120
97
  ### Getting Started<a class="anchor" id="getting-started"></a>
121
98
  Once the MultiPyVu module has been installed, be sure that the MultiVu executable is running on the PC connected to the cryostat before starting the server. For testing purposes, you can use MultiVu in simulation mode on an office computer, or run mpv.Server with the -s flag which runs the python code in scaffolding that mimics MultiVu. This is especially helpful for developing a script on a computer that does not have MultiVu running (Mac, Linux, or any PC without MultiVu). When running MultiVu and MultiPyVu, be sure that they are running under the same permissions.
@@ -181,7 +158,7 @@ with mpv.Client('127.0.0.1') as client:
181
158
  # do post-processing once the client has been closed
182
159
  ```
183
160
 
184
- If the host or port are not default values (localhost and 5000, respectively), then these parameters must be specified when instantiating MultiPyVu.Client().
161
+ If the host or port are not default values (localhost and 27183, respectively), then these parameters must be specified when instantiating MultiPyVu.Client().
185
162
 
186
163
  Alternatively, one can start a connection to the server using:
187
164
  ```python
@@ -191,7 +168,7 @@ client.open()
191
168
  client.close_client()
192
169
  # do post-processing once the client has been closed
193
170
  ```
194
- Using the above method could end up with the server hung up because errors need to be correctly accounted for. It is safer to use the Client as a context manager using a with-block.
171
+ Using the above method could end up with the server hung up because errors need to be correctly accounted for. It is safer to use the Client as a context manager using a with-block. In addition, a client object can only connect to the server once. For a second connection, one must instantiate a new client instance.
195
172
 
196
173
  The client can also close the server directly using:
197
174
  ```python
@@ -239,6 +216,10 @@ The <enum_options> mode is set using the client.temperature.approach_mode enum,
239
216
  ```python
240
217
  temperature, status = client.get_temperature()
241
218
  ```
219
+ One can also retrieve the setpoint, rate, and approach mode:
220
+ ```python
221
+ temperature, rate, approach = client.get_temperature_setpoints()
222
+ ```
242
223
 
243
224
  **Field**<a class="anchor" id="field"></a>
244
225
  ```python
@@ -260,6 +241,10 @@ The field and status are read back using:
260
241
  ```python
261
242
  field, status = client.get_field()
262
243
  ```
244
+ One can also retrieve the setpoint, rate, and approach mode:
245
+ ```python
246
+ field, rate, approach, driven = client.get_field_setpoints()
247
+ ```
263
248
 
264
249
  **Chamber**<a class="anchor" id="chamber"></a>
265
250
  ```python
@@ -325,7 +310,7 @@ For DynaCool, VersaLab, and PPMS customers with the horizontal rotator option, M
325
310
  Once configured, the following commands are simple to use:
326
311
  ```python
327
312
  position = 374.5
328
- rate_deg_per_sec = 100.0
313
+ rate_deg_per_sec = 30.0
329
314
  client.set_position(position, rate_deg_per_sec)
330
315
  pos, status = client.get_position()
331
316
  ```
@@ -400,7 +385,7 @@ The server status can be queried from the command line. First, we can see if th
400
385
  ```cmd
401
386
  $ python -m MultiPyVu -running
402
387
  ```
403
- By default, this queries the server at IP address = localhost and port = 5000. To query a different address, use the *-ip=* or *-p=* flags.
388
+ By default, this queries the server at IP address = localhost and port = 27183. To query a different address, use the *-ip=* or *-p=* flags.
404
389
 
405
390
  Similarly, in order to get the server status at a specific ip address, use:
406
391
  ```cmd
@@ -439,8 +424,8 @@ with mpv.Server(flags=['-s', 'DYNACOOL']) as server:
439
424
 
440
425
  ### Troubleshooting<a class="anchor" id="troubleshooting"></a>
441
426
  Typical connection issues are due to:
442
- - Firewall. You might need to allow connections on port 5000 (the default port number) in your firewall. Windows Firewall may cause issues depending upon your network settings. If the server is open and a connection fails disabling Firewalls temporarily may be your best option to troubleshoot. If your computers are on the same domain disabling the Domain Firewall may be sufficient.
443
- - Port conflict. If port 5000 is in use, a different number can be specified when instantiating MultiPyVu.Server() and MultiPyVu.Client().
427
+ - Firewall. You might need to allow connections on port 27183 (the default port number) in your firewall. Windows Firewall may cause issues depending upon your network settings. If the server is open and a connection fails disabling Firewalls temporarily may be your best option to troubleshoot. If your computers are on the same domain disabling the Domain Firewall may be sufficient.
428
+ - Port conflict. If port 27183 is in use, a different number can be specified when instantiating MultiPyVu.Server() and MultiPyVu.Client().
444
429
  ```python
445
430
  server = mpv.Server(port=6000)
446
431
  client = mpv.Client(port=6000)
@@ -449,6 +434,22 @@ client = mpv.Client(port=6000)
449
434
  - A log file named QdMultiVu.log shows the traffic between the server and client which can also be useful during troubleshooting.
450
435
 
451
436
  ## Changelog<a class="anchor" id="changelog"></a>
437
+ **3.8.0**
438
+ - September 2026
439
+ - Add support for the OptiCool Vector magnet
440
+ - Improvements to the GUI for a better look on MacOS.
441
+ - Improvements to wait_for() command.
442
+
443
+ **3.7.0**
444
+ - September 2025
445
+ - Point MultiPyVuDataFile to version 00.05.00, which ignores blank lines when importing .dat files into a Pandas Dataframe.
446
+
447
+ **3.6.1**
448
+ - August 2025
449
+ - Add commands to get the temperature and field setpoints.
450
+ - Remove dependencies on the distutils module.
451
+ - Minimum python version 3.7
452
+
452
453
  **3.5.4**
453
454
  - June 2025
454
455
  - Add the horizontal rotator option for DynaCool, VersaLab, and PPMS.
@@ -33,13 +33,13 @@ The components of MultiPyVu enable access to the set and read the temperature, f
33
33
 
34
34
  ### Module Requirements<a class="anchor" id="requirements"></a>
35
35
  MultiPyVu uses the following modules:
36
- - python version 3.10 or higher
36
+ - python version 3.7 or higher
37
37
  - pywin32 - version 300 or higher.
38
38
  - pandas - data read back from a *.dat* file is a Pandas Dataframe
39
39
  - pillow - supports server gui
40
40
  - pyyaml - supports logging
41
41
 
42
- For the Python 3 distribution Quantum Design recommends [Anaconda](https://www.anaconda.com/products/individual) as it includes most modules needed for this server and other packages useful for scientific computing. This code was built and tested using Python 3.8. If you are not sure which version of Python you are using, from a command prompt type:
42
+ To find which version of Python is used on the local computer, from a command prompt type:
43
43
  ```
44
44
  python --version
45
45
  ```
@@ -60,13 +60,13 @@ Remote Connection\example_MVDataFile_VISA.py | Simple example showing how to rou
60
60
  Data Processing\example_save_open_dat.py | Script showing how to save and read a MultiVu *.dat* file into a Pandas DataFrame, then plot with matplotlib.
61
61
  Measuring\example_stabilize.py | Measures the temperature while stabilizing at each temperature.
62
62
  Measuring\example_sweep.py | Measures the temperature while sweeping the temperature.
63
- Options\example_aux_therm.py | Gets the temperature of the auxilary thermometer from the OptiCool.
63
+ Measuring\example_get_setpoints.py | Shows how to get the temperature and magnetic field setpoints.
64
+ Options\example_aux_therm.py | Gets the temperature of the auxiliary thermometer from the OptiCool.
64
65
  Options\example_resistivity_option.py | Demonstrates how to set up the BRT module bridges for resistivity measurements and how to save the data.
65
66
  Options\example_horizontal_rotator.py | Demonstrates how to move the horizontal rotator to a new position.
66
- UsefulBatchFiles\whats_my_ip_address.cmd | This batch file script prints out the IP address for the computer, providing an easy way to get the server IP address needed for remote operation. Alternatively, the gui can be used to get the IP address by calling ```python -m MultiPyVu```.
67
- UsefulBatchFiles\show_process_with_port.cmd | Shows that active processes are running and what port is being used. By default, this looks for processes running on port 5000. To query a different port number, append it to the command line arguments. ```$ show_processes_with_port.cmd 4567```
67
+ UsefulBatchFiles\show_processes_with_port.cmd | Shows that active processes are running and what port is being used. By default, this looks for processes running on port 27183. To query a different port number, append it to the command line arguments. ```$ show_processes_with_port.cmd 45678```
68
68
  UsefulBatchFiles\RunServer.cmd | This runs the server GUI.
69
- UsefulBatchFiles\kill_process.cmd | This ends the processes with the specified PID (which can be identified using show_process_with_port.cmd). Run using ```$ kill_process.cmd 13579```
69
+ UsefulBatchFiles\kill_process.cmd | This ends the processes with the specified PID (which can be identified using show_processes_with_port.cmd). Run using ```$ kill_process.cmd 13579```
70
70
 
71
71
  ### Getting Started<a class="anchor" id="getting-started"></a>
72
72
  Once the MultiPyVu module has been installed, be sure that the MultiVu executable is running on the PC connected to the cryostat before starting the server. For testing purposes, you can use MultiVu in simulation mode on an office computer, or run mpv.Server with the -s flag which runs the python code in scaffolding that mimics MultiVu. This is especially helpful for developing a script on a computer that does not have MultiVu running (Mac, Linux, or any PC without MultiVu). When running MultiVu and MultiPyVu, be sure that they are running under the same permissions.
@@ -132,7 +132,7 @@ with mpv.Client('127.0.0.1') as client:
132
132
  # do post-processing once the client has been closed
133
133
  ```
134
134
 
135
- If the host or port are not default values (localhost and 5000, respectively), then these parameters must be specified when instantiating MultiPyVu.Client().
135
+ If the host or port are not default values (localhost and 27183, respectively), then these parameters must be specified when instantiating MultiPyVu.Client().
136
136
 
137
137
  Alternatively, one can start a connection to the server using:
138
138
  ```python
@@ -142,7 +142,7 @@ client.open()
142
142
  client.close_client()
143
143
  # do post-processing once the client has been closed
144
144
  ```
145
- Using the above method could end up with the server hung up because errors need to be correctly accounted for. It is safer to use the Client as a context manager using a with-block.
145
+ Using the above method could end up with the server hung up because errors need to be correctly accounted for. It is safer to use the Client as a context manager using a with-block. In addition, a client object can only connect to the server once. For a second connection, one must instantiate a new client instance.
146
146
 
147
147
  The client can also close the server directly using:
148
148
  ```python
@@ -190,6 +190,10 @@ The <enum_options> mode is set using the client.temperature.approach_mode enum,
190
190
  ```python
191
191
  temperature, status = client.get_temperature()
192
192
  ```
193
+ One can also retrieve the setpoint, rate, and approach mode:
194
+ ```python
195
+ temperature, rate, approach = client.get_temperature_setpoints()
196
+ ```
193
197
 
194
198
  **Field**<a class="anchor" id="field"></a>
195
199
  ```python
@@ -211,6 +215,10 @@ The field and status are read back using:
211
215
  ```python
212
216
  field, status = client.get_field()
213
217
  ```
218
+ One can also retrieve the setpoint, rate, and approach mode:
219
+ ```python
220
+ field, rate, approach, driven = client.get_field_setpoints()
221
+ ```
214
222
 
215
223
  **Chamber**<a class="anchor" id="chamber"></a>
216
224
  ```python
@@ -276,7 +284,7 @@ For DynaCool, VersaLab, and PPMS customers with the horizontal rotator option, M
276
284
  Once configured, the following commands are simple to use:
277
285
  ```python
278
286
  position = 374.5
279
- rate_deg_per_sec = 100.0
287
+ rate_deg_per_sec = 30.0
280
288
  client.set_position(position, rate_deg_per_sec)
281
289
  pos, status = client.get_position()
282
290
  ```
@@ -351,7 +359,7 @@ The server status can be queried from the command line. First, we can see if th
351
359
  ```cmd
352
360
  $ python -m MultiPyVu -running
353
361
  ```
354
- By default, this queries the server at IP address = localhost and port = 5000. To query a different address, use the *-ip=* or *-p=* flags.
362
+ By default, this queries the server at IP address = localhost and port = 27183. To query a different address, use the *-ip=* or *-p=* flags.
355
363
 
356
364
  Similarly, in order to get the server status at a specific ip address, use:
357
365
  ```cmd
@@ -390,8 +398,8 @@ with mpv.Server(flags=['-s', 'DYNACOOL']) as server:
390
398
 
391
399
  ### Troubleshooting<a class="anchor" id="troubleshooting"></a>
392
400
  Typical connection issues are due to:
393
- - Firewall. You might need to allow connections on port 5000 (the default port number) in your firewall. Windows Firewall may cause issues depending upon your network settings. If the server is open and a connection fails disabling Firewalls temporarily may be your best option to troubleshoot. If your computers are on the same domain disabling the Domain Firewall may be sufficient.
394
- - Port conflict. If port 5000 is in use, a different number can be specified when instantiating MultiPyVu.Server() and MultiPyVu.Client().
401
+ - Firewall. You might need to allow connections on port 27183 (the default port number) in your firewall. Windows Firewall may cause issues depending upon your network settings. If the server is open and a connection fails disabling Firewalls temporarily may be your best option to troubleshoot. If your computers are on the same domain disabling the Domain Firewall may be sufficient.
402
+ - Port conflict. If port 27183 is in use, a different number can be specified when instantiating MultiPyVu.Server() and MultiPyVu.Client().
395
403
  ```python
396
404
  server = mpv.Server(port=6000)
397
405
  client = mpv.Client(port=6000)
@@ -400,6 +408,22 @@ client = mpv.Client(port=6000)
400
408
  - A log file named QdMultiVu.log shows the traffic between the server and client which can also be useful during troubleshooting.
401
409
 
402
410
  ## Changelog<a class="anchor" id="changelog"></a>
411
+ **3.8.0**
412
+ - September 2026
413
+ - Add support for the OptiCool Vector magnet
414
+ - Improvements to the GUI for a better look on MacOS.
415
+ - Improvements to wait_for() command.
416
+
417
+ **3.7.0**
418
+ - September 2025
419
+ - Point MultiPyVuDataFile to version 00.05.00, which ignores blank lines when importing .dat files into a Pandas Dataframe.
420
+
421
+ **3.6.1**
422
+ - August 2025
423
+ - Add commands to get the temperature and field setpoints.
424
+ - Remove dependencies on the distutils module.
425
+ - Minimum python version 3.7
426
+
403
427
  **3.5.4**
404
428
  - June 2025
405
429
  - Add the horizontal rotator option for DynaCool, VersaLab, and PPMS.
@@ -6,19 +6,23 @@ build-backend = "setuptools.build_meta"
6
6
  name = "MultiPyVu"
7
7
  dynamic = [
8
8
  "version",
9
- "description",
10
9
  "requires-python",
11
- "dependencies",
12
10
  ]
13
11
  authors = [{name = "Damon D Jackson", email = "djackson@qdusa.com"}]
14
12
  maintainers = [
15
13
  { name = "Quantum Design, Inc.", email = "apps@qdusa.com" },
16
14
  ]
17
15
  readme = "README.md"
18
- license = {file = "LICENSE"}
16
+ description = "Control MultiVu using Python"
17
+ dependencies = [
18
+ "pandas",
19
+ "pywin32>=300; platform_system=='Windows'",
20
+ "pillow",
21
+ "pyyaml",
22
+ ]
23
+ license = "MIT"
19
24
  classifiers = [
20
25
  "Programming Language :: Python :: 3",
21
- "License :: OSI Approved :: MIT License",
22
26
  "Operating System :: OS Independent",
23
27
  "Intended Audience :: Science/Research",
24
28
  "Topic :: Scientific/Engineering :: Physics",
@@ -39,3 +43,6 @@ keywords = [
39
43
  [project.urls]
40
44
  "Quantum Design" = "https://qdusa.com"
41
45
  "Pharos" = "https://www.qdusa.com/register/account/login"
46
+
47
+ [tool.setuptools.dynamic]
48
+ version = {attr = "MultiPyVu.__version.__version__"}
@@ -0,0 +1,27 @@
1
+ """A setuptools based setup module.
2
+
3
+ See:
4
+ https://packaging.python.org/guides/distributing-packages-using-setuptools/
5
+ https://github.com/pypa/sampleproject
6
+ """
7
+
8
+ # Always prefer setuptools over distutils
9
+ from setuptools import find_packages, setup
10
+
11
+ # name, version, description, license, dependencies, and readme are
12
+ # configured in pyproject.toml. Only the settings without a pyproject.toml
13
+ # equivalent (package discovery/layout and non-Python package data) live here.
14
+ setup(
15
+ package_dir={"": "src"},
16
+ packages=find_packages(where="src"),
17
+ package_data={"MultiPyVu": [
18
+ "images/*.jpg",
19
+ "images/*.png",
20
+ "font/*.ttf",
21
+ "scripts/*",
22
+ "MultiVuDataFile/*.py",
23
+ "logging_config.yaml"
24
+ ]
25
+ },
26
+ python_requires=">=3.7",
27
+ )
@@ -13,7 +13,7 @@ from typing import Dict, List, Tuple, Union
13
13
 
14
14
  from .exceptions import MultiPyVuError
15
15
  from .ICommand import (ICommand, ICommandImp, ICommandObserverSim,
16
- ISimulateChange, catch_thread_error)
16
+ ISimulateChange)
17
17
  from .IEventManager import IObserver
18
18
 
19
19
 
@@ -90,7 +90,7 @@ class CommandChamberBase(ICommand):
90
90
 
91
91
  def convert_result(self, response: Dict[str, str]) -> Tuple:
92
92
  """
93
- Converts the CommandMultiVu response from get_state()
93
+ Converts the CommandMultiVu response from get_state_server()
94
94
  to something usable for the user.
95
95
 
96
96
  Parameters:
@@ -131,7 +131,7 @@ class CommandChamberBase(ICommand):
131
131
  raise NotImplementedError
132
132
 
133
133
  @abstractmethod
134
- def _set_state_imp(self, mode: int) -> Union[str, int]:
134
+ def _set_state_imp(self, mode: modeEnum) -> Union[str, int]:
135
135
  raise NotImplementedError
136
136
 
137
137
  def set_state_server(self, arg_string) -> Union[str, int]:
@@ -148,8 +148,8 @@ class CommandChamberBase(ICommand):
148
148
  for m in modeEnum:
149
149
  err_msg += f'\n\t{m.value}: {m.name}'
150
150
  raise MultiPyVuError(err_msg)
151
- self.state = set_mode
152
- return self._set_state_imp(set_mode)
151
+ self.state = modeEnum(set_mode)
152
+ return self._set_state_imp(self.state)
153
153
 
154
154
  def state_code_dict(self):
155
155
  return STATE_DICT
@@ -195,7 +195,7 @@ class CommandChamberImp(ICommandImp, CommandChamberBase):
195
195
  if self.instrument_name == 'OPTICOOL':
196
196
  err_msg = 'get_chamber() is not available for the OptiCool'
197
197
  raise MultiPyVuError(err_msg)
198
- error = self._mvu.GetChamber(state_variant)
198
+ can_error = self._mvu.GetChamber(state_variant)
199
199
  # On 6/10/25, I found that the PPMS was returning something greater
200
200
  # than 1 with the GetTemperature() command. After talking with Mark,
201
201
  # I have decided to only check for a value greater than 1 for all
@@ -206,7 +206,7 @@ class CommandChamberImp(ICommandImp, CommandChamberBase):
206
206
 
207
207
  return 0.0, self.state
208
208
 
209
- def _set_state_imp(self, mode: int) -> Union[str, int]:
209
+ def _set_state_imp(self, mode: modeEnum) -> Union[str, int]:
210
210
  can_error = self._mvu.SetChamber(mode)
211
211
  self.set_point = mode
212
212
 
@@ -216,7 +216,7 @@ class CommandChamberImp(ICommandImp, CommandChamberBase):
216
216
  else:
217
217
  # returning this string makes CommandMultiVu_base happy
218
218
  return 'Call was successful'
219
- elif can_error > 0:
219
+ elif can_error > 1:
220
220
  raise MultiPyVuError('Error when calling SetChamber()')
221
221
  return can_error
222
222
 
@@ -266,15 +266,22 @@ class CommandChamberImp(ICommandImp, CommandChamberBase):
266
266
  #
267
267
  ############################
268
268
 
269
- @catch_thread_error
270
269
  class SimulateChamberChange(ISimulateChange):
271
- # class variables
270
+ # These are class variables, not instance variables, so that the
271
+ # simulated instrument keeps its condition from one change
272
+ # thread to the next. See ISimulateChange for the reasoning.
272
273
  _stop_flag: bool = False
273
- _val: float
274
- _state: str
275
- _set_point: float
276
- _rate: float
277
- _flavor: str
274
+ _state_dict = STATE_DICT
275
+ # The starting values come from the Command*Base class so that
276
+ # the scaffolding and the real implementation begin in the
277
+ # same place.
278
+ _current_val: float = CommandChamberBase._current_val
279
+ _state: int = CommandChamberBase._state
280
+ _set_point: float = CommandChamberBase._set_point
281
+ # The chamber has no rate, and the flavor is set by
282
+ # CommandChamberSim._set_state_imp() before the thread runs.
283
+ _rate: float = 0.0
284
+ _flavor: str = ''
278
285
  _observers: List[IObserver] = []
279
286
 
280
287
  def __init__(self):
@@ -282,11 +289,11 @@ class SimulateChamberChange(ISimulateChange):
282
289
 
283
290
  @property
284
291
  def current_val(self):
285
- return SimulateChamberChange._val
292
+ return SimulateChamberChange._current_val
286
293
 
287
294
  @current_val.setter
288
295
  def current_val(self, new):
289
- SimulateChamberChange._val = new
296
+ SimulateChamberChange._current_val = new
290
297
 
291
298
  @property
292
299
  def set_point(self):
@@ -323,20 +330,20 @@ class SimulateChamberChange(ISimulateChange):
323
330
  if self.stop_requested():
324
331
  return
325
332
  if self.set_point == modeEnum.seal.value:
326
- self.state = STATE_DICT[1]
333
+ self.state = 1
327
334
  elif self.set_point == modeEnum.purge_seal.value:
328
- self.state = STATE_DICT[1]
335
+ self.state = 1
329
336
  elif self.set_point == modeEnum.vent_seal.value:
330
- self.state = STATE_DICT[2]
337
+ self.state = 2
331
338
  elif self.set_point == modeEnum.high_vacuum.value:
332
- self.state = STATE_DICT[7]
339
+ self.state = 7
333
340
  elif self.set_point == modeEnum.pump_continuous.value:
334
- self.state = STATE_DICT[8]
341
+ self.state = 8
335
342
  elif self.set_point == modeEnum.vent_continuous.value:
336
343
  if self.flavor == 'PPMS':
337
- self.state = STATE_DICT[5]
344
+ self.state = 5
338
345
  else:
339
- self.state = STATE_DICT[9]
346
+ self.state = 9
340
347
  else:
341
348
  msg = f'{self.set_point} is an invalid mode'
342
349
  raise ValueError(msg)
@@ -401,13 +408,12 @@ class CommandChamberSim(CommandChamberBase,
401
408
  raise MultiPyVuError(err_msg)
402
409
  return 0.0, self.state
403
410
 
404
- def _set_state_imp(self, mode: int) -> Union[str, int]:
405
- self.change_thread = self.get_sim_instance()
406
- state_string = STATE_DICT[self.state]
411
+ def _set_state_imp(self, mode: modeEnum) -> Union[str, int]:
412
+ self.change_thread: SimulateChamberChange = self.get_sim_instance()
407
413
  self.change_thread.set_params('',
408
414
  mode,
409
415
  0.0,
410
- state_string,
416
+ self.state,
411
417
  )
412
418
  self.change_thread.flavor = self.instrument_name
413
419
  self.change_thread.subscribe(self)
@@ -422,7 +428,4 @@ class CommandChamberSim(CommandChamberBase,
422
428
  return error
423
429
 
424
430
  def update(self, value, state):
425
- for state_number, state_str in STATE_DICT.items():
426
- if state_str == state:
427
- self.state = state_number
428
- break
431
+ self.state = state