├── Netzteil.sh ├── README.md ├── config.json ├── dpsGUI.ui ├── icon.png ├── pyDPS.py └── screenshot.png /Netzteil.sh: -------------------------------------------------------------------------------- 1 | sudo rfcomm connect rfcomm0 00:BA:55:89:13:49 && sudo chmod +rwx /dev/rfcomm0 && cd ~/pyQtDPS5020/ && python3 ~/pyQtDPS5020/pyQtDPS.py 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # PyDPS 3 | Linux GUI for all DPS variable power supplies with USB or Bluetooth connection. 4 | 5 | ## Dependencies 6 | > sudo pip3 install minimalmodbus 7 | 8 | > sudo pip3 install pyqt5 9 | 10 | (Optional for plot) 11 | > sudo pip3 install pyqtgraph numpy 12 | 13 | ## HowTo 14 | - Modify config.json: 15 | - "dev_init_command": OS-Command to connect to device 16 | - You will need your Device-MAC-Adress for bluetooth connection 17 | - If you're using USB, you may leave this blank and just set the correct "dev_path". This may vary for different linux distributions 18 | - "dev_path": Set directory, where the device is mounted 19 | - Leave anything else (you can change "update_rate", which sets GUI-update-rate) 20 | - Run the following command: 21 | 22 | > python3 pyQtDPS.py 23 | - You may need to run as root for read/write privileges: 24 | 25 | > sudo python3 pyDPS.py 26 | 27 | ![Screenshot](screenshot.png) 28 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev_init_command": "sudo rfcomm connect rfcomm0 00:BA:55:89:13:49", 3 | "dev_path": "/dev/rfcomm0", 4 | "serial_baudrate": 9600, 5 | "serial_bytesize": 8, 6 | "serial_timeout": 2, 7 | "update_rate": 400, 8 | "maxAmps":20, 9 | "plotLength":120, 10 | "plot_update_rate":400 11 | } 12 | -------------------------------------------------------------------------------- /dpsGUI.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | PyDPS 4 | 5 | 6 | 7 | 0 8 | 0 9 | 712 10 | 406 11 | 12 | 13 | 14 | PyDPS 15 | 16 | 17 | QToolTip 18 | { 19 | border: 1px solid #76797C; 20 | background-color: rgb(90, 102, 117);; 21 | color: white; 22 | padding: 0px; 23 | opacity: 200; 24 | } 25 | 26 | QWidget 27 | { 28 | color: #eff0f1; 29 | background-color: rgba(49, 54, 59, .9); 30 | selection-background-color:rgba(49, 54, 59, .9); 31 | selection-color: #eff0f1; 32 | background-clip: border; 33 | border-image: none; 34 | border: 0px transparent black; 35 | outline: 0; 36 | } 37 | 38 | QGroupBox::indicator 39 | { 40 | width: 18px; 41 | height: 18px; 42 | } 43 | QGroupBox::indicator 44 | { 45 | margin-left: 2px; 46 | } 47 | 48 | QGroupBox::indicator:unchecked:hover, 49 | QGroupBox::indicator:unchecked:focus, 50 | QGroupBox::indicator:unchecked:pressed 51 | { 52 | border: none; 53 | image: url(data/ui/icons/checkbox_unchecked_hovered.png); 54 | } 55 | 56 | QGroupBox::indicator:checked:hover, 57 | QGroupBox::indicator:checked:focus, 58 | QGroupBox::indicator:checked:pressed 59 | { 60 | border: none; 61 | image: url(data/ui/icons/checkbox_checked_hovered.png); 62 | } 63 | 64 | QGroupBox::indicator:checked:disabled 65 | { 66 | image: url(data/ui/icons/checkbox_checked_disabled.png); 67 | } 68 | 69 | QGroupBox::indicator:unchecked:disabled 70 | { 71 | image: url(data/ui/icons/checkbox_unchecked_disabled.png); 72 | } 73 | 74 | QRadioButton 75 | { 76 | spacing: 5px; 77 | outline: none; 78 | color: #eff0f1; 79 | margin-bottom: 2px; 80 | } 81 | 82 | QRadioButton:disabled 83 | { 84 | color: #76797C; 85 | } 86 | QRadioButton::indicator 87 | { 88 | width: 21px; 89 | height: 21px; 90 | } 91 | 92 | QRadioButton::indicator:unchecked 93 | { 94 | image: url(data/ui/icons/radio_unchecked.png); 95 | } 96 | 97 | 98 | QRadioButton::indicator:unchecked:hover, 99 | QRadioButton::indicator:unchecked:focus, 100 | QRadioButton::indicator:unchecked:pressed 101 | { 102 | border: none; 103 | outline: none; 104 | image: url(data/ui/icons/radio_unchecked_hovered.png); 105 | } 106 | 107 | QRadioButton::indicator:checked 108 | { 109 | border: none; 110 | outline: none; 111 | image: url(data/ui/icons/radio_checked.png); 112 | } 113 | 114 | QRadioButton::indicator:checked:hover, 115 | QRadioButton::indicator:checked:focus, 116 | QRadioButton::indicator:checked:pressed 117 | { 118 | border: none; 119 | outline: none; 120 | image: url(data/ui/icons/radio_checked_hovered.png); 121 | } 122 | 123 | QRadioButton::indicator:checked:disabled 124 | { 125 | outline: none; 126 | image: url(data/ui/icons/radio_disabled.png); 127 | } 128 | 129 | QRadioButton::indicator:unchecked:disabled 130 | { 131 | image: url(data/ui/icons/radio_disabled.png); 132 | } 133 | 134 | 135 | QMenuBar 136 | { 137 | background-color: #31363b; 138 | color: #eff0f1; 139 | } 140 | 141 | QMenuBar::item 142 | { 143 | background: transparent; 144 | } 145 | 146 | QMenuBar::item:selected 147 | { 148 | background: transparent; 149 | border: 1px solid #76797C; 150 | } 151 | 152 | QMenuBar::item:pressed 153 | { 154 | border: 1px solid #76797C; 155 | background-color: rgba(49, 54, 59, .9); 156 | color: #eff0f1; 157 | margin-bottom:-1px; 158 | padding-bottom:1px; 159 | } 160 | 161 | QMenu 162 | { 163 | border: 1px solid #76797C; 164 | color: #eff0f1; 165 | margin: 2px; 166 | } 167 | 168 | QMenu::icon 169 | { 170 | margin: 5px; 171 | } 172 | 173 | QMenu::item 174 | { 175 | padding: 5px 30px 5px 30px; 176 | border: 1px solid transparent; /* reserve space for selection border */ 177 | } 178 | 179 | QMenu::item:selected 180 | { 181 | color: #eff0f1; 182 | } 183 | 184 | QMenu::separator { 185 | height: 2px; 186 | background: lightblue; 187 | margin-left: 10px; 188 | margin-right: 5px; 189 | } 190 | 191 | QMenu::indicator { 192 | width: 18px; 193 | height: 18px; 194 | } 195 | 196 | /* non-exclusive indicator = check box style indicator 197 | (see QActionGroup::setExclusive) */ 198 | QMenu::indicator:non-exclusive:unchecked { 199 | image: url(data/ui/icons/checkbox_unchecked.png); 200 | } 201 | 202 | QMenu::indicator:non-exclusive:unchecked:selected { 203 | image: url(data/ui/icons/checkbox_unchecked_hovered.png); 204 | } 205 | 206 | QMenu::indicator:non-exclusive:checked { 207 | image: url(data/ui/icons/checkbox_checked.png); 208 | } 209 | 210 | QMenu::indicator:non-exclusive:checked:selected { 211 | image: url(data/ui/icons/checkbox_checked_hovered.png); 212 | } 213 | 214 | /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ 215 | QMenu::indicator:exclusive:unchecked { 216 | image: url(data/ui/icons/radio_unchecked.png); 217 | } 218 | 219 | QMenu::indicator:exclusive:unchecked:selected { 220 | image: url(data/ui/icons/radio_unchecked_hovered.png); 221 | } 222 | 223 | QMenu::indicator:exclusive:checked { 224 | image: url(data/ui/icons/radio_checked.png); 225 | } 226 | 227 | QMenu::indicator:exclusive:checked:selected { 228 | image: url(data/ui/icons/radio_checked_hovered.png); 229 | } 230 | 231 | QMenu::right-arrow { 232 | margin: 5px; 233 | image: url(data/ui/icons/right_arrow.png) 234 | } 235 | 236 | 237 | QWidget:disabled 238 | { 239 | color: #454545; 240 | background-color: #31363b; 241 | } 242 | 243 | QAbstractItemView 244 | { 245 | alternate-background-color: #31363b; 246 | color: #eff0f1; 247 | border: 1px solid 3A3939; 248 | border-radius: 2px; 249 | } 250 | 251 | QWidget:focus, QMenuBar:focus 252 | { 253 | border: 1px solid rgba(49, 54, 59, .9); 254 | } 255 | 256 | QTabWidget:focus, QCheckBox:focus, QRadioButton:focus, QSlider:focus 257 | { 258 | border: none; 259 | } 260 | 261 | QLineEdit 262 | { 263 | background-color: #232629; 264 | padding: 5px; 265 | border-style: solid; 266 | border: 1px solid #76797C; 267 | border-radius: 2px; 268 | color: #eff0f1; 269 | } 270 | 271 | QAbstractItemView QLineEdit 272 | { 273 | padding: 0; 274 | } 275 | 276 | QGroupBox { 277 | border:1px solid black; 278 | border-radius: 0px; 279 | margin-top: 20px; 280 | } 281 | 282 | QGroupBox::title { 283 | subcontrol-origin: margin; 284 | subcontrol-position: top center; 285 | padding-left: 10px; 286 | padding-right: 10px; 287 | padding-top: 10px; 288 | } 289 | 290 | QAbstractScrollArea 291 | { 292 | border-radius: 2px; 293 | border: 1px solid #76797C; 294 | background-color: transparent; 295 | } 296 | 297 | QScrollBar:horizontal 298 | { 299 | height: 15px; 300 | margin: 3px 15px 3px 15px; 301 | border: 1px transparent #2A2929; 302 | border-radius: 4px; 303 | background-color: #2A2929; 304 | } 305 | 306 | QScrollBar::handle:horizontal 307 | { 308 | background-color: #605F5F; 309 | min-width: 5px; 310 | border-radius: 4px; 311 | } 312 | 313 | QScrollBar::add-line:horizontal 314 | { 315 | margin: 0px 3px 0px 3px; 316 | border-image: url(data/ui/icons/right_arrow_disabled.png); 317 | width: 10px; 318 | height: 10px; 319 | subcontrol-position: right; 320 | subcontrol-origin: margin; 321 | } 322 | 323 | QScrollBar::sub-line:horizontal 324 | { 325 | margin: 0px 3px 0px 3px; 326 | border-image: url(data/ui/icons/left_arrow_disabled.png); 327 | height: 10px; 328 | width: 10px; 329 | subcontrol-position: left; 330 | subcontrol-origin: margin; 331 | } 332 | 333 | QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on 334 | { 335 | border-image: url(data/ui/icons/right_arrow.png); 336 | height: 10px; 337 | width: 10px; 338 | subcontrol-position: right; 339 | subcontrol-origin: margin; 340 | } 341 | 342 | 343 | QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on 344 | { 345 | border-image: url(data/ui/icons/left_arrow.png); 346 | height: 10px; 347 | width: 10px; 348 | subcontrol-position: left; 349 | subcontrol-origin: margin; 350 | } 351 | 352 | QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal 353 | { 354 | background: none; 355 | } 356 | 357 | 358 | QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal 359 | { 360 | background: none; 361 | } 362 | 363 | QScrollBar:vertical 364 | { 365 | background-color: #2A2929; 366 | width: 15px; 367 | margin: 15px 3px 15px 3px; 368 | border: 1px transparent #2A2929; 369 | border-radius: 4px; 370 | } 371 | 372 | QScrollBar::handle:vertical 373 | { 374 | background-color: #605F5F; 375 | min-height: 5px; 376 | border-radius: 4px; 377 | } 378 | 379 | QScrollBar::sub-line:vertical 380 | { 381 | margin: 3px 0px 3px 0px; 382 | border-image: url(data/ui/icons/up_arrow_disabled.png); 383 | height: 10px; 384 | width: 10px; 385 | subcontrol-position: top; 386 | subcontrol-origin: margin; 387 | } 388 | 389 | QScrollBar::add-line:vertical 390 | { 391 | margin: 3px 0px 3px 0px; 392 | border-image: url(data/ui/icons/down_arrow_disabled.png); 393 | height: 10px; 394 | width: 10px; 395 | subcontrol-position: bottom; 396 | subcontrol-origin: margin; 397 | } 398 | 399 | QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on 400 | { 401 | 402 | border-image: url(data/ui/icons/up_arrow.png); 403 | height: 10px; 404 | width: 10px; 405 | subcontrol-position: top; 406 | subcontrol-origin: margin; 407 | } 408 | 409 | 410 | QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on 411 | { 412 | border-image: url(data/ui/icons/down_arrow.png); 413 | height: 10px; 414 | width: 10px; 415 | subcontrol-position: bottom; 416 | subcontrol-origin: margin; 417 | } 418 | 419 | QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical 420 | { 421 | background: none; 422 | } 423 | 424 | 425 | QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical 426 | { 427 | background: none; 428 | } 429 | 430 | QTextEdit 431 | { 432 | background-color: #232629; 433 | color: #eff0f1; 434 | border: 1px solid #76797C; 435 | } 436 | 437 | QPlainTextEdit 438 | { 439 | background-color: #232629;; 440 | color: #eff0f1; 441 | border-radius: 2px; 442 | border: 1px solid #76797C; 443 | } 444 | 445 | QHeaderView::section 446 | { 447 | background-color: #76797C; 448 | color: #eff0f1; 449 | padding: 5px; 450 | border: 1px solid #76797C; 451 | } 452 | 453 | QSizeGrip { 454 | image: url(data/ui/icons/sizegrip.png); 455 | width: 12px; 456 | height: 12px; 457 | } 458 | 459 | 460 | QMainWindow::separator 461 | { 462 | background-color: #31363b; 463 | color: white; 464 | padding-left: 4px; 465 | spacing: 2px; 466 | border: 1px dashed #76797C; 467 | } 468 | 469 | QMainWindow::separator:hover 470 | { 471 | 472 | background-color: #787876; 473 | color: white; 474 | padding-left: 4px; 475 | border: 1px solid #76797C; 476 | spacing: 2px; 477 | } 478 | 479 | 480 | QMenu::separator 481 | { 482 | height: 1px; 483 | background-color: #76797C; 484 | color: white; 485 | padding-left: 4px; 486 | margin-left: 10px; 487 | margin-right: 5px; 488 | } 489 | 490 | 491 | QFrame 492 | { 493 | border-radius: 2px; 494 | border: 1px solid #76797C; 495 | } 496 | 497 | QFrame[frameShape="0"] 498 | { 499 | border-radius: 2px; 500 | border: 1px transparent #76797C; 501 | } 502 | 503 | QStackedWidget 504 | { 505 | border: 1px transparent black; 506 | } 507 | 508 | QToolBar { 509 | border: 1px transparent #393838; 510 | background: 1px solid #31363b; 511 | font-weight: bold; 512 | } 513 | 514 | QToolBar::handle:horizontal { 515 | image: url(data/ui/icons/Hmovetoolbar.png); 516 | } 517 | QToolBar::handle:vertical { 518 | image: url(data/ui/icons/Vmovetoolbar.png); 519 | } 520 | QToolBar::separator:horizontal { 521 | image: url(data/ui/icons/Hsepartoolbar.png); 522 | } 523 | QToolBar::separator:vertical { 524 | image: url(data/ui/icons/Vsepartoolbar.png); 525 | } 526 | QToolButton#qt_toolbar_ext_button { 527 | background: #58595a 528 | } 529 | 530 | QPushButton 531 | { 532 | color: #eff0f1; 533 | /*background-color: #31363b;*/ 534 | background-color: #404347; 535 | border-width: 0px; 536 | border-color: #76797C; 537 | border-style: solid; 538 | padding: 5px; 539 | border-radius: 2px; 540 | outline: none; 541 | } 542 | 543 | QPushButton:disabled 544 | { 545 | background-color: #371b1b; 546 | border-width: 0px; 547 | border-color: #454545; 548 | border-style: solid; 549 | padding-top: 5px; 550 | padding-bottom: 5px; 551 | padding-left: 10px; 552 | padding-right: 10px; 553 | border-radius: 0px; 554 | color: #454545; 555 | } 556 | 557 | QPushButton:disabled:hover 558 | { 559 | background-color: #632525; 560 | border-width: 0px; 561 | border-color: #454545; 562 | border-style: solid; 563 | padding-top: 5px; 564 | padding-bottom: 5px; 565 | padding-left: 10px; 566 | padding-right: 10px; 567 | border-radius: 0px; 568 | color: #5d5d5d; 569 | } 570 | QPushButton:focus { 571 | background-color: rgba(49, 54, 59, .9); 572 | color: white; 573 | } 574 | 575 | QPushButton:pressed 576 | { 577 | background-color: rgba(49, 54, 59, .9); 578 | padding-top: -15px; 579 | padding-bottom: -17px; 580 | } 581 | 582 | QComboBox 583 | { 584 | background-color: #76797C; 585 | selection-background-color: rgba(49, 54, 59, .9); 586 | border-style: solid; 587 | border: 1px solid black; 588 | border-radius: 0px; 589 | padding: 5px; 590 | } 591 | 592 | QPushButton:checked{ 593 | background-color: #76797C; 594 | border-color: #6A6969; 595 | } 596 | 597 | QComboBox:hover,QPushButton:hover,QAbstractSpinBox:hover,QLineEdit:hover,QTextEdit:hover,QPlainTextEdit:hover,QAbstractView:hover,QTreeView:hover 598 | { 599 | border: 1px solid rgba(49, 54, 59, .9); 600 | color: #eff0f1; 601 | } 602 | 603 | QComboBox:on 604 | { 605 | padding-top: 3px; 606 | padding-left: 4px; 607 | background-color: #76797C; 608 | selection-background-color: #4a4a4a; 609 | } 610 | 611 | QComboBox QAbstractItemView 612 | { 613 | background-color: #232629; 614 | border-radius: 0px; 615 | border: 1px solid #76797C; 616 | selection-background-color: #18465d; 617 | } 618 | 619 | QComboBox::drop-down 620 | { 621 | subcontrol-origin: padding; 622 | subcontrol-position: top right; 623 | width: 5px; 624 | border-left-width: 0px; 625 | border-left-color: darkgray; 626 | border-left-style: solid; 627 | border-top-right-radius: 0px; 628 | border-bottom-right-radius: 0px; 629 | } 630 | 631 | QComboBox::down-arrow 632 | { 633 | image: url(data/ui/icons/down_arrow_disabled.png); 634 | } 635 | QComboBox::up-arrow 636 | { 637 | image: url(data/ui/icons/up_arrow_disabled.png); 638 | } 639 | 640 | QComboBox::down-arrow:on, QComboBox::down-arrow:hover, 641 | QComboBox::down-arrow:focus 642 | { 643 | image: url(data/ui/icons/down_arrow.png); 644 | } 645 | QComboBox::up-arrow:on, QComboBox::up-arrow:hover, 646 | QComboBox::up-arrow:focus 647 | { 648 | image: url(data/ui/icons/up_arrow.png); 649 | } 650 | 651 | QAbstractSpinBox { 652 | padding: 5px; 653 | border: 1px solid #76797C; 654 | background-color: #232629; 655 | color: #eff0f1; 656 | border-radius: 2px; 657 | min-width: 75px; 658 | } 659 | 660 | QAbstractSpinBox:up-button 661 | { 662 | background-color: transparent; 663 | subcontrol-origin: border; 664 | subcontrol-position: center right; 665 | } 666 | 667 | QAbstractSpinBox:down-button 668 | { 669 | background-color: transparent; 670 | subcontrol-origin: border; 671 | subcontrol-position: center left; 672 | } 673 | 674 | QAbstractSpinBox::up-arrow,QAbstractSpinBox::up-arrow:off { 675 | image: url(data/ui/icons/up_arrow_disabled.png); 676 | width: 10px; 677 | height: 10px; 678 | } 679 | QAbstractSpinBox::up-arrow:disabled { 680 | image: url(data/ui/icons/up_arrow_disabled.png); 681 | width: 10px; 682 | height: 10px; 683 | } 684 | 685 | QAbstractSpinBox::up-arrow:hover 686 | { 687 | image: url(data/ui/icons/up_arrow.png); 688 | } 689 | 690 | 691 | QAbstractSpinBox::down-arrow,QAbstractSpinBox::down-arrow:off 692 | { 693 | image: url(data/ui/icons/down_arrow_disabled.png); 694 | width: 10px; 695 | height: 10px; 696 | } 697 | 698 | QAbstractSpinBox::down-arrow:disabled { 699 | image: url(data/ui/icons/down_arrow_disabled.png); 700 | width: 10px; 701 | height: 10px; 702 | } 703 | QAbstractSpinBox::down-arrow:hover 704 | { 705 | image: url(data/ui/icons/down_arrow.png); 706 | } 707 | 708 | 709 | QLabel 710 | { 711 | border: 0px solid black; 712 | } 713 | 714 | QTabWidget{ 715 | border: 0px transparent black; 716 | } 717 | 718 | QTabWidget::pane { 719 | border: 1px solid black; 720 | padding: 0px; 721 | margin: 0px; 722 | } 723 | 724 | QTabWidget::tab-bar { 725 | left: 0px; /* move to the right by 5px */ 726 | border: 1px solid black; 727 | } 728 | 729 | QTabBar 730 | { 731 | qproperty-drawBase: 0; 732 | border-radius: 0px; 733 | } 734 | 735 | QTabBar:focus 736 | { 737 | border: 0px transparent black; 738 | } 739 | 740 | QTabBar::close-button { 741 | image: url(data/ui/icons/close.png); 742 | background: transparent; 743 | } 744 | 745 | QTabBar::close-button:hover 746 | { 747 | image: url(data/ui/icons/close-hover.png); 748 | background: transparent; 749 | } 750 | 751 | QTabBar::close-button:pressed { 752 | image: url(data/ui/icons/close-pressed.png); 753 | background: transparent; 754 | } 755 | 756 | /* TOP TABS */ 757 | QTabBar::tab:top { 758 | color: #eff0f1; 759 | border: 0px solid #76797C; 760 | border-bottom: 0px transparent black; 761 | background-color: #31363b; 762 | padding: 40px; 763 | min-width: 50px; 764 | border-top-left-radius: 0px; 765 | border-top-right-radius: 0px; 766 | } 767 | 768 | QTabBar::tab:top:!selected 769 | { 770 | color: #eff0f1; 771 | background-color: #54575B; 772 | border: 0px solid #76797C; 773 | border-bottom: 0px transparent black; 774 | border-top-left-radius: 0px; 775 | border-top-right-radius: 0px; 776 | } 777 | 778 | QTabBar::tab:top:!selected:hover { 779 | background-color: rgba(49, 54, 59, .9); 780 | } 781 | 782 | /* BOTTOM TABS */ 783 | QTabBar::tab:bottom { 784 | color: #eff0f1; 785 | border: 0px solid #76797C; 786 | border-top: 0px transparent black; 787 | background-color: #54575B; 788 | padding: 16px; 789 | border-bottom-left-radius: 0px; 790 | border-bottom-right-radius: 0px; 791 | min-width: 50px; 792 | } 793 | 794 | QTabBar::tab:bottom:!selected 795 | { 796 | color: #eff0f1; 797 | background-color: #31363b; 798 | border: 0px solid #76797C; 799 | border-top: 0px transparent black; 800 | border-bottom-left-radius: 0px; 801 | border-bottom-right-radius: 0px; 802 | } 803 | 804 | QTabBar::tab:bottom:!selected:hover { 805 | background-color: rgba(49, 54, 59, .9); 806 | } 807 | 808 | /* LEFT TABS */ 809 | QTabBar::tab:left { 810 | color: #eff0f1; 811 | border: 0px solid #76797C; 812 | border-left: 0px transparent black; 813 | background-color: #31363b; 814 | padding: 8px; 815 | border-top-right-radius: 0px; 816 | border-bottom-right-radius: 0px; 817 | min-height: 50px; 818 | } 819 | 820 | QTabBar::tab:left:!selected 821 | { 822 | color: #eff0f1; 823 | background-color: #54575B; 824 | border: 0px solid #76797C; 825 | border-left: 0px transparent black; 826 | border-top-right-radius: 0px; 827 | border-bottom-right-radius: 0px; 828 | } 829 | 830 | QTabBar::tab:left:!selected:hover { 831 | background-color: rgba(49, 54, 59, .9); 832 | } 833 | 834 | 835 | /* RIGHT TABS */ 836 | QTabBar::tab:right { 837 | color: #eff0f1; 838 | border: 0px solid #76797C; 839 | border-right: 0px transparent black; 840 | background-color: #31363b; 841 | padding: 8px; 842 | border-top-left-radius: 0px; 843 | border-bottom-left-radius: 0px; 844 | min-height: 50px; 845 | } 846 | 847 | QTabBar::tab:right:!selected 848 | { 849 | color: #eff0f1; 850 | background-color: #54575B; 851 | border: 0px solid #76797C; 852 | border-right: 0px transparent black; 853 | border-top-left-radius: 0px; 854 | border-bottom-left-radius: 0px; 855 | } 856 | 857 | QTabBar::tab:right:!selected:hover { 858 | background-color: rgba(49, 54, 59, .9); 859 | } 860 | 861 | QTabBar QToolButton::right-arrow:enabled { 862 | image: url(data/ui/icons/right_arrow.png); 863 | } 864 | 865 | QTabBar QToolButton::left-arrow:enabled { 866 | image: url(data/ui/icons/left_arrow.png); 867 | } 868 | 869 | QTabBar QToolButton::right-arrow:disabled { 870 | image: url(data/ui/icons/right_arrow_disabled.png); 871 | } 872 | 873 | QTabBar QToolButton::left-arrow:disabled { 874 | image: url(data/ui/icons/left_arrow_disabled.png); 875 | } 876 | 877 | 878 | QDockWidget { 879 | background: #31363b; 880 | border: 1px solid #403F3F; 881 | titlebar-close-icon: url(data/ui/icons/close.png); 882 | titlebar-normal-icon: url(data/ui/icons/undock.png); 883 | } 884 | 885 | QDockWidget::close-button, QDockWidget::float-button { 886 | border: 1px solid transparent; 887 | border-radius: 2px; 888 | background: transparent; 889 | } 890 | 891 | QDockWidget::close-button:hover, QDockWidget::float-button:hover { 892 | background: rgba(255, 255, 255, 10); 893 | } 894 | 895 | QDockWidget::close-button:pressed, QDockWidget::float-button:pressed { 896 | padding: 1px -1px -1px 1px; 897 | background: rgba(255, 255, 255, 10); 898 | } 899 | 900 | QTreeView, QListView 901 | { 902 | border: 1px solid #76797C; 903 | background-color: #232629; 904 | } 905 | 906 | QTreeView:branch:selected, QTreeView:branch:hover 907 | { 908 | background: url(data/ui/icons/transparent.png); 909 | } 910 | 911 | QTreeView::branch:has-siblings:!adjoins-item { 912 | border-image: url(data/ui/icons/transparent.png); 913 | } 914 | 915 | QTreeView::branch:has-siblings:adjoins-item { 916 | border-image: url(data/ui/icons/transparent.png); 917 | } 918 | 919 | QTreeView::branch:!has-children:!has-siblings:adjoins-item { 920 | border-image: url(data/ui/icons/transparent.png); 921 | } 922 | 923 | QTreeView::branch:has-children:!has-siblings:closed, 924 | QTreeView::branch:closed:has-children:has-siblings { 925 | image: url(data/ui/icons/branch_closed.png); 926 | } 927 | 928 | QTreeView::branch:open:has-children:!has-siblings, 929 | QTreeView::branch:open:has-children:has-siblings { 930 | image: url(data/ui/icons/branch_open.png); 931 | } 932 | 933 | QTreeView::branch:has-children:!has-siblings:closed:hover, 934 | QTreeView::branch:closed:has-children:has-siblings:hover { 935 | image: url(data/ui/icons/branch_closed-on.png); 936 | } 937 | 938 | QTreeView::branch:open:has-children:!has-siblings:hover, 939 | QTreeView::branch:open:has-children:has-siblings:hover { 940 | image: url(data/ui/icons/branch_open-on.png); 941 | } 942 | 943 | QListView::item:!selected:hover, QTreeView::item:!selected:hover { 944 | background: #18465d; 945 | outline: 0; 946 | color: #eff0f1 947 | } 948 | 949 | QListView::item:selected:hover, QTreeView::item:selected:hover { 950 | background: #565a5e; 951 | color: #eff0f1; 952 | } 953 | 954 | QSlider::groove:horizontal { 955 | border: 1px solid #565a5e; 956 | height: 4px; 957 | background: #565a5e; 958 | margin: 0px; 959 | border-radius: 2px; 960 | } 961 | 962 | QSlider::handle:horizontal { 963 | background: #232629; 964 | border: 1px solid #565a5e; 965 | width: 16px; 966 | height: 16px; 967 | margin: -8px 0; 968 | border-radius: 9px; 969 | } 970 | 971 | QSlider::groove:vertical { 972 | border: 1px solid #565a5e; 973 | width: 4px; 974 | background: #565a5e; 975 | margin: 0px; 976 | border-radius: 3px; 977 | } 978 | 979 | QSlider::handle:vertical { 980 | background: #232629; 981 | border: 1px solid #565a5e; 982 | width: 16px; 983 | height: 16px; 984 | margin: 0 -8px; 985 | border-radius: 9px; 986 | } 987 | 988 | QToolButton { 989 | background-color: transparent; 990 | border: 1px transparent #76797C; 991 | border-radius: 2px; 992 | margin: 3px; 993 | padding: 5px; 994 | } 995 | 996 | QToolButton[popupMode="1"] { /* only for MenuButtonPopup */ 997 | padding-right: 20px; /* make way for the popup button */ 998 | border: 1px #76797C; 999 | border-radius: 5px; 1000 | } 1001 | 1002 | QToolButton[popupMode="2"] { /* only for InstantPopup */ 1003 | padding-right: 10px; /* make way for the popup button */ 1004 | border: 1px #76797C; 1005 | } 1006 | 1007 | 1008 | QToolButton:hover, QToolButton::menu-button:hover { 1009 | background-color: transparent; 1010 | border: 1px solid rgba(49, 54, 59, .9); 1011 | padding: 5px; 1012 | } 1013 | 1014 | QToolButton:checked, QToolButton:pressed, 1015 | QToolButton::menu-button:pressed { 1016 | background-color: rgba(49, 54, 59, .9); 1017 | border: 1px solid rgba(49, 54, 59, .9); 1018 | padding: 5px; 1019 | } 1020 | 1021 | /* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */ 1022 | QToolButton::menu-indicator { 1023 | image: url(data/ui/icons/down_arrow.png); 1024 | top: -7px; left: -2px; /* shift it a bit */ 1025 | } 1026 | 1027 | /* the subcontrols below are used only in the MenuButtonPopup mode */ 1028 | QToolButton::menu-button { 1029 | border: 1px transparent #76797C; 1030 | border-top-right-radius: 6px; 1031 | border-bottom-right-radius: 6px; 1032 | /* 16px width + 4px for border = 20px allocated above */ 1033 | width: 16px; 1034 | outline: none; 1035 | } 1036 | 1037 | QToolButton::menu-arrow { 1038 | image: url(data/ui/icons/down_arrow.png); 1039 | } 1040 | 1041 | QToolButton::menu-arrow:open { 1042 | border: 1px solid #76797C; 1043 | } 1044 | 1045 | QPushButton::menu-indicator { 1046 | subcontrol-origin: padding; 1047 | subcontrol-position: bottom right; 1048 | left: 8px; 1049 | } 1050 | 1051 | QTableView 1052 | { 1053 | border: 1px solid #76797C; 1054 | gridline-color: #31363b; 1055 | background-color: #232629; 1056 | } 1057 | 1058 | 1059 | QTableView, QHeaderView 1060 | { 1061 | border-radius: 0px; 1062 | } 1063 | 1064 | QTableView::item:pressed, QListView::item:pressed, QTreeView::item:pressed { 1065 | background: #18465d; 1066 | color: #eff0f1; 1067 | } 1068 | 1069 | QTableView::item:selected:active, QTreeView::item:selected:active, QListView::item:selected:active { 1070 | background: #565a5e; 1071 | color: #eff0f1; 1072 | } 1073 | 1074 | 1075 | QHeaderView 1076 | { 1077 | background-color: #31363b; 1078 | border: 1px transparent; 1079 | border-radius: 0px; 1080 | margin: 0px; 1081 | padding: 0px; 1082 | 1083 | } 1084 | 1085 | QHeaderView::section { 1086 | background-color: #31363b; 1087 | color: #eff0f1; 1088 | padding: 5px; 1089 | border: 1px solid #76797C; 1090 | border-radius: 0px; 1091 | text-align: center; 1092 | } 1093 | 1094 | QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one 1095 | { 1096 | border-top: 1px solid #76797C; 1097 | } 1098 | 1099 | QHeaderView::section::vertical 1100 | { 1101 | border-top: transparent; 1102 | } 1103 | 1104 | QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one 1105 | { 1106 | border-left: 1px solid #76797C; 1107 | } 1108 | 1109 | QHeaderView::section::horizontal 1110 | { 1111 | border-left: transparent; 1112 | } 1113 | 1114 | 1115 | QHeaderView::section:checked 1116 | { 1117 | color: white; 1118 | background-color: #334e5e; 1119 | } 1120 | 1121 | /* style the sort indicator */ 1122 | QHeaderView::down-arrow { 1123 | image: url(data/ui/icons/down_arrow.png); 1124 | } 1125 | 1126 | QHeaderView::up-arrow { 1127 | image: url(data/ui/icons/up_arrow.png); 1128 | } 1129 | 1130 | 1131 | QTableCornerButton::section { 1132 | background-color: #31363b; 1133 | border: 1px transparent #76797C; 1134 | border-radius: 0px; 1135 | } 1136 | 1137 | QToolBox { 1138 | padding: 5px; 1139 | border: 1px transparent black; 1140 | } 1141 | 1142 | QToolBox::tab { 1143 | color: #eff0f1; 1144 | background-color: #31363b; 1145 | border: 1px solid #76797C; 1146 | border-bottom: 1px transparent #31363b; 1147 | border-top-left-radius: 5px; 1148 | border-top-right-radius: 5px; 1149 | } 1150 | 1151 | QToolBox::tab:selected { /* italicize selected tabs */ 1152 | font: italic; 1153 | background-color: #31363b; 1154 | border-color: rgba(49, 54, 59, .9); 1155 | } 1156 | 1157 | QStatusBar::item { 1158 | border: 0px transparent dark; 1159 | } 1160 | 1161 | 1162 | QFrame[height="3"], QFrame[width="3"] { 1163 | background-color: #76797C; 1164 | } 1165 | 1166 | 1167 | QSplitter::handle { 1168 | background-color: black; 1169 | border: 1px solid black; 1170 | } 1171 | 1172 | QSplitter::handle:hover { 1173 | background-color: #787876; 1174 | border: 1px solid #76797C; 1175 | } 1176 | 1177 | QSplitter::handle:horizontal { 1178 | width: 1px; 1179 | } 1180 | 1181 | QSplitter::handle:vertical { 1182 | height: 1px; 1183 | } 1184 | 1185 | QProgressBar { 1186 | border: 1px solid #76797C; 1187 | border-radius: 5px; 1188 | text-align: center; 1189 | } 1190 | 1191 | QProgressBar::chunk { 1192 | background-color: black; 1193 | } 1194 | 1195 | QDateEdit 1196 | { 1197 | selection-background-color: rgba(49, 54, 59, .9); 1198 | border-style: solid; 1199 | border: 0px solid #3375A3; 1200 | border-radius: 2px; 1201 | padding: 1px; 1202 | min-width: 75px; 1203 | } 1204 | 1205 | QDateEdit:on 1206 | { 1207 | padding-top: 3px; 1208 | padding-left: 4px; 1209 | selection-background-color: #4a4a4a; 1210 | } 1211 | 1212 | QDateEdit QAbstractItemView 1213 | { 1214 | background-color: #232629; 1215 | border-radius: 2px; 1216 | border: 0px solid #3375A3; 1217 | selection-background-color: rgba(49, 54, 59, .9); 1218 | } 1219 | 1220 | QDateEdit::drop-down 1221 | { 1222 | subcontrol-origin: padding; 1223 | subcontrol-position: top right; 1224 | width: 15px; 1225 | border-left-width: 0px; 1226 | border-left-color: darkgray; 1227 | border-left-style: solid; 1228 | border-top-right-radius: 3px; 1229 | border-bottom-right-radius: 3px; 1230 | } 1231 | 1232 | QDateEdit::down-arrow:enabled 1233 | { 1234 | image: url(data/ui/icons/down_arrow_disabled.png); 1235 | } 1236 | 1237 | QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, 1238 | QDateEdit::down-arrow:focus 1239 | { 1240 | image: url(data/ui/icons/down_arrow.png); 1241 | } 1242 | 1243 | QLineEdit:disabled 1244 | { 1245 | background-color: #31363b; 1246 | padding: 5px; 1247 | border-style: solid; 1248 | border: 0px solid #76797C; 1249 | border-radius: 2px; 1250 | color: white; 1251 | } 1252 | 1253 | QPushButton:focus { 1254 | border: none; 1255 | outline: none; 1256 | background-color: none; 1257 | } 1258 | 1259 | QScrollArea { 1260 | background-color: rgb(24, 25, 29); 1261 | } 1262 | 1263 | QDateEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QTextEdit:disabled { 1264 | background-color: #31363b; 1265 | padding: 5px; 1266 | border-style: solid; 1267 | border: 0px solid #76797C; 1268 | border-radius: 2px; 1269 | color: white; 1270 | } 1271 | 1272 | QDateEdit, QSpinbox, QDoubleSpinBox, QTextEdit { 1273 | background-color: #31363b; 1274 | padding: 5px; 1275 | border-style: solid; 1276 | border: 0px solid #76797C; 1277 | border-radius: 0px; 1278 | color: white; 1279 | } 1280 | 1281 | QCheckBox { 1282 | spacing: 5px; 1283 | } 1284 | 1285 | QCheckBox::indicator { 1286 | width: 30px; 1287 | height: 30px; 1288 | } 1289 | 1290 | QCheckBox::indicator:unchecked { 1291 | image: url(data/ui/icons/checkbox_unchecked.png); 1292 | } 1293 | 1294 | QCheckBox::indicator:unchecked:hover { 1295 | image: url(data/ui/icons/checkbox_unchecked_hovered.png); 1296 | } 1297 | 1298 | QCheckBox::indicator:unchecked:pressed { 1299 | image: url(data/ui/icons/checkbox_checked_hovered.png); 1300 | } 1301 | 1302 | QCheckBox::indicator:checked { 1303 | image: url(data/ui/icons/checkbox_checked.png); 1304 | } 1305 | 1306 | QCheckBox::indicator:checked:hover { 1307 | image: url(data/ui/icons/checkbox_checked_hovered.png); 1308 | } 1309 | 1310 | QCheckBox::indicator:checked:pressed { 1311 | image: url(data/ui/icons/checkbox_unchecked_hovered.png); 1312 | } 1313 | 1314 | QCheckBox::indicator:indeterminate { 1315 | image: url(data/ui/icons/checkbox_indeterminate.png); 1316 | } 1317 | 1318 | QCheckBox::indicator:indeterminate:hover { 1319 | image: url(data/ui/icons/checkbox_indeterminate_hovered.png); 1320 | } 1321 | 1322 | QCheckBox::indicator:indeterminate:pressed { 1323 | image: url(data/ui/icons/checkbox_indeterminate_pressed.png); 1324 | } 1325 | 1326 | QMessageBox { 1327 | background-color:#31363b; 1328 | color:white 1329 | } 1330 | 1331 | 1332 | 1333 | 1334 | 1335 | 0 1336 | 1337 | 1338 | 0 1339 | 1340 | 1341 | 0 1342 | 1343 | 1344 | 0 1345 | 1346 | 1347 | 0 1348 | 1349 | 1350 | 1351 | 1352 | 1353 | 31 1354 | 1355 | 1356 | 1357 | Not connected 1358 | 1359 | 1360 | Qt::AlignCenter 1361 | 1362 | 1363 | 1364 | 1365 | 1366 | 1367 | Qt::Horizontal 1368 | 1369 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 0 1380 | 0 1381 | 1382 | 1383 | 1384 | 1385 | 14 1386 | 1387 | 1388 | 1389 | Ist 1390 | 1391 | 1392 | Qt::AlignCenter 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | 1401 | 1402 | 1403 | 1404 | 1405 | 1406 | 1407 | Spannung [V] 1408 | 1409 | 1410 | 1411 | 1412 | 1413 | 1414 | Strom [A] 1415 | 1416 | 1417 | 1418 | 1419 | 1420 | 1421 | Leistung [W] 1422 | 1423 | 1424 | 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | 1435 | Qt::Vertical 1436 | 1437 | 1438 | 1439 | 1440 | 1441 | 1442 | 1443 | 1444 | 1445 | 0 1446 | 0 1447 | 1448 | 1449 | 1450 | 1451 | 14 1452 | 1453 | 1454 | 1455 | Soll 1456 | 1457 | 1458 | Qt::AlignCenter 1459 | 1460 | 1461 | 1462 | 1463 | 1464 | 1465 | 1466 | 1467 | 1468 | 0 1469 | 0 1470 | 1471 | 1472 | 1473 | 1474 | 12 1475 | 1476 | 1477 | 1478 | 1479 | 1480 | 1481 | 1482 | 1483 | 0 1484 | 0 1485 | 1486 | 1487 | 1488 | 1489 | 12 1490 | 1491 | 1492 | 1493 | 1494 | 1495 | 1496 | 1497 | Spannung [V] 1498 | 1499 | 1500 | 1501 | 1502 | 1503 | 1504 | Strom [A] 1505 | 1506 | 1507 | 1508 | 1509 | 1510 | 1511 | 1512 | 1513 | Setzen 1514 | 1515 | 1516 | 1517 | 1518 | 1519 | 1520 | 1521 | 1522 | 1523 | 1524 | 1525 | 0 1526 | 0 1527 | 1528 | 1529 | 1530 | 1531 | 0 1532 | 64 1533 | 1534 | 1535 | 1536 | 1537 | 12 1538 | 1539 | 1540 | 1541 | POWER 1542 | 1543 | 1544 | true 1545 | 1546 | 1547 | 1548 | 1549 | 1550 | 1551 | 1552 | 1553 | 1554 | 1555 | 1556 | 0 1557 | 0 1558 | 1559 | 1560 | 1561 | 0.0 V (V-In) 1562 | 1563 | 1564 | Qt::AlignCenter 1565 | 1566 | 1567 | 1568 | 1569 | 1570 | 1571 | Protected 1572 | 1573 | 1574 | Qt::AlignCenter 1575 | 1576 | 1577 | 1578 | 1579 | 1580 | 1581 | Unlocked 1582 | 1583 | 1584 | 1585 | 1586 | 1587 | 1588 | CV/CC 1589 | 1590 | 1591 | Qt::AlignCenter 1592 | 1593 | 1594 | 1595 | 1596 | 1597 | 1598 | Qt::Vertical 1599 | 1600 | 1601 | 1602 | 20 1603 | 40 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 1610 | 1611 | Plot 1612 | 1613 | 1614 | false 1615 | 1616 | 1617 | 1618 | 1619 | 1620 | 1621 | 1622 | 1623 | 1624 | 1625 | 1626 | 1627 | 1628 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Haschtl/PyDPS/af3f5737c67370bedcec73ba88b8b3667330e006/icon.png -------------------------------------------------------------------------------- /pyDPS.py: -------------------------------------------------------------------------------- 1 | # Python3.6 2 | import json 3 | import os 4 | import sys 5 | import subprocess 6 | import time 7 | from threading import Thread, Lock 8 | 9 | try: 10 | from PyQt5 import uic 11 | from PyQt5 import QtWidgets 12 | from PyQt5 import QtCore 13 | from PyQt5 import QtGui 14 | except ImportError: 15 | sys.exit("\nERROR\nPyQt5 for Python3 not found! \nPlease install with 'pip3 install pyqt5\nOr apt install python3-pyqt5") 16 | 17 | try: 18 | import minimalmodbus 19 | except ImportError: 20 | sys.exit("\nERROR\nminimalmodbus for Python3 not found!\nPlease install with 'pip3 install minimalmodbus'") 21 | try: 22 | import pyqtgraph as pg 23 | plotEnabled = True 24 | except ImportError: 25 | plotEnabled = False 26 | 27 | LOCK = Lock() 28 | 29 | stopMe = False 30 | 31 | class Updater(QtCore.QThread): 32 | received = QtCore.pyqtSignal() 33 | 34 | def run(self): 35 | config = load_config() 36 | while not stopMe: 37 | self.sleep(config["update_rate"]) 38 | self.received.emit() 39 | 40 | class UpdaterFast(QtCore.QThread): 41 | received = QtCore.pyqtSignal() 42 | 43 | def run(self): 44 | config = load_config() 45 | while not stopMe: 46 | self.sleep(config["plot_update_rate"]) 47 | self.received.emit() 48 | 49 | 50 | class PyDPS(QtWidgets.QMainWindow): 51 | def __init__(self): 52 | super(PyDPS, self).__init__() 53 | if not plotEnabled: 54 | self.plotButton.hide() 55 | uic.loadUi("dpsGUI.ui", self) 56 | app_icon = QtGui.QIcon("icon.png") 57 | self.setWindowIcon(app_icon) 58 | self.config = load_config() 59 | self.running = True 60 | self.splitter.hide() 61 | self.ampSpinBox.setMaximum(self.config["maxAmps"]) 62 | 63 | self.setButton.clicked.connect(self.setValues) 64 | self.powerButton.clicked.connect(self.togglePower) 65 | self.lockedButton.clicked.connect(self.toggleLocked) 66 | self.plotButton.clicked.connect(self.startPlotThread) 67 | self.ok = False 68 | self.dataGetter = Thread(target= self.getData) 69 | self.dataGetter.start() 70 | self.show() 71 | 72 | #self.updater = Updater(self) 73 | #self.updater.received.connect(self.refresh) 74 | self.updater = QtCore.QTimer() 75 | self.updater.setInterval(self.config["update_rate"]) 76 | self.updater.timeout.connect(self.refresh) 77 | self.updater.start() 78 | 79 | def getData(self): 80 | while self.running: 81 | try: 82 | with LOCK: 83 | self.data=self.power_supply.read_registers(0,11) #read data from power supply 84 | #data[0] U-set x100 (R/W) 85 | #data[1] I-set x100 (R/W) 86 | #data[2] U-out x100 87 | #data[3] I-out x100 88 | #data[4] P-out x100 89 | #data[5] U-in x100 90 | #data[6] lock/unlock 1/0 (R/W) 91 | #data[7] Protected 1/0 92 | #data[8] operating mode CC/CV 1/0 93 | #data[9] on/off 1/0 (R/W) 94 | #data[10] display intensity 1..5 (R/W) 95 | self.ok = True 96 | time.sleep(0.05) 97 | except: 98 | print("Instrument not initialized yet") 99 | self.data= [0]*11 100 | self.ok = False 101 | if not os.path.exists(config["dev_path"]): 102 | print("Initializing USB or Bluetooth communication") 103 | try: 104 | self.processRunning = True 105 | self.process = subprocess.Popen(self.config["dev_init_command"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True) 106 | except: 107 | sys.exit("\nERROR\nSystem command from config.json exited with an error. \nPlease modify 'dev_init_command' in config.json") 108 | else: 109 | self.processRunning = False 110 | print("Setting permissions to access device") 111 | ok = os.system("sudo chmod +rwx "+config["dev_path"]) 112 | if ok != 0: 113 | sys.exit("\nERROR\nCould not set read/write permissions for "+config["dev_path"]) 114 | try: 115 | self.power_supply = minimalmodbus.Instrument(self.config["dev_path"], 1) 116 | self.power_supply.serial.baudrate = self.config["serial_baudrate"] 117 | self.power_supply.serial.bytesize = self.config["serial_bytesize"] 118 | self.power_supply.serial.timeout = self.config["serial_timeout"] 119 | self.power_supply.mode = minimalmodbus.MODE_RTU 120 | except: 121 | #self.closeWindow() 122 | #sys.exit("\nERROR\nFailed to initialize minimalmodbus instrument!\nPlease check serial-settings in config.json") 123 | print("\nERROR\nFailed to initialize minimalmodbus instrument!\nPlease check serial-settings in config.json") 124 | print("Starting thread to update GUI-values") 125 | time.sleep(1) 126 | 127 | def togglePower(self): 128 | if self.ok: 129 | try : 130 | print("Changing power-state") 131 | with LOCK: 132 | onoff=self.power_supply.read_register(9) 133 | # self.powerButton.setChecked(bool(onoff)) 134 | self.power_supply.write_register(9,(1-onoff)) 135 | if onoff==0: 136 | self.lockedButton.setText("Locked") 137 | else: 138 | self.lockedButton.setText("Unlocked") 139 | except : 140 | print ("\nERROR\nChanging power-state failed!\n") 141 | 142 | def toggleLocked(self): 143 | if self.ok: 144 | try : 145 | print("Changing locked-state") 146 | with LOCK: 147 | onoff=self.power_supply.read_register(6) 148 | # self.powerButton.setChecked(bool(onoff)) 149 | self.power_supply.write_register(6,(1-onoff)) 150 | except : 151 | print ("\nERROR\nChanging locked-state failed!\n") 152 | 153 | def setValues(self): 154 | if self.ok: 155 | try : 156 | print("Setting output values") 157 | volt = self.voltageSpinBox.value() 158 | amp = self.ampSpinBox.value() 159 | with LOCK: 160 | self.power_supply.write_register(0,int(volt*100)) 161 | self.power_supply.write_register(1,int(amp*100)) 162 | except : 163 | print ("\nERROR\nSetting output values failed!\n") 164 | 165 | def startPlotThread(self): 166 | if self.ok: 167 | self.initPlotWindow() 168 | 169 | def refresh(self): 170 | if self.ok: 171 | self.label_8.hide() 172 | self.splitter.show() 173 | self.ifValLCD(self.data[2]/100, self.voltageLCD) 174 | self.ifValLCD(self.data[3]/100, self.ampLCD) 175 | self.ifValLCD(self.data[4]/100, self.powerLCD) 176 | if self.vInLabel.text() != str(self.data[5]/100)+" V (V-In)": 177 | self.vInLabel.setText(str(self.data[5]/100)+" V (V-In)") 178 | if self.voltageSpinBox.maximum() != round(self.data[5]/100*0.909): 179 | self.voltageSpinBox.setMaximum(round(self.data[5]/100*0.909)) 180 | if(self.data[9]==1): 181 | self.powerButton.setStyleSheet("background-color: green") 182 | else: 183 | self.powerButton.setStyleSheet("background-color: red") 184 | if self.data[0]/100==round(self.voltageSpinBox.value(),2): 185 | self.voltageSpinBox.setStyleSheet("background-color: green") 186 | else: 187 | self.voltageSpinBox.setStyleSheet("background-color: red") 188 | if self.data[1]/100==round(self.ampSpinBox.value(),2): 189 | self.ampSpinBox.setStyleSheet("background-color: green") 190 | else: 191 | self.ampSpinBox.setStyleSheet("background-color: red") 192 | if self.data[6]==1: 193 | self.lockedButton.setStyleSheet("background-color: red") 194 | self.lockedButton.setText("Locked") 195 | else: 196 | self.lockedButton.setStyleSheet("background-color: green") 197 | self.lockedButton.setText("Unlocked") 198 | if self.data[7]==1: 199 | self.protectedLabel.setStyleSheet("background-color: red") 200 | self.protectedLabel.setText("Not Protected") 201 | else: 202 | self.protectedLabel.setStyleSheet("background-color: green") 203 | self.protectedLabel.setText("Protected") 204 | if self.data[8]==1: 205 | self.cvccLabel.setText("Konst. Strom") 206 | else: 207 | self.cvccLabel.setText("Konst. Spannung") 208 | else: 209 | self.label_8.show() 210 | self.splitter.hide() 211 | 212 | def ifValLCD(self, value, QObject): 213 | if value != QObject.value(): 214 | QObject.display(value) 215 | 216 | def closeEvent(self, event): 217 | self.closeWindow() 218 | 219 | def closeWindow(self): 220 | print("Closing PyQtDPS") 221 | if self.ok: 222 | with LOCK: 223 | self.power_supply.write_register(0,0) 224 | self.power_supply.write_register(1,0) 225 | self.power_supply.write_register(9,0) 226 | global stopMe 227 | stopMe = True 228 | self.running = False 229 | if self.processRunning: 230 | self.process.kill() 231 | self.close() 232 | 233 | def initPlotWindow(self): 234 | pg.setConfigOption('background', (49, 54, 59)) 235 | self.plotDialog = QtWidgets.QDialog() 236 | app_icon = QtGui.QIcon("icon.png") 237 | self.plotDialog.setWindowIcon(app_icon) 238 | layout = QtWidgets.QVBoxLayout(self.plotDialog) 239 | self.plotWidget = pg.PlotWidget() 240 | ax = self.plotWidget.getAxis('bottom') # This is the trick 241 | # Set grid x and y-axis 242 | ax.setGrid(255) 243 | ax.setLabel("Zeit [s]") 244 | ay = self.plotWidget.getAxis('left') 245 | ay.setGrid(255) 246 | ay.setLabel("Daten") 247 | self.plotWidget.addLegend() 248 | self.plotWidget.getPlotItem().setTitle("Spannung/Strom/Leistung") 249 | layout.addWidget(self.plotWidget) 250 | self.p = [0]*3 251 | pen = pg.mkPen(color=(255, 61, 61)) 252 | self.p[0] = self.plotWidget.plot( 253 | x=[0], y=[0], pen=pen, name='Spannung [V]') 254 | pen = pg.mkPen(color=(57, 255, 20), ) 255 | self.p[1] = self.plotWidget.plot( 256 | x=[0], y=[0], pen=pen, name='Strom [A]') 257 | pen = pg.mkPen(color=(214, 255, 127), style=QtCore.Qt.DotLine) 258 | self.p[2] = self.plotWidget.plot( 259 | x=[0], y=[0], pen=pen, fillLevel=0, fillBrush=(214, 255, 127, 30), name='Leistung [W]') 260 | self.plotTime = [0] 261 | self.plotVolt = [0] 262 | self.plotAmp = [0] 263 | self.plotPower = [0] 264 | self.plotDialog.show() 265 | # self.plotter = UpdaterFast(self) 266 | # self.plotter.received.connect(self.plotValues) 267 | self.plotter = QtCore.QTimer() 268 | self.plotter.setInterval(self.config["plot_update_rate"]) 269 | self.plotter.timeout.connect(self.plotValues) 270 | self.plotter.start() 271 | 272 | def plotValues(self): 273 | if self.ok: 274 | now = time.time() 275 | self.plotTime.append(float(now)) 276 | self.plotVolt.append(self.data[2]/100) 277 | self.plotAmp.append(self.data[3]/100) 278 | self.plotPower.append(self.data[4]/100) 279 | if float(now)-self.plotTime[0] > self.config["plotLength"]: 280 | self.plotTime = self.plotTime[1:] 281 | self.plotVolt = self.plotVolt[1:] 282 | self.plotAmp = self.plotAmp[1:] 283 | self.plotPower = self.plotPower[1:] 284 | plotTimeRelative = [] 285 | for x in self.plotTime: 286 | plotTimeRelative.append(x-self.plotTime[len(self.plotTime)-1]) 287 | self.p[0].setData(x=plotTimeRelative, y=self.plotVolt) 288 | self.p[1].setData(x=plotTimeRelative, y=self.plotAmp) 289 | self.p[2].setData(x=plotTimeRelative, y=self.plotPower) 290 | 291 | def load_config(path="config.json"): 292 | with open(path, encoding="UTF-8") as jsonfile: 293 | config = json.load(jsonfile, encoding="UTF-8") 294 | return config 295 | 296 | if __name__ == "__main__": 297 | # Initialize device 298 | config = load_config() 299 | app = QtWidgets.QApplication(sys.argv) 300 | myapp = PyDPS() 301 | app.exec_() 302 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Haschtl/PyDPS/af3f5737c67370bedcec73ba88b8b3667330e006/screenshot.png --------------------------------------------------------------------------------