├── ridengui ├── __init__.py ├── about.py ├── worker.py ├── main.py ├── about.ui ├── settings.py ├── settings.ui ├── mainwindow.py └── mainwindow.ui ├── screenshots ├── mainwindow.png ├── settingswizard1.png ├── settingswizard2.png └── settingswizard3.png ├── data └── share │ ├── icons │ └── hicolor │ │ └── 32x32 │ │ └── apps │ │ └── riden.png │ └── applications │ └── riden.desktop ├── pyproject.toml ├── .gitignore ├── LICENSE ├── README.md └── poetry.lock /ridengui/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /screenshots/mainwindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShayBox/RidenGUI/HEAD/screenshots/mainwindow.png -------------------------------------------------------------------------------- /screenshots/settingswizard1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShayBox/RidenGUI/HEAD/screenshots/settingswizard1.png -------------------------------------------------------------------------------- /screenshots/settingswizard2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShayBox/RidenGUI/HEAD/screenshots/settingswizard2.png -------------------------------------------------------------------------------- /screenshots/settingswizard3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShayBox/RidenGUI/HEAD/screenshots/settingswizard3.png -------------------------------------------------------------------------------- /data/share/icons/hicolor/32x32/apps/riden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShayBox/RidenGUI/HEAD/data/share/icons/hicolor/32x32/apps/riden.png -------------------------------------------------------------------------------- /data/share/applications/riden.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Encoding=UTF-8 4 | Name=Riden GUI 5 | Comment=Qt 5/6 based GUI for Riden RDXX power supplies written in Python 6 | Exec=env KDE_NO_GLOBAL_MENU=1 ridengui 7 | Icon=riden.png 8 | Terminal=false 9 | -------------------------------------------------------------------------------- /ridengui/about.py: -------------------------------------------------------------------------------- 1 | # Built-in modules 2 | from os.path import dirname 3 | 4 | # Third-party modules 5 | from qtpy.QtWidgets import QDialog 6 | from qtpy.uic import loadUi 7 | 8 | 9 | class AboutDialog(QDialog): 10 | def __init__(self, parent=None): 11 | super().__init__(parent) 12 | 13 | self.ui = loadUi(dirname(__file__) + "/about.ui", self) 14 | -------------------------------------------------------------------------------- /ridengui/worker.py: -------------------------------------------------------------------------------- 1 | # Third-party modules 2 | from qtpy.QtCore import QSettings, QThread, Signal 3 | 4 | # Local modules 5 | from riden import Riden 6 | 7 | 8 | class Worker(QThread): 9 | update = Signal() 10 | 11 | def __init__(self, riden: Riden, settings: QSettings, parent=None): 12 | super().__init__(parent) 13 | self.riden = riden 14 | self.settings = settings 15 | self.sleep = int(self.settings.value("polling", 500)) 16 | self.running = True 17 | 18 | def run(self): 19 | while self.running: 20 | self.riden.update() 21 | self.update.emit() 22 | self.msleep(self.sleep) 23 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "RidenGUI" 3 | version = "1.1.0" 4 | description = "Qt 5/6 based GUI for Riden RDXX power supplies written in Python" 5 | authors = ["Shayne Hartford "] 6 | 7 | [tool.poetry.dependencies] 8 | click = "^8.0.3" 9 | PyQt5 = { version = "^5.15.6", optional = true } 10 | PyQt6 = { version = "^6.2.3", optional = true } 11 | python = ">=3.7,<3.11" 12 | QtPy = "^2.0.1" 13 | riden = { git = "https://github.com/shaybox/riden.git" } 14 | 15 | [tool.poetry.dev-dependencies] 16 | black = "^22.1.0" 17 | 18 | [build-system] 19 | requires = ["setuptools", "poetry-core>=1.0.0"] 20 | build-backend = "poetry.core.masonry.api" 21 | 22 | [tool.poetry.extras] 23 | "PyQt5" = ["PyQt5"] 24 | "PyQt6" = ["PyQt6"] 25 | 26 | [tool.poetry.scripts] 27 | ridengui = "ridengui.main:main" 28 | 29 | [tool.black] 30 | line-length = 240 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | 62 | #Ipython Notebook 63 | .ipynb_checkpoints 64 | 65 | # pyenv 66 | .python-version -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Shayne Hartford 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 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ridengui/main.py: -------------------------------------------------------------------------------- 1 | # Built-in modules 2 | import faulthandler 3 | import logging 4 | import signal 5 | import sys 6 | 7 | # Third-party modules 8 | import click 9 | from qtpy.QtWidgets import QApplication 10 | 11 | # Local modules 12 | from ridengui.mainwindow import MainWindow 13 | 14 | 15 | @click.command() 16 | @click.option("-p", "--port", default=None, help="Serial port") 17 | @click.option("-b", "--baudrate", default=None, help="Serial baudrate") 18 | @click.option("-a", "--address", default=None, help="Modbus address") 19 | @click.option("-v", "--verbose", is_flag=True, help="Enable verbose mode") 20 | def main(port: str, baudrate: int, address: int, verbose: bool): 21 | logging.basicConfig(level=logging.DEBUG if verbose else logging.WARNING) 22 | 23 | logging.debug("Enabled built-in python fault handler for segfaults") 24 | faulthandler.enable() 25 | 26 | logging.debug("Enabled built-in python signal handler for Ctrl+C") 27 | signal.signal(signal.SIGINT, signal.SIG_DFL) 28 | 29 | logging.debug("Starting QApplication and MainWindow") 30 | app = QApplication(sys.argv) 31 | window = MainWindow(port, baudrate, address) 32 | window.show() 33 | sys.exit(app.exec_()) 34 | 35 | 36 | if __name__ == "__main__": 37 | main() 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RidenGUI 2 | 3 | Qt 5/6 based GUI for Riden RDXX power supplies written in Python 4 | 5 | #### Screenshots 6 | ![MainWindow](screenshots/mainwindow.png) 7 | ![SettingsWizard1](screenshots/settingswizard1.png) 8 | ![SettingsWizard2](screenshots/settingswizard2.png) 9 | ![SettingsWizard2](screenshots/settingswizard3.png) 10 | 11 | #### Issues 12 | Please report and discuss issues on [Discussions] 13 | 14 | #### Installation 15 | Requirements: 16 | - [Python] 3.7 or later 17 | - [Poetry] via pip 18 | - [PyQt5] or [PyQt6] 19 | ``` 20 | $ pip install --user pyqt5 21 | $ pip install --user git+https://github.com/shaybox/ridengui.git 22 | 23 | $ ridengui 24 | ``` 25 | 26 | ### Development 27 | `poetry` is a required build dependency (build tool) 28 | ``` 29 | git clone https://github.com/ShayBox/RidenGUI.git 30 | cd RidenGUI 31 | poetry env use 32 | 33 | $ poetry run ridengui 34 | ``` 35 | 36 | #### Usage 37 | There's icon and desktop entry files in the `data` directory. 38 | Run the command `ridengui` to start the GUI. 39 | Run the command `ridengui --help` to see the command line options. 40 | 41 | [Discussions]: https://github.com/ShayBox/RidenGUI/discussions 42 | [Python]: https://python.org 43 | [Poetry]: https://python-poetry.org 44 | [PyQt5]: https://pypi.org/project/PyQt5 45 | [PyQt6]: https://pypi.org/project/PyQt6 -------------------------------------------------------------------------------- /ridengui/about.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AboutDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 173 10 | 156 11 | 12 | 13 | 14 | About 15 | 16 | 17 | 18 | .. 19 | 20 | 21 | 22 | 23 | 24 | Qt::Horizontal 25 | 26 | 27 | QDialogButtonBox::Ok 28 | 29 | 30 | 31 | 32 | 33 | 34 | <html><head/><body><p><a href="https://github.com/ShayBox/RidenGUI"><span style=" text-decoration: underline; color:#0057ae;">RidenGUI Source Code </span></a></p></body></html> 35 | 36 | 37 | Qt::AlignCenter 38 | 39 | 40 | 41 | 42 | 43 | 44 | Qt::Vertical 45 | 46 | 47 | 48 | 20 49 | 40 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 20 59 | 60 | 61 | 62 | RidenGUI 63 | 64 | 65 | Qt::AlignCenter 66 | 67 | 68 | 69 | 70 | 71 | 72 | <html><head/><body><p><a href="https://eevblog.com/forum/testgear/ruideng-riden-rd6006-dc-power-supply"><span style=" text-decoration: underline; color:#0057ae;">Custom Firmware</span></a></p></body></html> 73 | 74 | 75 | Qt::AlignCenter 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | buttonBox 85 | accepted() 86 | AboutDialog 87 | accept() 88 | 89 | 90 | 248 91 | 254 92 | 93 | 94 | 157 95 | 274 96 | 97 | 98 | 99 | 100 | buttonBox 101 | rejected() 102 | AboutDialog 103 | reject() 104 | 105 | 106 | 316 107 | 260 108 | 109 | 110 | 286 111 | 274 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /ridengui/settings.py: -------------------------------------------------------------------------------- 1 | # Built-in modules 2 | import sys 3 | from os.path import dirname 4 | from subprocess import Popen 5 | 6 | # Third-party modules 7 | from qtpy.QtCore import QSettings 8 | from qtpy.QtGui import QColor 9 | from qtpy.QtWidgets import QApplication, QColorDialog, QWizard 10 | from qtpy.uic import loadUi 11 | 12 | 13 | class SettingsWizard(QWizard): 14 | def __init__(self, settings: QSettings, parent=None): 15 | super().__init__(parent) 16 | self.settings = settings 17 | self.parent = parent 18 | 19 | # Load wizard.ui 20 | self.ui = loadUi(dirname(__file__) + "/settings.ui", self) 21 | 22 | # Adjust widget sizes and resize window 23 | self.adjustSize() 24 | self.resize(self.minimumSize()) 25 | 26 | # Center window on primary screen 27 | self.move(QApplication.primaryScreen().geometry().center() - self.rect().center()) 28 | 29 | # Load settings and define defaults 30 | self.ui.portLine.setText(self.settings.value("serial/port", "/dev/ttyUSB0")) 31 | self.ui.baudrateCombo.setCurrentText(self.settings.value("serial/baudrate", "115200")) 32 | self.ui.addressSpin.setValue(int(self.settings.value("serial/address", 1))) 33 | self.ui.pollingSpin.setValue(int(self.settings.value("polling", 500))) 34 | self.ui.inputVoltagePush.setStyleSheet(self.settings.value("style/input-voltage", self.ui.inputVoltagePush.styleSheet())) 35 | self.ui.outputVoltagePush.setStyleSheet(self.settings.value("style/output-voltage", self.ui.outputVoltagePush.styleSheet())) 36 | self.ui.outputCurrentPush.setStyleSheet(self.settings.value("style/output-current", self.ui.outputCurrentPush.styleSheet())) 37 | self.ui.outputPowerPush.setStyleSheet(self.settings.value("style/output-power", self.ui.outputPowerPush.styleSheet())) 38 | self.ui.voltageSetPush.setStyleSheet(self.settings.value("style/voltage-set", self.ui.voltageSetPush.styleSheet())) 39 | self.ui.currentSetPush.setStyleSheet(self.settings.value("style/current-set", self.ui.currentSetPush.styleSheet())) 40 | self.ui.outputOnTextPush.setStyleSheet(self.settings.value("style/output-on-text", self.ui.outputOnTextPush.styleSheet())) 41 | self.ui.outputOffTextPush.setStyleSheet(self.settings.value("style/output-off-text", self.ui.outputOffTextPush.styleSheet())) 42 | self.ui.outputFaultTextPush.setStyleSheet(self.settings.value("style/output-fault-text", self.ui.outputFaultTextPush.styleSheet())) 43 | self.ui.outputOnButtonPush.setStyleSheet(self.settings.value("style/output-on-bg", self.ui.outputOnButtonPush.styleSheet())) 44 | self.ui.outputOffButtonPush.setStyleSheet(self.settings.value("style/output-off-bg", self.ui.outputOffButtonPush.styleSheet())) 45 | self.ui.outputFaultButtonPush.setStyleSheet(self.settings.value("style/output-fault-bg", self.ui.outputFaultButtonPush.styleSheet())) 46 | self.ui.inputVoltageLine.setText(self.settings.value("format/voltage-input", self.parent.default_voltage_input_format)) 47 | self.ui.outputVoltageLine.setText(self.settings.value("format/voltage-output", self.parent.default_voltage_output_format)) 48 | self.ui.outputCurrentLine.setText(self.settings.value("format/current-output", self.parent.default_current_output_format)) 49 | self.ui.outputPowerLine.setText(self.settings.value("format/power-output", self.parent.default_power_output_format)) 50 | 51 | for button in ( 52 | self.ui.inputVoltagePush, 53 | self.ui.outputVoltagePush, 54 | self.ui.outputCurrentPush, 55 | self.ui.outputPowerPush, 56 | self.ui.voltageSetPush, 57 | self.ui.currentSetPush, 58 | self.ui.outputOnTextPush, 59 | self.ui.outputOffTextPush, 60 | self.ui.outputFaultTextPush, 61 | self.ui.outputOnButtonPush, 62 | self.ui.outputOffButtonPush, 63 | self.ui.outputFaultButtonPush, 64 | ): 65 | button.clicked.connect(self.button_clicked) 66 | 67 | def button_clicked(self): 68 | sender = self.sender() 69 | stylesheet: str = sender.styleSheet() 70 | old_color = stylesheet.split(";")[-1].split(":")[1] 71 | new_color = QColor(old_color.replace("#", "")) 72 | new_color = QColorDialog.getColor(new_color, self) 73 | if new_color.isValid(): 74 | sender.setStyleSheet(stylesheet.replace(old_color, new_color.name())) 75 | 76 | def accept(self): 77 | # Save settings 78 | self.settings.setValue("serial/port", self.ui.portLine.text()) 79 | self.settings.setValue("serial/baudrate", self.ui.baudrateCombo.currentText()) 80 | self.settings.setValue("serial/address", self.ui.addressSpin.value()) 81 | self.settings.setValue("polling", self.ui.pollingSpin.value()) 82 | self.settings.setValue("style/input-voltage", self.ui.inputVoltagePush.styleSheet()) 83 | self.settings.setValue("style/output-voltage", self.ui.outputVoltagePush.styleSheet()) 84 | self.settings.setValue("style/output-current", self.ui.outputCurrentPush.styleSheet()) 85 | self.settings.setValue("style/output-power", self.ui.outputPowerPush.styleSheet()) 86 | self.settings.setValue("style/voltage-set", self.ui.voltageSetPush.styleSheet()) 87 | self.settings.setValue("style/current-set", self.ui.currentSetPush.styleSheet()) 88 | self.settings.setValue("style/output-on-text", self.ui.outputOnTextPush.styleSheet()) 89 | self.settings.setValue("style/output-off-text", self.ui.outputOffTextPush.styleSheet()) 90 | self.settings.setValue("style/output-fault-text", self.ui.outputFaultTextPush.styleSheet()) 91 | self.settings.setValue("style/output-on-bg", self.ui.outputOnButtonPush.styleSheet()) 92 | self.settings.setValue("style/output-off-bg", self.ui.outputOffButtonPush.styleSheet()) 93 | self.settings.setValue("style/output-fault-bg", self.ui.outputFaultButtonPush.styleSheet()) 94 | self.settings.setValue("format/voltage-input", self.ui.inputVoltageLine.text()) 95 | self.settings.setValue("format/voltage-output", self.ui.outputVoltageLine.text()) 96 | self.settings.setValue("format/current-output", self.ui.outputCurrentLine.text()) 97 | self.settings.setValue("format/power-output", self.ui.outputPowerLine.text()) 98 | self.settings.setValue("first-run", 0) 99 | self.settings.sync() 100 | 101 | # Close window 102 | super().accept() 103 | 104 | # Spawn a new instance of the application 105 | self.parent.close() 106 | Popen(sys.argv, start_new_session=True) 107 | 108 | def reject(self): 109 | # Close window 110 | super().reject() 111 | -------------------------------------------------------------------------------- /ridengui/settings.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SettingsWizard 4 | 5 | 6 | 7 | 0 8 | 0 9 | 306 10 | 307 11 | 12 | 13 | 14 | Settings Wizard 15 | 16 | 17 | 18 | .. 19 | 20 | 21 | QWizard::NoBackButtonOnStartPage 22 | 23 | 24 | 25 | Serial 26 | 27 | 28 | Serial communication settings 29 | 30 | 31 | 1 32 | 33 | 34 | 35 | 36 | 37 | 4 38 | 39 | 40 | 41 | 9600 42 | 43 | 44 | 45 | 46 | 19200 47 | 48 | 49 | 50 | 51 | 38400 52 | 53 | 54 | 55 | 56 | 57600 57 | 58 | 59 | 60 | 61 | 115200 62 | 63 | 64 | 65 | 66 | 230400 67 | 68 | 69 | 70 | 71 | 250000 72 | 73 | 74 | 75 | 76 | 460800 77 | 78 | 79 | 80 | 81 | 921600 82 | 83 | 84 | 85 | 86 | 1000000 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | Address 95 | 96 | 97 | addressSpin 98 | 99 | 100 | 101 | 102 | 103 | 104 | 255 105 | 106 | 107 | 1 108 | 109 | 110 | 111 | 112 | 113 | 114 | Polling (ms) 115 | 116 | 117 | 118 | 119 | 120 | 121 | 1 122 | 123 | 124 | 10000 125 | 126 | 127 | 500 128 | 129 | 130 | 131 | 132 | 133 | 134 | /dev/ttyUSB0 135 | 136 | 137 | 138 | 139 | 140 | 141 | Baudrate 142 | 143 | 144 | baudrateCombo 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 10 153 | 50 154 | false 155 | 156 | 157 | 158 | Serial Port 159 | 160 | 161 | portLine 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | Format 170 | 171 | 172 | Custom Python format strings 173 | 174 | 175 | 2 176 | 177 | 178 | 179 | 180 | 181 | Voltage In 182 | 183 | 184 | 185 | 186 | 187 | 188 | Current Out 189 | 190 | 191 | 192 | 193 | 194 | 195 | %05.2f 196 | 197 | 198 | 199 | 200 | 201 | 202 | Power Out 203 | 204 | 205 | 206 | 207 | 208 | 209 | %05.2f 210 | 211 | 212 | 213 | 214 | 215 | 216 | %6.2f 217 | 218 | 219 | 220 | 221 | 222 | 223 | Voltage Out 224 | 225 | 226 | 227 | 228 | 229 | 230 | %05.2f 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | CSS 239 | 240 | 241 | Custom CSS Stylesheet 242 | 243 | 244 | 3 245 | 246 | 247 | 248 | 249 | 250 | Text Colors 251 | 252 | 253 | inputVoltagePush 254 | 255 | 256 | 257 | 258 | 259 | 260 | color: #ff00ff 261 | 262 | 263 | Input Voltage 264 | 265 | 266 | 267 | 268 | 269 | 270 | color: #ffff00 271 | 272 | 273 | Output Voltage 274 | 275 | 276 | 277 | 278 | 279 | 280 | color: #00ffff 281 | 282 | 283 | Output Current 284 | 285 | 286 | 287 | 288 | 289 | 290 | color: #ff00ff 291 | 292 | 293 | Output Power 294 | 295 | 296 | 297 | 298 | 299 | 300 | color: #000000; 301 | 302 | 303 | Output OFF 304 | 305 | 306 | 307 | 308 | 309 | 310 | color: #000000; 311 | 312 | 313 | Output Fault 314 | 315 | 316 | 317 | 318 | 319 | 320 | color: #000000; 321 | 322 | 323 | Output ON 324 | 325 | 326 | 327 | 328 | 329 | 330 | color: #ffff00 331 | 332 | 333 | Voltage Set 334 | 335 | 336 | 337 | 338 | 339 | 340 | color: #ffff00 341 | 342 | 343 | Current Set 344 | 345 | 346 | 347 | 348 | 349 | 350 | Button Colors 351 | 352 | 353 | 354 | 355 | 356 | 357 | color:#000000;background-color:#00ff00; 358 | 359 | 360 | Output ON 361 | 362 | 363 | 364 | 365 | 366 | 367 | color:#000000;background-color:#808080; 368 | 369 | 370 | Output OFF 371 | 372 | 373 | 374 | 375 | 376 | 377 | color:#000000;background-color:#ff0000; 378 | 379 | 380 | Output Fault 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | portLine 389 | baudrateCombo 390 | addressSpin 391 | pollingSpin 392 | inputVoltageLine 393 | outputVoltageLine 394 | outputCurrentLine 395 | outputPowerLine 396 | inputVoltagePush 397 | outputVoltagePush 398 | outputCurrentPush 399 | outputPowerPush 400 | voltageSetPush 401 | currentSetPush 402 | outputOnTextPush 403 | outputOffTextPush 404 | outputFaultTextPush 405 | outputOnButtonPush 406 | outputOffButtonPush 407 | outputFaultButtonPush 408 | 409 | 410 | 411 | 412 | -------------------------------------------------------------------------------- /ridengui/mainwindow.py: -------------------------------------------------------------------------------- 1 | # Built-in modules 2 | import logging 3 | from os.path import dirname 4 | 5 | # Third-party modules 6 | from qtpy.QtCore import QSettings 7 | from qtpy.QtGui import QFontDatabase 8 | from qtpy.QtWidgets import QApplication, QMainWindow 9 | from qtpy.uic import loadUi 10 | from riden import Riden 11 | 12 | # Local modules 13 | from ridengui.about import AboutDialog 14 | from ridengui.settings import SettingsWizard 15 | from ridengui.worker import Worker 16 | 17 | 18 | class MainWindow(QMainWindow): 19 | def __init__(self, port: str = None, baudrate: int = None, address: int = None): 20 | super().__init__() 21 | 22 | # 23 | # Main window UI 24 | # 25 | 26 | logging.debug("Initializing MainWindow from mainwindow.ui") 27 | self.ui = loadUi(dirname(__file__) + "/mainwindow.ui", self) 28 | 29 | logging.debug("Configuring fixed font for labels") 30 | font = QFontDatabase.systemFont(QFontDatabase.FixedFont) 31 | font.setBold(True) 32 | font.setPointSize(36) 33 | self.ui.voltageInput.setFont(font) 34 | self.ui.voltageOutput.setFont(font) 35 | self.ui.currentOutput.setFont(font) 36 | self.ui.powerOutput.setFont(font) 37 | 38 | logging.debug("Resizing widgets and window to minimum size") 39 | self.adjustSize() 40 | self.resize(self.minimumSize()) 41 | 42 | # 43 | # Default value definitions 44 | # 45 | 46 | # Precition output formats 47 | # Display formats on real devices 48 | # Model V I P-on<99W P-on>99W 49 | # RD6006P 00.000 0.0000 00.000 000.00 50 | # RD6006 00.00 0.000 00.00 000.0 51 | # RD6012 00.00 00.00 00.00 000.0 52 | # RD6018 00.00 00.00 00.00 000.0 53 | 54 | logging.debug("Defining default value definitions") 55 | self.default_voltage_input_format = "%05.2f" 56 | self.default_voltage_output_format = "%05.2f" 57 | self.default_current_output_format = "%05.2f" 58 | self.default_power_output_format = "%6.2f" 59 | self.default_voltage_max = 61.0 60 | self.default_current_max = 0.0 61 | 62 | # 63 | # QSettings & Setting variables 64 | # 65 | 66 | logging.debug("Initializing QSettings") 67 | self.settings = QSettings("ShayBox", "RidenGUI") 68 | 69 | if self.settings.value("first-run", 1) == 1: 70 | logging.debug("First run detected, showing settings wizard") 71 | SettingsWizard(self.settings, self).exec() 72 | exit(0) 73 | 74 | logging.debug("Loading custom format strings from settings") 75 | self.voltage_input_format = self.settings.value("format/voltage-input", self.default_voltage_input_format) 76 | self.voltage_output_format = self.settings.value("format/voltage-output", self.default_voltage_output_format) 77 | self.current_output_format = self.settings.value("format/current-output", self.default_current_output_format) 78 | self.power_output_format = self.settings.value("format/power-output", self.default_power_output_format) 79 | 80 | logging.debug("Loading custom stylesheets from settings") 81 | self.output_on = self.settings.value("style/output-on-bg") + self.settings.value("style/output-on-text") 82 | self.output_off = self.settings.value("style/output-off-bg") + self.settings.value("style/output-off-text") 83 | self.output_fault = self.settings.value("style/output-fault-bg") + self.settings.value("style/output-fault-text") 84 | 85 | # 86 | # Riden 87 | # 88 | 89 | logging.debug("Initializing Riden library") 90 | self.r = Riden( 91 | port=port or self.settings.value("serial/port", "/dev/ttyUSB0"), 92 | baudrate=baudrate or int(self.settings.value("serial/baudrate", 115200)), 93 | address=address or int(self.settings.value("serial/address", 1)), 94 | ) 95 | 96 | logging.debug("Defining temporary variables for live feedback") 97 | self.prev_v_set = self.r.v_set 98 | self.prev_i_set = self.r.i_set 99 | 100 | # 101 | # Dynamic value definitions 102 | # 103 | 104 | logging.debug("Defining dynamic value definitions") 105 | if self.r.type == "RD6012": 106 | self.default_voltage_output_format = "%05.3f" 107 | self.default_current_output_format = "%05.4f" 108 | self.default_power_output_format = "%6.3f" 109 | self.default_current_max = 6.1 110 | elif self.r.type == "RD6006": 111 | self.default_current_output_format = "%04.3f" 112 | self.default_current_max = 6.1 113 | elif self.r.type == "RD6012": 114 | self.default_current_max = 12.1 115 | elif self.r.type == "RD6018": 116 | self.default_current_max = 18.1 117 | elif self.r.type == "RD6024": 118 | self.default_current_max = 24.1 119 | 120 | # 121 | # Qt Slots, Signals, and Messages 122 | # 123 | 124 | logging.debug("Connecting signals and slots") 125 | self.connect_signals() 126 | 127 | logging.debug("Setting permenant statusbar message") 128 | self.ui.statusbar.showMessage( 129 | "Connected to %s using %s at %s baud | FW: %s | SN: %s" 130 | % ( 131 | self.r.type, 132 | self.r.serial.port, 133 | self.r.serial.baudrate, 134 | self.r.fw, 135 | self.r.sn, 136 | ) 137 | ) 138 | 139 | # 140 | # Background worker 141 | # 142 | 143 | logging.debug("Starting worker thread") 144 | self.worker = Worker(self.r, self.settings, self) 145 | self.worker.update.connect(self.worker_signal) 146 | self.worker.start() 147 | 148 | def closeEvent(self, _): 149 | logging.debug("Saving settings to disk") 150 | self.settings.sync() 151 | 152 | logging.debug("Stopping worker thread") 153 | if hasattr(self, "worker"): 154 | self.worker.running = False 155 | if not self.worker.wait(1000): 156 | self.worker.terminate() 157 | self.worker.wait() 158 | 159 | def connect_signals(self): 160 | logging.debug("Connecting actionbar signals") 161 | self.ui.actionQuit.triggered.connect(self.close) 162 | self.ui.actionSettings.triggered.connect(lambda: SettingsWizard(self.settings, self).show()) 163 | self.ui.actionAboutRiden.triggered.connect(lambda: AboutDialog(self).show()) 164 | self.ui.actionAboutQt.triggered.connect(lambda: QApplication.aboutQt()) 165 | 166 | logging.debug("Connecting voltage/current min/max DoubleSpinBoxes to Dials") 167 | self.ui.voltageMinDoubleSpin.valueChanged.connect(lambda v: self.ui.voltageDial.setMinimum(int(v))) 168 | self.ui.voltageMaxDoubleSpin.valueChanged.connect(lambda v: self.ui.voltageDial.setMaximum(int(v))) 169 | self.ui.currentMinDoubleSpin.valueChanged.connect(lambda v: self.ui.currentDial.setMinimum(int(v))) 170 | self.ui.currentMaxDoubleSpin.valueChanged.connect(lambda v: self.ui.currentDial.setMaximum(int(v))) 171 | 172 | logging.debug("Connecting voltage/current min/max to DoubleSpinBoxes") 173 | self.ui.voltageMinDoubleSpin.valueChanged.connect(lambda v: self.ui.voltageDoubleSpin.setMinimum(int(v))) 174 | self.ui.voltageMaxDoubleSpin.valueChanged.connect(lambda v: self.ui.voltageDoubleSpin.setMaximum(int(v))) 175 | self.ui.currentMinDoubleSpin.valueChanged.connect(lambda v: self.ui.currentDoubleSpin.setMinimum(int(v))) 176 | self.ui.currentMaxDoubleSpin.valueChanged.connect(lambda v: self.ui.currentDoubleSpin.setMaximum(int(v))) 177 | 178 | logging.debug("Loading voltage/current min/max values from settings") 179 | self.ui.voltageMinDoubleSpin.setValue(int(self.settings.value("limits/voltage-min", 0)) / 1000) 180 | self.ui.voltageMaxDoubleSpin.setValue(int(self.settings.value("limits/voltage-max", self.default_voltage_max * 1000)) / 1000) 181 | self.ui.currentMinDoubleSpin.setValue(int(self.settings.value("limits/current-min", 0)) / 1000) 182 | self.ui.currentMaxDoubleSpin.setValue(int(self.settings.value("limits/current-max", self.default_current_max * 1000)) / 1000) 183 | 184 | logging.debug("Connecting voltage/current DoubleSpinBoxes to Dials") 185 | self.ui.voltageDoubleSpin.valueChanged.connect(lambda v: self.ui.voltageDial.setValue(int(v))) 186 | self.ui.currentDoubleSpin.valueChanged.connect(lambda v: self.ui.currentDial.setValue(int(v))) 187 | 188 | logging.debug("Connecting voltage/current Dials to DoubleSpinBoxes") 189 | self.ui.voltageDial.valueChanged.connect(lambda v: self.ui.voltageDoubleSpin.setValue(int(v))) 190 | self.ui.currentDial.valueChanged.connect(lambda v: self.ui.currentDoubleSpin.setValue(int(v))) 191 | 192 | logging.debug("Loading voltage/current values from riden") 193 | self.ui.voltageDoubleSpin.setValue(int(self.r.v_set)) 194 | self.ui.currentDoubleSpin.setValue(int(self.r.i_set)) 195 | 196 | logging.debug("Connecting voltage/current min/max DoubleSpinBoxes to settings") 197 | self.ui.voltageMinDoubleSpin.valueChanged.connect(lambda v: self.settings.setValue("limits/voltage-min", v * 1000)) 198 | self.ui.voltageMaxDoubleSpin.valueChanged.connect(lambda v: self.settings.setValue("limits/voltage-max", v * 1000)) 199 | self.ui.currentMinDoubleSpin.valueChanged.connect(lambda i: self.settings.setValue("limits/current-min", i * 1000)) 200 | self.ui.currentMaxDoubleSpin.valueChanged.connect(lambda i: self.settings.setValue("limits/current-max", i * 1000)) 201 | 202 | logging.debug("Connecting voltage/current step to DoubleSpinBoxes") 203 | 204 | def voltageStep(step: str): 205 | decimals = self.ui.voltageStepCombo.currentIndex() 206 | self.ui.voltageDoubleSpin.setSingleStep(float(step)) 207 | self.ui.voltageDoubleSpin.setDecimals(decimals) 208 | self.ui.voltageMinDoubleSpin.setDecimals(decimals) 209 | self.ui.voltageMaxDoubleSpin.setDecimals(decimals) 210 | 211 | def currentStep(step: str): 212 | decimals = self.ui.currentStepCombo.currentIndex() 213 | self.ui.currentDoubleSpin.setSingleStep(float(step)) 214 | self.ui.currentDoubleSpin.setDecimals(decimals) 215 | self.ui.currentMinDoubleSpin.setDecimals(decimals) 216 | self.ui.currentMaxDoubleSpin.setDecimals(decimals) 217 | 218 | self.ui.voltageStepCombo.currentTextChanged.connect(lambda s: voltageStep(s)) 219 | self.ui.currentStepCombo.currentTextChanged.connect(lambda s: currentStep(s)) 220 | 221 | logging.debug("Loading voltage/current step values from settings") 222 | self.ui.voltageStepCombo.setCurrentText(self.settings.value("limits/voltage-step", "0.01")) 223 | self.ui.currentStepCombo.setCurrentText(self.settings.value("limits/current-step", "0.01")) 224 | 225 | logging.debug("Connecting voltage/current step to settings") 226 | self.ui.voltageStepCombo.currentTextChanged.connect(lambda s: self.settings.setValue("limits/voltage-step", s)) 227 | self.ui.currentStepCombo.currentTextChanged.connect(lambda s: self.settings.setValue("limits/current-step", s)) 228 | 229 | logging.debug("Connecting output button to riden") 230 | self.ui.outputPush.clicked.connect(lambda: self.r.set_output(not self.r.output)) 231 | 232 | logging.debug("Connecting voltage/current DoubleSpinBoxes to riden") 233 | self.ui.voltageDoubleSpin.valueChanged.connect(lambda v: self.r.set_v_set(v) if self.ui.realtimeCheck.isChecked() else None) 234 | self.ui.currentDoubleSpin.valueChanged.connect(lambda i: self.r.set_i_set(i) if self.ui.realtimeCheck.isChecked() else None) 235 | 236 | logging.debug("Connecting voltage/current PushButtons to riden") 237 | self.ui.voltagePush.clicked.connect(lambda: self.r.set_v_set(self.ui.voltageDoubleSpin.value())) 238 | self.ui.currentPush.clicked.connect(lambda: self.r.set_i_set(self.ui.currentDoubleSpin.value())) 239 | 240 | def worker_signal(self): 241 | self.ui.keypad.setText("Locked" if self.r.keypad else "Unlocked") 242 | self.ui.constant.setText(self.r.cv_cc) 243 | self.ui.fault.setText("CC" if self.r.cv_cc == "CC" else self.r.ovp_ocp or "None") 244 | self.ui.energy.setText(f"{self.r.ah:.2f} Ah | {self.r.wh:.2f} Wh") 245 | self.ui.intTemp.setText(f"{self.r.int_c} °C | {self.r.int_f} °F") 246 | self.ui.extTemp.setText(f"{self.r.ext_c} °C | {self.r.ext_f} °F") 247 | self.ui.voltageInput.setText(self.voltage_input_format % self.r.v_in) 248 | self.ui.voltageOutput.setText(self.voltage_output_format % self.r.v_out) 249 | self.ui.currentOutput.setText(self.current_output_format % self.r.i_out) 250 | self.ui.powerOutput.setText(self.power_output_format % self.r.p_out) 251 | self.ui.outputPush.setText("CC" if self.r.cv_cc == "CC" else "ON" if self.r.output else "OFF") 252 | self.ui.outputPush.setStyleSheet(self.output_fault if self.r.cv_cc == "CC" else self.output_on if self.r.output else self.output_off) 253 | 254 | if self.ui.realtimeCheck.isChecked(): 255 | self.ui.voltagePush.setEnabled(False) 256 | self.ui.currentPush.setEnabled(False) 257 | else: 258 | if self.ui.voltageDoubleSpin.value() != self.prev_v_set: 259 | self.ui.voltagePush.setEnabled(True) 260 | 261 | if self.r.v_set != self.prev_v_set: 262 | self.ui.voltagePush.setEnabled(False) 263 | self.ui.voltageDoubleSpin.setValue(int(self.r.v_set)) 264 | self.prev_v_set = self.r.v_set 265 | 266 | if self.ui.currentDoubleSpin.value() != self.prev_i_set: 267 | self.ui.currentPush.setEnabled(True) 268 | 269 | if self.r.i_set != self.prev_i_set: 270 | self.ui.currentPush.setEnabled(False) 271 | self.ui.currentDoubleSpin.setValue(int(self.r.i_set)) 272 | self.prev_i_set = self.r.i_set 273 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "black" 3 | version = "22.1.0" 4 | description = "The uncompromising code formatter." 5 | category = "dev" 6 | optional = false 7 | python-versions = ">=3.6.2" 8 | 9 | [package.dependencies] 10 | click = ">=8.0.0" 11 | mypy-extensions = ">=0.4.3" 12 | pathspec = ">=0.9.0" 13 | platformdirs = ">=2" 14 | tomli = ">=1.1.0" 15 | typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} 16 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 17 | 18 | [package.extras] 19 | colorama = ["colorama (>=0.4.3)"] 20 | d = ["aiohttp (>=3.7.4)"] 21 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 22 | uvloop = ["uvloop (>=0.15.2)"] 23 | 24 | [[package]] 25 | name = "click" 26 | version = "8.0.4" 27 | description = "Composable command line interface toolkit" 28 | category = "main" 29 | optional = false 30 | python-versions = ">=3.6" 31 | 32 | [package.dependencies] 33 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 34 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 35 | 36 | [[package]] 37 | name = "colorama" 38 | version = "0.4.4" 39 | description = "Cross-platform colored terminal text." 40 | category = "main" 41 | optional = false 42 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 43 | 44 | [[package]] 45 | name = "importlib-metadata" 46 | version = "4.11.2" 47 | description = "Read metadata from Python packages" 48 | category = "main" 49 | optional = false 50 | python-versions = ">=3.7" 51 | 52 | [package.dependencies] 53 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} 54 | zipp = ">=0.5" 55 | 56 | [package.extras] 57 | docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] 58 | perf = ["ipython"] 59 | testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] 60 | 61 | [[package]] 62 | name = "modbus-tk" 63 | version = "1.1.2" 64 | description = "Implementation of modbus protocol in python" 65 | category = "main" 66 | optional = false 67 | python-versions = "*" 68 | 69 | [package.dependencies] 70 | pyserial = ">=3.1" 71 | 72 | [[package]] 73 | name = "mypy-extensions" 74 | version = "0.4.3" 75 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 76 | category = "dev" 77 | optional = false 78 | python-versions = "*" 79 | 80 | [[package]] 81 | name = "packaging" 82 | version = "21.3" 83 | description = "Core utilities for Python packages" 84 | category = "main" 85 | optional = false 86 | python-versions = ">=3.6" 87 | 88 | [package.dependencies] 89 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" 90 | 91 | [[package]] 92 | name = "pathspec" 93 | version = "0.9.0" 94 | description = "Utility library for gitignore style pattern matching of file paths." 95 | category = "dev" 96 | optional = false 97 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 98 | 99 | [[package]] 100 | name = "platformdirs" 101 | version = "2.5.1" 102 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 103 | category = "dev" 104 | optional = false 105 | python-versions = ">=3.7" 106 | 107 | [package.extras] 108 | docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] 109 | test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] 110 | 111 | [[package]] 112 | name = "pyparsing" 113 | version = "3.0.7" 114 | description = "Python parsing module" 115 | category = "main" 116 | optional = false 117 | python-versions = ">=3.6" 118 | 119 | [package.extras] 120 | diagrams = ["jinja2", "railroad-diagrams"] 121 | 122 | [[package]] 123 | name = "pyqt5" 124 | version = "5.15.6" 125 | description = "Python bindings for the Qt cross platform application toolkit" 126 | category = "main" 127 | optional = false 128 | python-versions = ">=3.6" 129 | 130 | [package.dependencies] 131 | PyQt5-Qt5 = ">=5.15.2" 132 | PyQt5-sip = ">=12.8,<13" 133 | 134 | [[package]] 135 | name = "pyqt5-qt5" 136 | version = "5.15.2" 137 | description = "The subset of a Qt installation needed by PyQt5." 138 | category = "main" 139 | optional = false 140 | python-versions = "*" 141 | 142 | [[package]] 143 | name = "pyqt5-sip" 144 | version = "12.9.1" 145 | description = "The sip module support for PyQt5" 146 | category = "main" 147 | optional = false 148 | python-versions = ">=3.5" 149 | 150 | [[package]] 151 | name = "pyqt6" 152 | version = "6.2.3" 153 | description = "Python bindings for the Qt cross platform application toolkit" 154 | category = "main" 155 | optional = false 156 | python-versions = ">=3.6.1" 157 | 158 | [package.dependencies] 159 | PyQt6-Qt6 = ">=6.2.3" 160 | PyQt6-sip = ">=13.2,<14" 161 | 162 | [[package]] 163 | name = "pyqt6-qt6" 164 | version = "6.2.3" 165 | description = "The subset of a Qt installation needed by PyQt6." 166 | category = "main" 167 | optional = false 168 | python-versions = "*" 169 | 170 | [[package]] 171 | name = "pyqt6-sip" 172 | version = "13.2.1" 173 | description = "The sip module support for PyQt6" 174 | category = "main" 175 | optional = false 176 | python-versions = ">=3.6" 177 | 178 | [[package]] 179 | name = "pyserial" 180 | version = "3.5" 181 | description = "Python Serial Port Extension" 182 | category = "main" 183 | optional = false 184 | python-versions = "*" 185 | 186 | [package.extras] 187 | cp2110 = ["hidapi"] 188 | 189 | [[package]] 190 | name = "qtpy" 191 | version = "2.0.1" 192 | description = "Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6)." 193 | category = "main" 194 | optional = false 195 | python-versions = ">=3.6" 196 | 197 | [package.dependencies] 198 | packaging = "*" 199 | 200 | [package.extras] 201 | test = ["pytest (>=6.0.0)", "pytest-cov (>=3.0.0)", "pytest-qt"] 202 | 203 | [[package]] 204 | name = "riden" 205 | version = "1.2.0" 206 | description = "A python library for Riden RD power supplies" 207 | category = "main" 208 | optional = false 209 | python-versions = ">=3.7,<4.0" 210 | develop = false 211 | 212 | [package.dependencies] 213 | click = "^8.0.3" 214 | modbus_tk = "^1.1.2" 215 | pyserial = "^3.5" 216 | 217 | [package.source] 218 | type = "git" 219 | url = "https://github.com/shaybox/riden.git" 220 | reference = "master" 221 | resolved_reference = "d07096181c34eea1b6433185c92ffae8a41838d7" 222 | 223 | [[package]] 224 | name = "tomli" 225 | version = "2.0.1" 226 | description = "A lil' TOML parser" 227 | category = "dev" 228 | optional = false 229 | python-versions = ">=3.7" 230 | 231 | [[package]] 232 | name = "typed-ast" 233 | version = "1.5.2" 234 | description = "a fork of Python 2 and 3 ast modules with type comment support" 235 | category = "dev" 236 | optional = false 237 | python-versions = ">=3.6" 238 | 239 | [[package]] 240 | name = "typing-extensions" 241 | version = "4.1.1" 242 | description = "Backported and Experimental Type Hints for Python 3.6+" 243 | category = "main" 244 | optional = false 245 | python-versions = ">=3.6" 246 | 247 | [[package]] 248 | name = "zipp" 249 | version = "3.7.0" 250 | description = "Backport of pathlib-compatible object wrapper for zip files" 251 | category = "main" 252 | optional = false 253 | python-versions = ">=3.7" 254 | 255 | [package.extras] 256 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] 257 | testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] 258 | 259 | [extras] 260 | PySide2 = [] 261 | PySide6 = [] 262 | 263 | [metadata] 264 | lock-version = "1.1" 265 | python-versions = ">=3.7,<3.11" 266 | content-hash = "87d53d5564e524f0850984f51887c7d1054062f035cb3cb32379002e3dd87548" 267 | 268 | [metadata.files] 269 | black = [ 270 | {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"}, 271 | {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"}, 272 | {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"}, 273 | {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"}, 274 | {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"}, 275 | {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"}, 276 | {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"}, 277 | {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"}, 278 | {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"}, 279 | {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"}, 280 | {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"}, 281 | {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"}, 282 | {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"}, 283 | {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"}, 284 | {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"}, 285 | {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"}, 286 | {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"}, 287 | {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"}, 288 | {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"}, 289 | {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"}, 290 | {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"}, 291 | {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"}, 292 | {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"}, 293 | ] 294 | click = [ 295 | {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, 296 | {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, 297 | ] 298 | colorama = [ 299 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 300 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 301 | ] 302 | importlib-metadata = [ 303 | {file = "importlib_metadata-4.11.2-py3-none-any.whl", hash = "sha256:d16e8c1deb60de41b8e8ed21c1a7b947b0bc62fab7e1d470bcdf331cea2e6735"}, 304 | {file = "importlib_metadata-4.11.2.tar.gz", hash = "sha256:b36ffa925fe3139b2f6ff11d6925ffd4fa7bc47870165e3ac260ac7b4f91e6ac"}, 305 | ] 306 | modbus-tk = [ 307 | {file = "modbus_tk-1.1.2.tar.gz", hash = "sha256:893514bbd8c92118d20a19979e0239e7cb2a63f8f1795a0271e57def09d11770"}, 308 | ] 309 | mypy-extensions = [ 310 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 311 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 312 | ] 313 | packaging = [ 314 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, 315 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, 316 | ] 317 | pathspec = [ 318 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, 319 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, 320 | ] 321 | platformdirs = [ 322 | {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, 323 | {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, 324 | ] 325 | pyparsing = [ 326 | {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, 327 | {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, 328 | ] 329 | pyqt5 = [ 330 | {file = "PyQt5-5.15.6-cp36-abi3-macosx_10_13_x86_64.whl", hash = "sha256:33ced1c876f6a26e7899615a5a4efef2167c263488837c7beed023a64cebd051"}, 331 | {file = "PyQt5-5.15.6-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:9d6efad0377aa78bf081a20ac752ce86096ded18f04c592d98f5b92dc879ad0a"}, 332 | {file = "PyQt5-5.15.6-cp36-abi3-win32.whl", hash = "sha256:9d2dcdaf82263ae56023410a7af15d1fd746c8e361733a7d0d1bd1f004ec2793"}, 333 | {file = "PyQt5-5.15.6-cp36-abi3-win_amd64.whl", hash = "sha256:f411ecda52e488e1d3c5cce7563e1b2ca9cf0b7531e3c25b03d9a7e56e07e7fc"}, 334 | {file = "PyQt5-5.15.6.tar.gz", hash = "sha256:80343bcab95ffba619f2ed2467fd828ffeb0a251ad7225be5fc06dcc333af452"}, 335 | ] 336 | pyqt5-qt5 = [ 337 | {file = "PyQt5_Qt5-5.15.2-py3-none-macosx_10_13_intel.whl", hash = "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154"}, 338 | {file = "PyQt5_Qt5-5.15.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a"}, 339 | {file = "PyQt5_Qt5-5.15.2-py3-none-win32.whl", hash = "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327"}, 340 | {file = "PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962"}, 341 | ] 342 | pyqt5-sip = [ 343 | {file = "PyQt5_sip-12.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b2e553e21b7ff124007a6b9168f8bb8c171fdf230d31ca0588df180f10bacbe"}, 344 | {file = "PyQt5_sip-12.9.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:5740a1770d6b92a5dca8bb0bda4620baf0d7a726beb864f69c667ddac91d6f64"}, 345 | {file = "PyQt5_sip-12.9.1-cp310-cp310-win32.whl", hash = "sha256:9699286fcdf4f75a4b91c7e4832c0f926af18d648c62a4ed72dd294c1a93705a"}, 346 | {file = "PyQt5_sip-12.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:e2792af660da7479799f53028da88190ae8b4a0ad5acc2acbfd6c7bbfe110d58"}, 347 | {file = "PyQt5_sip-12.9.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:7ee08ad0ebf85b935f5d8d38306f8665fff9a6026c14fc0a7d780649e889c096"}, 348 | {file = "PyQt5_sip-12.9.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2d21420b0739df2607864e2c80ca01994bc40cb116da6ad024ea8d9f407b0356"}, 349 | {file = "PyQt5_sip-12.9.1-cp36-cp36m-win32.whl", hash = "sha256:ffd25051962c593d1c3c30188b9fbd8589ba17acd23a0202dc987bd3552fa611"}, 350 | {file = "PyQt5_sip-12.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:78ef8f1f41819661aa8e3117d6c1cd76fa14aef265e5bfd515dbfc64d412416b"}, 351 | {file = "PyQt5_sip-12.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5e641182bfee0501267c55e687832e4efe05becdae9e555d3695d706009b6598"}, 352 | {file = "PyQt5_sip-12.9.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c9a977d2835a5fbf250b00d61267dc228bdec9e20c7420d4e8d54d6f20410f87"}, 353 | {file = "PyQt5_sip-12.9.1-cp37-cp37m-win32.whl", hash = "sha256:cec6ebf0b1163b18f09bc523160c467a9528b6dca129753827ac0bc432b332ae"}, 354 | {file = "PyQt5_sip-12.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:82c1b3080db7634fa318fddbb3cfaa30e63a67bca1001a76958c31f30b774a9d"}, 355 | {file = "PyQt5_sip-12.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cfaad4a773c18b963092589b1a98153d36624601de8597a4dc287e5a295d5625"}, 356 | {file = "PyQt5_sip-12.9.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ce7a8b3af9db378c46b345d9809d481a74c4bfcd3129486c054fbdbc6a3503f9"}, 357 | {file = "PyQt5_sip-12.9.1-cp38-cp38-win32.whl", hash = "sha256:8fe5b3e4bbb8b472d05631cad21028d073f9f8eda770041449514cb3824a867f"}, 358 | {file = "PyQt5_sip-12.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:5d59c4a5e856a35c41b47f5a23e1635b38cd1672f4f0122a68ebcb6889523ff2"}, 359 | {file = "PyQt5_sip-12.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b56aedf7b0a496e4a8bd6087566888cea448aa01c76126cdb8b140e3ff3f5d93"}, 360 | {file = "PyQt5_sip-12.9.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:53e23dcc0fc3857204abd47660e383b930941bd1aeaf3c78ed59c5c12dd48010"}, 361 | {file = "PyQt5_sip-12.9.1-cp39-cp39-win32.whl", hash = "sha256:ee188eac5fd94dfe8d9e04a9e7fbda65c3535d5709278d8b7367ebd54f00e27f"}, 362 | {file = "PyQt5_sip-12.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:989d51c41456cc496cb96f0b341464932b957040d26561f0bb4cf5a0914d6b36"}, 363 | {file = "PyQt5_sip-12.9.1.tar.gz", hash = "sha256:2f24f299b44c511c23796aafbbb581bfdebf78d0905657b7cee2141b4982030e"}, 364 | ] 365 | pyqt6 = [ 366 | {file = "PyQt6-6.2.3-cp36-abi3-macosx_10_14_universal2.whl", hash = "sha256:577334c9d4518022a4cb6f9799dfbd1b996167eb31404b5a63d6c43d603e6418"}, 367 | {file = "PyQt6-6.2.3-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:8a2f357b86fec8598f52f16d5f93416931017ca1986d5f68679c9565bfc21fff"}, 368 | {file = "PyQt6-6.2.3-cp36-abi3-win_amd64.whl", hash = "sha256:11c039b07962b29246de2da0912f4f663786185fd74d48daac7a270a43c8d92a"}, 369 | {file = "PyQt6-6.2.3.tar.gz", hash = "sha256:a9bfcac198fe4b703706f809bb686c7cef5f60a7c802fc145c6b57929c7a6a34"}, 370 | ] 371 | pyqt6-qt6 = [ 372 | {file = "PyQt6_Qt6-6.2.3-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:02c1f02c04cfac8affb66fc56cbf1d033fb36efee98dd40ba59e60c816018302"}, 373 | {file = "PyQt6_Qt6-6.2.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bdf799911f004f904b00b9424e590cdb9138e7fc687d036c73c458e4c6c2efbd"}, 374 | {file = "PyQt6_Qt6-6.2.3-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:7d6f37204714bf3a6686f4d32bddd8b13d7e1adec3039cd2d27901bb827d7610"}, 375 | {file = "PyQt6_Qt6-6.2.3-py3-none-win_amd64.whl", hash = "sha256:6c7fa27a71eb0da81f39ec7a8e2c298d5e2dfecbc923875dcc932478b3c50ef3"}, 376 | ] 377 | pyqt6-sip = [ 378 | {file = "PyQt6_sip-13.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:226e9e349aa16dc1132f106ca01fa99cf7cb8e59daee29304c2fea5fa33212ec"}, 379 | {file = "PyQt6_sip-13.2.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:0314d011633bc697e99f3f9897b484720e81a5f4ba0eaa5f05c5811e2e74ea53"}, 380 | {file = "PyQt6_sip-13.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:8b52d42e42e6e9f934ac7528cd154ac0210a532bb33fa1edfb4a8bbfb73ff88b"}, 381 | {file = "PyQt6_sip-13.2.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:e2e6a3972169891dbc33d806f50ebf17eaa47a487ff6e4910fe2485c47cb6c2b"}, 382 | {file = "PyQt6_sip-13.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:a3d53fab72f959b45aeb954124255b585ff8d497a514a2582e0afd808fc2f3da"}, 383 | {file = "PyQt6_sip-13.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:082a80264699d4e2e919a7de8b6662886a353863d2b30a0047fe73d42e65c98e"}, 384 | {file = "PyQt6_sip-13.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c456d5ccc4478254052082e298db01bb9d0495471c1659046697bb5dc9d2506c"}, 385 | {file = "PyQt6_sip-13.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:65f5aee6195bd0e785bd74f75ee080a5d5fb840c03210956e4ccbdde481b487c"}, 386 | {file = "PyQt6_sip-13.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:43afd9c9fdbc5f6ed2e22cae0752a8b8d9545c6d85f314bd27b861e21d4a97fe"}, 387 | {file = "PyQt6_sip-13.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0a49f2d0bb49bc9d72665d62fb5ab6549c72dcf49e1e52dc2046edb8832a17a3"}, 388 | {file = "PyQt6_sip-13.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0ede42e84a79871022e1a8e4d5c05f70821b2795910c4cd103e863ce62bc8d68"}, 389 | {file = "PyQt6_sip-13.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:b0d92f4a21706b18ab80c088cded94cd64d32a0c48e1729a4cc53fe5ab93cc1a"}, 390 | {file = "PyQt6_sip-13.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:616b6bad827e9c6e7ce5179883ca0f44110a42dcb045344aa28a495c05e19795"}, 391 | {file = "PyQt6_sip-13.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f4226d4ab239d8655f94c42b397f23e6e85b246f614ff81162ef9321e47f7619"}, 392 | {file = "PyQt6_sip-13.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:4b119a8fd880ece15a5bdff583edccd89dbc79d49de2e11cbbd6bba72713d1f3"}, 393 | {file = "PyQt6_sip-13.2.1.tar.gz", hash = "sha256:b7bce59900b2e0a04f70246de2ccf79ee7933036b6b9183cf039b62eeae2b858"}, 394 | ] 395 | pyserial = [ 396 | {file = "pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0"}, 397 | {file = "pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb"}, 398 | ] 399 | qtpy = [ 400 | {file = "QtPy-2.0.1-py3-none-any.whl", hash = "sha256:d93f2c98e97387fcc9d623d509772af5b6c15ab9d8f9f4c5dfbad9a73ad34812"}, 401 | {file = "QtPy-2.0.1.tar.gz", hash = "sha256:adfd073ffbd2de81dc7aaa0b983499ef5c59c96adcfdcc9dea60d42ca885eb8f"}, 402 | ] 403 | riden = [] 404 | tomli = [ 405 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 406 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 407 | ] 408 | typed-ast = [ 409 | {file = "typed_ast-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266"}, 410 | {file = "typed_ast-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596"}, 411 | {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985"}, 412 | {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76"}, 413 | {file = "typed_ast-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a"}, 414 | {file = "typed_ast-1.5.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837"}, 415 | {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78"}, 416 | {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e"}, 417 | {file = "typed_ast-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d"}, 418 | {file = "typed_ast-1.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd"}, 419 | {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88"}, 420 | {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7"}, 421 | {file = "typed_ast-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30"}, 422 | {file = "typed_ast-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4"}, 423 | {file = "typed_ast-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca"}, 424 | {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb"}, 425 | {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b"}, 426 | {file = "typed_ast-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7"}, 427 | {file = "typed_ast-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098"}, 428 | {file = "typed_ast-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344"}, 429 | {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e"}, 430 | {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e"}, 431 | {file = "typed_ast-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5"}, 432 | {file = "typed_ast-1.5.2.tar.gz", hash = "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27"}, 433 | ] 434 | typing-extensions = [ 435 | {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, 436 | {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, 437 | ] 438 | zipp = [ 439 | {file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"}, 440 | {file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"}, 441 | ] 442 | -------------------------------------------------------------------------------- /ridengui/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1040 10 | 728 11 | 12 | 13 | 14 | RidenGUI 15 | 16 | 17 | 18 | .. 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 12 29 | 30 | 31 | 32 | Keypad 33 | 34 | 35 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 12 44 | 45 | 46 | 47 | Constant 48 | 49 | 50 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 12 59 | 60 | 61 | 62 | Unlocked 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 12 71 | 72 | 73 | 74 | Voltage 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 12 83 | 84 | 85 | 86 | Fault 87 | 88 | 89 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 12 98 | 99 | 100 | 101 | None 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | Qt::Horizontal 111 | 112 | 113 | 114 | 115 | 116 | 117 | Qt::Vertical 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 12 128 | 129 | 130 | 131 | color:#ff0000 132 | 133 | 134 | Apply Voltage and Current changes in realtime 135 | 136 | 137 | 138 | 139 | 140 | 141 | Qt::Horizontal 142 | 143 | 144 | 145 | 40 146 | 20 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | Qt::Horizontal 155 | 156 | 157 | 158 | 40 159 | 20 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | Qt::Horizontal 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 12 180 | 181 | 182 | 183 | 00.00 Ah | 00.00 Wh 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 12 192 | 193 | 194 | 195 | 00.00°C | 00.00°F 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 12 204 | 205 | 206 | 207 | Energy 208 | 209 | 210 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 12 219 | 220 | 221 | 222 | Int Temp 223 | 224 | 225 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 12 234 | 235 | 236 | 237 | Ext Temp 238 | 239 | 240 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 12 249 | 250 | 251 | 252 | 00.00°C | 00.00°F 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | Qt::Vertical 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 12 272 | 75 273 | true 274 | 275 | 276 | 277 | Voltage 278 | 279 | 280 | Qt::AlignCenter 281 | 282 | 283 | voltageDial 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 12 292 | 293 | 294 | 295 | 1000.000000000000000 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 16 304 | 305 | 306 | 307 | color: #ffff00 308 | 309 | 310 | Qt::AlignCenter 311 | 312 | 313 | 0.000000000000000 314 | 315 | 316 | 0.100000000000000 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 12 325 | 326 | 327 | 328 | Minimum 329 | 330 | 331 | Qt::AlignCenter 332 | 333 | 334 | voltageMinDoubleSpin 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 12 343 | 344 | 345 | 346 | Maximum 347 | 348 | 349 | Qt::AlignCenter 350 | 351 | 352 | voltageMaxDoubleSpin 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 12 361 | 362 | 363 | 364 | 1000.000000000000000 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 12 373 | 374 | 375 | 376 | 2 377 | 378 | 379 | 380 | 1 381 | 382 | 383 | 384 | 385 | 0.1 386 | 387 | 388 | 389 | 390 | 0.01 391 | 392 | 393 | 394 | 395 | 0.001 396 | 397 | 398 | 399 | 400 | 0.0001 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 1 410 | 1 411 | 412 | 413 | 414 | 415 | 350 416 | 350 417 | 418 | 419 | 420 | 0 421 | 422 | 423 | 1 424 | 425 | 426 | true 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 12 435 | 436 | 437 | 438 | Step 439 | 440 | 441 | Qt::AlignCenter 442 | 443 | 444 | voltageStepCombo 445 | 446 | 447 | 448 | 449 | 450 | 451 | false 452 | 453 | 454 | 455 | 16 456 | 457 | 458 | 459 | Set 460 | 461 | 462 | 463 | 464 | 465 | 466 | Qt::Vertical 467 | 468 | 469 | 470 | 20 471 | 40 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 12 485 | 486 | 487 | 488 | Step 489 | 490 | 491 | Qt::AlignCenter 492 | 493 | 494 | currentStepCombo 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 16 503 | 504 | 505 | 506 | color: #ffff00 507 | 508 | 509 | Qt::AlignCenter 510 | 511 | 512 | 0.000000000000000 513 | 514 | 515 | 0.100000000000000 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 12 524 | 525 | 526 | 527 | Minimum 528 | 529 | 530 | Qt::AlignCenter 531 | 532 | 533 | currentMinDoubleSpin 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 1 542 | 1 543 | 544 | 545 | 546 | 547 | 350 548 | 350 549 | 550 | 551 | 552 | 0 553 | 554 | 555 | 1 556 | 557 | 558 | true 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 12 567 | 568 | 569 | 570 | 1000.000000000000000 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 12 579 | 580 | 581 | 582 | 1000.000000000000000 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 12 591 | 592 | 593 | 594 | Maximum 595 | 596 | 597 | Qt::AlignCenter 598 | 599 | 600 | currentMaxDoubleSpin 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 12 609 | 610 | 611 | 612 | 2 613 | 614 | 615 | 616 | 1 617 | 618 | 619 | 620 | 621 | 0.1 622 | 623 | 624 | 625 | 626 | 0.01 627 | 628 | 629 | 630 | 631 | 0.001 632 | 633 | 634 | 635 | 636 | 0.0001 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 12 646 | 75 647 | true 648 | 649 | 650 | 651 | Current 652 | 653 | 654 | Qt::AlignCenter 655 | 656 | 657 | currentDial 658 | 659 | 660 | 661 | 662 | 663 | 664 | false 665 | 666 | 667 | 668 | 16 669 | 670 | 671 | 672 | Set 673 | 674 | 675 | 676 | 677 | 678 | 679 | Qt::Vertical 680 | 681 | 682 | 683 | 20 684 | 40 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 1 700 | 1 701 | 702 | 703 | 704 | 705 | 36 706 | 75 707 | true 708 | 709 | 710 | 711 | color: #ff00ff 712 | 713 | 714 | 00.00 715 | 716 | 717 | Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 75 726 | true 727 | 728 | 729 | 730 | color: #ff00ff 731 | 732 | 733 | Watts 734 | 735 | 736 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 737 | 738 | 739 | 740 | 741 | 742 | 743 | Qt::Vertical 744 | 745 | 746 | 747 | 20 748 | 40 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 36 758 | 75 759 | true 760 | 761 | 762 | 763 | color: #ff00ff 764 | 765 | 766 | 00.00 767 | 768 | 769 | Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 75 778 | true 779 | 780 | 781 | 782 | color: #00ffff 783 | 784 | 785 | Amps 786 | 787 | 788 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 36 797 | 75 798 | true 799 | 800 | 801 | 802 | color: #00ffff 803 | 804 | 805 | 00.00 806 | 807 | 808 | Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 36 817 | 75 818 | true 819 | 820 | 821 | 822 | color: #00ff00 823 | 824 | 825 | 00.00 826 | 827 | 828 | Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 75 837 | true 838 | 839 | 840 | 841 | color: #00ff00 842 | 843 | 844 | Volts 845 | 846 | 847 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 848 | 849 | 850 | 851 | 852 | 853 | 854 | Qt::Vertical 855 | 856 | 857 | 858 | 20 859 | 40 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | Qt::Vertical 868 | 869 | 870 | 871 | 20 872 | 40 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 75 882 | true 883 | 884 | 885 | 886 | color: #ff00ff 887 | 888 | 889 | Volts 890 | 891 | 892 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 0 903 | 0 904 | 905 | 906 | 907 | 908 | 250 909 | 250 910 | 911 | 912 | 913 | 914 | 36 915 | 75 916 | true 917 | 918 | 919 | 920 | OFF 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | Qt::Vertical 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 0 939 | 0 940 | 1040 941 | 32 942 | 943 | 944 | 945 | 946 | File 947 | 948 | 949 | 950 | 951 | 952 | Edit 953 | 954 | 955 | 956 | 957 | 958 | 959 | View 960 | 961 | 962 | 963 | 964 | Help 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | Quit 978 | 979 | 980 | 981 | 982 | About RidenGUI 983 | 984 | 985 | 986 | 987 | GUI Settings 988 | 989 | 990 | GUI Settings 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | Riden Options 999 | 1000 | 1001 | Riden Options 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | About Qt 1010 | 1011 | 1012 | 1013 | 1014 | realtimeCheck 1015 | voltageDial 1016 | voltageMinDoubleSpin 1017 | voltageStepCombo 1018 | voltageMaxDoubleSpin 1019 | voltageDoubleSpin 1020 | voltagePush 1021 | currentDial 1022 | currentMinDoubleSpin 1023 | currentStepCombo 1024 | currentMaxDoubleSpin 1025 | currentDoubleSpin 1026 | currentPush 1027 | outputPush 1028 | 1029 | 1030 | 1031 | 1032 | --------------------------------------------------------------------------------