├── root └── home │ └── haso │ ├── camviewer │ ├── __init__.py │ ├── cfgviewer │ │ ├── __init__.py │ │ ├── cfgpanel │ │ │ ├── __init__.py │ │ │ ├── migrations │ │ │ │ └── __init__.py │ │ │ ├── static │ │ │ │ └── cfgpanel │ │ │ │ │ ├── images │ │ │ │ │ └── background.jpg │ │ │ │ │ └── style.css │ │ │ ├── tests.py │ │ │ ├── admin.py │ │ │ ├── models.py │ │ │ ├── apps.py │ │ │ ├── urls.py │ │ │ ├── templates │ │ │ │ └── cfgpanel │ │ │ │ │ ├── service_input.html │ │ │ │ │ ├── reboot.html │ │ │ │ │ ├── style.css │ │ │ │ │ └── index.html │ │ │ ├── constants.py │ │ │ ├── utils.py │ │ │ ├── config_utils.py │ │ │ └── views.py │ │ ├── cfgviewer │ │ │ ├── __init__.py │ │ │ ├── wsgi.py │ │ │ ├── urls.py │ │ │ └── settings.py │ │ ├── run.bat │ │ ├── reboot_bgd.sh │ │ ├── reboot.sh │ │ └── manage.py │ ├── version.txt │ ├── xset.bat │ ├── sub0.srt │ ├── sub1.srt │ ├── sub2.srt │ ├── sub3.srt │ ├── help_4in1.png │ ├── help_auto.png │ ├── help_single.png │ ├── no_signal.mp4 │ ├── rebooting.jpg │ ├── branding │ │ ├── splash.png │ │ └── app_logo.png │ ├── not_configured.mp4 │ ├── sscce_freezing_issue │ │ ├── not_configured.mp4 │ │ ├── start.sh │ │ ├── omx_count.sh │ │ ├── omx_kill_all.sh │ │ ├── omx_kill_single.sh │ │ ├── log_config.py │ │ ├── readme.txt │ │ ├── dbus_omxplayer.py │ │ └── player4cams.py │ ├── config_mon.cfg │ ├── fix_permissions.sh │ ├── reconfigure_xserver.sh │ ├── restart.sh │ ├── service │ │ ├── buttons │ │ │ └── run │ │ ├── watchdog │ │ │ └── run │ │ ├── camviewer │ │ │ └── run │ │ └── cfgviewer │ │ │ └── run │ ├── start.sh │ ├── omx_count.sh │ ├── stop.sh │ ├── omx_kill_all.sh │ ├── cleanup.sh │ ├── cfgviewer.sh │ ├── remove_services.sh │ ├── utils.py │ ├── omx_wait.sh │ ├── uninstall.sh │ ├── interfaces │ ├── omx_kill_single.sh │ ├── install_services.sh │ ├── log_config.py │ ├── watchdog.py │ ├── zmq_consumer.py │ ├── buttons.py │ ├── kill_running_apps.sh │ ├── player.py │ ├── event_handler.py │ ├── dbus_omxplayer.py │ ├── info_collector.py │ ├── info_window.py │ ├── player_split.py │ └── camviewer.py │ └── install.sh ├── doc └── FCS-1091_WCS-1090_UM_V1.1.pdf ├── README.md ├── .gitignore └── LICENSE /root/home/haso/camviewer/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/version.txt: -------------------------------------------------------------------------------- 1 | 1.9 2 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgviewer/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/xset.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo xset %1 %2 -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sub0.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,000 --> 00:00:05,000 3 | Kamera 1 4 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sub1.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,000 --> 00:00:05,000 3 | Kamera 2 4 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sub2.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,000 --> 00:00:05,000 3 | Kamera 3 4 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sub3.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,000 --> 00:00:05,000 3 | Kamera 4 4 | -------------------------------------------------------------------------------- /doc/FCS-1091_WCS-1090_UM_V1.1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/doc/FCS-1091_WCS-1090_UM_V1.1.pdf -------------------------------------------------------------------------------- /root/home/haso/camviewer/help_4in1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/help_4in1.png -------------------------------------------------------------------------------- /root/home/haso/camviewer/help_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/help_auto.png -------------------------------------------------------------------------------- /root/home/haso/camviewer/help_single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/help_single.png -------------------------------------------------------------------------------- /root/home/haso/camviewer/no_signal.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/no_signal.mp4 -------------------------------------------------------------------------------- /root/home/haso/camviewer/rebooting.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/rebooting.jpg -------------------------------------------------------------------------------- /root/home/haso/camviewer/branding/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/branding/splash.png -------------------------------------------------------------------------------- /root/home/haso/camviewer/not_configured.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/not_configured.mp4 -------------------------------------------------------------------------------- /root/home/haso/camviewer/branding/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/branding/app_logo.png -------------------------------------------------------------------------------- /root/home/haso/camviewer/sscce_freezing_issue/not_configured.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/sscce_freezing_issue/not_configured.mp4 -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/static/cfgpanel/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alewir/playstreamation/HEAD/root/home/haso/camviewer/cfgviewer/cfgpanel/static/cfgpanel/images/background.jpg -------------------------------------------------------------------------------- /root/home/haso/camviewer/config_mon.cfg: -------------------------------------------------------------------------------- 1 | auto eth0:0 2 | allow-hotplug eth0:0 3 | iface eth0:0 inet static 4 | link-speed 100 5 | link-duplex full 6 | ethernet-autoneg off 7 | address 192.168.1.188 8 | netmask 255.255.255.0 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # playstreamation 2 | 3 | Configuration and playback/management system for up to 4 streams (RTSP, e.g. from IP cameras). Using popcornmix/omxplayer. 4 | 5 | Applicable for Raspbian and so for Raspbian Pi (tested on version 2 and 3). It spawns omxplayer multiple instances for playing camera streams. 6 | 7 | For more details check wiki page: https://github.com/alewir/playstreamation/wiki 8 | 9 | Contact information: sir.alwi@gmail.com 10 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/tests.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | # Create your tests here. 14 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/admin.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | # Register your models here. 14 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/run.bat: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | python manage.py runserver 192.168.100.96:8083 -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/reboot_bgd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | sleep 3 16 | sudo reboot -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/reboot.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | exec bash reboot_bgd.sh & 16 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/fix_permissions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | chmod 755 *.py 16 | chmod 755 *.sh -------------------------------------------------------------------------------- /root/home/haso/camviewer/reconfigure_xserver.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | dpkg-reconfigure xserver-xorg 16 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sscce_freezing_issue/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | python player4cams.py 16 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/models.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | from __future__ import unicode_literals 14 | 15 | # Create your models here. 16 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/apps.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | from django.apps import AppConfig 14 | 15 | 16 | class ConfigPanel(AppConfig): 17 | name = 'cfgpanel' 18 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/restart.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | source ./stop.sh 16 | 17 | echo "Starting apps..." 18 | sleep 2 19 | 20 | source ./start.sh 21 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/service/buttons/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | export PS_HOME=/home/haso/camviewer 16 | 17 | cd "$PS_HOME" 18 | python buttons.py 19 | 20 | exit 0 21 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/service/watchdog/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | export PS_HOME=/home/haso/camviewer 16 | 17 | cd "$PS_HOME" 18 | python watchdog.py 19 | 20 | exit 0 21 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/service/camviewer/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | export PS_HOME=/home/haso/camviewer 16 | 17 | cd "$PS_HOME" 18 | startx ./camviewer.py 19 | 20 | exit 0 21 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/service/cfgviewer/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | export PS_HOME=/home/haso/camviewer 16 | 17 | cd "$PS_HOME" 18 | bash cfgviewer.sh 19 | 20 | exit 0 21 | 22 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/start.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | sudo svc -u /service/buttons/ 16 | sudo svc -u /service/camviewer/ 17 | sudo svc -u /service/cfgviewer/ 18 | 19 | exit 0 20 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/omx_count.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | win_coords=$1 16 | 17 | if [ -n "$win_coords" ]; then 18 | ps_count=`ps -ef | grep "[o]mxplayer.bin" | grep "$win_coords" | awk '{print $2}' | wc -l` 19 | echo ${ps_count} 20 | else 21 | echo -1 22 | fi 23 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/urls.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | from django.conf.urls import url 14 | 15 | from . import views 16 | 17 | app_name = "config" 18 | urlpatterns = [ 19 | url(r'^$', views.index, name='index'), 20 | url(r'^service/$', views.service_input, name='service'), 21 | ] 22 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | echo "Stopping services..." 16 | sudo svc -d /service/buttons/ 17 | sudo svc -d /service/camviewer/ 18 | sudo svc -d /service/cfgviewer/ 19 | 20 | echo "Killing apps..." 21 | sleep 3 22 | 23 | source kill_running_apps.sh 24 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sscce_freezing_issue/omx_count.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | win_coords=$1 16 | 17 | if [ -n "$win_coords" ]; then 18 | ps_count=`ps -ef | grep "[o]mxplayer.bin" | grep "$win_coords" | awk '{print $2}' | wc -l` 19 | echo ${ps_count} 20 | else 21 | echo -1 22 | fi 23 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/omx_kill_all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | ps -ef | grep "[o]mxplayer.bin" | awk '{print $2}' | xargs -n 1 sudo kill -s SIGINT 16 | 17 | screen -X -S camera0 kill 18 | screen -X -S camera1 kill 19 | screen -X -S camera2 kill 20 | screen -X -S camera3 kill 21 | 22 | exit 0 23 | 24 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sscce_freezing_issue/omx_kill_all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | ps -ef | grep "[o]mxplayer.bin" | awk '{print $2}' | xargs -n 1 sudo kill -s SIGINT 16 | 17 | screen -X -S camera0 kill 18 | screen -X -S camera1 kill 19 | screen -X -S camera2 kill 20 | screen -X -S camera3 kill 21 | 22 | exit 0 23 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | import os 16 | import sys 17 | 18 | if __name__ == "__main__": 19 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cfgviewer.settings") 20 | 21 | from django.core.management import execute_from_command_line 22 | 23 | execute_from_command_line(sys.argv) 24 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | rm -rfv *.log 16 | rm -rfv *.log.* 17 | find . -name "*.pyc" | xargs -n 1 rm -rfv 18 | rm -rfv start?.sh 19 | 20 | cp -v config_cam.cfg ../ 21 | cp -v config_mon.cfg ../ 22 | cp -v config_serial.cfg ../ 23 | cp -v interfaces ../ 24 | 25 | rm -rfv config_cam.cfg 26 | rm -rfv config_serial.cfg 27 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | export PS_HOME=/home/haso/camviewer 16 | 17 | cd "$PS_HOME"/cfgviewer 18 | 19 | IP_ADDRESS=`awk '$1=="address" {print $2}' "$PS_HOME"/config_mon.cfg` 20 | MON_URL="$IP_ADDRESS":8080 21 | 22 | python manage.py migrate 23 | python manage.py runserver --insecure "$MON_URL" > "$PS_HOME"/cfgviewer.log 2>&1 24 | 25 | cd - 26 | 27 | exit 0 28 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/remove_services.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | SERVICES=(camviewer cfgviewer watchdog buttons) 16 | 17 | for SCRIPT in ${SERVICES[*]} 18 | do 19 | echo "Cleaning up $SCRIPT" 20 | sudo rm -rvf /etc/service/service-$SCRIPT 21 | sudo rm -rvf /service/$SCRIPT 22 | done 23 | 24 | echo "Results:" 25 | sudo tree /service 26 | sudo tree /etc/service 27 | 28 | exit 0 29 | 30 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/utils.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | __author__ = 'alwi' 16 | 17 | NAME_MODE_SINGLE = 'pojedyńczy' 18 | NAME_MODE_SPLIT = '4 w 1' 19 | NAME_MODE_AUTO = 'cykliczny' 20 | 21 | MODE_SINGLE = "MODE_SINGLE" 22 | MODE_SPLIT = "MODE_SPLIT" 23 | MODE_AUTO = "MODE_AUTO" 24 | SCREEN_RES = "1060x600" 25 | 26 | APP_LOGO_PNG = "branding/app_logo.png" # 262x104 px 27 | APP_HELP_S_PNG = "help_single.png" 28 | APP_HELP_A_PNG = "help_auto.png" 29 | APP_HELP_4_PNG = "help_4in1.png" 30 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgviewer/wsgi.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | """ 14 | WSGI config for cfgviewer project. 15 | 16 | It exposes the WSGI callable as a module-level variable named ``application``. 17 | 18 | For more information on this file, see 19 | https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ 20 | """ 21 | 22 | import os 23 | 24 | from django.core.wsgi import get_wsgi_application 25 | 26 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cfgviewer.settings") 27 | 28 | application = get_wsgi_application() 29 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/omx_wait.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | sleep 5 # time for all players to initialize 16 | 17 | proc_check=$(ps -ef | grep '[o]mxplayer.bin') 18 | if [[ $? != 0 ]]; then 19 | echo "Proc check failed!" 20 | exit 1 21 | elif [ -n "$proc_check" ]; then 22 | echo "Running..." 23 | while [ "$(ps -ef | grep '[o]mxplayer.bin' | wc -l)" -gt 0 ]; do 24 | sleep 1 25 | done 26 | 27 | echo "All players stopped." 28 | exit 0 29 | else 30 | echo "No players were running." 31 | exit 0 32 | fi 33 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | bash stop.sh 16 | 17 | export INSTALL_DIR=~haso/camviewer 18 | 19 | sudo bash remove_services.sh 20 | 21 | sudo rm -rvf /etc/network/interfaces 22 | sudo mv -vf /etc/network/interfaces.old /etc/network/interfaces 23 | 24 | sudo insserv -r /etc/init.d/asplashscreen 25 | sudo rm -rvf /etc/init.d/asplashscreen 26 | 27 | sudo rm -rvf /etc/splash.jpg 28 | sudo mv -vf /etc/splash.jpg.old /etc/splash.jpg 29 | 30 | sudo pip uninstall django 31 | sudo pip uninstall pyping 32 | 33 | cd $INSTALL_DIR/.. 34 | sudo rm -rvf $INSTALL_DIR 35 | 36 | exit 0 -------------------------------------------------------------------------------- /root/home/haso/camviewer/interfaces: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | # interfaces(5) file used by ifup(8) and ifdown(8) 14 | 15 | # Please note that this file is written to be used with dhcpcd 16 | # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf' 17 | 18 | # Include files from /etc/network/interfaces.d: 19 | source-directory /etc/network/interfaces.d 20 | 21 | auto lo 22 | iface lo inet loopback 23 | 24 | auto eth0 25 | allow-hotplug eth0 26 | iface eth0 inet static 27 | address 192.168.100.199 28 | netmask 255.255.255.0 29 | gateway 192.168.100.1 30 | dns-nameservers 192.168.100.1 31 | 32 | source /home/haso/camviewer/config_mon.cfg 33 | -------------------------------------------------------------------------------- /root/home/haso/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sudo apt-get update 4 | 5 | sudo apt-get install python-dev python-pip 6 | # using SVN to easily clone only one of subdirectories from GIT 7 | sudo apt-get install subversion 8 | sudo apt-get install daemontools daemontools-run 9 | sudo apt-get install python-imaging-tk 10 | sudo apt-get install screen 11 | sudo apt-get install fbi 12 | 13 | # tested with version: 1.9.4 14 | sudo pip install django 15 | # tested with version: 0.0.4 16 | sudo pip install pyping 17 | # tested with version: 2.1.2 18 | sudo pip install fysom 19 | # tested with version: 15.2.0 20 | sudo pip install pyzmq 21 | 22 | export PS_USER=haso 23 | export REPO_URL=https://github.com/alewir/playstreamation.git/trunk/root/home/haso/camviewer/ 24 | 25 | cd /home/"$PS_USER" 26 | mkdir camviewer 27 | sudo chown "$PS_USER" camviewer 28 | cd camviewer 29 | export PS_HOME=`pwd` # TODO: this path needs to be stored and set at startup (preferably for all users) 30 | 31 | svn co "$REPO_URL" . 32 | sudo chown -R "$PS_USER" * 33 | 34 | bash fix_permissions.sh 35 | ./install_services.sh 36 | 37 | sudo mv -vf /etc/network/interfaces /etc/network/interfaces.old 38 | sudo ln -vs "$PS_HOME"/interfaces /etc/network/interfaces 39 | 40 | exit 0 41 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/omx_kill_single.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | win_coords=$1 16 | screen_name=$2 17 | 18 | echo 'coords='${win_coords} 19 | echo 'screen='${screen_name} 20 | 21 | if [ -n "$win_coords" ] && [ -n "$screen_name" ]; then 22 | echo "Killing all processes for ($screen_name) and ($win_coords)..." 23 | ps_list=`ps -ef | grep "[o]mxplayer.bin" | grep "$win_coords"` 24 | echo "ps results="${ps_list} 25 | pid_s=`echo "$ps_list" | awk '{print $2}'` 26 | echo "PIDS="${pid_s} 27 | echo "$pid_s" | xargs -n 1 sudo kill -s SIGKILL 28 | screen -X -S "$screen_name" kill 29 | exit 0 30 | else 31 | echo "No parameter given." 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/install_services.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | export INSTALL_DIR=~haso/camviewer 16 | 17 | sudo mkdir /etc/service 18 | sudo mkdir /service 19 | 20 | export INSTALL_DIR=~haso/camviewer 21 | 22 | sudo bash remove_services.sh 23 | 24 | SERVICES=(camviewer cfgviewer watchdog buttons) 25 | for SCRIPT in ${SERVICES[*]} 26 | do 27 | echo "Setting up $SCRIPT" 28 | chmod 755 "$INSTALL_DIR"/service/$SCRIPT/run 29 | sudo cp -rfv "$INSTALL_DIR"/service/$SCRIPT /service/ 30 | echo " -- Linking..." 31 | sudo ln -vsT /service/$SCRIPT /etc/service/service-$SCRIPT 32 | done 33 | 34 | echo "Results:" 35 | sudo tree /service 36 | sudo tree /etc/service 37 | 38 | exit 0 39 | 40 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sscce_freezing_issue/omx_kill_single.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | win_coords=$1 16 | screen_name=$2 17 | 18 | echo 'coords='${win_coords} 19 | echo 'screen='${screen_name} 20 | 21 | if [ -n "$win_coords" ] && [ -n "$screen_name" ]; then 22 | echo "Killing all processes for ($screen_name) and ($win_coords)..." 23 | ps_list=`ps -ef | grep "[o]mxplayer.bin" | grep "$win_coords"` 24 | echo "ps results="${ps_list} 25 | pid_s=`echo "$ps_list" | awk '{print $2}'` 26 | echo "PIDS="${pid_s} 27 | echo "$pid_s" | xargs -n 1 sudo kill -s SIGKILL 28 | screen -X -S "$screen_name" kill 29 | exit 0 30 | else 31 | echo "No parameter given." 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/log_config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from logging.handlers import RotatingFileHandler 3 | 4 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | 16 | log_level = logging.INFO 17 | 18 | log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 19 | 20 | log_handler_file = RotatingFileHandler(filename='camviewer.log', mode='w', maxBytes=10000000, backupCount=3) 21 | log_handler_console = logging.StreamHandler() 22 | log_handler_console.setLevel(log_level) 23 | log_handler_console.setFormatter(log_formatter) 24 | 25 | log = logging.getLogger('camviewer') 26 | log.setLevel(log_level) 27 | log_handler_file.setLevel(log_level) 28 | log_handler_file.setFormatter(log_formatter) 29 | log.addHandler(log_handler_console) 30 | log.addHandler(log_handler_file) 31 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/watchdog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | 16 | import time 17 | 18 | import RPi.GPIO as GPIO 19 | 20 | WDT_PIN_STROBE = 21 21 | WDT_PIN_REN = 16 22 | 23 | GPIO.setmode(GPIO.BCM) 24 | 25 | GPIO.setup(WDT_PIN_STROBE, GPIO.OUT) 26 | GPIO.setup(WDT_PIN_REN, GPIO.OUT) 27 | 28 | GPIO.output(WDT_PIN_REN, True) 29 | 30 | 31 | def strobe(): 32 | GPIO.output(WDT_PIN_STROBE, False) 33 | time.sleep(0.1) 34 | 35 | GPIO.output(WDT_PIN_STROBE, True) 36 | time.sleep(0.1) 37 | 38 | 39 | initializing = 1 40 | while True: 41 | for x in range(0, 10): # for ~2 second(s)... 42 | strobe() 43 | 44 | if initializing == 1: 45 | # and then: Reset Enabled 46 | GPIO.output(WDT_PIN_REN, False) 47 | initializing = 0 # once 48 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sscce_freezing_issue/log_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | import logging 14 | 15 | from logging.handlers import RotatingFileHandler 16 | 17 | # create & configure logger 18 | log_level = logging.INFO 19 | 20 | log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 21 | 22 | log_handler_file = RotatingFileHandler(filename='player4cams.log', mode='w', maxBytes=10000000, backupCount=3) 23 | log_handler_console = logging.StreamHandler() 24 | log_handler_console.setLevel(log_level) 25 | log_handler_console.setFormatter(log_formatter) 26 | 27 | log = logging.getLogger('player4cams') 28 | log.setLevel(log_level) 29 | log_handler_file.setLevel(log_level) 30 | log_handler_file.setFormatter(log_formatter) 31 | log.addHandler(log_handler_console) 32 | log.addHandler(log_handler_file) 33 | -------------------------------------------------------------------------------- /.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 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | .idea 91 | 92 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sscce_freezing_issue/readme.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | # prerequisites: 14 | sudo apt-get update && sudo apt-get upgrade 15 | sudo apt-get install screen 16 | sudo apt-get install subversion 17 | 18 | # SSCCE installation 19 | mkdir playstreamation_issue 20 | cd playstreamation_issue 21 | svn co https://github.com/alewir/playstreamation.git/trunk/root/home/haso/camviewer/sscce_freezing_issue/ . 22 | chmod 755 *.sh 23 | 24 | # Raspbian preparation 25 | # 26 | # Apply settings from 27 | # https://github.com/alewir/playstreamation/wiki/OS-preparation 28 | # OS preparation sections that are mandatory to apply: 29 | # Initial OS setup after installation 30 | # Update permissions for omxplayer process executed by a user ('haso' user is used as example) 31 | # Screen & Video 32 | # Basic video configuration 33 | # Disabling screen saver 34 | 35 | sudo reboot 36 | 37 | # start with: 38 | ./start.sh 39 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/zmq_consumer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import zmq 4 | 5 | from cfgviewer.cfgpanel.constants import ZMQ_PORT 6 | from log_config import log 7 | 8 | 9 | class ZmqConsumer: 10 | handle_event = None 11 | is_enabled = True 12 | 13 | def __init__(self, event_handler_method): 14 | self.handle_event = event_handler_method 15 | 16 | # ZeroMQ Server connection (Consumer) 17 | port = ZMQ_PORT 18 | context = zmq.Context() 19 | 20 | self.socket = context.socket(zmq.REP) 21 | self.socket.bind("tcp://*:%s" % port) 22 | self.mainloop() 23 | 24 | def mainloop(self): 25 | while self.is_enabled: 26 | try: 27 | msg = self.socket.recv() 28 | log.info('Message found in ZMQ: (%s)' % msg) 29 | 30 | if self.handle_event is not None: 31 | print 'Invoking event handler...' 32 | self.handle_event(msg) 33 | else: 34 | print 'No handler registered for events...' 35 | 36 | self.socket.send("Finished processing: %s" % msg) 37 | log.info('Message handling finished for: (%s)' % msg) 38 | except KeyboardInterrupt: 39 | log.info('\nKeyboard interrupt intercepted - exiting...') 40 | break 41 | 42 | log.info('Exiting ZMQ consumer mainloop.') 43 | 44 | def disable(self): 45 | self.is_enabled = False 46 | 47 | 48 | if __name__ == '__main__': 49 | ZmqConsumer(None) 50 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/templates/cfgpanel/service_input.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Konfiguracja MG-1 11 | 12 | 13 | 14 |

