From a675294ca4d4d2934022ad4245b5270c7d649d15 Mon Sep 17 00:00:00 2001 From: SvenVD Date: Sun, 3 May 2020 17:18:03 +0200 Subject: [PATCH 1/3] pull request SvenVD/rpisurv#100 basic touch screen control --- README.md | 7 +++++++ RELEASE_NOTES.md | 4 ++++ surveillance/core/util/draw.py | 32 ++++++++++++++++++++++++++++++-- surveillance/surveillance.py | 14 +++++++------- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2f38fa8..1a3d9f1 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,13 @@ Keys F1 to F12 (or keypad 0 to 9), will force the equal numbered screen to be sh Disable rotation (as in pause rotation, as in fix the current displayed screen) dynamically during runtime. By pressing "p" (or keypad "*") to pause or "r" (or "," or keypad ".")' to resume/rotate. This overrides the disable_autorotation option if this has been set in the config file. +Touchscreen control: +The width of the screen is divided in four sections, +- Touching on the first section trigger a pause event. +- Touching In the two sections in the middle trigger a resume event. +- Touching In the last section, a next screen event. +Note that a mouse can be used, however mouse cursor is hidden by default. + ## Troubleshooting diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9773021..71d6da6 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,4 +1,8 @@ # rpisurv 2 release notes +## Changes in 2.1.8 +[nicolake](https://github.com/SvenVD/rpisurv/pull/100) provided some code to be able for touch screens to control rpisurv with basic commands. +This has been incorporated into rpisurv. + ## Changes in 2.1.7 Http probe did not handle all exceptions which could crash rpisurv on rare occasions like described in the [link](https://www.tapatalk.com/groups/rpisurv/viewtopic.php?p=339#p339). Fixed by inserting a fallback exception handler in the http probe logic. diff --git a/surveillance/core/util/draw.py b/surveillance/core/util/draw.py index 921f310..e72b9a9 100644 --- a/surveillance/core/util/draw.py +++ b/surveillance/core/util/draw.py @@ -27,7 +27,7 @@ def placeholder(absposx,absposy,width,height,background_img_path,surface): refresh() return background_img -def check_keypress(): +def check_input(): try: for event in pygame.event.get(): if event.type == pygame.KEYDOWN: @@ -53,8 +53,36 @@ def check_keypress(): return numeric_key_counter else: return None + + + # Touch screen handling + # the width of the screen is divided in four sections, + # touching or clicking on the first section trigger a pause event, + # in the two sections in the middle trigger a resume event + # and in the last section, a next screen event. + elif event.type == pygame.MOUSEBUTTONUP: + #For debug set_visible(True) + #pygame.mouse.set_visible(True) + logger.debug("draw: pygame.MOUSEBUTTONUP detected") + pos = pygame.mouse.get_pos() + display_w = pygame.display.Info().current_w + logger.debug("draw touch/mouse handling: pygame detected display width of " + str(display_w)) + quarter = display_w / 4 + firstQuarter = quarter + lastQuarter = display_w - quarter + logger.debug("draw touch/mouse handling: firstQuarter " + str(firstQuarter) + " and lastquarter " + str(lastQuarter)) + if pos[0] > lastQuarter: + logger.debug("draw touch/mouse handling: detected touch/mouse in lastquarter") + touchResult = "next_event" + elif pos[0] > firstQuarter and pos[0] < lastQuarter: + logger.debug("draw touch/mouse handling: detected touch/mouse in middle") + touchResult = "resume_rotation" + else: + logger.debug("draw touch/mouse handling: detected touch/mouse in first quarter") + touchResult = "pause_rotation" + return touchResult except pygame.error as e: - logger.debug("Exception " + repr(e)) + logger.debug("draw: Exception " + repr(e)) exit(0) def refresh(): diff --git a/surveillance/surveillance.py b/surveillance/surveillance.py index 9680453..9c26f0f 100644 --- a/surveillance/surveillance.py +++ b/surveillance/surveillance.py @@ -81,11 +81,11 @@ def sigterm_handler(_signo, _stack_frame): sys.exit(0) -def handle_keypresses(): +def handle_input(): global disable_autorotation - event = draw.check_keypress() + event = draw.check_input() if event == "next_event": - logger.debug("Main: force next screen keyboard event detected, start rotate_next event") + logger.debug("Main: force next screen input event detected, start rotate_next event") screen_manager_main.rotate_next() # This can do not harm, but is not really needed in this case, since the screen was already updated in cache and we merely swap it on screen as is. # We do not check update_connectable_cameras this time as this is to slow for the user to wait for and we live with the fact if there is one unavailable or one became available since cache time, @@ -93,7 +93,7 @@ def handle_keypresses(): # logger.debug("MAIN: after keyboard next_event start update_active_screen with skip_update_connectable_camera true") # screen_manager_main.update_active_screen(skip_update_connectable_camera = True) if event == "end_event": - logger.debug("Main: quit_on_keyboard event detected") + logger.debug("Main: quit input event detected") screen_manager_main.destroy() if event == "resume_rotation": logger.debug("Main: resume_rotation event detected") @@ -112,7 +112,7 @@ def handle_keypresses(): #Setup logger logger = setup_logging() - fullversion_for_installer = "2.1.7" + fullversion_for_installer = "2.1.8" version = fullversion_for_installer logger.info("Starting rpisurv " + version) @@ -159,7 +159,7 @@ def handle_keypresses(): loop_counter += 1 #Handle keypresses - handle_keypresses() + handle_input() #Check free mem and log warning if memory_usage_check: @@ -174,7 +174,7 @@ def handle_keypresses(): screen_manager_main.update_active_screen() else: - logger.debug("MAIN: disable_autorotation is True, use keyboard only to rotate between screens") + logger.debug("MAIN: disable_autorotation is True, use input keyboard/mouse/touch only to rotate between screens") #Only update the screen/check connectable cameras every interval_check_status seconds if loop_counter % int(interval_check_status) == 0: From 287a1f79ff520372ea081351e75d65125a3d4017 Mon Sep 17 00:00:00 2001 From: SvenVD Date: Wed, 14 Oct 2020 01:14:13 +0200 Subject: [PATCH 2/3] Introduce force_coordinates feature --- README.md | 2 +- RELEASE_NOTES.md | 4 ++++ surveillance/conf/surveillance.yml | 18 ++++++++++++++++-- surveillance/core/CameraStream.py | 8 +++++++- surveillance/surveillance.py | 2 +- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1a3d9f1..afb23d4 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ If you like this software please consider donating: See [RELEASE_NOTES](https://github.com/SvenVD/rpisurv/blob/master/RELEASE_NOTES.md) ## Goal -Rpisurv is designed to be simple to use (no need to fiddle with coordinates or detailed layout configs) and to be able to run unattended for long periods of time. Therefore watchdogs and autohealing logic have been implemented. +Rpisurv is designed to be simple to use (no need to fiddle with coordinates or detailed layout configs, although you [can](https://gist.github.com/SvenVD/0cb1a40261b7c7f2d4cffac24dc9181d) if you really want) and to be able to run unattended for long periods of time. Therefore watchdogs and autohealing logic have been implemented. Version 2 adds functionality to define multiple screens which can be cycled between. ## Description diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 71d6da6..8ac52cb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,4 +1,8 @@ # rpisurv 2 release notes +## Changes in 2.1.9 +A long requested feature [link](https://www.tapatalk.com/groups/rpisurv/grid-lay-out-show-one-stream-bigger-then-others-t5.html) has now finally made it to rpisurv. +Instead of letting rpisurv calculate the layout for you, you can now create complex custom layouts yourself. [Examples click here](https://gist.github.com/SvenVD/0cb1a40261b7c7f2d4cffac24dc9181d) + ## Changes in 2.1.8 [nicolake](https://github.com/SvenVD/rpisurv/pull/100) provided some code to be able for touch screens to control rpisurv with basic commands. This has been incorporated into rpisurv. diff --git a/surveillance/conf/surveillance.yml b/surveillance/conf/surveillance.yml index 2c4a3c9..41330a2 100644 --- a/surveillance/conf/surveillance.yml +++ b/surveillance/conf/surveillance.yml @@ -42,15 +42,27 @@ essentials: #Optional: aidx: this is a one to one mapping with the omxplayer aidx (Audio stream index) option, the default for rpisurv is the value -1 (audio disabled). #To enable audio for this stream try setting this to 1. You do not have to set this option if you do not want audio, the default is -1 aidx: -1 + #Optional and advanced option: force_coordinates: If you are not happy with the pre-calculated position on the screen of a particular stream then you can override it with this option + #Note: Once you do this, the layout of this particular screen becomes the responsability of the user + #Note2: rpisurv will continue to draw other streams with the pre-calculated values if they do not have force_coordinates set. + #Remember that rpisurv autocalculation can be influenced by nr_of_columns option + #This can cause overlap with other streams but the user can correct this by manually calculating and setting the position of the other camera streams with force_coordinates + #Note2: You can also put camera streams on top of each other if you use this option and a combination of freeform_advanced_omxplayer_options: "--layer 1000" + #Note3: This works transparently with rotation of screens, every screen can have a different layout + #force_coordinates: [upperleft corner x position, upperleft corner y position, downright corner x position, downright corner y position] + #Minimal example see here: https://gist.github.com/SvenVD/0cb1a40261b7c7f2d4cffac24dc9181d + force_coordinates: [0, 800, 600, 1080] + #Foscam-fi9821w example - url: "rtsp://:@:/videoMain" #Dahua IPC-HDW4200S example or IPC-HDW4300S - url: "rtsp://:@:/cam/realmonitor?channel=1&subtype=1" #OPTIONAL AND ADVANCED PER SCREEN OPTIONS, YOU CAN CONFIGURE THIS PER SCREEN, IF NOT CONFIGURED A DEFAULT VALUE WILL BE USED - #NOT recommendeded to enable disable_probing_for_all_streams, it disables some autohealing functions of rpisurv + #NOT recommendeded to enable disable_probing_for_all_streams, it disables the removal of dead feeds which also disables auto-rearranging the screen layout. #Also if using multiple screens, enabling this will slow down rotation of one screen to the next if there are unconnectable screens - #This also disabled rpisurv only drawing the connectable screens using up all pixels. In other words, you will get a placeholder for an unconnectable stream instead of not showing at all + #This also disables rpisurv only drawing the connectable screens using up all pixels. + #In other words, you will get a placeholder for an unconnectable stream instead of not showing at all #Roughly the same as the obsoleted keep_first_screen_layout in rpisurv v1.0 #Defaults to False disable_probing_for_all_streams: False @@ -110,11 +122,13 @@ advanced: ##Enable this option if you want to have a fixed width of all your camera streams, ##By default rpisurv autocalculates this value, this can cause streams to get "stretched", ##if this value exceeds the available width, rpisurv will fallback to autocalculation + ##Note, this value will be ignored for a stream that uses force_coordinates #fixed_width: 500 ##Enable this option if you want to have a fixed height for all your camera streams, ##By default rpisurv autocalculates this value, this can cause streams to get "stretched", ##if this value exceeds the available height, rpisurv will fallback to autocalculation + ##Note, this value will be ignored for a stream that uses force_coordinates #fixed_height: 500 #Rpisurv sends usage stats to it's statistics server to give the rpisurv community an idea how widespread this software is being used diff --git a/surveillance/core/CameraStream.py b/surveillance/core/CameraStream.py index 7258ff4..acd967b 100644 --- a/surveillance/core/CameraStream.py +++ b/surveillance/core/CameraStream.py @@ -27,6 +27,8 @@ def __init__(self, name, camera_stream): self.name = name self.worker = None self.omxplayer_extra_options = "" + #This option overrides any other coordinates passed to this stream + self.force_coordinates=camera_stream.setdefault("force_coordinates", False) self.freeform_advanced_omxplayer_options = camera_stream.setdefault("freeform_advanced_omxplayer_options","") self.probe_timeout = camera_stream.setdefault("probe_timeout",3) self.imageurl = camera_stream.setdefault("imageurl", False) @@ -212,7 +214,11 @@ def refresh_image_from_url(self): logger.debug("CameraStream: This stream " + self.name + " is not an imageurl, skip refreshing imageurl") def start_stream(self, coordinates, pygamescreen, cached): - self.coordinates=coordinates + if self.force_coordinates and not cached: + logger.debug("CameraStream: This stream " + self.name + " uses force_coordinates " + str(self.force_coordinates) + " which will override pre-calculated coordinates of " + str(coordinates) ) + self.coordinates = self.force_coordinates + else: + self.coordinates=coordinates self.pygamescreen=pygamescreen logger.debug("CameraStream: Start stream " + self.name) diff --git a/surveillance/surveillance.py b/surveillance/surveillance.py index 9c26f0f..dfdf77c 100644 --- a/surveillance/surveillance.py +++ b/surveillance/surveillance.py @@ -112,7 +112,7 @@ def handle_input(): #Setup logger logger = setup_logging() - fullversion_for_installer = "2.1.8" + fullversion_for_installer = "2.1.9" version = fullversion_for_installer logger.info("Starting rpisurv " + version) From 7c18766030b8413a5a79a49868ebb3d97d64ef49 Mon Sep 17 00:00:00 2001 From: SvenVD Date: Sun, 18 Oct 2020 10:37:41 +0200 Subject: [PATCH 3/3] Enhance installer (https://www.tapatalk.com/groups/rpisurv/not-to-overwrite-the-placeholder-images-while-upda-t75.html) --- install.sh | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/install.sh b/install.sh index 0326588..55c303b 100755 --- a/install.sh +++ b/install.sh @@ -76,20 +76,37 @@ BACKUPCONFFILE=/tmp/surveillance.yml.$(date +%Y%m%d_%s) DESTPATH="/usr/local/bin/rpisurv" sudo mkdir -p "$DESTPATH" -if [ -f "$DESTPATH/$CONFFILE" ]; then sudo cp -v "$DESTPATH/$CONFFILE" "${BACKUPCONFFILE}";fi -echo -echo "Existing config file will be backed up to "${BACKUPCONFFILE}"" +if [ -f "$DESTPATH/$CONFFILE" ];then + echo + echo "Existing config file will be backed up to "${BACKUPCONFFILE}"" + sudo cp -v "$DESTPATH/$CONFFILE" "${BACKUPCONFFILE}" + + echo + echo "Do you want to overwrite your current config file with the example config file?" + echo "Newer major versions of rpisurv are not backwards compatible with old format of config file" + echo "Type yes/no" + read USEEXAMPLECONFIG +else + USEEXAMPLECONFIG="yes" +fi + +if [ -d /usr/local/bin/rpisurv/images/ ];then + echo + echo "Do you want to overwrite you current images directory (/usr/local/bin/rpisurv/images/) with the images from the installer?" + echo "Type yes/no" + read OVERWRITESIMAGES +else + OVERWRITESIMAGES="yes" +fi -echo -echo "Do you want to overwrite you current config file with the example config file?" -echo "Newer major versions of rpisurv are not backwards compatible with old format of config file" -echo "Type yes/no" -read ANSWER +if [ x"$OVERWRITESIMAGES" == x"no" ]; then + RSYNCOPTIONS="--exclude /images" +fi -sudo rsync -av "$SOURCEDIR/" "$DESTPATH/" +sudo rsync -av $RSYNCOPTIONS "$SOURCEDIR/" "$DESTPATH/" -if [ x"$ANSWER" == x"no" ]; then +if [ x"$USEEXAMPLECONFIG" == x"no" ]; then #Putting back old config file if [ -f "${BACKUPCONFFILE}" ]; then sudo cp -v "${BACKUPCONFFILE}" "$DESTPATH/$CONFFILE" ; fi fi