├── res └── icon.png ├── requirements.txt ├── README.md ├── remotedevice.ui ├── dms.ui └── dms.py /res/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIPC/dms/master/res/icon.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | netifaces==0.11.0 2 | PyQt5==5.15.9 3 | python_dvr==0.0.1 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Device Management System [![Telegram](https://openipc.org/images/telegram_button.svg)][telegram] 2 | 3 | 4 | ### Installation 5 | 6 | ``` 7 | git clone https://github.com/OpenIPC/dms.git 8 | cd dms 9 | pip3 install --upgrade pip 10 | pip3 install -r ./requirements.txt 11 | ``` 12 | 13 | ### Run project 14 | 15 | ``` 16 | python3 ./dms.py 17 | ``` 18 | 19 | 20 | More information about the [project][project] is available in our [website][website] and on the [wiki][wiki]. 21 | 22 |

23 | Open Collective donate button 24 |

25 | 26 | 27 | [firmware]: https://github.com/openipc/firmware/ 28 | [mit]: https://opensource.org/license/mit/ 29 | [opencollective]: https://opencollective.com/openipc 30 | [paypal]: https://www.paypal.com/donate/?hosted_button_id=C6F7UJLA58MBS 31 | [project]: https://github.com/openipc/ 32 | [telegram]: https://t.me/OpenIPC 33 | [website]: https://openipc.org/ 34 | [wiki]: https://github.com/openipc/wiki/ 35 | -------------------------------------------------------------------------------- /remotedevice.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DigitalChannels 4 | 5 | 6 | 7 | 0 8 | 0 9 | 882 10 | 721 11 | 12 | 13 | 14 | Digital Channels 15 | 16 | 17 | 18 | res/icon.pngres/icon.png 19 | 20 | 21 | 22 | 23 | 5 24 | 305 25 | 88 26 | 25 27 | 28 | 29 | 30 | Local Search 31 | 32 | 33 | 34 | 35 | 36 | 195 37 | 305 38 | 88 39 | 25 40 | 41 | 42 | 43 | Add all 44 | 45 | 46 | 47 | 48 | 49 | 0 50 | 0 51 | 881 52 | 305 53 | 54 | 55 | 56 | false 57 | 58 | 59 | QAbstractItemView::NoEditTriggers 60 | 61 | 62 | true 63 | 64 | 65 | QAbstractItemView::DragOnly 66 | 67 | 68 | Qt::LinkAction 69 | 70 | 71 | true 72 | 73 | 74 | QAbstractItemView::SingleSelection 75 | 76 | 77 | QAbstractItemView::SelectRows 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 1 87 | 88 | 89 | 90 | 91 | IP Address 92 | 93 | 94 | 95 | 96 | Port 97 | 98 | 99 | 100 | 101 | MAC Address 102 | 103 | 104 | 105 | 106 | CloudID 107 | 108 | 109 | 110 | 111 | Name 112 | 113 | 114 | 115 | 116 | Chan 117 | 118 | 119 | 120 | 121 | Type 122 | 123 | 124 | 125 | 126 | 127 | 128 | 0 129 | 330 130 | 881 131 | 301 132 | 133 | 134 | 135 | true 136 | 137 | 138 | QFrame::StyledPanel 139 | 140 | 141 | QFrame::Sunken 142 | 143 | 144 | QAbstractScrollArea::AdjustIgnored 145 | 146 | 147 | false 148 | 149 | 150 | false 151 | 152 | 153 | false 154 | 155 | 156 | QAbstractItemView::NoDragDrop 157 | 158 | 159 | Qt::LinkAction 160 | 161 | 162 | true 163 | 164 | 165 | QAbstractItemView::SingleSelection 166 | 167 | 168 | QAbstractItemView::SelectRows 169 | 170 | 171 | false 172 | 173 | 174 | false 175 | 176 | 177 | false 178 | 179 | 180 | 1 181 | 182 | 183 | 25 184 | 185 | 186 | false 187 | 188 | 189 | 190 | 191 | # 192 | 193 | 194 | 195 | 196 | Title 197 | 198 | 199 | 200 | 201 | IP Address 202 | 203 | 204 | 205 | 206 | Port 207 | 208 | 209 | 210 | 211 | SyncRes 212 | 213 | 214 | 215 | 216 | SyncTime 217 | 218 | 219 | 220 | 221 | Delay 222 | 223 | 224 | 225 | 226 | Chan 227 | 228 | 229 | 230 | 231 | Proto 232 | 233 | 234 | 235 | 236 | Username 237 | 238 | 239 | 240 | 241 | Password 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | ItemIsSelectable|ItemIsDragEnabled|ItemIsDropEnabled|ItemIsUserCheckable|ItemIsEnabled 250 | 251 | 252 | 253 | 254 | 255 | 256 | 100 257 | 305 258 | 88 259 | 25 260 | 261 | 262 | 263 | 264 | NETIP 265 | 266 | 267 | 268 | 269 | ONVIF 270 | 271 | 272 | 273 | 274 | 275 | 276 | 195 277 | 635 278 | 88 279 | 25 280 | 281 | 282 | 283 | CAM 284 | 285 | 286 | channel name 287 | 288 | 289 | 290 | 291 | 292 | 5 293 | 635 294 | 88 295 | 25 296 | 297 | 298 | 299 | admin 300 | 301 | 302 | 303 | 304 | 305 | 100 306 | 635 307 | 88 308 | 25 309 | 310 | 311 | 312 | 313 | 314 | 315 | password 316 | 317 | 318 | 319 | 320 | 321 | 5 322 | 665 323 | 88 324 | 25 325 | 326 | 327 | 328 | All 329 | 330 | 331 | 332 | 333 | 334 | 100 335 | 665 336 | 88 337 | 25 338 | 339 | 340 | 341 | All 342 | 343 | 344 | 345 | 346 | 347 | 195 348 | 665 349 | 88 350 | 25 351 | 352 | 353 | 354 | All 355 | 356 | 357 | 358 | 359 | 360 | 290 361 | 635 362 | 88 363 | 25 364 | 365 | 366 | 367 | 368 | False 369 | 370 | 371 | 372 | 373 | True 374 | 375 | 376 | 377 | 378 | 379 | 380 | 385 381 | 635 382 | 88 383 | 25 384 | 385 | 386 | 387 | T&Z 388 | 389 | 390 | 3 391 | 392 | 393 | true 394 | 395 | 396 | 397 | OFF 398 | 399 | 400 | 401 | 402 | UTC 403 | 404 | 405 | 406 | 407 | Local 408 | 409 | 410 | 411 | 412 | T&Z 413 | 414 | 415 | 416 | 417 | 418 | 419 | 480 420 | 635 421 | 88 422 | 25 423 | 424 | 425 | 426 | 2 427 | 428 | 429 | 430 | 150 431 | 432 | 433 | 434 | 435 | 250 436 | 437 | 438 | 439 | 440 | 333 441 | 442 | 443 | 444 | 445 | 667 446 | 447 | 448 | 449 | 450 | 1000 451 | 452 | 453 | 454 | 455 | 2000 456 | 457 | 458 | 459 | 460 | 3000 461 | 462 | 463 | 464 | 465 | 466 | 467 | 290 468 | 665 469 | 88 470 | 25 471 | 472 | 473 | 474 | All 475 | 476 | 477 | 478 | 479 | 480 | 385 481 | 665 482 | 88 483 | 25 484 | 485 | 486 | 487 | All 488 | 489 | 490 | 491 | 492 | 493 | 480 494 | 665 495 | 88 496 | 25 497 | 498 | 499 | 500 | All 501 | 502 | 503 | 504 | 505 | 506 | 790 507 | 695 508 | 88 509 | 25 510 | 511 | 512 | 513 | Cancel 514 | 515 | 516 | 517 | 518 | 519 | 695 520 | 695 521 | 88 522 | 25 523 | 524 | 525 | 526 | &Save 527 | 528 | 529 | 530 | 531 | 532 | 533 | -------------------------------------------------------------------------------- /dms.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | true 7 | 8 | 9 | 10 | 0 11 | 0 12 | 1024 13 | 681 14 | 15 | 16 | 17 | DMS 18 | 19 | 20 | 21 | res/icon.pngres/icon.png 22 | 23 | 24 | 25 | 16 26 | 16 27 | 28 | 29 | 30 | Qt::ToolButtonIconOnly 31 | 32 | 33 | 34 | 35 | 36 | 20 37 | 590 38 | 75 39 | 25 40 | 41 | 42 | 43 | &Search 44 | 45 | 46 | 47 | 48 | 49 | 0 50 | 40 51 | 631 52 | 545 53 | 54 | 55 | 56 | 57 | 0 58 | 0 59 | 60 | 61 | 62 | false 63 | 64 | 65 | QAbstractItemView::NoEditTriggers 66 | 67 | 68 | false 69 | 70 | 71 | true 72 | 73 | 74 | QAbstractItemView::SelectRows 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 1 87 | 88 | 89 | 8 90 | 91 | 92 | true 93 | 94 | 95 | 25 96 | 97 | 98 | 90 99 | 100 | 101 | false 102 | 103 | 104 | false 105 | 106 | 107 | true 108 | 109 | 110 | false 111 | 112 | 113 | 30 114 | 115 | 116 | 30 117 | 118 | 119 | 120 | 121 | # 122 | 123 | 124 | AlignCenter 125 | 126 | 127 | 128 | 129 | IP 130 | 131 | 132 | 133 | 134 | Port 135 | 136 | 137 | 138 | 139 | MAC 140 | 141 | 142 | 143 | 144 | CloudID 145 | 146 | 147 | 148 | 149 | Version 150 | 151 | 152 | 153 | 154 | Date 155 | 156 | 157 | 158 | 159 | Name 160 | 161 | 162 | 163 | 164 | 165 | 166 | 10 167 | 10 168 | 101 169 | 25 170 | 171 | 172 | 173 | admin 174 | 175 | 176 | 177 | 178 | 179 | 120 180 | 10 181 | 110 182 | 25 183 | 184 | 185 | 186 | 187 | 188 | 189 | password 190 | 191 | 192 | 193 | 194 | 195 | 240 196 | 10 197 | 110 198 | 25 199 | 200 | 201 | 202 | newpassword 203 | 204 | 205 | 206 | 207 | 208 | 360 209 | 10 210 | 75 211 | 25 212 | 213 | 214 | 215 | &Change 216 | 217 | 218 | 219 | 220 | 221 | 440 222 | 10 223 | 110 224 | 25 225 | 226 | 227 | 228 | 000.000.000.000 229 | 230 | 231 | 0.0.0.0 232 | 233 | 234 | 15 235 | 236 | 237 | Qt::AlignCenter 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 555 247 | 10 248 | 75 249 | 25 250 | 251 | 252 | 253 | AutoIP 254 | 255 | 256 | 257 | 258 | 259 | 635 260 | 10 261 | 260 262 | 25 263 | 264 | 265 | 266 | Host interface 267 | 268 | 269 | 270 | 271 | 272 | 900 273 | 10 274 | 116 275 | 25 276 | 277 | 278 | 279 | QComboBox::InsertAtCurrent 280 | 281 | 282 | Host IP 283 | 284 | 285 | false 286 | 287 | 288 | 289 | 290 | false 291 | 292 | 293 | 294 | 105 295 | 590 296 | 75 297 | 25 298 | 299 | 300 | 301 | &Add IP 302 | 303 | 304 | 305 | 306 | 307 | 635 308 | 40 309 | 380 310 | 545 311 | 312 | 313 | 314 | 1 315 | 316 | 317 | 318 | System 319 | 320 | 321 | 322 | 323 | Network 324 | 325 | 326 | 327 | 328 | 0 329 | 0 330 | 370 331 | 170 332 | 333 | 334 | 335 | QFrame::Box 336 | 337 | 338 | QFrame::Raised 339 | 340 | 341 | 1 342 | 343 | 344 | 345 | 346 | 85 347 | 135 348 | 110 349 | 25 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 000.000.000.000 363 | 364 | 365 | 0.0.0.0 366 | 367 | 368 | 15 369 | 370 | 371 | true 372 | 373 | 374 | Qt::AlignCenter 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 5 384 | 110 385 | 76 386 | 18 387 | 388 | 389 | 390 | DNS1 391 | 392 | 393 | 394 | 395 | 396 | 5 397 | 75 398 | 76 399 | 18 400 | 401 | 402 | 403 | Gateway 404 | 405 | 406 | 407 | 408 | 409 | 85 410 | 70 411 | 110 412 | 25 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 000.000.000.000 426 | 427 | 428 | 0.0.0.0 429 | 430 | 431 | 15 432 | 433 | 434 | true 435 | 436 | 437 | Qt::AlignCenter 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 85 447 | 40 448 | 110 449 | 25 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 000.000.000.000 463 | 464 | 465 | 255.255.255.0 466 | 467 | 468 | 15 469 | 470 | 471 | true 472 | 473 | 474 | Qt::AlignCenter 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | false 483 | 484 | 485 | 486 | 205 487 | 70 488 | 155 489 | 25 490 | 491 | 492 | 493 | Public DNS 494 | 495 | 496 | 497 | 498 | 499 | 85 500 | 10 501 | 110 502 | 25 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 000.000.000.000 516 | 517 | 518 | 000.000.000.000 519 | 520 | 521 | 15 522 | 523 | 524 | true 525 | 526 | 527 | Qt::AlignCenter 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 5 537 | 140 538 | 76 539 | 18 540 | 541 | 542 | 543 | DNS2 544 | 545 | 546 | 547 | 548 | 549 | 5 550 | 15 551 | 76 552 | 18 553 | 554 | 555 | 556 | IP Address 557 | 558 | 559 | 560 | 561 | 562 | 5 563 | 45 564 | 76 565 | 18 566 | 567 | 568 | 569 | Subnet 570 | 571 | 572 | 573 | 574 | false 575 | 576 | 577 | 578 | 205 579 | 40 580 | 155 581 | 25 582 | 583 | 584 | 585 | IP+1 586 | 587 | 588 | 589 | 590 | false 591 | 592 | 593 | 594 | 205 595 | 10 596 | 155 597 | 25 598 | 599 | 600 | 601 | Defaults 602 | 603 | 604 | 605 | 606 | 607 | 85 608 | 105 609 | 110 610 | 25 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 000.000.000.000 624 | 625 | 626 | 0.0.0.0 627 | 628 | 629 | 15 630 | 631 | 632 | true 633 | 634 | 635 | Qt::AlignCenter 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | true 644 | 645 | 646 | 647 | 205 648 | 135 649 | 155 650 | 25 651 | 652 | 653 | 654 | Digital Channels 655 | 656 | 657 | 658 | 659 | 660 | 661 | 0 662 | 170 663 | 371 664 | 70 665 | 666 | 667 | 668 | QFrame::StyledPanel 669 | 670 | 671 | QFrame::Raised 672 | 673 | 674 | 675 | 676 | 5 677 | 5 678 | 111 679 | 22 680 | 681 | 682 | 683 | Upgrade 684 | 685 | 686 | 687 | 688 | 689 | 5 690 | 25 691 | 111 692 | 22 693 | 694 | 695 | 696 | AutoUpgrade 697 | 698 | 699 | 700 | 701 | 702 | 5 703 | 45 704 | 111 705 | 22 706 | 707 | 708 | 709 | NTP 710 | 711 | 712 | 713 | 714 | 715 | 115 716 | 5 717 | 111 718 | 22 719 | 720 | 721 | 722 | SmartNet 723 | 724 | 725 | 726 | 727 | 728 | 115 729 | 25 730 | 111 731 | 22 732 | 733 | 734 | 735 | IPChange 736 | 737 | 738 | 739 | 740 | 741 | 115 742 | 45 743 | 111 744 | 22 745 | 746 | 747 | 748 | AutoAdd 749 | 750 | 751 | 752 | 753 | 754 | 200 755 | 5 756 | 111 757 | 22 758 | 759 | 760 | 761 | Cloud 762 | 763 | 764 | 765 | 766 | 767 | 200 768 | 45 769 | 111 770 | 22 771 | 772 | 773 | 774 | ONVIF Auth 775 | 776 | 777 | 778 | 779 | 780 | 200 781 | 25 782 | 111 783 | 22 784 | 785 | 786 | 787 | RTSP 788 | 789 | 790 | 791 | 792 | 793 | 794 | Encode 795 | 796 | 797 | 798 | 799 | Settings 800 | 801 | 802 | 803 | 804 | 5 805 | 5 806 | 116 807 | 26 808 | 809 | 810 | 811 | 812 | 813 | 814 | Language 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 445 823 | 590 824 | 75 825 | 25 826 | 827 | 828 | 829 | Upgrade 830 | 831 | 832 | 833 | 834 | 835 | 275 836 | 590 837 | 75 838 | 25 839 | 840 | 841 | 842 | Reboot 843 | 844 | 845 | 846 | 847 | false 848 | 849 | 850 | 851 | 360 852 | 590 853 | 75 854 | 25 855 | 856 | 857 | 858 | Export 859 | 860 | 861 | 862 | 863 | false 864 | 865 | 866 | 867 | 190 868 | 590 869 | 75 870 | 25 871 | 872 | 873 | 874 | Add ID 875 | 876 | 877 | 878 | 879 | 880 | 635 881 | 590 882 | 150 883 | 25 884 | 885 | 886 | 887 | Save 888 | 889 | 890 | 891 | 892 | false 893 | 894 | 895 | 896 | 915 897 | 590 898 | 100 899 | 25 900 | 901 | 902 | 903 | Open DIR 904 | 905 | 906 | 907 | 908 | false 909 | 910 | 911 | 912 | 790 913 | 590 914 | 120 915 | 25 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 20 926 | 620 927 | 416 928 | 25 929 | 930 | 931 | 932 | QFrame::Panel 933 | 934 | 935 | QFrame::Sunken 936 | 937 | 938 | Select firmware file... 939 | 940 | 941 | Qt::PlainText 942 | 943 | 944 | false 945 | 946 | 947 | 0 948 | 949 | 950 | 951 | 952 | 953 | 445 954 | 620 955 | 75 956 | 25 957 | 958 | 959 | 960 | Browse 961 | 962 | 963 | 964 | 965 | 966 | 967 | 0 968 | 0 969 | 1024 970 | 30 971 | 972 | 973 | 974 | 975 | 976 | false 977 | 978 | 979 | false 980 | 981 | 982 | Disconnected 983 | 984 | 985 | 986 | 987 | 988 | 989 | tableWidget 990 | cellClicked(int,int) 991 | editIPAddress 992 | update() 993 | 994 | 995 | 162 996 | 119 997 | 998 | 999 | 743 1000 | 119 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 5 1008 | 1009 | 1010 | 5 1011 | 1012 | 1013 | true 1014 | 1015 | 1016 | true 1017 | 1018 | 1019 | true 1020 | 1021 | 1022 | 1023 | -------------------------------------------------------------------------------- /dms.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import struct 6 | import json 7 | from locale import getdefaultlocale 8 | from subprocess import check_output 9 | from socket import * 10 | from datetime import * 11 | 12 | import netifaces 13 | import logging 14 | 15 | from dvrip import DVRIPCam 16 | 17 | from PyQt5.QtWidgets import * 18 | from PyQt5.QtGui import * 19 | from PyQt5 import uic, QtCore, QtWidgets 20 | from PyQt5.QtCore import Qt, QSettings 21 | 22 | (Ui_MainWindow, QMainWindow) = uic.loadUiType('dms.ui') 23 | (Ui_Form, QtWidgets.QDialog) = uic.loadUiType('remotedevice.ui') 24 | 25 | cam = DVRIPCam('') 26 | udptimeout = 3 27 | tcptimeout = 10 28 | 29 | if os.path.exists('debug'): 30 | debug = True 31 | else: 32 | debug = False 33 | 34 | if debug: 35 | debugLevel = logging.DEBUG 36 | devices = ({'00:00:00:00:00:64': {'ChannelNum': 9, 'DeviceType': 4, 'GateWay': '0xFE01A8C0', 'HostIP': '0x0A01A8C0', 'HostName': 'NBD80N32RA-KL', 'HttpPort': 80, 'MAC': '00:00:00:00:00:64', 'MaxBps': 0, 'MonMode': 'TCP', 'NetConnectState': 0, 'OtherFunction': 'D=2023-03-21 13:21:32 V=78775aada187e84', 'SN': '0000000000000081', 'SSLPort': 8443, 'Submask': '0x00FFFFFF', 'TCPMaxConn': 10, 'TCPPort': 34567, 'TransferPlan': 'Quality', 'UDPPort': 34568, 'UseHSDownLoad': False, 'Brand': 'xm'}, '00:00:00:00:00:17': {'ChannelNum': 1, 'DeviceType': 1, 'GateWay': '0x0101A8C0', 'HostIP': '0x0801A8C0', 'HostName': 'LocalHost', 'HttpPort': 80, 'MAC': '00:00:00:00:00:17', 'MaxBps': 0, 'MonMode': 'TCP', 'NetConnectState': 1, 'OtherFunction': 'D=2023-03-21 13:21:34 V=1482fd4408e15a7', 'SN': '0000000000000006', 'SSLPort': 8443, 'Submask': '0x00FFFFFF', 'TCPMaxConn': 10, 'TCPPort': 34567, 'TransferPlan': 'Quality', 'UDPPort': 34568, 'UseHSDownLoad': False, 'Brand': 'xm'}, '00:00:00:00:00:1e': {'BuildDate': '2020-07-04 09:25:14', 'ChannelNum': 1, 'GateWay': '0x0101A8C0', 'HostIP': '0x0701A8C0', 'HostName': 'IVG-85HF20PYA-S', 'HttpPort': 80, 'MAC': '00:00:00:00:00:1e', 'MonMode': 'TCP', 'NetConnectState': 1, 'OtherFunction': 'D=2023-03-21 13:21:34 V=d0384e6d8a46c2f', 'SN': '0000000000000033', 'SSLPort': 8443, 'Submask': '0x00FFFFFF', 'TCPMaxConn': 10, 'TCPPort': 34567, 'UDPPort': 34568, 'UseHSDownLoad': True, 'Version': 'V5.00.R02.000559A7.10010.040400.0020000', 'Brand': 'xm'}, '00:00:00:00:00:48': {'BuildDate': '2022- 2-23 16:34: 0', 'ChannelNum': 1, 'DeviceType': 0, 'GateWay': '0xFE01A8C0', 'HostIP': '0x0501A8C0', 'HostName': 'IVG-N4', 'HttpPort': 80, 'MAC': '00:00:00:00:00:48', 'MonMode': 'TCP', 'NetConnectState': 1, 'OtherFunction': 'D=2023-03-21 13:21:33 V=a721ad83d521bc7', 37 | 'SN': '000000000000002a', 'SSLPort': 8443, 'Submask': '0x00FFFFFF', 'TCPMaxConn': 10, 'TCPPort': 34567, 'UDPPort': 34568, 'UseHSDownLoad': False, 'Version': 'V5.00.R02.000629G3.10010.140200.0020000', 'Brand': 'xm'}, '00:00:00:00:00:6b': {'BuildDate': '2020-07-04 09:25:14', 'ChannelNum': 1, 'GateWay': '0x0101A8C0', 'HostIP': '0x0401A8C0', 'HostName': 'IVG-85HF20PYA-S', 'HttpPort': 80, 'MAC': '00:00:00:00:00:6b', 'MonMode': 'TCP', 'NetConnectState': 1, 'OtherFunction': 'D=2023-03-21 13:21:33 V=088a5643e0387f2', 'SN': '0000000000000095', 'SSLPort': 8443, 'Submask': '0x00FFFFFF', 'TCPMaxConn': 10, 'TCPPort': 34567, 'UDPPort': 34568, 'UseHSDownLoad': False, 'Version': 'V5.00.R02.000559A7.10010.040400.0020000', 'Brand': 'xm'}, '00:00:00:00:00:43': {'BuildDate': '2020-07-04 09:25:14', 'ChannelNum': 1, 'GateWay': '0x0201A8C0', 'HostIP': '0x0601A8C0', 'HostName': 'IVG-85HF20PYA-S', 'HttpPort': 80, 'MAC': '00:00:00:00:00:43', 'MonMode': 'TCP', 'NetConnectState': 1, 'OtherFunction': 'D=2023-03-21 13:21:34 V=6d1150f906f4948', 'SN': '0000000000000039', 'SSLPort': 8443, 'Submask': '0x00FFFFFF', 'TCPMaxConn': 10, 'TCPPort': 34567, 'UDPPort': 34568, 'UseHSDownLoad': False, 'Version': 'V5.00.R02.000559A7.10010.040400.0020000', 'Brand': 'xm'}, '00:00:00:00:00:22': {'BuildDate': '2020- 9- 1 14:38:48', 'ChannelNum': 1, 'GateWay': '0x0101A8C0', 'HostIP': '0x6414A8C0', 'HostName': 'camera_', 'HttpPort': 80, 'MAC': '00:00:00:00:00:22', 'MonMode': 'TCP', 'NetConnectState': 1, 'OtherFunction': 'D=2023-03-21 13:21:34 V=bdf396972028edf', 'SN': '0000000000000061', 'SSLPort': 8443, 'Submask': '0x00FFFFFF', 'TCPMaxConn': 10, 'TCPPort': 34567, 'UDPPort': 34568, 'UseHSDownLoad': True, 'Version': 'V5.00.R02.000529B2.10010.040600.0020000', 'Brand': 'xm'}}) 38 | RemoteDeviceV3 = [{"ConnType": "SINGLE", "Decoder": [{"Channel": 0, "ConfName": "chConfig", "DevType": "IPC", "Enable": True, "IPAddress": "192.168.1.10", "Interval": 10, "MacAddr": "", "MainRtspUrl": "", "PassWord": "", "Port": 34567, "Protocol": "TCP", "SerialNo": "", "StreamType": "MAIN", "SubRtspUrl": "", "TransModel": 0, "UserName": "admin"}], "EnCheckTime": False, "Enable": True, "SingleConnId": "0x00000001", "SynchResolution": False, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": [{"Channel": 3, "ConfName": "LocalHost", "DevType": "IPC", "Enable": True, "IPAddress": "192.168.20.5", "Interval": 10, "MacAddr": "00:00:00:00:00:49", "MainRtspUrl": "", "PassWord": "assword", "Port": 34567, "Protocol": "TCP", "SerialNo": "0000000000000054", "StreamType": "MAIN", "SubRtspUrl": "", "TransModel": 0, "UserName": "admin"}], "EnCheckTime": False, "Enable": True, "SingleConnId": "0x00000001", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": [{"Channel": 0, "ConfName": "SmartNet", "DevType": "IPC", "Enable": True, "IPAddress": "192.168.1.11", "Interval": 10, "MacAddr": "00:00:00:00:00:e4", "MainRtspUrl": "", "PassWord": "", "Port": 34567, "Protocol": "TCP", "SerialNo": "000000000000009b", "StreamType": "MAIN", "SubRtspUrl": "", "TransModel": 0, "UserName": "admin"}], "EnCheckTime": False, "Enable": True, "SingleConnId": "0x00000001", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": [{"Channel": 0, "ConfName": "LocalHost", "DevType": "IPC", "Enable": True, "IPAddress": "192.168.20.253", "Interval": 10, "MacAddr": "00:00:00:00:00:f6", "MainRtspUrl": "", "PassWord": "assword", "Port": 34567, "Protocol": "TCP", "SerialNo": "00000000000000d8", "StreamType": "MAIN", "SubRtspUrl": "", "TransModel": 0, "UserName": "admin"}], "EnCheckTime": True, "Enable": True, "SingleConnId": "0x00000001", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": [{"Channel": 0, "ConfName": "chConfig", "DevType": "IPC", "Enable": True, "IPAddress": "192.168.1.9", "Interval": 10, "MacAddr": "", "MainRtspUrl": "", "PassWord": "", "Port": 34567, "Protocol": "TCP", "SerialNo": "", "StreamType": "MAIN", "SubRtspUrl": "", "TransModel": 0, "UserName": "admin"}], "EnCheckTime": True, "Enable": True, "SingleConnId": "0x00000001", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": [{"Channel": 0, "ConfName": "IVG-85HF20PYA-S", "DevType": "IPC", "Enable": True, "IPAddress": "192.168.250.249", "Interval": 10, 39 | "MacAddr": "00:00:00:00:00:63", "MainRtspUrl": "", "PassWord": "2assword", "Port": 34567, "Protocol": "TCP", "SerialNo": "00000000000000b2", "StreamType": "MAIN", "SubRtspUrl": "", "TransModel": 0, "UserName": "admin"}], "EnCheckTime": True, "Enable": True, "SingleConnId": "0x00000001", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": 'null', "EnCheckTime": True, "Enable": False, "SingleConnId": "0x00000000", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": 'null', "EnCheckTime": True, "Enable": False, "SingleConnId": "0x00000000", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": 'null', "EnCheckTime": True, "Enable": False, "SingleConnId": "0x00000000", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": [{"Channel": 0, "ConfName": "LocalHost", "DevType": "IPC", "Enable": True, "IPAddress": "192.168.54.214", "Interval": 10, "MacAddr": "00:00:00:00:00:af", "MainRtspUrl": "", "PassWord": "", "Port": 34567, "Protocol": "TCP", "SerialNo": "00000000000000c9", "StreamType": "MAIN", "SubRtspUrl": "", "TransModel": 0, "UserName": "admin"}], "EnCheckTime": True, "Enable": True, "SingleConnId": "0x00000001", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": [{"Channel": 0, "ConfName": "Hikvision", "DevType": "IPC", "Enable": True, "IPAddress": "192.168.1.64", "Interval": 10, "MacAddr": "00:00:00:00:00:2b", "MainRtspUrl": "", "PassWord": "a1234567", "Port": 80, "Protocol": "ONVIF", "SerialNo": "", "StreamType": "MAIN", "SubRtspUrl": "", "TransModel": 0, "UserName": "admin"}], "EnCheckTime": True, "Enable": True, "SingleConnId": "0x00000001", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": 'null', "EnCheckTime": True, "Enable": False, "SingleConnId": "0x00000000", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": 'null', "EnCheckTime": True, "Enable": False, "SingleConnId": "0x00000000", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": 'null', "EnCheckTime": True, "Enable": False, "SingleConnId": "0x00000000", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": 'null', "EnCheckTime": True, "Enable": False, "SingleConnId": "0x00000000", "SynchResolution": True, "TourIntv": 10}, {"ConnType": "SINGLE", "Decoder": 'null', "EnCheckTime": True, "Enable": False, "SingleConnId": "0x00000000", "SynchResolution": True, "TourIntv": 10}] 40 | ChannelTitle = ["CAM01", "Test2", "D03", "5MP 123456789 0", 41 | "D05", "CAM04", "D07", "D08", "D09", "D10", "D11", "D12", "D13", "D14", "D15", "D16"] 42 | DecodeParam = [{"deleyTimeMs": 150}, {"deleyTimeMs": 333}, {"deleyTimeMs": 2000}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}, { 43 | "deleyTimeMs": 333}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}, {"deleyTimeMs": 333}] 44 | DigTimeSyn = [{"TimeSyn": "OFF"}, {"TimeSyn": "OFF"}, {"TimeSyn": "OFF"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, { 45 | "TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}, {"TimeSyn": "T&Z"}] 46 | DecodeDeleyTime = ["0x00000096", "0x000000FA", "0x0000014D", 47 | "0x0000029B", "0x000003E8", "0x000007D0", "0x00000BB8"] 48 | NetLocalSearch = [{"ChannelNum": 16, "DeviceType": 305201157, "GateWay": "0xFE01A8C0", "HostIP": "0x0401A8C0", "HostName": "NBD80S16S-KL", "HttpPort": 80, "MAC": "00:00:00:00:00:b6", "Manufacturer": 4, "MaxBps": 0, "MonMode": "TCP", "NetConnectState": 0, "OtherFunction": "", "SN": "00000000000000cfcdp6", "SSLPort": 8443, "Submask": "0x00FFFFFF", "TCPMaxConn": 10, "TCPPort": 34567, "TransferPlan": "Quality", "UDPPort": 34568, "UseHSDownLoad": False, "pAddr": "", "pGateway": "", "pLocalLinkAddr": ""}, {"ChannelNum": 4, "DeviceType": 305201156, "GateWay": "0x0201A8C0", "HostIP": "0x0801A8C0", "HostName": "LocalHost", "HttpPort": 80, "MAC": "00:00:00:00:00:71", "Manufacturer": 4, "MaxBps": 0, "MonMode": "TCP", "NetConnectState": 1, 49 | "OtherFunction": "", "SN": "0000000000000041", "SSLPort": 8443, "Submask": "0x00FFFFFF", "TCPMaxConn": 10, "TCPPort": 34567, "TransferPlan": "Quality", "UDPPort": 34568, "UseHSDownLoad": False, "pAddr": "", "pGateway": "", "pLocalLinkAddr": ""}, {"ChannelNum": 1, "DeviceType": 0, "GateWay": "0xFE01A8C0", "HostIP": "0x0601A8C0", "HostName": "LocalHost", "HttpPort": 80, "MAC": "00:00:00:00:00:ce", "Manufacturer": 4, "MaxBps": 0, "MonMode": "TCP", "NetConnectState": 1, "OtherFunction": "", "SN": "0000000000000083", "SSLPort": 8443, "Submask": "0x00FFFFFF", "TCPMaxConn": 10, "TCPPort": 34567, "TransferPlan": "Transmission", "UDPPort": 34568, "UseHSDownLoad": False, "pAddr": "", "pGateway": "", "pLocalLinkAddr": ""}, {"ChannelNum": 1, "DeviceType": 7, "GateWay": "0xFE01A8C0", "HostIP": "0x0701A8C0", "HostName": "LocalHost", "HttpPort": 80, "MAC": "00:00:00:00:00:cf", "Manufacturer": 4, "MaxBps": 0, "MonMode": "TCP", "NetConnectState": 1, "OtherFunction": "", "SN": "0000000000000084", "SSLPort": 8443, "Submask": "0x00FFFFFF", "TCPMaxConn": 10, "TCPPort": 34567, "TransferPlan": "Transmission", "UDPPort": 34568, "UseHSDownLoad": False, "pAddr": "", "pGateway": "", "pLocalLinkAddr": ""}] 50 | else: 51 | debugLevel = logging.INFO 52 | devices = {} 53 | 54 | 55 | def log(*args): 56 | # logging.debug(*args) 57 | print(*args) 58 | 59 | 60 | logging.basicConfig(format='%(asctime)s> %(message)s', 61 | level=debugLevel, datefmt='[%H:%M:%S]') 62 | 63 | 64 | class RemoteDevices(QtWidgets.QDialog, Ui_Form): 65 | def __init__(self, parent=None): 66 | QtWidgets.QDialog.__init__(self, parent=parent) 67 | self.setupUi(self) 68 | 69 | def keyPressEvent(self, event): 70 | if event.key() == QtCore.Qt.Key_Escape: 71 | self.hide() 72 | 73 | 74 | class MainWindow (QMainWindow): 75 | def __init__(self, parent=None): 76 | QMainWindow.__init__(self, parent) 77 | self.ui = Ui_MainWindow() 78 | self.ui.setupUi(self) 79 | 80 | def __del__(self): 81 | self.ui = None 82 | 83 | def filedialog(self): 84 | options = QFileDialog.Options() 85 | fileName, _ = QFileDialog.getOpenFileName( 86 | self, "Select upgrade file", settings.value("fwdir", '.'), "Firmware files (*.bin)", options=options) 87 | if fileName: 88 | self.ui.labFilename.setText(fileName) 89 | settings.setValue("fwdir", os.path.dirname(fileName)) 90 | 91 | def getCheckedDevices(self, column): 92 | checked_list = [] 93 | for i in range(self.ui.tableWidget.rowCount()): 94 | if self.ui.tableWidget.cellWidget(i, 0).isChecked(): 95 | selected_dev = self.ui.tableWidget.item(i, column).text() 96 | checked_list.append([selected_dev]) 97 | else: 98 | pass 99 | return checked_list 100 | 101 | def btnAutoIP(self): 102 | for dev in w.getCheckedDevices(3): 103 | log(dev[0]) 104 | # tcpSetAddresses(['config', dev[0], w.ui.editIPAddress.text(), w.ui.editSubnetAddress.text(), w.ui.editGatewayAddress.text(), '']) 105 | 106 | def btnChangePassword(self): 107 | newPassword = self.ui.editNewPassword.text() 108 | if newPassword: 109 | log(self.getCheckedDevices(1), newPassword) 110 | 111 | def onRowClick(self): 112 | selected_dev = w.ui.tableWidget.item( 113 | self.ui.tableWidget.currentRow(), 3).text() 114 | self.ui.editIPAddress.setText(ip2str(devices[selected_dev]["HostIP"])) 115 | self.ui.editSubnetAddress.setText( 116 | ip2str(devices[selected_dev]["Submask"])) 117 | self.ui.editGatewayAddress.setText( 118 | ip2str(devices[selected_dev]["GateWay"])) 119 | # w.ui.editDNS1Address.setText(ip2str(devices[selected_dev]["DNS"])) 120 | # for item in devices: 121 | # print(item) 122 | # print(devices[selected_dev]) 123 | # print(devices[1]) 124 | # self.ui.statusbar.showMessage(selected_dev) 125 | 126 | def keyPressEvent(self, event): 127 | if event.key() == QtCore.Qt.Key_Escape: 128 | app.quit() 129 | 130 | 131 | def onBtnSearch(): 132 | global devices 133 | QApplication.setOverrideCursor(Qt.WaitCursor) 134 | if not debug: 135 | devices = {} 136 | try: 137 | devices = udpSearch(devices) 138 | except Exception as error: 139 | print(" ".join([str(x) for x in list(error.args)])) 140 | QApplication.restoreOverrideCursor() 141 | count = 0 142 | w.ui.tableWidget.setRowCount(len(devices)) 143 | for dev in devices: 144 | w.ui.tableWidget.setCellWidget(count, 0, QCheckBox()) 145 | w.ui.tableWidget.setItem(count, 1, QTableWidgetItem( 146 | ip2str(devices[dev]["HostIP"]))) 147 | w.ui.tableWidget.setItem( 148 | count, 2, QTableWidgetItem(str(devices[dev]["TCPPort"]))) 149 | w.ui.tableWidget.setItem( 150 | count, 3, QTableWidgetItem(devices[dev]["MAC"])) 151 | w.ui.tableWidget.setItem( 152 | count, 4, QTableWidgetItem(devices[dev]["SN"])) 153 | w.ui.tableWidget.setItem(count, 5, QTableWidgetItem( 154 | devices[dev].get("Version", "")[0:18])) 155 | w.ui.tableWidget.setItem(count, 6, QTableWidgetItem( 156 | devices[dev].get("BuildDate", "")[0:10])) 157 | w.ui.tableWidget.setItem( 158 | count, 7, QTableWidgetItem(devices[dev]["HostName"])) 159 | count += 1 160 | 161 | 162 | def ip2str(s): 163 | return inet_ntoa(struct.pack("I", int(s, 16))) 164 | 165 | 166 | def str2ip(s): 167 | return "0x%08X" % struct.unpack("I", inet_aton(s)) 168 | 169 | 170 | def udpSearch(devices): 171 | sender = socket(AF_INET, SOCK_DGRAM) 172 | sender.bind((w.ui.comboIPAddresses.currentText(), 0)) 173 | sender.settimeout(1) 174 | sender.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 175 | sender.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) 176 | 177 | listener = socket(AF_INET, SOCK_DGRAM) 178 | listener.bind(('', 34569)) 179 | listener.settimeout(udptimeout) 180 | listener.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 181 | listener.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) 182 | for i in range(2): 183 | sender.sendto( 184 | struct.pack("BBHIIHHI", 255, 0, 0, 0, 0, 0, 185 | 1530, 0), ("255.255.255.255", 34569) 186 | ) 187 | while True: 188 | data = listener.recvfrom(1024) 189 | head, ver, typ, session, packet, info, msg, leng = struct.unpack( 190 | "BBHIIHHI", data[0][:20] 191 | ) 192 | if (msg == 1531) and leng > 0: 193 | answer = json.loads( 194 | data[0][20: 20 + leng].replace(b"\x00", b"")) 195 | if answer["NetWork.NetCommon"]["MAC"] not in devices.keys(): 196 | devices[answer["NetWork.NetCommon"]["MAC"]] = answer[ 197 | "NetWork.NetCommon" 198 | ] 199 | devices[answer["NetWork.NetCommon"]["MAC"]][u"Brand"] = u"xm" 200 | return devices 201 | 202 | 203 | def cbProgress(s): 204 | w.ui.statusbar.showMessage(s) 205 | 206 | 207 | def upgradeFirmware(ip, username, password, filename): 208 | QApplication.setOverrideCursor(Qt.WaitCursor) 209 | if cam.login(): 210 | log("Auth success") 211 | cam.upgrade(filename, 0x4000, cbProgress) 212 | else: 213 | log("Auth failed") 214 | QApplication.restoreOverrideCursor() 215 | 216 | 217 | def udpSetAddresses(data): 218 | config = {} 219 | for k in [u"HostName", u"HttpPort", u"MAC", u"MaxBps", u"MonMode", u"SSLPort", u"TCPMaxConn", u"TCPPort", u"TransferPlan", u"UDPPort", "UseHSDownLoad"]: 220 | if k in devices[data[1]]: 221 | config[k] = devices[data[1]][k] 222 | config[u"DvrMac"] = devices[data[1]][u"MAC"] 223 | config[u"EncryptType"] = 1 224 | config[u"GateWay"] = str2ip(data[4]) 225 | config[u"HostIP"] = str2ip(data[2]) 226 | config[u"Submask"] = str2ip(data[3]) 227 | config[u"Username"] = w.ui.editUsername.text() 228 | config[u"Password"] = DVRIPCam.sofia_hash( 229 | '', w.ui.editCurrentPassword.text()) 230 | devices[data[1]][u"GateWay"] = config[u"GateWay"] 231 | devices[data[1]][u"HostIP"] = config[u"HostIP"] 232 | devices[data[1]][u"Submask"] = config[u"Submask"] 233 | config = json.dumps( 234 | config, ensure_ascii=False, sort_keys=True, separators=(", ", " : ") 235 | ).encode("utf8") 236 | if not debug: 237 | server = socket(AF_INET, SOCK_DGRAM) 238 | server.bind((w.ui.comboIPAddresses.currentText(), 34569)) 239 | server.settimeout(udptimeout) 240 | server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 241 | server.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) 242 | clen = len(config) 243 | 244 | server.sendto( 245 | struct.pack( 246 | "BBHIIHHI%ds2s" % clen, 247 | 255, 248 | 0, 249 | 254, 250 | 0, 251 | 0, 252 | 0, 253 | 1532, 254 | clen + 2, 255 | config, 256 | b"\x0a\x00", 257 | ), 258 | ("255.255.255.255", 34569), 259 | ) 260 | answer = {"Ret": 203} 261 | e = 0 262 | while True: 263 | try: 264 | data = server.recvfrom(1024) 265 | head, ver, typ, session, packet, info, msg, leng = struct.unpack( 266 | "BBHIIHHI", data[0][:20] 267 | ) 268 | if (msg == 1533) and leng > 0: 269 | answer = json.loads( 270 | data[0][20: 20 + leng].replace(b"\x00", b"")) 271 | break 272 | except: 273 | e += 1 274 | if e > 3: 275 | break 276 | server.close() 277 | return answer 278 | 279 | 280 | def btnSave(): 281 | if w.ui.tableWidget.selectedItems(): 282 | QApplication.setOverrideCursor(Qt.WaitCursor) 283 | selected_dev = w.ui.tableWidget.item( 284 | w.ui.tableWidget.currentRow(), 3).text() 285 | udpSetAddresses(['config', selected_dev, w.ui.editIPAddress.text( 286 | ), w.ui.editSubnetAddress.text(), w.ui.editGatewayAddress.text(), '']) 287 | QApplication.restoreOverrideCursor() 288 | 289 | 290 | def btnUpgrade(): 291 | if w.ui.tableWidget.selectedItems() and w.ui.labFilename.text(): 292 | QApplication.setOverrideCursor(Qt.WaitCursor) 293 | selected_dev = w.ui.tableWidget.item( 294 | w.ui.tableWidget.currentRow(), 1).text() 295 | upgradeFirmware(w.ui.editIPAddress.text(), w.ui.editUsername.text( 296 | ), w.ui.editCurrentPassword.text(), w.ui.labFilename.text()) 297 | QApplication.restoreOverrideCursor() 298 | 299 | 300 | def netipLogin(): 301 | global cam 302 | if w.ui.tableWidget.selectedItems(): 303 | selected_dev = w.ui.tableWidget.item( 304 | w.ui.tableWidget.currentRow(), 1).text() 305 | ip = w.ui.editIPAddress.text() 306 | username = w.ui.editUsername.text() 307 | password = w.ui.editCurrentPassword.text() 308 | 309 | if not cam.socket: 310 | QApplication.setOverrideCursor(Qt.WaitCursor) 311 | cam = DVRIPCam(ip, username=username, password=password) 312 | if cam.login(): 313 | w.ui.status2.setText(w.tr(f"Connected to {ip}")) 314 | else: 315 | w.ui.status2.setText(w.tr("Login failed")) 316 | QApplication.restoreOverrideCursor() 317 | 318 | return cam 319 | else: 320 | w.ui.status2.setText(w.tr(f"Disconnected")) 321 | cam.close() 322 | 323 | 324 | def netipSendCommand(command, *args): 325 | if cam.login(): 326 | getattr(cam, command)(*args) 327 | w.ui.statusbar.showMessage(w.tr(f"{command} OK")) 328 | else: 329 | w.ui.statusbar.showMessage(w.tr("Command failed")) 330 | 331 | 332 | def getDigitalChannels(): 333 | global RemoteDeviceV3 334 | QApplication.setOverrideCursor(Qt.WaitCursor) 335 | if not debug: 336 | RemoteDeviceV3 = {} 337 | try: 338 | if cam.login(): 339 | RemoteDeviceV3 = cam.get_info("NetWork.RemoteDeviceV3") 340 | r.show() 341 | except Exception as error: 342 | print(" ".join([str(x) for x in list(error.args)])) 343 | else: 344 | r.show() 345 | QApplication.restoreOverrideCursor() 346 | r.tableChannels.setRowCount(len(RemoteDeviceV3)) 347 | count = 0 348 | for channel in RemoteDeviceV3: 349 | chkBoxEnable = QTableWidgetItem() 350 | chkBoxEnable.setFlags( 351 | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) 352 | if RemoteDeviceV3[count]['Enable']: 353 | chkBoxEnable.setCheckState(QtCore.Qt.Checked) 354 | else: 355 | chkBoxEnable.setCheckState(QtCore.Qt.Unchecked) 356 | r.tableChannels.setItem(count, 0, chkBoxEnable) 357 | 358 | r.tableChannels.setItem( 359 | count, 1, QTableWidgetItem(str(ChannelTitle[count]))) 360 | 361 | comboSyncRes = QComboBox() 362 | comboSyncRes.setFrame(False) 363 | comboSyncRes.addItems(['False', 'True']) 364 | r.tableChannels.setCellWidget(count, 4, comboSyncRes) 365 | 366 | comboTimeSyn = QComboBox() 367 | comboTimeSyn.setFrame(False) 368 | comboTimeSyn.addItems(['OFF', 'T&Z', 'Local', 'UTC']) 369 | r.tableChannels.setCellWidget(count, 5, comboTimeSyn) 370 | 371 | comboDelayDecode = QComboBox() 372 | comboDelayDecode.setFrame(False) 373 | comboDelayDecode.addItems([str(int(x, 16)) for x in DecodeDeleyTime]) 374 | r.tableChannels.setIndexWidget( 375 | r.tableChannels.model().index(count, 6), comboDelayDecode) 376 | 377 | comboProtocol = QComboBox() 378 | comboProtocol.setFrame(False) 379 | comboProtocol.addItems(['TCP', 'ONVIF', 'RTSP']) 380 | r.tableChannels.setCellWidget(count, 8, comboProtocol) 381 | 382 | if RemoteDeviceV3[count]['Decoder'] != 'null': 383 | r.tableChannels.setItem(count, 2, QTableWidgetItem( 384 | str(RemoteDeviceV3[count]['Decoder'][0]['IPAddress']))) 385 | r.tableChannels.setItem(count, 3, QTableWidgetItem( 386 | str(RemoteDeviceV3[count]['Decoder'][0]['Port']))) 387 | comboSyncRes.setCurrentText( 388 | str(not RemoteDeviceV3[count]['SynchResolution'])) 389 | comboTimeSyn.setCurrentText(str(str(DigTimeSyn[count]['TimeSyn']))) 390 | comboDelayDecode.setCurrentText( 391 | str(DecodeParam[count]['deleyTimeMs'])) 392 | r.tableChannels.setItem(count, 7, QTableWidgetItem( 393 | str(RemoteDeviceV3[count]['Decoder'][0]['Channel']))) 394 | comboProtocol.setCurrentText( 395 | str(RemoteDeviceV3[count]['Decoder'][0]['Protocol'])) 396 | r.tableChannels.setItem(count, 9, QTableWidgetItem( 397 | RemoteDeviceV3[count]['Decoder'][0]['UserName'])) 398 | r.tableChannels.setItem(count, 10, QTableWidgetItem( 399 | RemoteDeviceV3[count]['Decoder'][0]['PassWord'])) 400 | count += 1 401 | 402 | 403 | def btnDigitalChannelsSave(): 404 | trow = [] 405 | for row in range(16): 406 | for i in range(2, 7): 407 | try: 408 | trow.append(r.tableChannels.item( 409 | r.tableChannels.verticalHeader().logicalIndex(row), i).text()) 410 | except: 411 | print(" ".join([str(x) for x in list(error.args)])) 412 | print(trow) 413 | 414 | 415 | def btnDigitalSearch(): 416 | global NetLocalSearch 417 | QApplication.setOverrideCursor(Qt.WaitCursor) 418 | if not debug: 419 | NetLocalSearch = {} 420 | try: 421 | if cam.login(): 422 | NetLocalSearch = cam.get_info("NetLocalSearch") 423 | except Exception as error: 424 | print(" ".join([str(x) for x in list(error.args)])) 425 | QApplication.restoreOverrideCursor() 426 | count = 0 427 | r.tableSearch.setRowCount(len(NetLocalSearch)) 428 | for dev in NetLocalSearch: 429 | r.tableSearch.setItem( 430 | count, 0, QTableWidgetItem(ip2str(dev["HostIP"]))) 431 | r.tableSearch.setItem( 432 | count, 1, QTableWidgetItem(str(dev["TCPPort"]))) 433 | r.tableSearch.setItem( 434 | count, 2, QTableWidgetItem(dev["MAC"])) 435 | r.tableSearch.setItem( 436 | count, 3, QTableWidgetItem(dev["SN"])) 437 | devtype = {305201157: 'NVR', 305201156: 'DVR', 7: 'IPCWIFI', 0: 'IPC'} 438 | r.tableSearch.setItem(count, 4, QTableWidgetItem(dev["HostName"])) 439 | r.tableSearch.setItem( 440 | count, 5, QTableWidgetItem(str(dev["ChannelNum"]))) 441 | r.tableSearch.setItem( 442 | count, 6, QTableWidgetItem(devtype[dev["DeviceType"]])) 443 | count += 1 444 | 445 | 446 | def onComboSelectInterface(): 447 | iface = str(w.ui.comboInterfaces.currentText()) 448 | w.ui.comboIPAddresses.clear() 449 | for addr_info in netifaces.ifaddresses(iface)[netifaces.AF_INET]: 450 | w.ui.comboIPAddresses.addItem( 451 | str(addr_info['addr'])) 452 | w.ui.comboIPAddresses.setCurrentText( 453 | str(netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr'])) 454 | 455 | 456 | if __name__ == '__main__': 457 | app = QApplication(sys.argv) 458 | app.setOrganizationName("OpenIPC") 459 | app.setOrganizationDomain("openipc.org") 460 | app.setApplicationName("DMS") 461 | settings = QSettings() 462 | # locale = getdefaultlocale() 463 | locale = 'ru' 464 | 465 | translator = QtCore.QTranslator(app) 466 | translator.load('res/%s.qm' % locale[0]) 467 | app.installTranslator(translator) 468 | 469 | w = MainWindow() 470 | w.show() 471 | r = RemoteDevices() 472 | 473 | r.tableChannels.setColumnWidth(0, 5) 474 | r.tableChannels.setColumnWidth(1, 150) 475 | r.tableChannels.setColumnWidth(2, 110) 476 | r.tableChannels.setColumnWidth(3, 50) 477 | r.tableChannels.setColumnWidth(4, 75) 478 | r.tableChannels.setColumnWidth(5, 75) 479 | r.tableChannels.setColumnWidth(6, 75) 480 | r.tableChannels.setColumnWidth(7, 50) 481 | r.tableChannels.setColumnWidth(8, 65) 482 | r.tableChannels.setColumnWidth(9, 75) 483 | r.tableChannels.setColumnWidth(10, 85) 484 | # r.tableChannels.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) 485 | r.tableChannels.verticalHeader().setSectionResizeMode(QHeaderView.Fixed) 486 | r.tableChannels.verticalHeader().setSectionsMovable(True) 487 | r.tableChannels.verticalHeader().setAcceptDrops(True) 488 | r.btnDigitalChannelsSave.clicked.connect(btnDigitalChannelsSave) 489 | 490 | r.tableSearch.setColumnWidth(0, 110) 491 | r.tableSearch.setColumnWidth(1, 50) 492 | r.tableSearch.setColumnWidth(2, 120) 493 | r.tableSearch.setColumnWidth(3, 155) 494 | r.tableSearch.setColumnWidth(4, 200) 495 | r.tableSearch.setColumnWidth(5, 50) 496 | r.tableSearch.verticalHeader().setSectionsMovable(True) 497 | r.btnDigitalSearch.clicked.connect(btnDigitalSearch) 498 | 499 | w.ui.btnAutoIP.clicked.connect(w.btnAutoIP) 500 | w.ui.searchDevices.clicked.connect(onBtnSearch) 501 | w.ui.btnBrowse.clicked.connect(w.filedialog) 502 | w.ui.btnSave.clicked.connect(btnSave) 503 | w.ui.btnUpgrade.clicked.connect(btnUpgrade) 504 | w.ui.btnReboot.clicked.connect(lambda: netipSendCommand("reboot")) 505 | w.ui.btnDigitalChannels.clicked.connect(getDigitalChannels) 506 | w.ui.btnChangePassword.clicked.connect(w.btnChangePassword) 507 | w.ui.tableWidget.cellClicked.connect(w.onRowClick) 508 | w.ui.tableWidget.cellDoubleClicked.connect(netipLogin) 509 | w.ui.comboInterfaces.currentTextChanged.connect(onComboSelectInterface) 510 | 511 | w.ui.tableWidget.horizontalHeader().resizeSection(0, 1) 512 | w.ui.tableWidget.horizontalHeader().setSectionResizeMode( 513 | QHeaderView.ResizeToContents) 514 | 515 | w.ui.statusbar.setFixedHeight(25) 516 | w.ui.statusbar.showMessage(w.tr("Idle")) 517 | w.ui.status2 = QLabel("Disconnected") 518 | w.ui.statusbar.addPermanentWidget(w.ui.status2) 519 | 520 | # need to find replacement for netifaces, no binary builds for python 3.10 on windows 521 | hostinterfaces = netifaces.interfaces() 522 | hostdefaultgw = netifaces.gateways()['default'][netifaces.AF_INET][1] 523 | badinterfaces = ['lo', 'docker', 'veth', 'vbox'] 524 | for iface in hostinterfaces: 525 | addrs = netifaces.ifaddresses(iface) 526 | if netifaces.AF_INET not in addrs: 527 | badinterfaces.append(iface) 528 | w.ui.comboInterfaces.addItems( 529 | [x for x in hostinterfaces if not any(x.startswith(s) for s in badinterfaces)]) 530 | if hostdefaultgw: 531 | w.ui.comboInterfaces.setCurrentText(hostdefaultgw) 532 | 533 | sys.exit(app.exec_()) 534 | --------------------------------------------------------------------------------