15 | Menu serwisowe monitora 16 |
17 |

18 | 19 |
{% csrf_token %} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 |
Adres MAC 
 
31 |

Nowy numer seryjny

Wartość 

40 |

Autoryzacja

Hasło serwisowe 
47 | 48 |
49 |
50 | 51 |
52 | 53 | 54 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/buttons.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | from cfgviewer.cfgpanel.utils import btn_enter, btn_esc, btn_up, btn_down, btn_left, btn_right 16 | from cfgviewer.cfgpanel.constants import PIN_ENTER, PIN_ESC, PIN_UP, PIN_DOWN, PIN_LEFT, PIN_RIGHT 17 | # noinspection PyUnresolvedReferences 18 | from gpiozero import Button 19 | # noinspection PyUnresolvedReferences 20 | from signal import pause 21 | 22 | 23 | def main(): 24 | button_enter = Button(PIN_ENTER) 25 | button_enter.when_pressed = btn_enter 26 | 27 | button_esc = Button(PIN_ESC) 28 | button_esc.when_pressed = btn_esc 29 | 30 | button_up = Button(PIN_UP) 31 | button_up.when_pressed = btn_up 32 | 33 | button_down = Button(PIN_DOWN) 34 | button_down.when_pressed = btn_down 35 | 36 | button_left = Button(PIN_LEFT) 37 | button_left.when_pressed = btn_left 38 | 39 | button_right = Button(PIN_RIGHT) 40 | button_right.when_pressed = btn_right 41 | 42 | pause() 43 | 44 | 45 | if __name__ == "__main__": 46 | main() 47 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgviewer/urls.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | """cfgviewer URL Configuration 14 | 15 | The `urlpatterns` list routes URLs to views. For more information please see: 16 | https://docs.djangoproject.com/en/1.9/topics/http/urls/ 17 | Examples: 18 | Function views 19 | 1. Add an import: from my_app import views 20 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 21 | Class-based views 22 | 1. Add an import: from other_app.views import Home 23 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 24 | Including another URLconf 25 | 1. Add an import: from blog import urls as blog_urls 26 | 2. Import the include() function: from django.conf.urls import url, include 27 | 3. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) 28 | """ 29 | 30 | from django.conf.urls import include 31 | from django.conf.urls import url 32 | from django.contrib import admin 33 | 34 | urlpatterns = [ 35 | url(r'^config/', include('cfgpanel.urls')), 36 | url(r'^admin/', admin.site.urls), 37 | ] 38 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/kill_running_apps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | PID=`ps -ef | grep "python [b]uttons.py" | awk '{print $2}'` 16 | if [ -n "$PID" ] ; then 17 | echo "Closing GPIO-Buttons driver..." 18 | echo "$PID" | xargs -n 1 sudo kill -TERM 19 | else 20 | echo "GPIO-Buttons driver not running." 21 | fi 22 | 23 | PID=`ps -ef | grep "python [m]anage.py runserver" | awk '{print $2}'` 24 | if [ -n "$PID" ] ; then 25 | echo "Closing CFGviewer..." 26 | echo "$PID" | xargs -n 1 sudo kill -TERM 27 | else 28 | echo "CFGviewer not running." 29 | fi 30 | 31 | PID=`ps -ef | grep "[c]amviewer.py" | awk '{print $2}'` 32 | if [ -n "$PID" ] ; then 33 | echo "Closing CAMviewer..." 34 | echo "$PID" | xargs -n 1 sudo kill -TERM 35 | else 36 | echo "CAMviewer not running." 37 | fi 38 | 39 | PID=`ps -ef | grep "[o]mxplayer.bin" | awk '{print $2}'` 40 | if [ -n "$PID" ] ; then 41 | echo "Closing OMXplayer..." 42 | sudo python dbus_omxplayer.py 43 | else 44 | echo "OMXplayer not running." 45 | fi 46 | 47 | ./omx_kill_all.sh 48 | 49 | # NOTE: watchdog.py process <= should not be killed (WDT will fire) 50 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/templates/cfgpanel/reboot.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Konfiguracja MG-1 11 | 12 | 13 | 14 |

15 | Monitor jest restartowany. Proszę czekać... 16 |
17 | Pozostało: -- 18 |

19 | 20 |

21 | UWAGA: Jeśli strona konfiguracji nie otworzy się w ciągu około 30 sekund, należy odświeżyć przeglądarkę (klawisz F5). 22 |

23 | 24 | 45 | 46 | 47 | {% if redirect_address == "" %} 48 |
49 |

Trwa odświeżanie strony: {{ current_mon_address }}:8080/config

50 | 58 |
59 | {% endif %} 60 | 61 | 62 | {% if redirect_address != "" %} 63 |
64 |

Trwa przekierowywanie do adresu: {{ redirect_address }}:8080/config

65 | 75 |
76 | {% endif %} 77 | 78 | 79 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/static/cfgpanel/style.css: -------------------------------------------------------------------------------- 1 | h1, .param_group { 2 | color: yellow; 3 | } 4 | 5 | .error_msg { 6 | color: pink; 7 | } 8 | 9 | .error_msg_c { 10 | color: red; 11 | background: lightgray; 12 | } 13 | 14 | body { 15 | color: white; 16 | background: blue url("images/background.jpg"); 17 | } 18 | 19 | table { 20 | border: 1px solid lightblue; 21 | width: 1000px; 22 | table-layout: fixed; 23 | background: green url("images/background.jpg"); 24 | word-wrap: break-word; 25 | } 26 | 27 | th { 28 | background-color: #336699; 29 | } 30 | 31 | .col_name { 32 | width: 6%; 33 | } 34 | 35 | .col_ip { 36 | width: 13%; 37 | } 38 | 39 | .col_port { 40 | width: 6%; 41 | } 42 | 43 | .col_stream_m { 44 | width: 4%; 45 | } 46 | 47 | .col_stream_s { 48 | width: 4%; 49 | } 50 | 51 | .col_user { 52 | width: 13%; 53 | } 54 | 55 | .col_pass { 56 | width: 13%; 57 | } 58 | 59 | .col_type { 60 | width: 13%; 61 | } 62 | 63 | .col_err { 64 | width: 24%; 65 | } 66 | 67 | input { 68 | width: 120px; 69 | align: center; 70 | text-align: center; 71 | margin-left: 5px; 72 | } 73 | 74 | select { 75 | width: 130px; 76 | text-align: center; 77 | } 78 | 79 | #current_cam_stream_m1, 80 | #current_cam_stream_m2, 81 | #current_cam_stream_m3, 82 | #current_cam_stream_m4, 83 | #current_cam_stream_s1, 84 | #current_cam_stream_s2, 85 | #current_cam_stream_s3, 86 | #current_cam_stream_s4 { 87 | width: 30px; 88 | } 89 | 90 | input:disabled { 91 | background: darkgray; 92 | } 93 | 94 | input[name='new_cam_port1'], 95 | input[name='new_cam_port2'], 96 | input[name='new_cam_port3'], 97 | input[name='new_cam_port4'] { 98 | width: 50px; 99 | } 100 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/templates/cfgpanel/style.css: -------------------------------------------------------------------------------- 1 | h1, .param_group { 2 | color: yellow; 3 | } 4 | 5 | .error_msg { 6 | color: pink; 7 | } 8 | 9 | .error_msg_c { 10 | color: red; 11 | background: lightgray; 12 | } 13 | 14 | body { 15 | color: white; 16 | background: blue url("images/background.jpg"); 17 | } 18 | 19 | table { 20 | border: 1px solid lightblue; 21 | width: 1000px; 22 | table-layout: fixed; 23 | background: green url("images/background.jpg"); 24 | word-wrap: break-word; 25 | } 26 | 27 | th { 28 | background-color: #336699; 29 | } 30 | 31 | .col_name { 32 | width: 6%; 33 | } 34 | 35 | .col_ip { 36 | width: 13%; 37 | } 38 | 39 | .col_port { 40 | width: 6%; 41 | } 42 | 43 | .col_stream_m { 44 | width: 4%; 45 | } 46 | 47 | .col_stream_s { 48 | width: 4%; 49 | } 50 | 51 | .col_user { 52 | width: 13%; 53 | } 54 | 55 | .col_pass { 56 | width: 13%; 57 | } 58 | 59 | .col_type { 60 | width: 13%; 61 | } 62 | 63 | .col_err { 64 | width: 24%; 65 | } 66 | 67 | input { 68 | width: 120px; 69 | align: center; 70 | text-align: center; 71 | margin-left: 5px; 72 | } 73 | 74 | select { 75 | width: 130px; 76 | text-align: center; 77 | } 78 | 79 | #current_cam_stream_m1, 80 | #current_cam_stream_m2, 81 | #current_cam_stream_m3, 82 | #current_cam_stream_m4, 83 | #current_cam_stream_s1, 84 | #current_cam_stream_s2, 85 | #current_cam_stream_s3, 86 | #current_cam_stream_s4 { 87 | width: 30px; 88 | } 89 | 90 | input:disabled { 91 | background: darkgray; 92 | } 93 | 94 | input[name='new_cam_port1'], 95 | input[name='new_cam_port2'], 96 | input[name='new_cam_port3'], 97 | input[name='new_cam_port4'] { 98 | width: 50px; 99 | } 100 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/constants.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | ZMQ_PORT = '5555' 16 | 17 | PIN_ENTER = 26 18 | PIN_ESC = 17 19 | PIN_UP = 14 20 | PIN_DOWN = 15 21 | PIN_LEFT = 19 22 | PIN_RIGHT = 04 23 | 24 | BTN_SIGNAL_ESC = 'ESC' 25 | BTN_SIGNAL_ENTER = 'ENTER' 26 | BTN_SIGNAL_LEFT = 'LEFT' 27 | BTN_SIGNAL_RIGHT = 'RIGHT' 28 | BTN_SIGNAL_UP = 'UP' 29 | BTN_SIGNAL_DOWN = 'DOWN' 30 | 31 | AUTO_CLOSE_TIME = 20 32 | CYCLE_TIME_DEFAULT = 10 33 | CYCLE_TIME_MAX_INCR = 3600 34 | 35 | MAX_CAM_AMOUNT = 4 36 | 37 | WIN_SINGLE = '0,0,1060,600' 38 | 39 | KEYWORD_NETMASK = "netmask" 40 | KEYWORD_ADDRESS = "address" 41 | 42 | CFG_VERSION_FILENAME = "version.txt" 43 | CFG_CAM_IP_FILENAME = "config_cam.cfg" 44 | CFG_MON_IP_FILENAME = "config_mon.cfg" 45 | CFG_SERIAL_FILENAME = "config_serial.cfg" 46 | 47 | DEFAULT_SERIAL = "not defined" 48 | DEFAULT_VERSION = 'X.X' 49 | 50 | MON_ADDRESS_NOT_CONFIGURED = "not configured" 51 | MON_NETMASK_NOT_CONFIGURED = "not configured" 52 | 53 | EMPTY_CONFIG_CONTENT = '||||||\n||||||\n||||||\n||||||\n' 54 | 55 | CFG_PATH = '../' 56 | ADMIN_PASS = 'secret' 57 | 58 | ERR_MSG_DETAILS = u'%s - invalid value (%s) - required format is: %s' 59 | ERR_MSG_VALIDATION = u'There were validation errors. New configuration values were not saved.' 60 | 61 | REGEX_IP_FORMAT = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' 62 | REQUIRED_FORMAT_IP_ADDRESS = '<0-255>.<0-255>.<0-255>.<0-255>' 63 | 64 | REGEX_IP_ADDRESS = r'%s' % REGEX_IP_FORMAT 65 | REGEX_MON_ADDRESS = r'%s%s' % (KEYWORD_ADDRESS, REGEX_IP_FORMAT) 66 | REGEX_MON_NETMASK = r'%s%s' % (KEYWORD_NETMASK, REGEX_IP_FORMAT) 67 | 68 | CAM_STATUS_INIT = '...inicjalizacja...' # Default value 69 | CAM_STATUS_UNDEFINED = '' # used when address IP is not defined for camera 70 | CAM_STATUS_OK = 'TAK' 71 | CAM_STATUS_NOT_CONNECTED = 'NIE' 72 | CAM_STATUS_CON_ERROR = 'ERR' 73 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | import re 14 | 15 | import zmq 16 | 17 | from constants import * 18 | 19 | 20 | # ZeroMQ Client connection (Producer) 21 | btn_port = ZMQ_PORT 22 | context = zmq.Context() 23 | socket = context.socket(zmq.REQ) 24 | socket.connect('tcp://localhost:%s' % btn_port) 25 | 26 | 27 | def handle_signal(signal_name): 28 | try: 29 | socket.send(signal_name) 30 | print 'Sent req=%s' % signal_name 31 | rep = socket.recv() 32 | print "Received reply %s" % rep 33 | except zmq.error.ZMQError: 34 | print 'processing...' 35 | 36 | 37 | def replace(input_file, pattern, subst): 38 | print 'Replacing (%s) to (%s) in (%s)' % (pattern, subst, input_file) 39 | try: 40 | # Read contents from file as a single string 41 | with open(input_file, 'r') as file_handle: 42 | file_string = file_handle.read() 43 | print 'Current mon config content: (%s)' % file_string 44 | file_handle.close() 45 | 46 | # Use RE package to allow for replacement (also allowing for (multiline) REGEX) 47 | file_string = (re.sub(pattern, subst, file_string)) 48 | 49 | # Write contents to file. 50 | # Using mode 'w' truncates the file. 51 | with open(input_file, 'w') as file_handle: 52 | file_handle.write(file_string) 53 | print 'New mon config content: (%s)' % file_string 54 | file_handle.close() 55 | except BaseException as be: 56 | print 'ERROR: Could not replace file content (%s).' % repr(be) 57 | 58 | 59 | def btn_enter(): 60 | handle_signal(BTN_SIGNAL_ENTER) 61 | 62 | 63 | def btn_esc(): 64 | handle_signal(BTN_SIGNAL_ESC) 65 | 66 | 67 | def btn_up(): 68 | handle_signal(BTN_SIGNAL_UP) 69 | 70 | 71 | def btn_down(): 72 | handle_signal(BTN_SIGNAL_DOWN) 73 | 74 | 75 | def btn_left(): 76 | handle_signal(BTN_SIGNAL_LEFT) 77 | 78 | 79 | def btn_right(): 80 | handle_signal(BTN_SIGNAL_RIGHT) 81 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/player.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | import logging 14 | import os 15 | from subprocess import Popen, PIPE, STDOUT 16 | 17 | from log_config import log 18 | 19 | KEY_OMXPLAYER_QUIT = 'q' 20 | 21 | PLAYER_NAME = 'omxplayer' 22 | logger = logging.getLogger(__name__) 23 | DEV_NULL = open(os.devnull, 'w') 24 | 25 | 26 | class Player: 27 | def __init__(self, ident, uri, win, live=True): 28 | self.id = ident 29 | self.live = live 30 | self.uri = uri 31 | self.win = win 32 | self.process = None 33 | 34 | def play(self): 35 | self._stop() 36 | 37 | # e.g. (no auth): omxplayer -o hdmi --blank --live --fps 24 -r rtsp://172.16.1.195 38 | # e.g. (auth) : sudo omxplayer -o hdmi --blank --live "rtsp://172.16.1.195/av0_0&user=admin&password=admin" 39 | 40 | command = ['omxplayer', 41 | '--adev', 'hdmi', 42 | '--aidx', "-1", # disable audio 43 | '--timeout', '5', 44 | '--blank', 45 | '--live' if self.live else '--no-osd', 46 | '--aspect-mode', 'fill', 47 | '--avdict', 'rtsp_transport:tcp', 48 | '--subtitles', '/home/haso/camviewer/sub%d.srt' % self.id, 49 | self.uri] 50 | log.info('Starting Player[single]... (%s)' % repr(command)) 51 | self.process = Popen(command, stdin=PIPE, stdout=DEV_NULL, stderr=STDOUT, close_fds=True, bufsize=0) # async. execution, instant exit 52 | log.info('Player[single] started.') 53 | 54 | def wait_to_finish(self): 55 | log.info('Waiting for player[single] process to stop.') 56 | self.process.wait() 57 | self.process = None 58 | log.info('Player[single] process stopped.') 59 | 60 | def _stop(self): 61 | if self.process is not None: 62 | try: 63 | self.process.stdin.write(KEY_OMXPLAYER_QUIT) # send quit command 'q' (player must not use '--no-keys' option) 64 | self.process.terminate() 65 | self.process.wait() 66 | 67 | log.info('Player[single] gracefully terminated (%s)' % self.process.returncode) 68 | return self.process.returncode 69 | except EnvironmentError as e: 70 | logger.error("Can't stop player[single] %s: %s", self.uri, e) 71 | 72 | self.process = None 73 | return None 74 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/event_handler.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | from threading import Thread 14 | 15 | from log_config import log 16 | from zmq_consumer import ZmqConsumer 17 | 18 | BTN_NAME_ESC = 'ESC' 19 | BTN_NAME_ENTER = 'ENTER' 20 | BTN_NAME_UP = 'UP' 21 | BTN_NAME_DOWN = 'DOWN' 22 | BTN_NAME_LEFT = 'LEFT' 23 | BTN_NAME_RIGHT = 'RIGHT' 24 | 25 | 26 | class EventHandlerThread(Thread): 27 | event_consumer = None 28 | 29 | handle_esc = None 30 | handle_enter = None 31 | handle_up = None 32 | handle_down = None 33 | handle_left = None 34 | handle_right = None 35 | 36 | def __init__(self): 37 | super(EventHandlerThread, self).__init__() 38 | 39 | def handle_button(self, btn_name): 40 | if btn_name == BTN_NAME_ESC and self.handle_esc is not None: 41 | print 'Invoking ESC handler...' 42 | self.handle_esc() 43 | elif btn_name == BTN_NAME_ENTER and self.handle_enter is not None: 44 | print 'Invoking ENTER handler...' 45 | self.handle_enter() 46 | elif btn_name == BTN_NAME_UP and self.handle_up is not None: 47 | print 'Invoking UP handler...' 48 | self.handle_up() 49 | elif btn_name == BTN_NAME_DOWN and self.handle_down is not None: 50 | print 'Invoking DOWN handler...' 51 | self.handle_down() 52 | elif btn_name == BTN_NAME_LEFT and self.handle_left is not None: 53 | print 'Invoking LEFT handler...' 54 | self.handle_left() 55 | elif btn_name == BTN_NAME_RIGHT and self.handle_right is not None: 56 | print 'Invoking RIGHT handler...' 57 | self.handle_right() 58 | else: 59 | print 'Unknown button name (%s) received...' % btn_name 60 | pass 61 | 62 | def run(self): 63 | try: 64 | log.info('Entering EventHandlerThread...') 65 | 66 | self.event_consumer = ZmqConsumer(self.handle_button) 67 | 68 | log.info('Exiting EventHandlerThread...') 69 | except KeyboardInterrupt: 70 | self.stop() 71 | exit(0) 72 | 73 | def set_esc_handler(self, handler_method): 74 | self.handle_esc = handler_method 75 | 76 | def set_enter_handler(self, handler_method): 77 | self.handle_enter = handler_method 78 | 79 | def set_up_handler(self, handler_method): 80 | self.handle_up = handler_method 81 | 82 | def set_down_handler(self, handler_method): 83 | self.handle_down = handler_method 84 | 85 | def set_left_handler(self, handler_method): 86 | self.handle_left = handler_method 87 | 88 | def set_right_handler(self, handler_method): 89 | self.handle_right = handler_method 90 | 91 | def stop(self): 92 | if self.event_consumer is not None: 93 | self.event_consumer.disable() 94 | self.join(5) 95 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sscce_freezing_issue/dbus_omxplayer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | import os 16 | import time 17 | # noinspection PyUnresolvedReferences 18 | import dbus 19 | 20 | from log_config import log 21 | 22 | DBUS_FILE_NAME_OMXPLAYER = '/tmp/omxplayerdbus.%s' % os.getlogin() 23 | DBUS_RETRY_INTERVAL = 0.2 24 | 25 | ACTION_POS = "ACTION_STATUS" 26 | ACTION_PREV = "ACTION_PREVIOUS" 27 | ACTION_STOP = "ACTION_STOP" 28 | ACTION_QUIT = "ACTION_QUIT" 29 | 30 | 31 | # noinspection PyUnusedLocal 32 | def action_pos(stream_name, if_player, if_props, if_root): 33 | position = if_props.Position() / 1000000 34 | return position 35 | 36 | 37 | # noinspection PyUnusedLocal 38 | def action_stop(stream_name, if_player, if_props, if_root): 39 | if_player.Stop() 40 | log.debug('\t\t[%s] - Stop sent to dbus PLAYER interface.' % stream_name) 41 | return None 42 | 43 | 44 | # noinspection PyUnusedLocal 45 | def action_prev(stream_name, if_player, if_props, if_root): 46 | if_player.Previous() 47 | log.debug('\t\t[%s] - Previous sent to dbus PLAYER interface.' % stream_name) 48 | return None 49 | 50 | 51 | # noinspection PyUnusedLocal 52 | def action_quit(stream_name, if_player, if_props, if_root): 53 | if_root.Quit() 54 | log.debug('\t\t[%s] - Quit sent to dbus ROOT interface.' % stream_name) 55 | return None 56 | 57 | 58 | actions = { 59 | ACTION_POS: action_pos, 60 | ACTION_PREV: action_prev, 61 | ACTION_STOP: action_stop, 62 | ACTION_QUIT: action_quit 63 | } 64 | 65 | 66 | def main(): 67 | log.debug('Opening: %s' % DBUS_FILE_NAME_OMXPLAYER) 68 | 69 | for i in range(0, 4): 70 | try: 71 | log.debug('stream-%d connecting...' % i) 72 | action_result = send_dbus_action(i, ACTION_POS) 73 | log.debug('[stream-%d] action finished. %s' % (i, action_result if action_result is not None else "")) 74 | except OMXPlayerStopError: 75 | log.debug('[stream-%d] action failed.' % i) 76 | 77 | 78 | class OMXPlayerStopError(BaseException): 79 | pass 80 | 81 | 82 | def send_dbus_action(stream_id, action_name): 83 | screen_name = 'camera%d' % stream_id 84 | 85 | # wait for omxplayer to initialise 86 | done, retry = 0, 0 87 | while done == 0: 88 | try: 89 | dbus_if_player, dbus_if_props, dbus_if_root = open_dbus_attempt(screen_name) 90 | log.debug('\t[%s] - dbus connected for stream URL: [%s]' % (screen_name, dbus_if_props.GetSource())) 91 | action_function = actions.get(action_name) 92 | result = action_function(screen_name, dbus_if_player, dbus_if_props, dbus_if_root) 93 | done = 1 94 | return result 95 | except Exception as e: 96 | retry += 1 97 | time.sleep(DBUS_RETRY_INTERVAL) 98 | if retry >= 10: 99 | log.debug('\t[%s] - dbus connection FAILED: (%s)' % (screen_name, repr(e))) 100 | raise OMXPlayerStopError() 101 | 102 | 103 | def open_dbus_attempt(screen_name): 104 | with open(DBUS_FILE_NAME_OMXPLAYER, 'r+') as f: 105 | omxplayer_dbus = f.read().strip() 106 | 107 | dbus_bus = dbus.bus.BusConnection(omxplayer_dbus) 108 | d_stream_id = 'org.mpris.MediaPlayer2.omxplayer.%s' % screen_name 109 | dbus_object = dbus_bus.get_object(d_stream_id, '/org/mpris/MediaPlayer2', introspect=False) 110 | dbus_if_props = dbus.Interface(dbus_object, 'org.freedesktop.DBus.Properties') 111 | dbus_if_player = dbus.Interface(dbus_object, 'org.mpris.MediaPlayer2.Player') 112 | dbus_if_root = dbus.Interface(dbus_object, 'org.mpris.MediaPlayer2') 113 | return dbus_if_player, dbus_if_props, dbus_if_root 114 | 115 | 116 | if __name__ == '__main__': 117 | main() 118 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgviewer/settings.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | """ 14 | Django settings for cfgviewer project. 15 | 16 | Generated by 'django-admin startproject' using Django 1.9. 17 | 18 | For more information on this file, see 19 | https://docs.djangoproject.com/en/1.9/topics/settings/ 20 | 21 | For the full list of settings and their values, see 22 | https://docs.djangoproject.com/en/1.9/ref/settings/ 23 | """ 24 | 25 | 26 | import os 27 | 28 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 29 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 30 | 31 | # Quick-start development settings - unsuitable for production 32 | # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ 33 | 34 | # SECURITY WARNING: keep the secret key used in production secret! 35 | SECRET_KEY = '%t^%^v%(gqu)fmklr1sp)4ti57#b^4a@r*zd!8&!igcvde#@r+' 36 | 37 | # SECURITY WARNING: don't run with debug turned on in production! 38 | DEBUG = False 39 | ALLOWED_HOSTS = [ 40 | '*' 41 | ] 42 | 43 | # Application definition 44 | INSTALLED_APPS = [ 45 | 'cfgpanel.apps.ConfigPanel', 46 | 'django.contrib.admin', 47 | 'django.contrib.auth', 48 | 'django.contrib.contenttypes', 49 | 'django.contrib.sessions', 50 | 'django.contrib.messages', 51 | 'django.contrib.staticfiles', 52 | ] 53 | 54 | MIDDLEWARE_CLASSES = [ 55 | 'django.middleware.security.SecurityMiddleware', 56 | 'django.contrib.sessions.middleware.SessionMiddleware', 57 | 'django.middleware.common.CommonMiddleware', 58 | 'django.middleware.csrf.CsrfViewMiddleware', 59 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 60 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 61 | 'django.contrib.messages.middleware.MessageMiddleware', 62 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 63 | ] 64 | 65 | ROOT_URLCONF = 'cfgviewer.urls' 66 | 67 | TEMPLATES = [ 68 | { 69 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 70 | 'DIRS': [], 71 | 'APP_DIRS': True, 72 | 'OPTIONS': { 73 | 'context_processors': [ 74 | 'django.template.context_processors.debug', 75 | 'django.template.context_processors.request', 76 | 'django.contrib.auth.context_processors.auth', 77 | 'django.contrib.messages.context_processors.messages', 78 | ], 79 | }, 80 | }, 81 | ] 82 | 83 | WSGI_APPLICATION = 'cfgviewer.wsgi.application' 84 | 85 | # Database 86 | # https://docs.djangoproject.com/en/1.9/ref/settings/#databases 87 | 88 | DATABASES = { 89 | 'default': { 90 | 'ENGINE': 'django.db.backends.sqlite3', 91 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 92 | } 93 | } 94 | 95 | # Password validation 96 | # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators 97 | 98 | AUTH_PASSWORD_VALIDATORS = [ 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 101 | }, 102 | { 103 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 104 | }, 105 | { 106 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 107 | }, 108 | { 109 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 110 | }, 111 | ] 112 | 113 | # Internationalization 114 | # https://docs.djangoproject.com/en/1.9/topics/i18n/ 115 | 116 | LANGUAGE_CODE = 'en-us' 117 | 118 | TIME_ZONE = 'UTC' 119 | 120 | USE_I18N = True 121 | 122 | USE_L10N = True 123 | 124 | USE_TZ = True 125 | 126 | # Static files (CSS, JavaScript, Images) 127 | # https://docs.djangoproject.com/en/1.9/howto/static-files/ 128 | 129 | STATIC_URL = '/static/' 130 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/dbus_omxplayer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | import time 16 | # noinspection PyUnresolvedReferences 17 | import dbus 18 | 19 | from log_config import log 20 | 21 | DBUS_FILE_NAME_OMXPLAYER = '/tmp/omxplayerdbus.root' 22 | DBUS_RETRY_INTERVAL = 0.2 23 | 24 | ACTION_POS = "ACTION_STATUS" 25 | ACTION_PREV = "ACTION_PREVIOUS" 26 | ACTION_STOP = "ACTION_STOP" 27 | ACTION_QUIT = "ACTION_QUIT" 28 | 29 | 30 | # noinspection PyUnusedLocal 31 | def action_pos(stream_name, if_player, if_props, if_root): 32 | position = if_props.Position() / 1000000 33 | return position 34 | 35 | 36 | # noinspection PyUnusedLocal 37 | def action_stop(stream_name, if_player, if_props, if_root): 38 | if_player.Stop() 39 | log.debug('\t\t[%s] - Stop sent to dbus PLAYER interface.' % stream_name) 40 | return None 41 | 42 | 43 | # noinspection PyUnusedLocal 44 | def action_prev(stream_name, if_player, if_props, if_root): 45 | if_player.Previous() 46 | log.debug('\t\t[%s] - Previous sent to dbus PLAYER interface.' % stream_name) 47 | return None 48 | 49 | 50 | # noinspection PyUnusedLocal 51 | def action_quit(stream_name, if_player, if_props, if_root): 52 | if_root.Quit() 53 | log.debug('\t\t[%s] - Quit sent to dbus ROOT interface.' % stream_name) 54 | return None 55 | 56 | 57 | actions = { 58 | ACTION_POS: action_pos, 59 | ACTION_PREV: action_prev, 60 | ACTION_STOP: action_stop, 61 | ACTION_QUIT: action_quit 62 | } 63 | 64 | 65 | def main(): # For testing purpose 66 | log.debug('Opening: %s' % DBUS_FILE_NAME_OMXPLAYER) 67 | 68 | for i in range(0, 4): 69 | try: 70 | log.debug('stream-%d connecting...' % i) 71 | action_result = send_dbus_action(i, ACTION_POS) 72 | log.debug('[stream-%d] action finished. %s' % (i, action_result if action_result is not None else "")) 73 | except OMXPlayerStopError: 74 | log.debug('[stream-%d] action failed.' % i) 75 | 76 | 77 | class OMXPlayerStopError(BaseException): 78 | pass 79 | 80 | 81 | def send_dbus_stop(): 82 | # wait for omxplayer to initialise 83 | done, retry = 0, 0 84 | while done == 0: 85 | try: 86 | with open(DBUS_FILE_NAME_OMXPLAYER, 'r+') as f: 87 | omxplayer_dbus = f.read().strip() 88 | 89 | dbus_bus = dbus.bus.BusConnection(omxplayer_dbus) 90 | dbus_object = dbus_bus.get_object('org.mpris.MediaPlayer2.omxplayer', '/org/mpris/MediaPlayer2', introspect=False) 91 | dbus_if_props = dbus.Interface(dbus_object, 'org.freedesktop.DBus.Properties') 92 | dbus_if_player = dbus.Interface(dbus_object, 'org.mpris.MediaPlayer2.Player') 93 | done = 1 94 | print "OK" 95 | 96 | print dbus_if_props.Duration() 97 | print dbus_if_props.GetSource() 98 | dbus_if_player.Stop() 99 | 100 | except Exception as e: 101 | retry += 1 102 | time.sleep(0.2) 103 | 104 | if retry >= 10: 105 | print "ERROR while opening DBUS (%s)" % e 106 | raise OMXPlayerStopError() 107 | 108 | 109 | def open_dbus_attempt(screen_name): 110 | with open(DBUS_FILE_NAME_OMXPLAYER, 'r+') as f: 111 | omxplayer_dbus = f.read().strip() 112 | 113 | dbus_bus = dbus.bus.BusConnection(omxplayer_dbus) 114 | d_stream_id = 'org.mpris.MediaPlayer2.omxplayer.%s' % screen_name 115 | dbus_object = dbus_bus.get_object(d_stream_id, '/org/mpris/MediaPlayer2', introspect=False) 116 | dbus_if_props = dbus.Interface(dbus_object, 'org.freedesktop.DBus.Properties') 117 | dbus_if_player = dbus.Interface(dbus_object, 'org.mpris.MediaPlayer2.Player') 118 | dbus_if_root = dbus.Interface(dbus_object, 'org.mpris.MediaPlayer2') 119 | return dbus_if_player, dbus_if_props, dbus_if_root 120 | 121 | 122 | def send_dbus_action(stream_id, action_name): 123 | screen_name = 'camera%d' % stream_id 124 | 125 | # wait for omxplayer to initialise 126 | done, retry = 0, 0 127 | while done == 0: 128 | try: 129 | dbus_if_player, dbus_if_props, dbus_if_root = open_dbus_attempt(screen_name) 130 | log.debug('\t[%s] - dbus connected for stream URL: [%s]' % (screen_name, dbus_if_props.GetSource())) 131 | action_function = actions.get(action_name) 132 | result = action_function(screen_name, dbus_if_player, dbus_if_props, dbus_if_root) 133 | done = 1 134 | return result 135 | except Exception as e: 136 | retry += 1 137 | time.sleep(DBUS_RETRY_INTERVAL) 138 | if retry >= 10: 139 | log.debug('\t[%s] - dbus connection FAILED: (%s)' % (screen_name, repr(e))) 140 | raise OMXPlayerStopError() 141 | 142 | 143 | if __name__ == '__main__': 144 | main() 145 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/info_collector.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | import threading 16 | import time 17 | 18 | import pyping 19 | 20 | from cfgviewer.cfgpanel.config_utils import parse_interfaces_cfg, parse_cam_config, ConfigEntry 21 | from cfgviewer.cfgpanel.utils import * 22 | from info_window import PING_DELAY 23 | from log_config import log 24 | 25 | 26 | def ping(cam_address): 27 | try: 28 | log.debug('Pinging camera with IP = (%s)' % cam_address) 29 | ping_resp = pyping.ping(cam_address) 30 | ping_status = ping_resp.ret_code 31 | log.debug('Ping return code for %s = %d' % (cam_address, ping_status)) 32 | 33 | if ping_status == 0: 34 | return CAM_STATUS_OK 35 | else: 36 | return CAM_STATUS_NOT_CONNECTED 37 | except BaseException as e: 38 | log.error('PYPING library error: (%s)' % e.message) 39 | return CAM_STATUS_CON_ERROR 40 | 41 | 42 | def fetch_version(): 43 | try: 44 | log.debug('Opening software version file: %r.' % CFG_VERSION_FILENAME) 45 | with open(CFG_VERSION_FILENAME) as version_file: 46 | version_cfg_content = version_file.read().strip() 47 | version_file.close() 48 | return version_cfg_content 49 | except IOError: 50 | log.debug('Camera IP config file not found...') 51 | return DEFAULT_VERSION 52 | 53 | 54 | def fetch_cfg_mon(): 55 | try: 56 | log.debug('Opening monitor IP config file: %r.' % CFG_MON_IP_FILENAME) 57 | with open(CFG_MON_IP_FILENAME) as cfg_mon_file: 58 | str_mon_cfg = cfg_mon_file.read().strip() 59 | interface_cfg_content = parse_interfaces_cfg(str_mon_cfg) 60 | cfg_mon_file.close() 61 | return interface_cfg_content 62 | except IOError: 63 | log.error('Monitor IP config file not found...') 64 | return MON_ADDRESS_NOT_CONFIGURED, MON_NETMASK_NOT_CONFIGURED 65 | 66 | 67 | def fetch_serial_number(): 68 | log.debug('Opening serial number config file: %r.' % CFG_SERIAL_FILENAME) 69 | try: 70 | with open(CFG_SERIAL_FILENAME) as cfg_serial_file: 71 | serial_cfg_content = cfg_serial_file.read().strip() 72 | cfg_serial_file.close() 73 | return serial_cfg_content 74 | except IOError: 75 | log.debug('Serial number config file not found...') 76 | return DEFAULT_SERIAL 77 | 78 | 79 | class InfoCollectorThread(threading.Thread): 80 | cfg_version = 'N/A' 81 | cfg_revision = 'build_number' 82 | cfg_serial = 'N/A' 83 | cfg_address_mon = 'N/A' 84 | cfg_netmask_mon = 'N/A' 85 | 86 | is_enabled = True 87 | 88 | msg_output = 'ENTER = przejdź do podglądu widoku z kamery.' 89 | 90 | cams_configs = [ConfigEntry(), ConfigEntry(), ConfigEntry(), ConfigEntry()] 91 | cams_statuses = [CAM_STATUS_INIT, CAM_STATUS_INIT, CAM_STATUS_INIT, CAM_STATUS_INIT] 92 | 93 | def __init__(self): 94 | super(InfoCollectorThread, self).__init__() 95 | 96 | try: 97 | self.cfg_revision = '000' # TODO: Get build/revision number somehow (a bit tricky after moving from SVN to GIT) 98 | except OSError: 99 | log.error('Could not get revision number...') 100 | 101 | def run(self): 102 | try: 103 | log.info('Entering StatusReaderThread...') 104 | 105 | fetch_serial_number() 106 | self.update_model() 107 | 108 | log.info('Exiting StatusReaderThread...') 109 | except KeyboardInterrupt: 110 | self.stop() 111 | exit(0) 112 | 113 | def update_model(self): 114 | log.info('Entering Ping method...') 115 | self.is_enabled = True 116 | 117 | while self.is_enabled: 118 | self.cfg_version = fetch_version() 119 | self.cfg_address_mon, self.cfg_netmask_mon = fetch_cfg_mon() 120 | self.cfg_serial = fetch_serial_number() 121 | 122 | self.fetch_cams_config() 123 | 124 | # wait a while before next data read 125 | time.sleep(PING_DELAY) 126 | 127 | # finish refreshing only after stop invoked... 128 | return 129 | 130 | def stop(self): 131 | self.is_enabled = False 132 | self.join(5) 133 | pass 134 | 135 | def fetch_cams_config(self): 136 | cam_config_entries = parse_cam_config(CFG_CAM_IP_FILENAME) 137 | 138 | for i in range(0, MAX_CAM_AMOUNT): 139 | cam_config_entry = cam_config_entries[i] 140 | cam_address = cam_config_entry.address 141 | if not cam_address: 142 | cam_status = CAM_STATUS_UNDEFINED 143 | else: 144 | cam_status = ping(cam_address) 145 | 146 | self.cams_configs[i] = cam_config_entry 147 | self.cams_statuses[i] = cam_status 148 | log.info('Camera[%d]: IP=(%s), STATUS=(%s)' % (i + 1, cam_address, cam_status)) 149 | 150 | def is_any_cam(self): 151 | for i in range(0, MAX_CAM_AMOUNT): 152 | cam_address = self.cams_configs[i].address 153 | if cam_address: 154 | cam_status = self.cams_statuses[i] 155 | available = cam_status == CAM_STATUS_OK 156 | log.info("Cam[%d] status=(%s)" % (i, available)) 157 | 158 | if available: 159 | return True 160 | 161 | return False 162 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/config_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | import os 14 | import string 15 | 16 | from constants import * 17 | 18 | CAM_TYPE_HASO_KG1 = 'haso_kg1' 19 | CAM_TYPE_SAMSUNG_SNZ5200 = 'samsung_snz5200' 20 | CAM_TYPE_LEVELONE_FCS1091 = 'levelone_fcs1091' 21 | 22 | 23 | class ConfigEntry(object): 24 | address = '' 25 | port = '' 26 | stream_m = '' 27 | stream_s = '' 28 | user = '' 29 | password = '' 30 | cam_type = '' 31 | 32 | def __str__(self): 33 | return self.main_stream_url() 34 | 35 | def cfg_info(self): 36 | if self.user: 37 | auth = '%s:%s' % (self.user, '***' if self.password else '') 38 | else: 39 | auth = '' 40 | 41 | if self.cam_type == CAM_TYPE_HASO_KG1: 42 | profiles = '' 43 | type_name = 'HASO_KG-1' 44 | elif self.cam_type == CAM_TYPE_SAMSUNG_SNZ5200: 45 | profiles = '%s/%s' % (self.stream_m, self.stream_s) 46 | type_name = 'Samsung_SNZ-5200' 47 | elif self.cam_type == CAM_TYPE_LEVELONE_FCS1091: 48 | profiles = '' 49 | type_name = 'LevelOne_FCS-1091' 50 | else: # UNKNOWN type 51 | profiles = '' 52 | type_name = 'nieznany' 53 | 54 | return self.port, type_name, auth, profiles 55 | 56 | def main_stream_url(self): 57 | if self.cam_type == CAM_TYPE_HASO_KG1: 58 | if self.user: 59 | return 'rtsp://%s:%s/av0_0&user=%s&password=%s' % (self.address, self.port, self.user, self.password) 60 | else: 61 | return 'rtsp://%s:%s/av0_0' % (self.address, self.port) 62 | elif self.cam_type == CAM_TYPE_SAMSUNG_SNZ5200: 63 | if self.user: 64 | return 'rtsp://%s:%s@%s:%s/profile%s/media.smp' % (self.user, self.password, self.address, self.port, self.stream_m) 65 | else: 66 | return 'rtsp://%s:%s/profile%s/media.smp' % (self.address, self.port, self.stream_m) 67 | elif self.cam_type == CAM_TYPE_LEVELONE_FCS1091: 68 | if self.user: 69 | return 'rtsp://%s:%s@%s:%s/img/media.sav' % (self.user, self.password, self.address, self.port) 70 | else: 71 | return 'rtsp://%s:%s/img/media.sav' % (self.address, self.port) 72 | else: # UNKNOWN TYPE 73 | if self.user: 74 | return 'rtsp://%s:%s@%s:%s/%s' % (self.user, self.password, self.address, self.port, self.stream_m) 75 | else: 76 | return 'rtsp://%s:%s/%s' % (self.address, self.port, self.stream_m) 77 | 78 | def sub_stream_url(self): 79 | if self.cam_type == CAM_TYPE_HASO_KG1: 80 | if self.user: 81 | return 'rtsp://%s:%s/av0_1&user=%s&password=%s' % (self.address, self.port, self.user, self.password) 82 | else: 83 | return 'rtsp://%s:%s/av0_1' % (self.address, self.port) 84 | elif self.cam_type == CAM_TYPE_SAMSUNG_SNZ5200: 85 | if self.user: 86 | return 'rtsp://%s:%s@%s:%s/profile%s/media.smp' % (self.user, self.password, self.address, self.port, self.stream_s) 87 | else: 88 | return 'rtsp://%s:%s/profile%s/media.smp' % (self.address, self.port, self.stream_s) 89 | elif self.cam_type == CAM_TYPE_LEVELONE_FCS1091: 90 | if self.user: 91 | return 'rtsp://%s:%s@%s:%s/img/media.sav' % (self.user, self.password, self.address, self.port) 92 | else: 93 | return 'rtsp://%s:%s/img/media.sav' % (self.address, self.port) 94 | else: # UNKNOWN TYPE 95 | if self.user: 96 | return 'rtsp://%s:%s@%s:%s/%s' % (self.user, self.password, self.address, self.port, self.stream_s) 97 | else: 98 | return 'rtsp://%s:%s/%s' % (self.address, self.port, self.stream_s) 99 | 100 | 101 | def parse_interfaces_cfg(str_mon): 102 | cfg_mon_str = string.split(str_mon, '\n') 103 | cfg_address = "N/A" 104 | cfg_netmask = "N/A" 105 | 106 | for str_cfg_part in cfg_mon_str: 107 | if str_cfg_part.find(KEYWORD_ADDRESS) == 0: 108 | cfg_address = str_cfg_part[7:].strip() 109 | elif str_cfg_part.find(KEYWORD_NETMASK) == 0: 110 | cfg_netmask = str_cfg_part[7:].strip() 111 | 112 | return cfg_address, cfg_netmask 113 | 114 | 115 | def parse_cam_config(cam_cfg_path): 116 | print 'Loading cameras config...' 117 | print os.system('pwd') 118 | 119 | current_config_string = EMPTY_CONFIG_CONTENT 120 | try: 121 | with open(cam_cfg_path) as f: 122 | current_config_string = f.read() 123 | f.close() 124 | except IOError as ioe: 125 | print('Could not open (%s) file. (%s)' % (cam_cfg_path, repr(ioe))) 126 | 127 | cam_config = [(ConfigEntry()), (ConfigEntry()), (ConfigEntry()), (ConfigEntry())] 128 | config_lines = string.split(current_config_string, '\n') 129 | for i in range(0, MAX_CAM_AMOUNT): 130 | if config_lines[i]: 131 | params = string.split(config_lines[i], '|') 132 | cfg_entry = cam_config[i] 133 | 134 | cfg_entry.address = params[0] 135 | cfg_entry.port = params[1] 136 | cfg_entry.stream_m = params[2] 137 | cfg_entry.stream_s = params[3] 138 | cfg_entry.user = params[4] 139 | cfg_entry.password = params[5] 140 | cfg_entry.cam_type = params[6] 141 | 142 | for i in range(0, MAX_CAM_AMOUNT): 143 | print 'Loaded: %s' % str(cam_config[i]) 144 | 145 | return cam_config 146 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/sscce_freezing_issue/player4cams.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import time 4 | from subprocess import Popen, PIPE, STDOUT, check_output 5 | 6 | from log_config import log 7 | from dbus_omxplayer import send_dbus_action, ACTION_POS 8 | 9 | VIDEO_NOT_CONFIGURED = 'not_configured.mp4' 10 | 11 | SCRIPT_OMX_COUNT = "omx_count.sh" 12 | SCRIPT_OMX_KILL_ALL = 'omx_kill_all.sh' 13 | SCRIPT_OMX_KILL_SINGLE = "omx_kill_single.sh" 14 | 15 | BASH_SHEBANG = '#!/usr/bin/env bash\n' 16 | DEV_NULL = open(os.devnull, 'w') 17 | SCREEN_NAME_PATTERN = 'camera%d' 18 | 19 | PROC_CHECK_INTERVAL_S = 5 20 | PERIODIC_RESTART_EVERY_CHECK = 8640 # default: 720 for 5 seconds interval = 1h 21 | 22 | logger = logging.getLogger(__name__) 23 | 24 | 25 | class Playstreamation: 26 | def __init__(self, cam_streams_array_4, win_coords_array_4): 27 | self.cam_streams = cam_streams_array_4 28 | self.win_coords = win_coords_array_4 29 | self.start_commands = [] 30 | self.stream_position = [] 31 | self.check_counters = [] 32 | self.restart_counters = [] 33 | 34 | self.auto_restart_enabled = True 35 | 36 | def play(self): 37 | for stream_id in range(0, len(self.cam_streams)): 38 | start_cmd = self.prepare_player_start_command(stream_id) 39 | 40 | self.start_commands.append(start_cmd) 41 | self.check_counters.append(0) 42 | self.restart_counters.append(0) 43 | 44 | self.start_player(stream_id) 45 | 46 | while self.auto_restart_enabled: 47 | # periodically restart players that are not running anymore (e.g. there was no connectivity for a moment) 48 | try: 49 | time.sleep(PROC_CHECK_INTERVAL_S) 50 | except KeyboardInterrupt: 51 | log.info("Exiting...") 52 | self.auto_restart_enabled = False 53 | kill_all_omx_processes() 54 | break 55 | 56 | log.info("Checking if streams are working...") 57 | streams_to_start = [] 58 | for stream_id in range(0, len(self.cam_streams)): 59 | win_coords = self.win_coords[stream_id] 60 | 61 | omx_proc_count = check_output(['bash', SCRIPT_OMX_COUNT, win_coords]) 62 | ps_count = omx_proc_count.rstrip('\n') 63 | 64 | self.check_counters[stream_id] += 1 65 | check_number = self.check_counters[stream_id] 66 | instance_no = self.restart_counters[stream_id] 67 | 68 | pos_previous = self.stream_position[stream_id] 69 | 70 | if omx_proc_count is not None: 71 | stream_freeze_detected = False 72 | proc_count_int = int(omx_proc_count) 73 | if proc_count_int == 1: 74 | if pos_previous >= 0: 75 | # noinspection PyBroadException 76 | try: 77 | pos = send_dbus_action(stream_id, ACTION_POS) 78 | self.stream_position[stream_id] = pos 79 | 80 | if pos_previous == pos: 81 | stream_freeze_detected = True 82 | except BaseException: 83 | pos = '[unknown]' 84 | else: 85 | pos = '[not tracking]' 86 | else: 87 | pos = '[instances issue]' 88 | 89 | log.info(" -- Player[stream-%d/%d] check %d proc=%s pos=%s freeze detected=%s" % (stream_id, instance_no, check_number, ps_count, pos, stream_freeze_detected)) 90 | if self.auto_restart_enabled: 91 | if proc_count_int == 0: 92 | log.info(' --- Player[stream-%d/%d] not running - scheduling start...' % (stream_id, check_number)) 93 | streams_to_start.append(stream_id) 94 | elif proc_count_int > 1: 95 | # just recover from glitches with many players opened for single stream (should not happen) 96 | log.info(' --- Player[stream-%d/%d] running in too many instances - killing all and scheduling start.' % (stream_id, check_number)) 97 | kill_single_omx_window(stream_id, win_coords) 98 | streams_to_start.append(stream_id) 99 | elif proc_count_int == 1: 100 | if stream_freeze_detected: 101 | log.info(' --- Player[stream-%d/%d] stream freeze detected - immediate restart.' % (stream_id, check_number)) 102 | self.player_immediate_restart(stream_id, win_coords) 103 | elif check_number % PERIODIC_RESTART_EVERY_CHECK == 0: # restart stream periodically even if it is still running (workaround for image freezing after w while) 104 | log.info(' --- Player[stream-%d/%d] performing periodic instant restart.' % (stream_id, check_number)) 105 | self.player_immediate_restart(stream_id, win_coords) 106 | else: 107 | pass # keep playing 108 | else: 109 | log.error('Invalid processes count received (None).') 110 | 111 | log.info('Performing scheduled starts...') 112 | 113 | # try to start scheduled streams 114 | for stream_id_to_start in streams_to_start: 115 | self.start_player(stream_id_to_start) 116 | 117 | def prepare_player_start_command(self, i): 118 | # prepare starting script for omxplayer in proper window 119 | log.info('Setting up Players[stream-%d]...' % i) 120 | 121 | stream_url = self.cam_streams[i] 122 | win_coords = self.win_coords[i] 123 | screen_name = SCREEN_NAME_PATTERN % i 124 | dbus_name = "org.mpris.MediaPlayer2.omxplayer.%s" % screen_name 125 | 126 | if not stream_url: 127 | url = VIDEO_NOT_CONFIGURED 128 | cmd = "omxplayer --adev hdmi --aidx -1 --timeout 5 --blank --no-keys --no-osd --loop --win %s --dbus_name %s %s" % (win_coords, dbus_name, url) 129 | # NOTE: allowed options are either --live or --no-osd and not both 130 | self.stream_position.append(-1) 131 | else: 132 | url = stream_url 133 | cmd = "omxplayer --adev hdmi --aidx -1 --timeout 5 --blank --no-keys --live --aspect-mode fill --avdict rtsp_transport:tcp --win %s --dbus_name %s \"%s\"" % (win_coords, dbus_name, url) # quotes around stream are required in some cases 134 | self.stream_position.append(0) 135 | log.info(' - Player[stream-%d] - omx command: (%s).' % (i, cmd)) 136 | 137 | script_path = './start%d.sh' % i 138 | store_as_script_on_disk(i, cmd, script_path) 139 | 140 | # prepare starting commands for current script 141 | start_cmd = ['screen', '-dmS', screen_name, "sh", script_path] 142 | log.info(' - Player[stream-%d] - start command: (%s).' % (i, start_cmd)) 143 | return start_cmd 144 | 145 | def player_immediate_restart(self, stream_id, win_coords): 146 | kill_single_omx_window(stream_id, win_coords) 147 | self.start_player(stream_id) 148 | 149 | def start_player(self, i): 150 | player_start_command = self.start_commands[i] 151 | Popen(player_start_command, stdin=PIPE, stdout=DEV_NULL, stderr=STDOUT, close_fds=True, bufsize=0) # async. execution, instant exit 152 | self.check_counters[i] = 0 153 | self.restart_counters[i] += 1 154 | if self.stream_position[i] > 0: 155 | self.stream_position[i] = 0 156 | log.info(' --- Player[stream-%d] started with command: (%s)' % (i, repr(player_start_command))) 157 | 158 | def disable_auto_restart(self): 159 | self.auto_restart_enabled = False 160 | 161 | 162 | def store_as_script_on_disk(i, content, script_path): 163 | f = open(script_path, 'w+') 164 | f.write(BASH_SHEBANG) 165 | f.write(content + '\n') 166 | f.truncate() 167 | f.close() 168 | log.info(' - Player[stream-%d] - start script stored on disk: (%s).' % (i, script_path)) 169 | 170 | 171 | def kill_single_omx_window(i, win_coords_filter): 172 | screen_name_filter = SCREEN_NAME_PATTERN % i 173 | kill_single_command = ['bash', SCRIPT_OMX_KILL_SINGLE, win_coords_filter, screen_name_filter] 174 | log.info(' --- Player[stream-%d] stopping players for single window, cmd=(%s)' % (i, kill_single_command)) 175 | kill_result = check_output(kill_single_command) 176 | log.info(' --- Player[stream-%d] kill single window result: (\n%s)', i, kill_result) 177 | 178 | 179 | def kill_all_omx_processes(): 180 | kill_all_command = ['bash', SCRIPT_OMX_KILL_ALL] 181 | log.info(" --- Player - stopping players for all windows, cmd=(%s)" % kill_all_command) 182 | kill_result = check_output(kill_all_command) 183 | log.info(' --- Player - kill all windows result: (%s)', kill_result) 184 | 185 | 186 | def main_for_testing(): 187 | cam_streams = [ 188 | "", 189 | "rtsp://172.16.1.195:554/av0_1", # rtsp://mpv.cdn3.bigCDN.com:554/bigCDN/mp4:bigbuckbunnyiphone_400.mp4 190 | "rtsp://172.16.1.190:554/av0_1", # some address where there is no stream 191 | "rtsp://172.16.1.196:554/av0_1" # rtsp://mm2.pcslab.com/mm/7h2000.mp4 192 | ] 193 | 194 | win_coords = [ 195 | '0,0,528,298', 196 | '532,0,1060,298', 197 | '0,302,528,600', 198 | '532,302,1060,600' 199 | ] 200 | 201 | player = Playstreamation(cam_streams, win_coords) 202 | player.play() 203 | 204 | 205 | if __name__ == "__main__": 206 | main_for_testing() 207 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/info_window.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | import _tkinter 16 | import tkFont 17 | from Tkconstants import BOTTOM, TOP, X, E, SUNKEN, LEFT, RIGHT, Y 18 | from Tkinter import Tk, Frame, Label, BOTH, StringVar 19 | 20 | from PIL import Image, ImageTk 21 | 22 | from cfgviewer.cfgpanel.constants import MAX_CAM_AMOUNT, CAM_STATUS_INIT 23 | from log_config import log 24 | from utils import MODE_SPLIT, MODE_AUTO, SCREEN_RES, APP_LOGO_PNG, APP_HELP_S_PNG, APP_HELP_A_PNG, APP_HELP_4_PNG, MODE_SINGLE 25 | 26 | BORDER_WIDTH = 3 27 | DEF_RELIEF = SUNKEN 28 | DEF_FONT = "Helvetica" 29 | MONO_FONT = "Courier" 30 | FRM_BACKGROUND = "#AAAAAA" 31 | MSG_BACKGROUND = "#BBBBBB" 32 | MSG_TITLE_FOREGROUND = "#0B2161" 33 | MSG_HELP_FOREGROUND = "#015f94" 34 | SEP_L = "------------------------------------" 35 | 36 | TXT_UPDATE_INTERVAL = 400 # ms 37 | PING_DELAY = 3 # s 38 | 39 | try: 40 | TK_ROOT = Tk() 41 | TK_ROOT.geometry("%s+0+0" % SCREEN_RES) 42 | except _tkinter.TclError: 43 | print 'ERROR: This application requires X window server.' 44 | exit(-1) 45 | 46 | 47 | class SysInfo(Frame): 48 | txt_var_serial = StringVar() 49 | txt_var_mon_cfg = StringVar() 50 | txt_var_cam_cfg_page = StringVar() 51 | txt_var_cam_cfg_stream = StringVar() 52 | txt_var_version = StringVar() 53 | txt_var_mode_name = StringVar() 54 | 55 | img_help_single = ImageTk.PhotoImage(Image.open(APP_HELP_S_PNG)) 56 | img_help_auto = ImageTk.PhotoImage(Image.open(APP_HELP_A_PNG)) 57 | img_help_4in1 = ImageTk.PhotoImage(Image.open(APP_HELP_4_PNG)) 58 | 59 | def __init__(self, parent, info_collector_thread): 60 | Frame.__init__(self, parent, background=FRM_BACKGROUND) 61 | 62 | # load images 63 | img_logo = ImageTk.PhotoImage(Image.open(APP_LOGO_PNG)) 64 | 65 | # init frame 66 | self.parent = parent 67 | self.parent.title("MyFrame") 68 | self.info_collector = info_collector_thread 69 | 70 | self.columnconfigure(0, weight=1) 71 | self.rowconfigure(1, weight=1) 72 | 73 | font_huge = tkFont.Font(family=DEF_FONT, size=36, weight="bold") 74 | font_mono = tkFont.Font(family=MONO_FONT, size=11) 75 | font_normal = tkFont.Font(family=DEF_FONT, size=14) 76 | font_normal_bold = tkFont.Font(family=DEF_FONT, size=16, weight="bold") 77 | font_small = tkFont.Font(family=DEF_FONT, size=10, weight="bold") 78 | font_tiny = tkFont.Font(family=DEF_FONT, size=10) 79 | 80 | frm_main = Frame(self, relief=DEF_RELIEF, background=MSG_BACKGROUND) 81 | frm_main.pack(side=BOTTOM, fill=BOTH, expand=True, padx=10, pady=10) 82 | 83 | frm_title = Frame(self, background=FRM_BACKGROUND) 84 | frm_title.pack(side=TOP, fill=X) 85 | 86 | frm_name = Frame(frm_title, background=FRM_BACKGROUND) 87 | frm_name.pack(side=RIGHT) 88 | 89 | frm_logo = Frame(frm_title, background=FRM_BACKGROUND) 90 | frm_logo.pack(side=LEFT) 91 | 92 | lbl_logo = Label(frm_logo, image=img_logo, background=FRM_BACKGROUND, relief=DEF_RELIEF, borderwidth=BORDER_WIDTH) 93 | lbl_logo.image = img_logo 94 | lbl_logo.pack(padx=10, pady=10) 95 | 96 | # TITLE 97 | 98 | lbl_name = Label(frm_name, text="Monitor górniczy MG-1", background=FRM_BACKGROUND, foreground=MSG_TITLE_FOREGROUND, font=font_huge) 99 | lbl_name.pack(padx=10, pady=10, anchor=E) 100 | 101 | lbl_serial = Label(frm_name, textvariable=self.txt_var_serial, background=FRM_BACKGROUND, foreground=MSG_HELP_FOREGROUND, font=font_normal_bold) 102 | lbl_serial.pack(padx=10, pady=10, anchor=E) 103 | 104 | # HELP 105 | 106 | frm_help = Frame(frm_main, borderwidth=0) 107 | frm_help.pack(side=LEFT, fill=Y) 108 | 109 | self.lbl_help = Label(frm_help, image=self.img_help_4in1, background=FRM_BACKGROUND, relief=DEF_RELIEF, borderwidth=BORDER_WIDTH) 110 | self.lbl_help.image = self.img_help_4in1 # default 111 | self.lbl_help.pack(fill=Y, expand=True) 112 | 113 | # CFG MESSAGE 114 | 115 | frm_sysinfo = Frame(frm_main, relief=DEF_RELIEF, background=MSG_BACKGROUND, borderwidth=BORDER_WIDTH) 116 | frm_sysinfo.pack(side=RIGHT, fill=BOTH, expand=True) 117 | 118 | frm_vertical_sep = Label(frm_main, background=FRM_BACKGROUND, borderwidth=0, width=1) 119 | frm_vertical_sep.pack(side=RIGHT, fill=BOTH) 120 | 121 | lbl_empty = Label(frm_sysinfo, text="", background=MSG_BACKGROUND) 122 | lbl_empty.pack(fill=X, expand=True) 123 | 124 | lbl_mon_cfg_title = Label(frm_sysinfo, text="Adres IP monitora", background=MSG_BACKGROUND, foreground=MSG_TITLE_FOREGROUND, font=font_normal) 125 | lbl_mon_cfg_title.pack(fill=X) 126 | lbl_mon_cfg = Label(frm_sysinfo, textvariable=self.txt_var_mon_cfg, background=MSG_BACKGROUND, font=font_normal) 127 | lbl_mon_cfg.pack(fill=X) 128 | 129 | lbl_empty = Label(frm_sysinfo, text="", background=MSG_BACKGROUND) 130 | lbl_empty.pack(fill=X, expand=True) 131 | 132 | lbl_cam_cfg_title = Label(frm_sysinfo, text="Adresy IP kamer", background=MSG_BACKGROUND, foreground=MSG_TITLE_FOREGROUND, font=font_normal) 133 | lbl_cam_cfg_title.pack(fill=X) 134 | lbl_cam_cfg_page = Label(frm_sysinfo, textvariable=self.txt_var_cam_cfg_page, background=MSG_BACKGROUND, font=font_normal) 135 | lbl_cam_cfg_page.pack(fill=X) 136 | lbl_cam_cfg_stream = Label(frm_sysinfo, textvariable=self.txt_var_cam_cfg_stream, background=MSG_BACKGROUND, font=font_mono, justify=LEFT) 137 | lbl_cam_cfg_stream.pack(fill=X) 138 | 139 | lbl_empty = Label(frm_sysinfo, text="", background=MSG_BACKGROUND, font=font_small) 140 | lbl_empty.pack(fill=X, expand=True) 141 | 142 | lbl_misc_title = Label(frm_sysinfo, text="Informacje dodatkowe", background=MSG_BACKGROUND, foreground=MSG_TITLE_FOREGROUND, font=font_small) 143 | lbl_misc_title.pack(fill=X) 144 | lbl_mode = Label(frm_sysinfo, textvariable=self.txt_var_mode_name, background=MSG_BACKGROUND, font=font_tiny) 145 | lbl_mode.pack(fill=X) 146 | self.txt_var_mode_name.set("") 147 | lbl_version = Label(frm_sysinfo, textvariable=self.txt_var_version, background=MSG_BACKGROUND, font=font_tiny) 148 | lbl_version.pack(fill=X) 149 | 150 | # pack main content panel 151 | self.pack(fill=BOTH, expand=True) 152 | 153 | self.after(TXT_UPDATE_INTERVAL, self.on_timer) 154 | 155 | def on_timer(self): 156 | log.debug("View update.") 157 | try: 158 | self.update_view() 159 | except BaseException as e: 160 | log.error('Could not update view (%s).' % repr(e)) 161 | 162 | if self.info_collector.is_enabled: 163 | self.after(TXT_UPDATE_INTERVAL, self.on_timer) 164 | 165 | def update_view(self): 166 | info_serial = "Numer seryjny: %s" % self.info_collector.cfg_serial 167 | self.txt_var_serial.set(info_serial) 168 | 169 | str_mon_info = self.info_collector.cfg_address_mon + "\n" + self.info_collector.cfg_netmask_mon 170 | 171 | self.txt_var_mon_cfg.set(str_mon_info) 172 | config_info = "[odwiedź %s:8080/config/ aby zmienić]" % self.info_collector.cfg_address_mon 173 | 174 | cams_configs = self.info_collector.cams_configs 175 | cams_statuses = self.info_collector.cams_statuses 176 | cam_status = '' 177 | for i in range(0, MAX_CAM_AMOUNT): 178 | cam_config = cams_configs[i] 179 | address = cam_config.address 180 | port, type_name, auth, profiles = cam_config.cfg_info() 181 | status = cams_statuses[i] 182 | cam_address = '- nie skonfigurowano -' if not address and status != CAM_STATUS_INIT else address.rjust(15, ' ') 183 | if address: 184 | cam_status += 'kam:%s %s poł:%s port:%s %s %s %s\n' % ((i + 1), cam_address, status, port, type_name.ljust(17, ' '), auth, profiles) 185 | else: 186 | cam_status += 'kam:%s %s %s\n' % ((i + 1), cam_address.rjust(15, ' '), status) 187 | 188 | self.txt_var_cam_cfg_page.set("%s\n\n" % config_info) 189 | self.txt_var_cam_cfg_stream.set("%s" % cam_status.rstrip('\n')) 190 | self.txt_var_version.set("Wersja: %s.%s" % (self.info_collector.cfg_version, self.info_collector.cfg_revision)) 191 | 192 | log.debug("Labels updated.") 193 | # print subprocess.check_output(['scrot', '-d', '3']) # FOR DOCUMENTATION PURPOSE ONLY 194 | 195 | def set_mode_name(self, mode, mode_description): 196 | self.txt_var_mode_name.set("Tryb: %s" % mode_description) 197 | if mode == MODE_SPLIT: 198 | self.lbl_help.configure(image=self.img_help_4in1) 199 | elif mode == MODE_SINGLE: 200 | self.lbl_help.configure(image=self.img_help_single) 201 | elif mode == MODE_AUTO: 202 | self.lbl_help.configure(image=self.img_help_auto) 203 | 204 | 205 | def create(info_collector_thread): 206 | return SysInfo(TK_ROOT, info_collector_thread) 207 | 208 | 209 | def show(): 210 | TK_ROOT.update() 211 | TK_ROOT.deiconify() 212 | TK_ROOT.mainloop() 213 | 214 | 215 | def close(): 216 | try: 217 | TK_ROOT.withdraw() 218 | except RuntimeError: 219 | print 'ERROR: Could not withdraw...' 220 | 221 | TK_ROOT.quit() 222 | 223 | 224 | def finish(): 225 | TK_ROOT.destroy() 226 | 227 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/player_split.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | import logging 14 | import os 15 | import time 16 | from subprocess import Popen, PIPE, STDOUT, check_output 17 | 18 | from dbus_omxplayer import send_dbus_action, ACTION_POS 19 | from log_config import log 20 | 21 | HOME_DIR = '/home/haso/camviewer/' 22 | VIDEO_NOT_CONFIGURED = 'not_configured.mp4' 23 | 24 | SCRIPT_OMX_WAIT = 'omx_wait.sh' 25 | SCRIPT_OMX_COUNT = "omx_count.sh" 26 | SCRIPT_OMX_KILL_ALL = 'omx_kill_all.sh' 27 | SCRIPT_OMX_KILL_SINGLE = "omx_kill_single.sh" 28 | 29 | BASH_SHEBANG = '#!/usr/bin/env bash\n' 30 | DEV_NULL = open(os.devnull, 'w') 31 | SCREEN_NAME_PATTERN = 'camera%d' 32 | 33 | PROC_CHECK_INTERVAL_S = 5 34 | PERIODIC_RESTART_EVERY_CHECK = 8640 # every 12h 35 | 36 | # TODO: These screen resolution settings should be moved to some configuration file of got from the system settings somehow 37 | SCREEN_W = 1060 38 | SCREEN_H = 600 39 | 40 | WIN_0 = '%s,%s,%s,%s' % (0, 0, (SCREEN_W / 2) - 2, (SCREEN_H / 2) - 2) 41 | WIN_1 = '%s,%s,%s,%s' % ((SCREEN_W / 2) + 2, 0, SCREEN_W, (SCREEN_H / 2) - 2) 42 | WIN_2 = '%s,%s,%s,%s' % (0, (SCREEN_H / 2) + 2, (SCREEN_W / 2) - 2, SCREEN_H) 43 | WIN_3 = '%s,%s,%s,%s' % ((SCREEN_W / 2) + 2, (SCREEN_H / 2) + 2, SCREEN_W, SCREEN_H) 44 | WIN_COORDS = [WIN_0, WIN_1, WIN_2, WIN_3] 45 | 46 | logger = logging.getLogger(__name__) 47 | 48 | 49 | class PlayerSplit: 50 | def __init__(self, cam_configs_array_4): 51 | self.cam_configs = cam_configs_array_4 52 | self.start_commands = [] 53 | self.stream_position = [] 54 | self.check_counters = [] 55 | self.restart_counters = [] 56 | 57 | self.auto_restart_enabled = True 58 | self.total_stream_count = 0 59 | 60 | def play(self): 61 | for stream_id in range(0, len(self.cam_configs)): 62 | start_cmd = self.prepare_player_start_command(stream_id) 63 | 64 | self.start_commands.append(start_cmd) 65 | self.check_counters.append(0) 66 | self.restart_counters.append(0) 67 | 68 | self.start_player(stream_id) 69 | 70 | while self.auto_restart_enabled: 71 | # periodically restart players that are not running anymore (e.g. there was no connectivity for a moment) 72 | time.sleep(PROC_CHECK_INTERVAL_S) 73 | 74 | log.info("Checking if streams are working...") 75 | streams_to_start = [] 76 | for stream_id in range(0, len(self.cam_configs)): 77 | win_coords = WIN_COORDS[stream_id] 78 | omx_proc_count = check_output(['bash', SCRIPT_OMX_COUNT, win_coords]) 79 | ps_count = omx_proc_count.rstrip('\n') 80 | 81 | self.check_counters[stream_id] += 1 82 | check_number = self.check_counters[stream_id] 83 | instance_no = self.restart_counters[stream_id] 84 | 85 | pos_previous = self.stream_position[stream_id] 86 | 87 | if omx_proc_count is not None: 88 | stream_freeze_detected = False 89 | proc_count_int = int(omx_proc_count) 90 | if proc_count_int == 1: 91 | if pos_previous >= 0: 92 | # noinspection PyBroadException 93 | try: 94 | pos = send_dbus_action(stream_id, ACTION_POS) 95 | self.stream_position[stream_id] = pos 96 | 97 | if pos_previous == pos: 98 | stream_freeze_detected = True 99 | except BaseException: 100 | pos = '[unknown]' 101 | else: 102 | pos = '[not tracking]' 103 | else: 104 | pos = '[instances issue]' 105 | 106 | log.info(" -- Player[stream-%d/%d] check %d proc=%s pos=%s freeze detected=%s" % (stream_id, instance_no, check_number, ps_count, pos, stream_freeze_detected)) 107 | if self.auto_restart_enabled: 108 | if proc_count_int == 0: 109 | log.info(' --- Player[stream-%d/%d] not running - scheduling start...' % (stream_id, check_number)) 110 | streams_to_start.append(stream_id) 111 | elif proc_count_int > 1: 112 | # just recover from glitches with many players opened for single stream (should not happen) 113 | log.info(' --- Player[stream-%d/%d] running in too many instances - killing all and scheduling start.' % (stream_id, check_number)) 114 | kill_single_omx_window(stream_id, win_coords) 115 | streams_to_start.append(stream_id) 116 | elif proc_count_int == 1: 117 | if stream_freeze_detected: 118 | log.info(' --- Player[stream-%d/%d] stream freeze detected - immediate restart.' % (stream_id, check_number)) 119 | self.player_immediate_restart(stream_id, win_coords) 120 | elif check_number % PERIODIC_RESTART_EVERY_CHECK == 0: # restart stream periodically even if it is still running (workaround for image freezing after w while) 121 | log.info(' --- Player[stream-%d/%d] performing periodic instant restart.' % (stream_id, check_number)) 122 | self.player_immediate_restart(stream_id, win_coords) 123 | else: 124 | pass # keep playing 125 | else: 126 | log.error('Invalid processes count received (None).') 127 | 128 | log.info('Performing scheduled starts...') 129 | 130 | if len(streams_to_start) < self.total_stream_count: 131 | # try to start scheduled streams 132 | for stream_id_to_start in streams_to_start: 133 | self.start_player(stream_id_to_start) 134 | else: 135 | # something is wrong - stopping players for all streams and exiting... 136 | log.info(' --- Player[split] >>> All streams are down (or none is configured)...') 137 | self.disable_auto_restart() 138 | 139 | kill_all_omx_processes() # showing 1-4 streams playing 'not_configured.mp4' are also omx processes and we need to close them 140 | 141 | # invoke script that will return the control when all streams are stopped 142 | wait_command = ['bash', SCRIPT_OMX_WAIT] 143 | log.info('Starting omx_wait[split] script... (%s)' % repr(wait_command)) 144 | wait_process = Popen(wait_command, stdin=PIPE, stdout=DEV_NULL, stderr=STDOUT, close_fds=True, bufsize=0) # async. execution, instant exit 145 | wait_process.wait() 146 | 147 | log.info('Player[split] stopped.') 148 | break 149 | 150 | def prepare_player_start_command(self, i): 151 | # prepare starting script for omxplayer in proper window 152 | log.info('Setting up Players[stream-%d]...' % i) 153 | 154 | cam_config = self.cam_configs[i] 155 | address = cam_config.address 156 | win_coords = WIN_COORDS[i] 157 | screen_name = SCREEN_NAME_PATTERN % i 158 | dbus_name = "org.mpris.MediaPlayer2.omxplayer.%s" % screen_name 159 | 160 | if not address: 161 | url = HOME_DIR + VIDEO_NOT_CONFIGURED 162 | cmd = "omxplayer --adev hdmi --aidx -1 --timeout 5 --blank --no-keys --no-osd --loop --win %s --dbus_name %s %s" % (win_coords, dbus_name, url) 163 | # NOTE: allowed options are either --live or --no-osd and not both 164 | self.stream_position.append(-1) 165 | else: 166 | url = cam_config.sub_stream_url() 167 | cmd = "omxplayer --adev hdmi --aidx -1 --timeout 5 --blank --no-keys --live --aspect-mode fill --avdict rtsp_transport:tcp --win %s --dbus_name %s \"%s\"" % (win_coords, dbus_name, url) # quotes around stream are required in some cases 168 | self.stream_position.append(0) 169 | self.total_stream_count += 1 170 | log.info(' - Player[stream-%d] - omx command: (%s).' % (i, cmd)) 171 | 172 | script_path = HOME_DIR + ('start%d.sh' % i) 173 | store_as_script_on_disk(i, cmd, script_path) 174 | 175 | # prepare starting commands for current script 176 | start_cmd = ['screen', '-dmS', screen_name, "sh", script_path] 177 | log.info(' - Player[stream-%d] - start command: (%s).' % (i, start_cmd)) 178 | return start_cmd 179 | 180 | def player_immediate_restart(self, stream_id, win_coords): 181 | kill_single_omx_window(stream_id, win_coords) 182 | self.start_player(stream_id) 183 | 184 | def start_player(self, i): 185 | player_start_command = self.start_commands[i] 186 | Popen(player_start_command, stdin=PIPE, stdout=DEV_NULL, stderr=STDOUT, close_fds=True, bufsize=0) # async. execution, instant exit 187 | self.check_counters[i] = 0 188 | self.restart_counters[i] += 1 189 | if self.stream_position[i] > 0: 190 | self.stream_position[i] = 0 191 | log.info(' --- Player[stream-%d] started with command: (%s)' % (i, repr(player_start_command))) 192 | 193 | def disable_auto_restart(self): 194 | self.auto_restart_enabled = False 195 | 196 | 197 | def store_as_script_on_disk(i, content, script_path): 198 | f = open(script_path, 'w+') 199 | f.write(BASH_SHEBANG) 200 | f.write(content + '\n') 201 | f.truncate() 202 | f.close() 203 | log.info(' - Player[stream-%d] - start script stored on disk: (%s).' % (i, script_path)) 204 | 205 | 206 | def kill_single_omx_window(i, win_coords_filter): 207 | screen_name_filter = SCREEN_NAME_PATTERN % i 208 | kill_single_command = ['bash', SCRIPT_OMX_KILL_SINGLE, win_coords_filter, screen_name_filter] 209 | log.info(' --- Player[stream-%d] stopping players for single window, cmd=(%s)' % (i, kill_single_command)) 210 | kill_result = check_output(kill_single_command) 211 | log.info(' --- Player[stream-%d] kill single window result: (\n%s)', i, kill_result) 212 | 213 | 214 | def kill_all_omx_processes(): 215 | kill_all_command = ['bash', SCRIPT_OMX_KILL_ALL] 216 | log.info(" --- Player - stopping players for all windows, cmd=(%s)" % kill_all_command) 217 | kill_result = check_output(kill_all_command) 218 | log.info(' --- Player - kill all windows result: (%s)', kill_result) 219 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/templates/cfgpanel/index.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Konfiguracja MG-1 11 | 12 | 43 | 44 | 45 | 46 | 47 |

Ustawienia monitora górniczego MG-1

48 | 49 |
{% csrf_token %} 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 206 | 207 | 208 | 209 | 212 | 213 | 214 | 216 | 217 | 218 | 219 | 220 | 221 | 222 |
65 |

Konfiguracja monitora

Adres IP{{ info_mon_address }}
Maska{{ info_mon_netmask }}

79 |

Konfiguracja oczekiwanych adresów kamer

Urz.IPPortHD4w1UżytkownikHasłoTypInfo.
Kam. 1:
101 | 118 | {{ info_cam_data1 }}
Kam. 2:  130 | 147 | {{ info_cam_data2 }}
Kam. 3:  159 | 176 | {{ info_cam_data3 }}
Kam. 4:  188 | 205 | {{ info_cam_data4 }}
210 | UWAGA: Adresy IP kamer muszą znajdować się w tej samej przestrzeni adresowej IPv4, co adres IP monitora. 211 |

215 |

Numer seryjny 

Wartość {{ current_serial_number }}
223 | 224 |
225 |
226 | 227 |
228 | 229 | {% if op_status != "" %} 230 |
231 |
232 |

Status operacji

233 |

{{ op_status }}

234 |
235 | {% endif %} 236 | 237 | 238 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/camviewer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | 16 | import getpass 17 | import os.path 18 | import time 19 | from subprocess import Popen, PIPE, STDOUT 20 | from Queue import Queue 21 | from threading import Timer 22 | 23 | from fysom import Fysom 24 | 25 | import event_handler 26 | import info_collector 27 | import info_window 28 | from cfgviewer.cfgpanel.constants import AUTO_CLOSE_TIME, CYCLE_TIME_DEFAULT, WIN_SINGLE, CFG_CAM_IP_FILENAME, CYCLE_TIME_MAX_INCR, EMPTY_CONFIG_CONTENT, CAM_STATUS_OK 29 | from dbus_omxplayer import send_dbus_stop, OMXPlayerStopError 30 | from log_config import log 31 | from player import Player, DEV_NULL 32 | from player_split import PlayerSplit, kill_all_omx_processes 33 | from utils import NAME_MODE_SINGLE, NAME_MODE_SPLIT, NAME_MODE_AUTO, MODE_SINGLE, MODE_SPLIT, MODE_AUTO 34 | 35 | _FSM_TRANSITION_ = 'name' 36 | _FSM_SRC_ = 'src' 37 | _FSM_DST_ = 'dst' 38 | 39 | TRANSITION_INIT = 'init' 40 | TRANSITION_INFO = 'show_info' 41 | TRANSITION_CAM_SINGLE = 'view_cam_single' 42 | TRANSITION_CAM_SPLIT = 'view_cam_split' 43 | TRANSITION_CAM_AUTO = 'view_cam_auto' 44 | 45 | STATE_SYSINFO = 'SysInfo' 46 | STATE_STREAMING_SINGLE = 'StreamingSingle' 47 | STATE_STREAMING_SPLIT = 'StreamingSplit' 48 | STATE_STREAMING_AUTO = 'StreamingAuto' 49 | 50 | fsm = Fysom({ 51 | 'initial': {'state': STATE_SYSINFO, 'event': TRANSITION_INIT, 'defer': True}, 52 | 'events': 53 | [ 54 | {_FSM_TRANSITION_: TRANSITION_INFO, _FSM_SRC_: STATE_STREAMING_SINGLE, _FSM_DST_: STATE_SYSINFO}, 55 | {_FSM_TRANSITION_: TRANSITION_INFO, _FSM_SRC_: STATE_STREAMING_SPLIT, _FSM_DST_: STATE_SYSINFO}, 56 | {_FSM_TRANSITION_: TRANSITION_INFO, _FSM_SRC_: STATE_STREAMING_AUTO, _FSM_DST_: STATE_SYSINFO}, 57 | {_FSM_TRANSITION_: TRANSITION_CAM_SINGLE, _FSM_SRC_: STATE_SYSINFO, _FSM_DST_: STATE_STREAMING_SINGLE}, 58 | {_FSM_TRANSITION_: TRANSITION_CAM_SPLIT, _FSM_SRC_: STATE_SYSINFO, _FSM_DST_: STATE_STREAMING_SPLIT}, 59 | {_FSM_TRANSITION_: TRANSITION_CAM_AUTO, _FSM_SRC_: STATE_SYSINFO, _FSM_DST_: STATE_STREAMING_AUTO} 60 | ] 61 | }) 62 | 63 | 64 | def stop_single_omx_dbus(): 65 | try: 66 | send_dbus_stop() 67 | except OMXPlayerStopError: 68 | log.info('ERROR: Could not stop OMXPlayer through DBUS.') 69 | 70 | 71 | def full_reboot(): 72 | kill_all_omx_processes() 73 | 74 | command = ['sudo', '/usr/bin/fbi', '-T', '1', '--noverbose', '-a', '/home/haso/camviewer/rebooting.jpg'] 75 | Popen(command, stdin=PIPE, stdout=DEV_NULL, stderr=STDOUT, close_fds=True, bufsize=0) 76 | time.sleep(3) 77 | 78 | command = ['sudo', 'reboot'] 79 | log.info("Rebooting device with cmd=(%s)" % command) 80 | Popen(command, stdin=PIPE, stdout=DEV_NULL, stderr=STDOUT, close_fds=True, bufsize=0) 81 | 82 | 83 | # noinspection PyMethodMayBeStatic 84 | class Camviewer: 85 | _info_collector_thread = info_collector.InfoCollectorThread() 86 | _event_handler_thread = event_handler.EventHandlerThread() 87 | _transitions_queue = Queue() 88 | _cam_stop_user_request = True # we cannot distinguish 89 | _streaming = True 90 | _auto_close_timer = None 91 | _cycle_time = CYCLE_TIME_DEFAULT 92 | _mode = None 93 | 94 | def __init__(self): 95 | self._player_split = None 96 | 97 | self._info_collector_thread.start() 98 | self._info_window_ref = info_window.create(self._info_collector_thread) 99 | self._set_mode(MODE_SPLIT) 100 | 101 | self._event_handler_thread.set_esc_handler(self.action_button_esc) 102 | self._event_handler_thread.set_up_handler(self.action_handle_up) 103 | self._event_handler_thread.set_down_handler(self.action_button_down) 104 | self._event_handler_thread.set_enter_handler(self.action_handle_enter) 105 | self._event_handler_thread.set_left_handler(self.action_handle_left) 106 | self._event_handler_thread.set_right_handler(self.action_handle_right) 107 | 108 | self._event_handler_thread.start() 109 | 110 | def _async_transition(self, transition_name): 111 | log.info('Storing transition: %s [%s]' % (fsm.current, transition_name)) 112 | self._transitions_queue.put(transition_name) 113 | 114 | def _set_mode(self, mode): 115 | self._mode = mode 116 | 117 | # Update mode name on info screen too 118 | if mode == MODE_SINGLE: 119 | self._info_window_ref.set_mode_name(MODE_SINGLE, NAME_MODE_SINGLE) 120 | elif mode == MODE_SPLIT: 121 | self._info_window_ref.set_mode_name(MODE_SPLIT, NAME_MODE_SPLIT) 122 | elif mode == MODE_AUTO: 123 | self._info_window_ref.set_mode_name(MODE_AUTO, '%s [co %d sekund]' % (NAME_MODE_AUTO, int(self._cycle_time))) 124 | else: 125 | log.error("Invalid mode given: (%s)" % mode) 126 | 127 | def main_control_loop(self): 128 | fsm.onSysInfo = self.on_state_sys_info 129 | fsm.onStreamingSingle = self.on_state_streaming_single 130 | fsm.onStreamingSplit = self.on_state_streaming_split 131 | fsm.onStreamingAuto = self.on_state_streaming_auto 132 | 133 | self._async_transition(TRANSITION_INIT) # [NONE] ==init==> [SysInfo] 134 | 135 | while True: 136 | log.info('Waiting for transition...') 137 | transition_name = self._transitions_queue.get(block=True) 138 | 139 | # execute transition - using 'Hollywood principle' in flow control 140 | if fsm.can(transition_name): 141 | log.info('Executing transition: %s' % transition_name) 142 | fsm.trigger(transition_name) 143 | else: 144 | log.warn('Transition (%s) not allowed in state (%s). Skipping...' % (transition_name, fsm.current)) 145 | 146 | self._transitions_queue.task_done() 147 | 148 | log.info("Camviewer app stopped.") 149 | self._event_handler_thread.stop() 150 | self._info_collector_thread.stop() 151 | return 152 | 153 | def auto_sysinfo_close(self): 154 | current = fsm.current 155 | 156 | any_configured = self._info_collector_thread.is_any_cam() 157 | 158 | log.info("Timer fired (%s)." % current) 159 | if current == STATE_SYSINFO and any_configured: 160 | log.info("Timer - closing SysInfo.") 161 | info_window.close() 162 | else: 163 | # Check again later 164 | log.info("Timer - will check again later...") 165 | self._auto_close_timer = Timer(AUTO_CLOSE_TIME, self.auto_sysinfo_close) 166 | self._auto_close_timer.start() 167 | 168 | def on_state_sys_info(self, e): 169 | log.info("Showing sysinfo screen.") 170 | 171 | if self._auto_close_timer is not None: 172 | self._auto_close_timer.cancel() 173 | 174 | self._auto_close_timer = Timer(AUTO_CLOSE_TIME, self.auto_sysinfo_close) 175 | self._auto_close_timer.start() 176 | 177 | info_window.show() # halts here until window is closed... 178 | 179 | log.info("Cancelling auto_close_timer...") 180 | self._auto_close_timer.cancel() 181 | 182 | log.info("Exiting sysinfo screen.") 183 | if self._mode == MODE_SINGLE: 184 | self._async_transition(TRANSITION_CAM_SINGLE) # [SysInfo] ==view_cam_single==> [StreamingSingle] 185 | elif self._mode == MODE_SPLIT: 186 | self._async_transition(TRANSITION_CAM_SPLIT) # [SysInfo] ==view_cam_split==> [StreamingSplit] 187 | elif self._mode == MODE_AUTO: 188 | self._async_transition(TRANSITION_CAM_AUTO) # [SysInfo] ==view_cam_auto==> [StreamingAuto] 189 | else: 190 | log.error("Unknown mode: (%s)" % self._mode) 191 | 192 | def on_state_streaming_single(self, e): 193 | log.info('Entering state StreamingSingle.') 194 | self._streaming = True 195 | self.handle_player_single() 196 | log.info('Exiting state StreamingSingle.') 197 | self._async_transition(TRANSITION_INFO) # [StreamingSingle] ==show_info==> [SysInfo] 198 | 199 | def on_state_streaming_split(self, e): 200 | log.info('Entering state StreamingSplit.') 201 | self._streaming = True 202 | self.handle_player_split() 203 | log.info('Exiting state StreamingSplit.') 204 | self._async_transition(TRANSITION_INFO) # [StreamingSplit] ==show_info==> [SysInfo] 205 | 206 | def on_state_streaming_auto(self, e): 207 | log.info('Entering state StreamingAuto.') 208 | self._streaming = True 209 | self.handle_player_auto() 210 | log.info('Exiting state StreamingAuto.') 211 | self._async_transition(TRANSITION_INFO) # [StreamingAuto] ==show_info==> [SysInfo] 212 | 213 | def handle_player_single(self): 214 | while self._streaming: 215 | cams_configs = self._info_collector_thread.cams_configs # not all cams might have been found on startup 216 | self._cam_stop_user_request = False 217 | 218 | any_stream = False 219 | for i in range(0, len(cams_configs)): 220 | cam_config = cams_configs[i] 221 | if cam_config.address: 222 | status = self._info_collector_thread.cams_statuses[i] 223 | if status == CAM_STATUS_OK: 224 | any_stream = True 225 | log.info('Starting Player[single] on address: (%s)' % cam_config.main_stream_url()) 226 | player_single = Player(i, cam_config.main_stream_url(), WIN_SINGLE) 227 | player_single.play() 228 | player_single.wait_to_finish() # if closed switch automatically to another 229 | 230 | if not self._streaming: # streaming mode exit was requested 231 | break 232 | else: 233 | log.info('Skipping Player[single] camera address: (%s). Not accessible.' % cam_config.main_stream_url()) 234 | player_single = Player(i, '/home/haso/camviewer/no_signal.mp4', WIN_SINGLE, False) 235 | player_single.play() 236 | player_single.wait_to_finish() 237 | continue 238 | else: 239 | log.info('Skipping Player[single] camera address: (%s). Not configured.' % cam_config.main_stream_url()) 240 | continue 241 | 242 | # After full cycle 243 | if self._cam_stop_user_request and any_stream: 244 | log.info("Player[single] stopped manually. Continuing...") 245 | continue # cycle again through all cams 246 | else: 247 | log.info("Player[single] stopped by itself. Exiting...") 248 | break # stream was closed (show info screen) 249 | 250 | def handle_player_auto(self): 251 | while self._streaming: 252 | cams_configs = self._info_collector_thread.cams_configs # not all cams might have been found on startup 253 | cam_statuses = self._info_collector_thread.cams_statuses 254 | any_stream = False 255 | for i in range(0, len(cams_configs)): 256 | self._cam_stop_user_request = False 257 | cam_config = cams_configs[i] 258 | if cam_config.address: 259 | status = cam_statuses[i] 260 | if status == CAM_STATUS_OK: 261 | any_stream = True 262 | log.info('Starting Player[auto] on address: (%s)' % cam_config.main_stream_url()) 263 | player_single = Player(i, cam_config.main_stream_url(), WIN_SINGLE) 264 | player_single.play() 265 | cycle_close_timer = Timer(self._cycle_time, self.stop_auto_cycle) 266 | cycle_close_timer.start() 267 | player_single.wait_to_finish() 268 | cycle_close_timer.cancel() 269 | 270 | if self._cam_stop_user_request: 271 | log.info("Player[auto] stopped by timer. Continuing...") 272 | continue # Closed by timer 273 | else: 274 | log.info("Player[auto] stopped by itself. Exiting...") 275 | self._streaming = False 276 | break # stream was closed (show info screen) 277 | else: 278 | log.info('Skipping Player[auto] camera address: (%s). Not accessible.' % cam_config.main_stream_url()) 279 | player_single = Player(i, '/home/haso/camviewer/no_signal.mp4', WIN_SINGLE, False) 280 | player_single.play() 281 | player_single.wait_to_finish() 282 | else: 283 | log.info('Skipping Player[auto] camera address: (%s). Not configured.' % cam_config.main_stream_url()) 284 | continue 285 | if not any_stream: 286 | log.info("Player[auto] stopped because no stream was accessible. Exiting...") 287 | break 288 | 289 | def stop_auto_cycle(self): 290 | self._cam_stop_user_request = True 291 | stop_single_omx_dbus() 292 | 293 | def handle_player_split(self): 294 | self._cam_stop_user_request = False 295 | cams_configs = self._info_collector_thread.cams_configs 296 | 297 | self._player_split = PlayerSplit(cams_configs) 298 | self._player_split.play() 299 | 300 | if self._cam_stop_user_request: 301 | log.info("Player[split] stopped manually. Done.") 302 | else: 303 | log.info("Player[split] exited by itself.") 304 | kill_all_omx_processes() 305 | 306 | def action_button_esc(self): 307 | log.info('Handle ESC - begin.') 308 | if fsm.current == STATE_STREAMING_SINGLE: 309 | self._stop_streaming_single() 310 | elif fsm.current == STATE_STREAMING_SPLIT: 311 | self._stop_streaming_split() 312 | elif fsm.current == STATE_STREAMING_AUTO: 313 | self._stop_streaming_auto() 314 | else: 315 | log.info('\tHandle ESC - skipped in state (%s).' % fsm.current) 316 | log.info('Handle ESC - end.') 317 | 318 | def action_handle_up(self): 319 | log.info('Handle UP - begin.') 320 | log.info(' - Simulating ESC button to stop whatever is currently streamed...') 321 | self.action_button_esc() 322 | full_reboot() 323 | log.info('Handle UP - end.') 324 | 325 | def action_handle_left(self): 326 | log.info('Handle LEFT - begin.') 327 | if fsm.current == STATE_SYSINFO: 328 | self._decrease_time() 329 | elif fsm.current == STATE_STREAMING_SINGLE: 330 | self._next_stream_single() 331 | else: 332 | log.info('\tHandle LEFT - skipped in state (%s).' % fsm.current) 333 | log.info('Handle LEFT - end.') 334 | 335 | def action_handle_right(self): 336 | log.info('Handle RIGHT - begin.') 337 | if fsm.current == STATE_SYSINFO: 338 | self._increase_time() 339 | elif fsm.current == STATE_STREAMING_SINGLE: 340 | self._next_stream_single() 341 | else: 342 | log.info('\tHandle RIGHT - skipped in state (%s).' % fsm.current) 343 | log.info('Handle RIGHT - end.') 344 | 345 | def action_button_down(self): 346 | log.info('Handle DOWN - begin.') 347 | if fsm.current == STATE_SYSINFO: 348 | self._change_mode() 349 | else: 350 | log.info('\tHandle DOWN - skipped in state (%s).' % fsm.current) 351 | log.info('Handle DOWN - end.') 352 | 353 | def action_handle_enter(self): 354 | log.info('Handle ENTER - begin.') 355 | if fsm.current == STATE_STREAMING_SINGLE: 356 | self._next_stream_single() 357 | elif fsm.current == STATE_SYSINFO: 358 | self._exit_sysinfo() 359 | else: 360 | log.info('\tHandle ENTER - skipped in state (%s).' % fsm.current) 361 | log.info('Handle ENTER - end.') 362 | 363 | def _exit_sysinfo(self): 364 | log.info('\tClosing SysInfo window to start streaming.') 365 | info_window.close() 366 | 367 | def _change_mode(self): 368 | log.info('Current mode: (%s).' % self._mode) 369 | if self._mode == MODE_SINGLE: 370 | log.info('\tChanging mode to SPLIT.') 371 | self._set_mode(MODE_SPLIT) 372 | elif self._mode == MODE_SPLIT: 373 | log.info('\tChanging mode to AUTO.') 374 | self._set_mode(MODE_AUTO) 375 | elif self._mode == MODE_AUTO: 376 | log.info('\tChanging mode to SINGLE.') 377 | self._set_mode(MODE_SINGLE) 378 | else: 379 | log.info('Invalid mode detected. Skipping btn.') 380 | 381 | def _next_stream_single(self): 382 | log.info('\tStopping OMXplayer to go to next cam.') 383 | self._cam_stop_user_request = True 384 | stop_single_omx_dbus() 385 | 386 | def _stop_streaming_single(self): 387 | log.info('\tStopping streaming[single] to show sys info.') 388 | self._streaming = False 389 | stop_single_omx_dbus() 390 | 391 | def _stop_streaming_split(self): 392 | log.info('\tStopping streaming[split] to show sys info.') 393 | self._player_split.disable_auto_restart() 394 | self._streaming = False 395 | self._cam_stop_user_request = True 396 | kill_all_omx_processes() 397 | 398 | def _stop_streaming_auto(self): 399 | log.info('\tStopping streaming[auto] to show sys info.') 400 | self._streaming = False 401 | stop_single_omx_dbus() 402 | 403 | def _decrease_time(self): 404 | if self._cycle_time > 1200: 405 | self._cycle_time -= 600 406 | elif self._cycle_time > 300: 407 | self._cycle_time -= 60 408 | elif self._cycle_time > 120: 409 | self._cycle_time -= 30 410 | elif self._cycle_time > 60: 411 | self._cycle_time -= 15 412 | elif self._cycle_time > 30: 413 | self._cycle_time -= 10 414 | elif self._cycle_time > CYCLE_TIME_DEFAULT: 415 | self._cycle_time -= 5 416 | 417 | self._set_mode(self._mode) # Update mode information 418 | 419 | def _increase_time(self): 420 | if self._cycle_time < 30: 421 | self._cycle_time += 5 422 | elif self._cycle_time < 60: 423 | self._cycle_time += 10 424 | elif self._cycle_time < 120: 425 | self._cycle_time += 15 426 | elif self._cycle_time < 300: 427 | self._cycle_time += 30 428 | elif self._cycle_time < 1200: 429 | self._cycle_time += 60 430 | elif self._cycle_time < CYCLE_TIME_MAX_INCR: 431 | self._cycle_time += 600 432 | 433 | self._set_mode(self._mode) # Update mode information 434 | 435 | 436 | def main(): 437 | log.info("Starting CAMVIEWER as (%s)..." % getpass.getuser()) 438 | log.info('Working dir (%s)' % os.system('pwd')) 439 | log.info('Disabling screensaver result (%s)' % os.system('%s %s %s' % ('xset', 's', 'off'))) 440 | log.info('Setting screensaver noblank result (%s)' % os.system('%s %s %s' % ('xset', 's', 'noblank'))) 441 | log.info('Disabling DPMS result (%s)' % os.system('%s %s' % ('xset', '-dpms'))) 442 | 443 | cam_config_exists = os.path.isfile(CFG_CAM_IP_FILENAME) 444 | if cam_config_exists: 445 | pass 446 | else: 447 | log.info("Cameras not configured. Creating an empty config file...") 448 | with open(CFG_CAM_IP_FILENAME, "w+") as f: 449 | f.write(EMPTY_CONFIG_CONTENT) 450 | f.close() 451 | 452 | camviewer = Camviewer() 453 | camviewer.main_control_loop() 454 | log.info("Camviewer mainloop finished.") 455 | exit(0) 456 | 457 | 458 | if __name__ == "__main__": 459 | main() 460 | -------------------------------------------------------------------------------- /root/home/haso/camviewer/cfgviewer/cfgpanel/views.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | # Copyright (C) 2016. Haso S.C. J. Macioszek & A. Paszek 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | import re 16 | import socket 17 | import subprocess 18 | 19 | from django.shortcuts import render 20 | 21 | from config_utils import parse_interfaces_cfg, parse_cam_config, CAM_TYPE_HASO_KG1 22 | from constants import CFG_PATH, ADMIN_PASS, ERR_MSG_DETAILS, ERR_MSG_VALIDATION, REGEX_IP_FORMAT, REQUIRED_FORMAT_IP_ADDRESS, REGEX_IP_ADDRESS, KEYWORD_ADDRESS, KEYWORD_NETMASK 23 | from constants import CFG_SERIAL_FILENAME, CFG_MON_IP_FILENAME, DEFAULT_SERIAL, MON_ADDRESS_NOT_CONFIGURED, MON_NETMASK_NOT_CONFIGURED, CFG_CAM_IP_FILENAME 24 | from utils import replace, btn_esc 25 | 26 | 27 | def is_valid_ip(addr): 28 | try: 29 | socket.inet_aton(addr) 30 | return True 31 | except socket.error: 32 | return False 33 | 34 | 35 | def index(request): 36 | # read current configuration value 37 | try: 38 | cfg_mon_file = open(CFG_PATH + CFG_MON_IP_FILENAME) 39 | str_mon = cfg_mon_file.read() 40 | 41 | current_mon_address, current_mon_netmask = parse_interfaces_cfg(str_mon) 42 | except IOError: 43 | current_mon_address, current_mon_netmask = MON_ADDRESS_NOT_CONFIGURED, MON_NETMASK_NOT_CONFIGURED 44 | 45 | cam_config_entry = parse_cam_config(CFG_PATH + CFG_CAM_IP_FILENAME) 46 | 47 | print 'Current config loaded.' 48 | 49 | current_cam_address1 = cam_config_entry[0].address 50 | current_cam_address2 = cam_config_entry[1].address 51 | current_cam_address3 = cam_config_entry[2].address 52 | current_cam_address4 = cam_config_entry[3].address 53 | 54 | current_cam_port1 = cam_config_entry[0].port 55 | current_cam_port2 = cam_config_entry[1].port 56 | current_cam_port3 = cam_config_entry[2].port 57 | current_cam_port4 = cam_config_entry[3].port 58 | 59 | current_cam_stream_m1 = cam_config_entry[0].stream_m 60 | current_cam_stream_m2 = cam_config_entry[1].stream_m 61 | current_cam_stream_m3 = cam_config_entry[2].stream_m 62 | current_cam_stream_m4 = cam_config_entry[3].stream_m 63 | 64 | current_cam_stream_s1 = cam_config_entry[0].stream_s 65 | current_cam_stream_s2 = cam_config_entry[1].stream_s 66 | current_cam_stream_s3 = cam_config_entry[2].stream_s 67 | current_cam_stream_s4 = cam_config_entry[3].stream_s 68 | 69 | current_cam_user1 = cam_config_entry[0].user 70 | current_cam_user2 = cam_config_entry[1].user 71 | current_cam_user3 = cam_config_entry[2].user 72 | current_cam_user4 = cam_config_entry[3].user 73 | 74 | current_cam_pass1 = cam_config_entry[0].password 75 | current_cam_pass2 = cam_config_entry[1].password 76 | current_cam_pass3 = cam_config_entry[2].password 77 | current_cam_pass4 = cam_config_entry[3].password 78 | 79 | current_cam_type1 = cam_config_entry[0].cam_type 80 | current_cam_type2 = cam_config_entry[1].cam_type 81 | current_cam_type3 = cam_config_entry[2].cam_type 82 | current_cam_type4 = cam_config_entry[3].cam_type 83 | 84 | print 'Current config data fetched.' 85 | 86 | # read new values from request and validate them (only if changed) 87 | 88 | new_mon_address = request.POST.get('new_mon_address', current_mon_address) 89 | new_mon_netmask = request.POST.get('new_mon_netmask', current_mon_netmask) 90 | 91 | new_cam_address1 = request.POST.get('new_cam_address1', current_cam_address1) 92 | new_cam_address2 = request.POST.get('new_cam_address2', current_cam_address2) 93 | new_cam_address3 = request.POST.get('new_cam_address3', current_cam_address3) 94 | new_cam_address4 = request.POST.get('new_cam_address4', current_cam_address4) 95 | 96 | new_cam_port1 = request.POST.get('new_cam_port1', current_cam_port1) 97 | new_cam_port2 = request.POST.get('new_cam_port2', current_cam_port2) 98 | new_cam_port3 = request.POST.get('new_cam_port3', current_cam_port3) 99 | new_cam_port4 = request.POST.get('new_cam_port4', current_cam_port4) 100 | 101 | new_cam_stream_m1 = request.POST.get('new_cam_stream_m1', current_cam_stream_m1) 102 | new_cam_stream_m2 = request.POST.get('new_cam_stream_m2', current_cam_stream_m2) 103 | new_cam_stream_m3 = request.POST.get('new_cam_stream_m3', current_cam_stream_m3) 104 | new_cam_stream_m4 = request.POST.get('new_cam_stream_m4', current_cam_stream_m4) 105 | 106 | new_cam_stream_s1 = request.POST.get('new_cam_stream_s1', current_cam_stream_s1) 107 | new_cam_stream_s2 = request.POST.get('new_cam_stream_s2', current_cam_stream_s2) 108 | new_cam_stream_s3 = request.POST.get('new_cam_stream_s3', current_cam_stream_s3) 109 | new_cam_stream_s4 = request.POST.get('new_cam_stream_s4', current_cam_stream_s4) 110 | 111 | new_cam_user1 = request.POST.get('new_cam_user1', current_cam_user1) 112 | new_cam_user2 = request.POST.get('new_cam_user2', current_cam_user2) 113 | new_cam_user3 = request.POST.get('new_cam_user3', current_cam_user3) 114 | new_cam_user4 = request.POST.get('new_cam_user4', current_cam_user4) 115 | 116 | new_cam_pass1 = request.POST.get('new_cam_pass1', current_cam_pass1) 117 | new_cam_pass2 = request.POST.get('new_cam_pass2', current_cam_pass2) 118 | new_cam_pass3 = request.POST.get('new_cam_pass3', current_cam_pass3) 119 | new_cam_pass4 = request.POST.get('new_cam_pass4', current_cam_pass4) 120 | 121 | new_cam_type1 = request.POST.get('new_cam_type1', current_cam_type1) 122 | new_cam_type2 = request.POST.get('new_cam_type2', current_cam_type2) 123 | new_cam_type3 = request.POST.get('new_cam_type3', current_cam_type3) 124 | new_cam_type4 = request.POST.get('new_cam_type4', current_cam_type4) 125 | 126 | new_serial_number = request.POST.get('new_serial_number', '') 127 | 128 | admin_password = request.POST.get('admin_password', '') 129 | if new_serial_number != '' and admin_password == ADMIN_PASS: 130 | with open(CFG_PATH + CFG_SERIAL_FILENAME, 'w+') as f: 131 | f.write(new_serial_number.strip()) 132 | op_status = u'Zmieniono numer seryjny.' 133 | elif new_serial_number != '' and admin_password != ADMIN_PASS: 134 | op_status = u'Niepoprawne hasło serwisowe.' 135 | else: 136 | op_status = '' 137 | 138 | redirect_address = '' 139 | info_mon_address = '' 140 | info_mon_netmask = '' 141 | 142 | info_cam_data1 = '' 143 | info_cam_data2 = '' 144 | info_cam_data3 = '' 145 | info_cam_data4 = '' 146 | 147 | info_serial_number = '' 148 | 149 | change_mon_address = False 150 | change_mon_netmask = False 151 | change_cam_address = False 152 | reboot_needed = False 153 | 154 | if new_mon_address != current_mon_address: 155 | if re.match(REGEX_IP_ADDRESS, new_mon_address) and is_valid_ip(new_mon_address): 156 | change_mon_address = True 157 | else: 158 | info_mon_address = ERR_MSG_DETAILS % ('IP monitora', new_mon_address, REQUIRED_FORMAT_IP_ADDRESS) 159 | op_status = ERR_MSG_VALIDATION 160 | if new_mon_netmask != current_mon_netmask: 161 | if re.match(REGEX_IP_ADDRESS, new_mon_netmask) and is_valid_ip(new_mon_netmask): 162 | change_mon_netmask = True 163 | else: 164 | info_mon_netmask = ERR_MSG_DETAILS % ('Maska monitora', new_mon_address, REQUIRED_FORMAT_IP_ADDRESS) 165 | op_status = ERR_MSG_VALIDATION 166 | 167 | # cameras addresses 168 | if new_cam_address1 != current_cam_address1 \ 169 | or new_cam_port1 != current_cam_port1 \ 170 | or new_cam_stream_m1 != current_cam_stream_m1 \ 171 | or new_cam_stream_s1 != current_cam_stream_s1 \ 172 | or new_cam_user1 != current_cam_user1 \ 173 | or new_cam_pass1 != current_cam_pass1 \ 174 | or new_cam_type1 != current_cam_type1: 175 | 176 | if is_valid_ip_field_value(new_cam_address1): 177 | change_cam_address = True 178 | else: 179 | info_cam_data1 = ERR_MSG_DETAILS % ('IP kamery 1', new_cam_address1, REQUIRED_FORMAT_IP_ADDRESS) 180 | op_status = ERR_MSG_VALIDATION 181 | 182 | if new_cam_address2 != current_cam_address2 \ 183 | or new_cam_port2 != current_cam_port2 \ 184 | or new_cam_stream_m2 != current_cam_stream_m2 \ 185 | or new_cam_stream_s2 != current_cam_stream_s2 \ 186 | or new_cam_user2 != current_cam_user2 \ 187 | or new_cam_pass2 != current_cam_pass2 \ 188 | or new_cam_type2 != current_cam_type2: 189 | 190 | if is_valid_ip_field_value(new_cam_address2): 191 | change_cam_address = True 192 | else: 193 | info_cam_data2 = ERR_MSG_DETAILS % ('IP kamery 2', new_cam_address2, REQUIRED_FORMAT_IP_ADDRESS) 194 | op_status = ERR_MSG_VALIDATION 195 | 196 | if new_cam_address3 != current_cam_address3 \ 197 | or new_cam_port3 != current_cam_port3 \ 198 | or new_cam_stream_m3 != current_cam_stream_m3 \ 199 | or new_cam_stream_s3 != current_cam_stream_s3 \ 200 | or new_cam_user3 != current_cam_user3 \ 201 | or new_cam_pass3 != current_cam_pass3 \ 202 | or new_cam_type3 != current_cam_type3: 203 | 204 | if is_valid_ip_field_value(new_cam_address3): 205 | change_cam_address = True 206 | else: 207 | info_cam_data3 = ERR_MSG_DETAILS % ('IP kamery 3', new_cam_address3, REQUIRED_FORMAT_IP_ADDRESS) 208 | op_status = ERR_MSG_VALIDATION 209 | 210 | if new_cam_address4 != current_cam_address4 \ 211 | or new_cam_port4 != current_cam_port4 \ 212 | or new_cam_stream_m4 != current_cam_stream_m4 \ 213 | or new_cam_stream_s4 != current_cam_stream_s4 \ 214 | or new_cam_user4 != current_cam_user4 \ 215 | or new_cam_pass4 != current_cam_pass4 \ 216 | or new_cam_type4 != current_cam_type4: 217 | 218 | if is_valid_ip_field_value(new_cam_address4): 219 | change_cam_address = True 220 | else: 221 | info_cam_data4 = ERR_MSG_DETAILS % ('IP kamery 4', new_cam_address4, REQUIRED_FORMAT_IP_ADDRESS) 222 | op_status = ERR_MSG_VALIDATION 223 | 224 | # update current values 225 | if op_status == '': 226 | print 'Checking current values...' 227 | if change_mon_address: 228 | replace(CFG_PATH + CFG_MON_IP_FILENAME, r'%s %s' % (KEYWORD_ADDRESS, REGEX_IP_FORMAT), KEYWORD_ADDRESS + ' ' + new_mon_address.strip()) 229 | reboot_needed = True 230 | redirect_address = new_mon_address # after reboot user should be redirected to the new address he set 231 | new_mon_address = '' 232 | 233 | if change_mon_netmask: 234 | replace(CFG_PATH + CFG_MON_IP_FILENAME, r'%s %s' % (KEYWORD_NETMASK, REGEX_IP_FORMAT), KEYWORD_NETMASK + ' ' + new_mon_netmask.strip()) 235 | reboot_needed = True 236 | new_mon_netmask = '' 237 | 238 | if change_cam_address: 239 | with open(CFG_PATH + CFG_CAM_IP_FILENAME, 'w+') as f: 240 | f.write('%s|%s|%s|%s|%s|%s|%s\n' % ( 241 | new_cam_address1.strip(), port_check(new_cam_port1), new_cam_stream_m1.strip(), new_cam_stream_s1.strip(), new_cam_user1.strip(), new_cam_pass1.strip(), new_cam_type1.strip())) 242 | f.write('%s|%s|%s|%s|%s|%s|%s\n' % ( 243 | new_cam_address2.strip(), port_check(new_cam_port2), new_cam_stream_m2.strip(), new_cam_stream_s2.strip(), new_cam_user2.strip(), new_cam_pass2.strip(), new_cam_type2.strip())) 244 | f.write('%s|%s|%s|%s|%s|%s|%s\n' % ( 245 | new_cam_address3.strip(), port_check(new_cam_port3), new_cam_stream_m3.strip(), new_cam_stream_s3.strip(), new_cam_user3.strip(), new_cam_pass3.strip(), new_cam_type3.strip())) 246 | f.write('%s|%s|%s|%s|%s|%s|%s\n' % ( 247 | new_cam_address4.strip(), port_check(new_cam_port4), new_cam_stream_m4.strip(), new_cam_stream_s4.strip(), new_cam_user4.strip(), new_cam_pass4.strip(), new_cam_type4.strip())) 248 | f.close() 249 | 250 | new_cam_address1 = '' 251 | new_cam_address2 = '' 252 | new_cam_address3 = '' 253 | new_cam_address4 = '' 254 | 255 | new_cam_port1 = '' 256 | new_cam_port2 = '' 257 | new_cam_port3 = '' 258 | new_cam_port4 = '' 259 | 260 | new_cam_stream_m1 = '' 261 | new_cam_stream_m2 = '' 262 | new_cam_stream_m3 = '' 263 | new_cam_stream_m4 = '' 264 | 265 | new_cam_stream_s1 = '' 266 | new_cam_stream_s2 = '' 267 | new_cam_stream_s3 = '' 268 | new_cam_stream_s4 = '' 269 | 270 | new_cam_user1 = '' 271 | new_cam_user2 = '' 272 | new_cam_user3 = '' 273 | new_cam_user4 = '' 274 | 275 | new_cam_pass1 = '' 276 | new_cam_pass2 = '' 277 | new_cam_pass3 = '' 278 | new_cam_pass4 = '' 279 | 280 | new_cam_type1 = CAM_TYPE_HASO_KG1 281 | new_cam_type2 = CAM_TYPE_HASO_KG1 282 | new_cam_type3 = CAM_TYPE_HASO_KG1 283 | new_cam_type4 = CAM_TYPE_HASO_KG1 284 | 285 | btn_esc() # emulates ESC button pressed - exits from streaming to configuration view 286 | 287 | # read new values and send to view 288 | try: 289 | cfg_mon_file = open(CFG_PATH + CFG_MON_IP_FILENAME) 290 | str_mon = cfg_mon_file.read() 291 | current_mon_address, current_mon_netmask = parse_interfaces_cfg(str_mon) 292 | print 'New monitor config values: (%s) (%s)' % (current_mon_address, current_mon_netmask) 293 | except IOError: 294 | current_mon_address, current_mon_netmask = MON_ADDRESS_NOT_CONFIGURED, MON_NETMASK_NOT_CONFIGURED 295 | 296 | cam_config_entry = parse_cam_config(CFG_PATH + CFG_CAM_IP_FILENAME) 297 | 298 | print 'New config loaded.' 299 | 300 | current_cam_address1 = cam_config_entry[0].address 301 | current_cam_address2 = cam_config_entry[1].address 302 | current_cam_address3 = cam_config_entry[2].address 303 | current_cam_address4 = cam_config_entry[3].address 304 | 305 | current_cam_port1 = cam_config_entry[0].port 306 | current_cam_port2 = cam_config_entry[1].port 307 | current_cam_port3 = cam_config_entry[2].port 308 | current_cam_port4 = cam_config_entry[3].port 309 | 310 | current_cam_stream_m1 = cam_config_entry[0].stream_m 311 | current_cam_stream_m2 = cam_config_entry[1].stream_m 312 | current_cam_stream_m3 = cam_config_entry[2].stream_m 313 | current_cam_stream_m4 = cam_config_entry[3].stream_m 314 | 315 | current_cam_stream_s1 = cam_config_entry[0].stream_s 316 | current_cam_stream_s2 = cam_config_entry[1].stream_s 317 | current_cam_stream_s3 = cam_config_entry[2].stream_s 318 | current_cam_stream_s4 = cam_config_entry[3].stream_s 319 | 320 | current_cam_user1 = cam_config_entry[0].user 321 | current_cam_user2 = cam_config_entry[1].user 322 | current_cam_user3 = cam_config_entry[2].user 323 | current_cam_user4 = cam_config_entry[3].user 324 | 325 | current_cam_pass1 = cam_config_entry[0].password 326 | current_cam_pass2 = cam_config_entry[1].password 327 | current_cam_pass3 = cam_config_entry[2].password 328 | current_cam_pass4 = cam_config_entry[3].password 329 | 330 | current_cam_type1 = cam_config_entry[0].cam_type 331 | current_cam_type2 = cam_config_entry[1].cam_type 332 | current_cam_type3 = cam_config_entry[2].cam_type 333 | current_cam_type4 = cam_config_entry[3].cam_type 334 | 335 | print 'New config data fetched.' 336 | 337 | try: 338 | cfg_serial_file = open(CFG_PATH + CFG_SERIAL_FILENAME) 339 | current_serial_number = cfg_serial_file.read() 340 | except IOError: 341 | current_serial_number = DEFAULT_SERIAL 342 | 343 | # return to same page to set new values or display message 344 | context = { 345 | 'current_mon_address': current_mon_address.strip(), 346 | 'current_mon_netmask': current_mon_netmask.strip(), 347 | 348 | 'current_cam_address1': current_cam_address1.strip(), 349 | 'current_cam_address2': current_cam_address2.strip(), 350 | 'current_cam_address3': current_cam_address3.strip(), 351 | 'current_cam_address4': current_cam_address4.strip(), 352 | 353 | 'current_cam_port1': current_cam_port1.strip(), 354 | 'current_cam_port2': current_cam_port2.strip(), 355 | 'current_cam_port3': current_cam_port3.strip(), 356 | 'current_cam_port4': current_cam_port4.strip(), 357 | 358 | 'current_cam_stream_m1': current_cam_stream_m1.strip(), 359 | 'current_cam_stream_m2': current_cam_stream_m2.strip(), 360 | 'current_cam_stream_m3': current_cam_stream_m3.strip(), 361 | 'current_cam_stream_m4': current_cam_stream_m4.strip(), 362 | 363 | 'current_cam_stream_s1': current_cam_stream_s1.strip(), 364 | 'current_cam_stream_s2': current_cam_stream_s2.strip(), 365 | 'current_cam_stream_s3': current_cam_stream_s3.strip(), 366 | 'current_cam_stream_s4': current_cam_stream_s4.strip(), 367 | 368 | 'current_cam_user1': current_cam_user1.strip(), 369 | 'current_cam_user2': current_cam_user2.strip(), 370 | 'current_cam_user3': current_cam_user3.strip(), 371 | 'current_cam_user4': current_cam_user4.strip(), 372 | 373 | 'current_cam_pass1': current_cam_pass1.strip(), 374 | 'current_cam_pass2': current_cam_pass2.strip(), 375 | 'current_cam_pass3': current_cam_pass3.strip(), 376 | 'current_cam_pass4': current_cam_pass4.strip(), 377 | 378 | 'current_cam_type1': current_cam_type1.strip(), 379 | 'current_cam_type2': current_cam_type2.strip(), 380 | 'current_cam_type3': current_cam_type3.strip(), 381 | 'current_cam_type4': current_cam_type4.strip(), 382 | 383 | 'current_serial_number': current_serial_number.strip(), 384 | 'new_mon_address': new_mon_address.strip(), 385 | 'new_mon_netmask': new_mon_netmask.strip(), 386 | 387 | 'new_cam_address1': new_cam_address1.strip(), 388 | 'new_cam_address2': new_cam_address2.strip(), 389 | 'new_cam_address3': new_cam_address3.strip(), 390 | 'new_cam_address4': new_cam_address4.strip(), 391 | 392 | 'new_cam_port1': new_cam_port1.strip(), 393 | 'new_cam_port2': new_cam_port2.strip(), 394 | 'new_cam_port3': new_cam_port3.strip(), 395 | 'new_cam_port4': new_cam_port4.strip(), 396 | 397 | 'new_cam_stream_m1': new_cam_stream_m1.strip(), 398 | 'new_cam_stream_m2': new_cam_stream_m2.strip(), 399 | 'new_cam_stream_m3': new_cam_stream_m3.strip(), 400 | 'new_cam_stream_m4': new_cam_stream_m4.strip(), 401 | 402 | 'new_cam_stream_s1': new_cam_stream_s1.strip(), 403 | 'new_cam_stream_s2': new_cam_stream_s2.strip(), 404 | 'new_cam_stream_s3': new_cam_stream_s3.strip(), 405 | 'new_cam_stream_s4': new_cam_stream_s4.strip(), 406 | 407 | 'new_cam_user1': new_cam_user1.strip(), 408 | 'new_cam_user2': new_cam_user2.strip(), 409 | 'new_cam_user3': new_cam_user3.strip(), 410 | 'new_cam_user4': new_cam_user4.strip(), 411 | 412 | 'new_cam_pass1': new_cam_pass1.strip(), 413 | 'new_cam_pass2': new_cam_pass2.strip(), 414 | 'new_cam_pass3': new_cam_pass3.strip(), 415 | 'new_cam_pass4': new_cam_pass4.strip(), 416 | 417 | 'new_cam_type1': new_cam_type1.strip(), 418 | 'new_cam_type2': new_cam_type2.strip(), 419 | 'new_cam_type3': new_cam_type3.strip(), 420 | 'new_cam_type4': new_cam_type4.strip(), 421 | 422 | 'info_mon_address': info_mon_address.strip(), 423 | 'info_mon_netmask': info_mon_netmask.strip(), 424 | 425 | 'info_cam_data1': info_cam_data1.strip(), 426 | 'info_cam_data2': info_cam_data2.strip(), 427 | 'info_cam_data3': info_cam_data3.strip(), 428 | 'info_cam_data4': info_cam_data4.strip(), 429 | 430 | 'info_serial_number': info_serial_number.strip(), 431 | 'redirect_address': redirect_address, 432 | 'op_status': op_status, 433 | } 434 | if reboot_needed: 435 | print 'Reboot required..' 436 | # Network interfaces and then cfgviewer server itself need to be reboot 437 | subprocess.call(['bash', 'reboot.sh']) # should fire after some delay and go asynchronously 438 | return render(request, 'cfgpanel/reboot.html', context) 439 | pass 440 | 441 | return render(request, 'cfgpanel/index.html', context) 442 | 443 | 444 | def port_check(port_val): 445 | port_val = port_val.strip() 446 | return port_val if port_val is not None and len(port_val) > 0 else 554 447 | 448 | 449 | def is_valid_ip_field_value(address_value): 450 | if address_value == '': 451 | return True 452 | 453 | return re.match(REGEX_IP_ADDRESS, address_value) and is_valid_ip(address_value) 454 | 455 | 456 | def service_input(request): 457 | mac_address = 'nieustalony' 458 | try: 459 | get_mac_cmd = "ifconfig | grep eth0:0 | awk '{print $5}'" 460 | sys_cmd_process = subprocess.Popen([get_mac_cmd], stdout=subprocess.PIPE, shell=True) 461 | (mac_address, err) = sys_cmd_process.communicate() 462 | if err: 463 | print 'ERROR while getting MAC address (%s).' % err 464 | except BaseException: 465 | pass 466 | print 'MAC address: (%s).' % mac_address 467 | 468 | context = { 469 | 'mac_address': str(mac_address).strip() 470 | } 471 | return render(request, 'cfgpanel/service_input.html', context) 472 | --------------------------------------------------------------------------------