├── .dockerignore ├── .gitignore ├── .vscode └── launch.json ├── Dockerfile ├── LICENSE ├── README.md ├── config └── raspiCamSrv.service ├── docker-compose.yml ├── docs ├── API.md ├── Authentication.md ├── Background Processes.md ├── CameraControls.md ├── Configuration.md ├── Console.md ├── ConsoleActionButtons.md ├── ConsoleVButtons.md ├── FocusHandling.md ├── Information.md ├── LiveScreen.md ├── PhotoSeries.md ├── PhotoSeriesExp.md ├── PhotoSeriesFocus.md ├── PhotoSeriesTimelapse.md ├── PhotoViewer.md ├── Phototaking.md ├── ReleaseNotes.md ├── ScalerCrop.md ├── Settings.md ├── SettingsAButtons.md ├── SettingsAPI.md ├── SettingsConfiguration.md ├── SettingsDevices.md ├── SettingsUsers.md ├── SettingsVButtons.md ├── SetupDocker.md ├── Trigger.md ├── TriggerActions.md ├── TriggerActive.md ├── TriggerCameraActions.md ├── TriggerEventViewer.md ├── TriggerMotion.md ├── TriggerNotification.md ├── TriggerTriggerActions.md ├── TriggerTriggers.md ├── Troubelshooting.md ├── Tuning.md ├── UserGuide.md ├── Webcam.md ├── ZoomPan.md ├── api │ └── postman │ │ ├── raspiCamSrv.postman_collection.json │ │ └── raspiCamSrv.postman_collection.pdf ├── bp_Hotspot_Bookworm.md ├── bp_Hotspot_Bullseye.md ├── bp_PiZero_Standalone.md ├── gpioDevices │ └── StepperMotor.md ├── img │ ├── AFMessage.jpg │ ├── AFTrigger2.jpg │ ├── AFWindows1.jpg │ ├── AFWindows2.jpg │ ├── AFWindows3.jpg │ ├── API_Postman_collection.jpg │ ├── API_Postman_variables.jpg │ ├── Auth_Login.jpg │ ├── Auth_Password.jpg │ ├── Auth_RegisterInitial.jpg │ ├── Auth_UserManagement.jpg │ ├── Auth_UserManagement_old.jpg │ ├── AutoExposure.jpg │ ├── CameraStreamUsage.jpg │ ├── Config.jpg │ ├── Console.jpg │ ├── Console_AButtons.jpg │ ├── Console_AButtonsDeviceBusy.jpg │ ├── Console_VButtons.jpg │ ├── Console_VButtons_commandline.jpg │ ├── Console_VButtons_conf.jpg │ ├── Cropping_ScalerCrop_0.jpg │ ├── Cropping_ScalerCrop_2.jpg │ ├── Cropping_SensorModes.jpg │ ├── Exposure.jpg │ ├── Focus.jpg │ ├── Foto0.jpg │ ├── Foto1.jpg │ ├── FotoBuffer0.jpg │ ├── FotoBuffer1.jpg │ ├── FotoBuffer3.jpg │ ├── Image.jpg │ ├── Info-CamProps.jpg │ ├── Info-Cameras.jpg │ ├── Info-StreamingClients.jpg │ ├── Info_SensorMode.jpg │ ├── Live.jpg │ ├── Live0.jpg │ ├── Live_start.jpg │ ├── MetaHistogram.jpg │ ├── Metadata1.jpg │ ├── Metadata2.jpg │ ├── PhotoSeries4.jpg │ ├── PhotoSeries5.jpg │ ├── PhotoSeries6.jpg │ ├── PhotoSeries7.jpg │ ├── PhotoSeries8.jpg │ ├── PhotoSeriesExp1.jpg │ ├── PhotoSeriesExp2.jpg │ ├── PhotoSeriesExp3.jpg │ ├── PhotoSeriesExpTab1.jpg │ ├── PhotoSeriesExpTab1_3.jpg │ ├── PhotoSeriesFoc1.jpg │ ├── PhotoSeriesFoc2.jpg │ ├── PhotoSeriesStateChart.jpg │ ├── PhotoSeriesTL1.jpg │ ├── PhotoSeriesTL2.jpg │ ├── PhotoSeriesTL3.jpg │ ├── PhotoSeriesTL4.jpg │ ├── Photos.jpg │ ├── Photoseries0.jpg │ ├── Photoseries1.jpg │ ├── Photoseries2.jpg │ ├── Photoseries2b.jpg │ ├── Photoseries3.jpg │ ├── Photoseries3b.jpg │ ├── ProcessIndicator0.jpg │ ├── ProcessIndicator1.jpg │ ├── ProcessIndicator10.jpg │ ├── ProcessIndicator11.jpg │ ├── ProcessIndicator12.jpg │ ├── ProcessIndicator13.jpg │ ├── ProcessIndicator14.jpg │ ├── ProcessIndicator15.jpg │ ├── ProcessIndicator2.jpg │ ├── ProcessIndicator3.jpg │ ├── ProcessIndicator4.jpg │ ├── ProcessIndicator5.jpg │ ├── ProcessIndicator6.jpg │ ├── ProcessIndicator7.jpg │ ├── ProcessIndicator8.jpg │ ├── ProcessIndicator9.jpg │ ├── ProcessIndicatorLive2Active.jpg │ ├── ProcessIndicatorLiveActive.jpg │ ├── RN282_img1.jpg │ ├── Settings.jpg │ ├── SettingsVButtons.jpg │ ├── Settings_AButtons.jpg │ ├── Settings_API.jpg │ ├── Settings_API_1.jpg │ ├── Settings_API_2.jpg │ ├── Settings_API_3.jpg │ ├── Settings_API_4.jpg │ ├── Settings_API_5.jpg │ ├── Settings_API_a.jpg │ ├── Settings_API_change.jpg │ ├── Settings_API_na.jpg │ ├── Settings_Auth_Streaming.jpg │ ├── Settings_CamSel.jpg │ ├── Settings_Config.jpg │ ├── Settings_ConfigStore.jpg │ ├── Settings_Devices.jpg │ ├── Settings_Devices_Calibration.jpg │ ├── Settings_Devices_Calibration_State.jpg │ ├── Settings_full.jpg │ ├── Settings_microphone.jpg │ ├── Settings_noHistogram.jpg │ ├── Settings_no_microphone.jpg │ ├── TLSeriesStateChart.vsdx │ ├── Tooltip.jpg │ ├── Trigger_Action.jpg │ ├── Trigger_Actions1.jpg │ ├── Trigger_Actions2.jpg │ ├── Trigger_Actions3.jpg │ ├── Trigger_Actions4.jpg │ ├── Trigger_Actions5.jpg │ ├── Trigger_Active.jpg │ ├── Trigger_Calendar.jpg │ ├── Trigger_ConfirmCleanup.jpg │ ├── Trigger_Control.jpg │ ├── Trigger_DB.jpg │ ├── Trigger_DB_Eventactions.jpg │ ├── Trigger_DB_Events.jpg │ ├── Trigger_EventCard.jpg │ ├── Trigger_Events.jpg │ ├── Trigger_Events_Photo.jpg │ ├── Trigger_LoadProfile.jpg │ ├── Trigger_Logfile.jpg │ ├── Trigger_Motion.jpg │ ├── Trigger_Motion_Algos.jpg │ ├── Trigger_Motion_BGSubtract_Test_l.gif │ ├── Trigger_Motion_FrameDiff_Test_l.gif │ ├── Trigger_Motion_OpticalFlow_Test_l.gif │ ├── Trigger_Notification.jpg │ ├── Trigger_Notification0.jpg │ ├── Trigger_Notification1.jpg │ ├── Trigger_Notification2.jpg │ ├── Trigger_Notification3.jpg │ ├── Trigger_Notification3a.jpg │ ├── Trigger_NotificationError.jpg │ ├── Trigger_Storage.jpg │ ├── Trigger_Trigger1.jpg │ ├── Trigger_Trigger2.jpg │ ├── Trigger_Trigger3.jpg │ ├── Trigger_Trigger4.jpg │ ├── Trigger_Trigger5.jpg │ ├── Trigger_TriggerActions.jpg │ ├── Tuning1.jpg │ ├── Tuning2.jpg │ ├── Tuning3.jpg │ ├── Tuning4.jpg │ ├── Tuning5.jpg │ ├── Tuning6.jpg │ ├── UnsavedChangesIndicator.jpg │ ├── Video1.jpg │ ├── Video2.jpg │ ├── Webcam1.jpg │ ├── Webcam2.jpg │ ├── Zoom.jpg │ ├── Zoom_Graph.jpg │ ├── bp_PiZero_Connect.jpg │ ├── docker_CreateContainer.jpg │ ├── docker_InitDb.jpg │ ├── docker_StartContainer.jpg │ ├── goup.gif │ └── pi_zero_cover.jpg └── picamera2-manual.pdf ├── raspiCamSrv ├── __init__.py ├── api.py ├── auth.py ├── auth_su.py ├── camCfg.py ├── camera_pi.py ├── config.py ├── console.py ├── db.py ├── dbx.py ├── gpioDeviceTypes.py ├── gpioDevices.py ├── home.py ├── images.py ├── info.py ├── motionAlgoIB.py ├── motionDetector.py ├── photoseries.py ├── photoseriesCfg.py ├── schema.sql ├── settings.py ├── static │ ├── device_Buzzer.jpg │ ├── device_DigitalInputDevice.jpg │ ├── device_DigitalOutputDevice.jpg │ ├── device_DistanceSensor.jpg │ ├── device_InputDevice.jpg │ ├── device_LED.jpg │ ├── device_LightSensor.jpg │ ├── device_LineSensor.jpg │ ├── device_Motor.jpg │ ├── device_OutputDevice.jpg │ ├── device_RGBLED.jpg │ ├── device_RotaryEncoder.jpg │ ├── device_Servo.jpg │ ├── device_StepperMotor.jpg │ ├── device_TonalBuzzer.jpg │ ├── device_button.jpg │ ├── device_motionSensor.jpg │ ├── favicon.ico │ ├── histogramfailed.jpg │ ├── onlineHelp.png │ ├── recording_active.jpg │ ├── recording_active.png │ ├── recording_audio_active.png │ ├── recording_audio_inactive.png │ ├── recording_events_active.png │ ├── recording_events_inactive.png │ ├── recording_events_wait.png │ ├── recording_inactive.png │ ├── recording_live2_active.png │ ├── recording_live2_inactive.png │ ├── recording_live_active.png │ ├── recording_live_inactive.png │ ├── recording_series_active.png │ ├── recording_series_inactive.png │ ├── recording_trigger_active.png │ ├── recording_trigger_inactive.png │ ├── recording_trigger_test.png │ ├── recording_trigger_wait.png │ ├── recording_video_active.png │ ├── recording_video_inactive.png │ ├── recordingphotoseries.jpg │ ├── recordingvideo.jpg │ ├── recordingvideo_sound.jpg │ ├── save_changes.png │ ├── underconstruction.jpg │ └── w3.css ├── sun.py ├── templates │ ├── auth │ │ ├── login.html │ │ ├── password.html │ │ └── register.html │ ├── base.html │ ├── config │ │ └── main.html │ ├── console │ │ └── console.html │ ├── home │ │ └── index.html │ ├── images │ │ └── main.html │ ├── info │ │ └── info.html │ ├── photoseries │ │ └── main.html │ ├── settings │ │ └── main.html │ ├── trigger │ │ └── trigger.html │ └── webcam │ │ └── webcam.html ├── trigger.py ├── triggerHandler.py ├── version.py └── webcam.py └── requirements.txt /.dockerignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | **/.env 3 | **/.git 4 | **/.venv 5 | **/.vscode 6 | config 7 | **/docs 8 | **/instance 9 | **/logs 10 | raspiCamSrv/static/config 11 | raspiCamSrv/static/events 12 | raspiCamSrv/static/photos 13 | raspiCamSrv/static/photoseries 14 | raspiCamSrv/static/tuning 15 | **/tests 16 | **/.dockerignore 17 | **/.gitignore 18 | **/docker-compose* 19 | **/Dockerfile* 20 | LICENSE 21 | README.md 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | tests/ 6 | logs/ 7 | output/ 8 | raspiCamSrv/static/photos/ 9 | raspiCamSrv/static/timelapse/ 10 | raspiCamSrv/static/photoseries/ 11 | raspiCamSrv/static/config/ 12 | raspiCamSrv/static/events/ 13 | raspiCamSrv/static/tuning/ 14 | *.mp4 15 | *.h264 16 | 17 | # C extensions 18 | *.so 19 | 20 | # Distribution / packaging 21 | .Python 22 | build/ 23 | develop-eggs/ 24 | dist/ 25 | downloads/ 26 | eggs/ 27 | .eggs/ 28 | lib/ 29 | lib64/ 30 | parts/ 31 | sdist/ 32 | var/ 33 | wheels/ 34 | share/python-wheels/ 35 | *.egg-info/ 36 | .installed.cfg 37 | *.egg 38 | MANIFEST 39 | 40 | # PyInstaller 41 | # Usually these files are written by a python script from a template 42 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 43 | *.manifest 44 | *.spec 45 | 46 | # Installer logs 47 | pip-log.txt 48 | pip-delete-this-directory.txt 49 | 50 | # Unit test / coverage reports 51 | htmlcov/ 52 | .tox/ 53 | .nox/ 54 | .coverage 55 | .coverage.* 56 | .cache 57 | nosetests.xml 58 | coverage.xml 59 | *.cover 60 | *.py,cover 61 | .hypothesis/ 62 | .pytest_cache/ 63 | cover/ 64 | 65 | # Translations 66 | *.mo 67 | *.pot 68 | 69 | # Django stuff: 70 | *.log 71 | local_settings.py 72 | db.sqlite3 73 | db.sqlite3-journal 74 | 75 | # Flask stuff: 76 | instance/ 77 | .webassets-cache 78 | 79 | # Scrapy stuff: 80 | .scrapy 81 | 82 | # Sphinx documentation 83 | docs/_build/ 84 | 85 | # PyBuilder 86 | .pybuilder/ 87 | target/ 88 | 89 | # Jupyter Notebook 90 | .ipynb_checkpoints 91 | 92 | # IPython 93 | profile_default/ 94 | ipython_config.py 95 | 96 | # pyenv 97 | # For a library or package, you might want to ignore these files since the code is 98 | # intended to run in multiple environments; otherwise, check them in: 99 | # .python-version 100 | 101 | # pipenv 102 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 103 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 104 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 105 | # install all needed dependencies. 106 | #Pipfile.lock 107 | 108 | # poetry 109 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 110 | # This is especially recommended for binary packages to ensure reproducibility, and is more 111 | # commonly ignored for libraries. 112 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 113 | #poetry.lock 114 | 115 | # pdm 116 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 117 | #pdm.lock 118 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 119 | # in version control. 120 | # https://pdm.fming.dev/#use-with-ide 121 | .pdm.toml 122 | 123 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 124 | __pypackages__/ 125 | 126 | # Celery stuff 127 | celerybeat-schedule 128 | celerybeat.pid 129 | 130 | # SageMath parsed files 131 | *.sage.py 132 | 133 | # Environments 134 | .env 135 | .venv 136 | env/ 137 | venv/ 138 | ENV/ 139 | env.bak/ 140 | venv.bak/ 141 | 142 | # Spyder project settings 143 | .spyderproject 144 | .spyproject 145 | 146 | # Rope project settings 147 | .ropeproject 148 | 149 | # mkdocs documentation 150 | /site 151 | 152 | # mypy 153 | .mypy_cache/ 154 | .dmypy.json 155 | dmypy.json 156 | 157 | # Pyre type checker 158 | .pyre/ 159 | 160 | # pytype static type analyzer 161 | .pytype/ 162 | 163 | # Cython debug symbols 164 | cython_debug/ 165 | 166 | # PyCharm 167 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 168 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 169 | # and can be added to the global gitignore or merged into this file. For a more nuclear 170 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 171 | #.idea/ 172 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Verwendet IntelliSense zum Ermitteln möglicher Attribute. 3 | // Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen. 4 | // Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: Aktuelle Datei", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${file}", 12 | "console": "integratedTerminal", 13 | "justMyCode": false 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM dtcooper/raspberrypi-os:bookworm 3 | 4 | LABEL maintainer="signag" 5 | 6 | RUN apt update && apt -y upgrade 7 | 8 | RUN apt update && apt install -y \ 9 | gcc-aarch64-linux-gnu \ 10 | systemd \ 11 | systemd-timesyncd \ 12 | python3 \ 13 | python3-dev \ 14 | python3-pip \ 15 | python3-venv \ 16 | python3-opencv \ 17 | python3-gpiozero \ 18 | python3-lgpio \ 19 | ffmpeg \ 20 | python3-picamera2 --no-install-recommends 21 | 22 | 23 | RUN ln -s /usr/bin/python3 /usr/bin/python 24 | 25 | # Prevents Python from writing pyc files. 26 | ENV PYTHONDONTWRITEBYTECODE=1 27 | 28 | # Keeps Python from buffering stdout and stderr to avoid situations where 29 | # the application crashes without emitting any logs due to buffering. 30 | ENV PYTHONUNBUFFERED=1 31 | 32 | # Set environment variables 33 | ENV DEBIAN_FRONTEND=noninteractive 34 | 35 | WORKDIR /app 36 | 37 | # Copy the source code into the container. 38 | COPY . . 39 | 40 | # Install Python dependencies in virtual environment 41 | RUN python -m venv --system-site-packages .venv 42 | ENV PATH=".venv/bin:$PATH" 43 | RUN pip install --no-cache-dir -r requirements.txt 44 | 45 | # Expose the port that the application listens on. 46 | EXPOSE 5000 47 | 48 | # Initialize database for Flask 49 | RUN flask --app raspiCamSrv init-db 50 | 51 | # Run the application. 52 | CMD flask --app raspiCamSrv run --port 5000 --host=0.0.0.0 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 signag 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/raspiCamSrv.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=raspiCamSrv 3 | After=network.target 4 | 5 | [Service] 6 | ExecStart=/home//prg/raspi-cam-srv/.venv/bin/flask --app raspiCamSrv run --port 5000 --host=0.0.0.0 7 | Environment="PATH=/home//prg/raspi-cam-srv/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 8 | WorkingDirectory=/home//prg/raspi-cam-srv 9 | StandardOutput=inherit 10 | StandardError=inherit 11 | Restart=always 12 | User= 13 | 14 | [Install] 15 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | name: raspi-cam-srv 2 | services: 3 | raspi-cam-srv: 4 | container_name: raspi-cam-srv 5 | build: . 6 | image: signag/raspi-cam-srv 7 | network_mode: "host" 8 | ports: 9 | - "5000:5000" 10 | devices: 11 | - /dev/video0:/dev/video0 12 | - /dev/gpiochip0:/dev/gpiochip0 13 | volumes: 14 | - /run/udev/:/run/udev:ro 15 | - /run/systemd:/run/systemd:ro 16 | - /etc/timezone:/etc/timezone:ro 17 | - /etc/localtime:/etc/localtime:ro 18 | environment: 19 | - GPIOZERO_PIN_FACTORY=lgpio 20 | - SYSTEMD_BUS_ADDRESS=unix:path=/run/systemd/private 21 | restart: unless-stopped 22 | privileged: true 23 | -------------------------------------------------------------------------------- /docs/API.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv API 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | The **raspiCamSrv** API allows access to several RaspberryPi camera functions through WebService endpoints. 6 | 7 | Configuration of the API is done on the [Settings/API](./SettingsAPI.md) screen. 8 | 9 | ## Postman Test Collection 10 | 11 | For testing the API, a [Postman](https://www.postman.com/) collection is available at [docs/api/postman](https://github.com/signag/raspi-cam-srv/tree/main/docs/api/postman) which can be downloaded and imported into a Postman instance. 12 | 13 | ![PostmanColl](./img/API_Postman_collection.jpg) 14 | 15 | ## API Documentation 16 | 17 | The [docs/api/postman](https://github.com/signag/raspi-cam-srv/tree/main/docs/api/postman) folder contains also the [API Documentation](./api/postman/raspiCamSrv.postman_collection.pdf) generated from Postman. 18 | 19 | ## Variables 20 | 21 | The collection uses a set of variables: 22 | 23 | ![PostmanVars](./img/API_Postman_variables.jpg) 24 | 25 | ```base_url```, ```user``` and ```pwd``` need to be adjusted to the current environment for a user which has been previously created in raspiCamSrv. 26 | 27 | ```access_token``` and ```refresh_token``` will be automatically filled from responses of the /api/login and /api/refresh endpoints. 28 | 29 | ## Usage 30 | 31 | ### 1. Login 32 | 33 | Use the ```api login``` request to log in to **raspiCamSrv** and receive an Access Token and a Refresh Token 34 | 35 | ### 2. Interact with **raspiCamSrv** 36 | 37 | Use any of the GET requests to interact with **raspiCamSrv**. 38 | 39 | These requests use the Access Token for authentication. 40 | 41 | ### 3. Refresh the Access Token 42 | 43 | If a request returns a token expiration error, refresh the Access Token using the ```api refresh``` request. 44 | 45 | This will use the Refresh Token for authentication and return a fresh Access Token. 46 | 47 | 48 | -------------------------------------------------------------------------------- /docs/Authentication.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Authorization 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | Access to the raspiCamSrv server requires login with Username and Password. 6 | A user session will live as long as the browser remains open, even if the tab with a **raspiCamSrv** dialog has been closed. 7 | 8 | The basic principle is that the first user in the system will be automatically registered as SuperUser. 9 | Only the SuperUser will be able to register new users or remove users from the system. 10 | 11 | After the database has been initialized with ```flask --app raspiCamSrv init-db``` (see [RaspiCamSrv Installation](../README.md#raspicamsrv-installation) Step 11), there is no user in the database. 12 | 13 | In this situation, any connect to the server will open the *Register* screen: 14 | ![Register Initial](./img/Auth_RegisterInitial.jpg) 15 | 16 | Now, the SuperUser can complete his registration and will then be redirected to the *Log In* screen: 17 | ![Log In](./img/Auth_Login.jpg) 18 | From now on, the *Register* screen will no longer be available through the menu. 19 | Also, direct access through the *Register* screen URL will only be allowed for the SuperUser. Other users will be redirected to the *Live* screen. 20 | 21 | ## User Management 22 | 23 | For management of users, the *Settings* screen has an additional section *Users* which is visible only for the SuperUser: 24 | ![User Management](./img/Auth_UserManagement.jpg) 25 | 26 | The list shows all registered users with 27 | - unique user ID 28 | - user name 29 | - Initial, indicating whether the user has been initially created by the SuperUser and needs to change password on first log-in. 30 | - SuperUser, indicating the user registered as SuperUser 31 | 32 | The SuperUser can 33 | - register new users using the *Register New User* button 34 | - remove users which have been selected in the list 35 | 36 | ## Password 37 | 38 | Users with flag "Initial" will automatically be requested to change their password when they log in for the first time. 39 | All users can change their password before they are logged in. 40 | 41 | ![Password](./img/Auth_Password.jpg) 42 | After the password has been successfully changed, the *Log In* screen will be opened. 43 | 44 | ## Old User Schema 45 | 46 | The functionality described above is available for systems installed after Feb. 15, 2024. 47 | Systems installed before but updated (git pull) later, still work with the old user schema. 48 | 49 | In this case, all users are considered SuperUsers. 50 | 51 | The [User Management](#user-management) functionality in the *Settings* screen will be available for all users. 52 | However, a hint is shown to update the database schema: 53 | 54 | ![User Management Old](./img/Auth_UserManagement_old.jpg) -------------------------------------------------------------------------------- /docs/Background Processes.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Tasks and Background Processes 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | The figure below gives an overview of the different tasks available in **raspiCamSrv** and their relation to **raspiCamSrv** [Configurations](./Configuration.md) and camera strams. 6 | For more information on the components, see the [Picamera2 manual](./picamera2-manual.pdf), chapter 4.2. 7 | 8 | ![stream usage](./img/CameraStreamUsage.jpg) 9 | 10 | The tasks marked in green are executed in background processes (Threads) and may run simultaneously. 11 | 12 | The status of each of these processes is indicated with [status indicators](./UserGuide.md#process-status-indicators): 13 | 14 | ![Status Indicator](./img/ProcessIndicator4.jpg) 15 | 16 | 17 | ## Default Configuration 18 | 19 | The association between **raspiCamSrv** [Configurations](./Configuration.md) and camera streams shown in the figure above, is the default configuration. 20 | 21 | In addition, default values for other configuration parameters are harmonized in such a way that all background processes can run simultaneously. 22 | This is especially important for the live stream which will remain active while a video is recorded, while photos are taken or while a Photo Series is executed. 23 | 24 | **raspiCamSrv** merges the different configurations to a single one which is applied when the camera is started. 25 | 26 | This requires that the following configuration parameters must have the same values for the different configurations: 27 | 28 | - *Transform* 29 | - *Colour Space* 30 | - *Queue* 31 | 32 | The values for *Buffer Count* can be different. In the merge process, the largest number of buffers will be selected. 33 | 34 | ## Configuration Changes 35 | 36 | All configuration scan be changed, including the association between configuration and camera stream (except raw). 37 | 38 | If a configuration change, for example Transform, is made for a single configuration, for example *Video*, it is no longer possible to use a common configuration for all tasks. 39 | 40 | If then, for example, a video is recorded, the video thread needs to run in exclusive mode because it cannot share configuration with the Live Stream. For this purpose: 41 | 42 | 1. The Live Stream must be stopped and paused during video recording 43 | 2. The Encoder for the Live Stream must be stopped 44 | 3. The camera must be stopped 45 | 4. The camera must be configured with the Video configuration 46 | 5. The camera must be started 47 | 6. The encoder for video must be started while the video is being recorded 48 | 7. The encoder must be stopped when video recording is finished 49 | 8. The camera must be stopped 50 | 9. The camera must be configured for the LiveStream, including eventally compatible configurations 51 | 10. The camera must be started 52 | 11. The MJPEG encoder for Live Stream must be started 53 | 12. The Live Stream Thread must be started 54 | 55 | In case of harmonized configurations, only steps 7 and 8 would have been required. 56 | -------------------------------------------------------------------------------- /docs/CameraControls.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Camera Controls 2 | 3 | [![Up](img/goup.gif)](./LiveScreen.md) 4 | 5 | Picamera2 allows for a set of 36 camera control parameters which can be adjusted while the camera is active. 6 | From these, 8 parameters are just part of the image metadata and cannot be applied to the camera. 7 | 8 | In principle, the remaining 28 parameters can be applied to the camera at different times 9 | 1. As part of the [Camera Configuration](./Configuration.md). 10 | Here **raspiCamSrv** supports adding any of these parameters to the configuration. 11 | Control parameters included in the configuration have precedence over parameters not in the configuration. 12 | 2. After camera configuration before camera start. 13 | In **raspiCamSrv**, this applies for all photos and videos taken in a raspiCamSrv session. 14 | 3. After the camera has been started. 15 | In **raspiCamSrv**, this is only used for the live stream shown in the upper left quarter. 16 | If controls have been modified and submitted, they will be directly applied to the live stream. 17 | 18 | Modification of camera controls does not affect raw photos. 19 | 20 | In **raspiCamSrv** all controls are explained through tooltips on the parameter name: 21 | ![Tooltip](img/Tooltip.jpg) 22 | The texts for the tooltips have been mainly taken from the [Picamera2 Manual](./picamera2-manual.pdf) or the 23 | underlying [libcamera documentation](https://libcamera.org/api-html/index.html). 24 | 25 | The controls are grouped into 26 | - [Focus Handling](./FocusHandling.md) 27 | - [Zoom & Pan](./ZoomPan.md) 28 | - [Auto-Exposure](#auto-exposure) 29 | - [Exposure](#exposure) 30 | - [Image](#image) 31 | 32 | ## Basics 33 | All Control Parameter tabs (except Zoom and Pan) are structured similarly: 34 | - Every tab is a form. This means that all parameters shown can be modified without any effect. 35 | Only when the form is submitted through the **Submit** button, the settings are saved in the server configuration and directly applied to the live stream. 36 | - Every parameter has a preceeding checkbox by which allows activation/deactivation of the control parameter within the configuration. 37 | Only if the checkbox is checked, the parameter can be modified. 38 | If the checkbox is unchecked, the control is not effective independently from its value. 39 | - Individual parameters may have restictions either as distinct values or ranges of allowed values. 40 | It should normally not be possible to enter a value which will not be accepted by the camera. 41 | - Some camera systems support only a subset of the available control parameters. 42 | For example cameras 1 and 2 have no focus management. 43 | This is recognized by **rapiCamSrv** and these parameters will not presented to the user. 44 | - All forms for the different parameter groups on different tabs are part of the same web page. 45 | If values are modified without submitting, the modification will be visible even if another tab has been selected in the meantime. 46 | **If modifications are not submitted on their own tab, they will be lost in the next request/response cycle which can be triggered by a submit on another tab**. 47 | 48 | ## Auto-Exposure 49 | ![Auto-Exposure](img/AutoExposure.jpg) 50 | 51 | This tab includes parameters which control the Auto Exposure (AE) algorithm of the camera. 52 | 53 | ## Exposure 54 | ![Exposure](img/Exposure.jpg) 55 | 56 | This tab includes parameters related to exposure control. 57 | 58 | ## Image 59 | ![Image](img/Image.jpg) 60 | 61 | This tab includes parameters controlling the image appearance -------------------------------------------------------------------------------- /docs/Configuration.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Camera Configuration 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | Configuration parameters are so basic that they need to be applied before the camera is started. 6 | 7 | Picamera2 provides three configuration bases which can be taken as is for a specific use case or they can be adjusted in one or several aspects. 8 | 9 | These are 10 | - Preview configuration 11 | for previews on a screen connected to the Raspberry Pi 12 | - Still configuration 13 | for photos 14 | - Video configuration 15 | for videos 16 | 17 | **raspiCamSrv** does not make direct use of these configurations. 18 | 19 | Instead, the following configurations can be fully configured: 20 | - Live View configuration 21 | which will be applied to the live stream 22 | - Photo configuration 23 | which will be applied when normal photos are taken 24 | - Raw Photo configuration 25 | which will be applied when raw photos are taken 26 | - Video configuration 27 | which will be applied when videos are recorded 28 | 29 | Configuration changes may have an impact on the way how tasks and background processes are executed. If specific parameters, such as [Transform](#transform) are changed for a specific use case only, for example for *Video*, video recording will require that the Live Stream is stopped and paused while the video is being recorded. 30 | For more details, see [raspiCamSrv Tasks and Background Processes](./Background%20Processes.md). 31 | 32 | ## Configuration Tab 33 | 34 | The *Config* submenu includes a tab *Tuning* which is described in [raspiCamSrv Camera Tuning](./Tuning.md) and not here. 35 | 36 | An individual configuration tab is available for each use case. All tabs have essentially the same structure: 37 | 38 | As a general aspect, the green [Submenue](./UserGuide.md#submenue) bar includes an option to synchronize the aspect ratio of [stream sizes](#stream-size-width-height) across all configurations if this has been changed for the current configuration. 39 | If this option is activated after it was previously deactivated, all aspect ratios will be set to the one of the current configuration. 40 | 41 | ![Configuration](img/Config.jpg) 42 | 43 | 44 | **As always: any modifications need to be submitted before they can be effective** 45 | 46 | ### Transform 47 | 48 | With *Transform*, you can specify whether the image needs to be flipped horizontally, vertically or both. The latter case is identical to rotation of 180°. 49 | 50 | **NOTE:** When this is modified for one configuration, the settings are automatically transferred to all other configurations.
51 | This is necessary because **raspiCamSrv** simultaneously configures all streams (lores, main and raw) in order to allow using these in parallel for different purposes, such as live stream and video recording. The transform settings cannot be different for different streams at the same time. 52 | 53 | ### Colour Space 54 | 55 | This allows selecting one of the supported colour spaces 56 | 57 | ### Buffer Count 58 | 59 | Specifies the number of buffers used by the camera for the specific use case. 60 | 61 | Values are preset in accordance with corresponding settings of the Picamera2 standard use cases 62 | 63 | ### Queue 64 | 65 | Specifies whether the camera is allowed to queue up a frame ready for a capture request. 66 | 67 | ### Sensor Mode 68 | 69 | When **raspiCamSrv** starts up, one of the first things is to query the camera system for the available Sensor Modes. 70 | These can be inspected on the [Info](./Information.md) screen. 71 | 72 | 73 | These modes are offered for selection here. 74 | When a Sensor Mode is selected, its main characteristics are shown to the right. 75 | 76 | In addition to the available Sensor Modes, a "Custom" mode can be selected which allows especially to set the intended stream size (width and height if the image in pixels) 77 | 78 | For the *Raw Photo* use case, "Custom" cannot be selected. Raw photos will allways use the stream size of the selected Sensor Mode. 79 | 80 | ### Stream 81 | 82 | Specifies the stream to be used for the respective use case. 83 | 84 | The camera system supports three streams (see [Picamera2 Manual](./picamera2-manual.pdf)): 85 | - the **main** stream 86 | - the **lowres** stream 87 | - and the **raw** stream 88 | 89 | The latter is for raw data output which bypasses the image signal processor. 90 | 91 | For the *Raw Photo* use case, this is the only stream which can be selected. 92 | 93 | ### Stream Size (width, height) 94 | 95 | If a standard Sensor Mode has been selected, the size related to the mode is shown. 96 | 97 | If "Custom" has been selected as sensor mode, you may enter any size here (except for *Raw Photos*). 98 | Produced photos or videos will then be in the specified format. 99 | 100 | If the option to synchronize aspect ratios (right side of green Submenue bar) is selected, the *Stream Size*s for all other configurations will be adjusted to reproduce the aspect ratio of the current configuration. 101 | 102 | **NOTE:** If, after submitting a *Live View* configuration, you get an error message ``` 103 | lores Stream Size must not exceed main Stream Size (Photo)```, you need to go to the *Photo* configuration and adjust its *Stream Size* to the desired value. 104 | 105 | ### Stream size aligned with Sensor Modes 106 | 107 | If this option is activated, and if a stream size has been specified which is different from stream sizes of the available Sensor Modes, the Picamera2 Configuration will be asked to align the stream size. This may result in slightly different sizes which are, however, in better accordance with available Sensor Modes. 108 | 109 | ### Stream Format 110 | 111 | It can be selected from a number of pixel and image formats supported by Picamera2. 112 | For details, see [Picamera2 Manual](./picamera2-manual.pdf), Appendix A. 113 | 114 | Whereas for *Live Stream*, *Photo* and *Video* a format can be selected from the same list, the formats available for *Raw Photo* are different. These are specified in the Sensor Modes (see [Info](./Information.md)). 115 | **raspiCamSrv** queries these from Picamera2 at server startup and offers the found formats in the configuration screen. 116 | 117 | ### Display 118 | 119 | This parameter is just shown for completeness. 120 | It specifies the stream which shall be used for display on a monitor connected to the system. 121 | This is not relevant in the scenario addressed by **raspiCamSrv**, which is usually headless. 122 | 123 | ### Encode 124 | 125 | This specifies the stream which needs to be sent to the encoder. 126 | 127 | Settings are preconfigured and cannot be modified. 128 | 129 | Encoding is only necessary for the *Live View* (MJPEG encoding) and the *Video* use cases. 130 | 131 | For *Video*, the encoder depends on the video format chosen. 132 | 133 | 134 | ## Controls included in Configuration 135 | 136 | A configuration for a specific use case may also include Camera Controls. 137 | 138 | Actually, Picamera2 requires that at least one control is included in the configuration. 139 | 140 | **raspiCamSrv** preconfigurs a control with specific settings in accordance with the Picamera2 standard use case configurations. 141 | 142 | In addition, the button **Add Active Ctrls** will include all controls which are currently active in the [Camera Controls](./CameraControls.md) configuration. 143 | 144 | Values are taken as configured and cannot be modified here. 145 | 146 | In case a control parameter has a wrong value, it can be selected and then removed from the configuration with the **Remove Selected Ctrls** button. 147 | -------------------------------------------------------------------------------- /docs/Console.md: -------------------------------------------------------------------------------- 1 | # Console 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | The Console group of dialogs provides functions for user interactions with the Raspberry Pi. 6 | 7 | ![Console](./img/Console.jpg) 8 | 9 | - [Versatile Buttons](./ConsoleVButtons.md) allow interaction with the Operating System by running OS commands or scripts. 10 | - [Action Buttons](./ConsoleActionButtons.md) allow execution of various types [Actions] for interaction with GPIO-connected output devices or the camera system. -------------------------------------------------------------------------------- /docs/ConsoleActionButtons.md: -------------------------------------------------------------------------------- 1 | # Console - Action Buttons 2 | 3 | [![Up](img/goup.gif)](./Console.md) 4 | 5 | This page shows buttons which have been configured in the [Settings / Action Buttons](./SettingsAButtons.md): 6 | 7 | ![aButtons](./img/Console_AButtons.jpg) 8 | The example layout of this screenshot is based on the example configuration shown for the [Settings / Action Buttons](./SettingsAButtons.md) screen. 9 | 10 | ## Button Execution 11 | 12 | When the [Action](./TriggerActions.md), configured for a button is executed, the behavior for the action is slightly different compared to invocation of an action on behalf of a [Trigger](./TriggerTriggers.md). 13 | 14 | - If a device is busy at the time when a button is pressed, the action is not executed. Instead a "Device busy" information is shown in the status line: 15 | ![busy](./img/Console_AButtonsDeviceBusy.jpg) 16 | 17 | 18 | - Also, the action is not executed in an own thread but synchronously, so that the user needs to wait for action completion which is confirmed in the message line. 19 | -------------------------------------------------------------------------------- /docs/ConsoleVButtons.md: -------------------------------------------------------------------------------- 1 | # Console - Versatile Buttons 2 | 3 | [![Up](img/goup.gif)](./Console.md) 4 | 5 | This page shows buttons which have been configured in the [Settings / Versatile Buttons](./SettingsVButtons.md): 6 | 7 | ![vButtons](./img/Console_VButtons.jpg) 8 | The example layout of this screenshot is based on the example configuration shown for the [Settings / Versatile Buttons](./SettingsVButtons.md) screen. 9 | 10 | ## Button Execution 11 | 12 | When a button is clicked which is configured to require confirmation, a confirmation dialog is shown where execution can be refused: 13 | 14 | ![vButtonConfirm](./img/Console_VButtons_conf.jpg) 15 | 16 | ## Execution Result 17 | 18 | In the bottom part of the dialog the result of the command execution is shown: 19 | 20 | - *Command*
The command configured for the button. 21 | - *Run Arguments*
Command execution is done using the Python [subprocess.run](https://docs.python.org/3/library/subprocess.html) method which receives arguments as a list. This list is obtained by parsing the command string with spaces as separators. 22 | - *Return Code*
The return code returned from command execution. 23 | - *Stdout*
Output which command execution has sent to Stdout.
Multiline output can be scrolled. 24 | - *Stderr*
Error information which command execution has sent to Stderr.
Multiline output can be scrolled. 25 | - Status Line
The status line at the bottom shows whether the command could be executed or not, irrespective of errors which might have occurred during command execution. 26 | 27 | The last *Execution Result* remains visible within the live time of the Flask server. 28 | 29 | Of course, no result will be visible if the Flask server has been restarted or of the Raspberry Pi has been rebooted. 30 | 31 | ## Interactive Commandline 32 | 33 | If the [Settings / Versatile Buttons](./SettingsVButtons.md) have declared the commandline to be interactive, commands can be directly entered on the commandline: 34 | 35 | ![Commandline](./img/Console_VButtons_commandline.jpg) -------------------------------------------------------------------------------- /docs/FocusHandling.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Focus Handling 2 | 3 | [![Up](img/goup.gif)](./LiveScreen.md) 4 | 5 | Focus handling is not supported by camera versions 1 and 2. 6 | 7 | ![Focus handling](img/Focus.jpg) 8 | 9 | This tab includes various controls which affect the Auto Focus (AF) algorithm of the camera. 10 | 11 | The **Autofocus Mode** can be set to "Manual", "Auto" or "Continuous" 12 | 13 | ## Manual Focus 14 | 15 | When *Autofocus Mode* "Manual" is chosen, also the *Focal Distance* field must be activated and the distance must be set manually. 16 | 17 | Pressing **Submit** will apply the setting to the live stream and the changed focus will be immediately visible. 18 | 19 | ## Continuous Focus 20 | 21 | When *Autofocus Mode* is set to "Continuous", the camera will, after submitting, continuously try to focus under consideration of settings for other focus handling parameters. 22 | 23 | ## Automatic Focus 24 | 25 | When *Autofocus Mode* is set to "Auto", the camera will automatically focus after an autofocus cycle has been triggered. 26 | 27 | Before the cycle can be triggered through the **Trigger Autofocus** button, the settings must be applied with the **Submit** button. 28 | 29 | Submitting the "Auto" *Autofocus Mode* will have no effect on the live stream. 30 | 31 | ## Trigger Autofocus 32 | 33 | The effect of the autofocus cycle will essentially depend on the settings for the other AF control parameters. 34 | 35 | Whether or not the autofocus cycle was successful, will be shown in the message area at the bottom of the application window: 36 | ![AFMessage](img/AFMessage.jpg) 37 | 38 | If the autofocus cycle was successful, **raspiCamSrv** will request metadata from the camera and determine the focal distance from the LensPosition. 39 | 40 | The Value will be entered in the *Focal Distance* field, which will also be activated automatically. 41 | 42 | Also, the *Autofocus Mode* will be automatically set to "Manual" so that the measured *Focal Distance* can be used for future photos. 43 | 44 | ![AFTrigger](img/AFTrigger2.jpg) 45 | 46 | ## Autofocus Windows 47 | 48 | These are rectangle areas within the image which will be used by the AF algorithm to focus. 49 | 50 | Multiple rectangle areas can be specified. 51 | 52 | **raspiCamSrv** supports graphical specification of these areas in the following way. 53 | 54 | 1. Activate the checkbox for *Autofocus Windows*. 55 | As result, a canvas will be drawn over the live stream area which is visible as thin red border: 56 | ![AfWindows1](img/AFWindows1.jpg) 57 | 2. Now you can use the mouse to draw rectangles on this canvas: 58 | Position the cursor at one corner of the intended rectangle, 59 | press the left mouse button, 60 | and drag with mouse button down to the opposite corner. 61 | 3. When the mouse button is released, the rectangle coordinates will be scaled to the current scaler crop settings and entered in the *Autofocus Windows* field. 62 | ![AfWindows2](img/AFWindows2.jpg) 63 | 4. If required, you can draw additional rectangles in the same way. 64 | While drawing rectangles, previously drawn rectangles will vanish without getting lost. 65 | 5. Finally, when the mouse pointer leaves the canvas area, all rectangles will be shown over the live stream area. 66 | ![AfWindows3](img/AFWindows3.jpg) 67 | **Don't forget to push Submit because otherwise, these settings will get lost!** 68 | 6. In order to remove all areas, just deactivate the *Autofocus Windows* checkbox and activate it again. 69 | 70 | The canvas and the rectangles representing the AF Windows will remain visible as long as the *Autofocus Windows* checkbox is activated and whenever the *Focus* tab is visible. 71 | 72 | 73 | -------------------------------------------------------------------------------- /docs/LiveScreen.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Live Screen 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | The **Live** screen is the central part of the application. 6 | After photos or videos have been taken in the current session, its layout is as shown below: 7 | 8 | ![Live Screen](img/Live0.jpg) 9 | 10 | ## Layout 11 | 12 | ### Top Left Quarter 13 | This is the area where a Live stream is shown, except for phases when videos are recorded. 14 | 15 | ### Top Right Quarter 16 | This area allows selecting and configuration of all [Camera Controls](./CameraControls.md). These are parameters which affect the characteristics of images and outputs of the camera and which can be modified while the camera is running. 17 | The menu row of this section groups the controls into several categories. 18 | 19 | ### Bottom Left Quarter 20 | The bottom part of the screen is only shown if a Photo or video has been taken within the server's life time and if the user did not decide to hide this area. 21 | 22 | The bottom left quarter presents function buttons for [Photo/Video taking](./Phototaking.md) 23 | In addition, there are also buttons controlling the photo buffer to which users can add or remove individual photos and navigate between them. 24 | 25 | Raw photos or videos are not shown directly. Instead a placeholder in the configured photo format is shown. 26 | 27 | ### Bottom Right Quarter 28 | Here, the metadata of the currently visible photo/video are shown. 29 | The metadata are captured within the same **Capturing Request** together with the photo itself. 30 | In the case of videos, the metadata are captured immediately before recording starts. 31 | -------------------------------------------------------------------------------- /docs/PhotoSeriesExp.md: -------------------------------------------------------------------------------- 1 | # Photo Series of type "Exposure Series" 2 | 3 | [![Up](img/goup.gif)](./PhotoSeries.md) 4 | 5 | 6 | Exposure series iterate through a specified range of an exposure parameter, keeping all other exposure parameters constant. 7 | In general, exposure is controlled by three parameters: aperture, exposure time and ISO value. 8 | 9 | Raspberry Pi cameras have a fixed or manually controlled aperture and ISO values are not standardized. 10 | Instead of ISO values, the Analogue gaing can be set. Roughly, the relation is *ISO* = 100 * *AnalogueGain*. 11 | 12 | The *Exposure Series* subdialog allows specifying necessary parameters for series where either *Exposure Time* or *Analogue Gain* is varied. 13 | 14 | ![Exposure Series](img/PhotoSeriesExp1.jpg) 15 | 16 | The dialog references the active Photo Series which is managed in the [Series](./PhotoSeries.md) subdialog of the *Photo Series* dialog. 17 | 18 | The *Number of Shots* is shown here, because it will be affected by the chosen *Start*, *Stop* and *Interval* values. 19 | 20 | To configure the active Photo Series as *Exposure Series*, proceed as follows 21 | 22 | 1. Activate the *Exposure Series* checkbox 23 | 2. Select the exposure parameter which shall be kept at a fixed value by checking one of the check boxes under *Exposure Time* or *Analogue Gain* 24 | 3. For the selected parameter, enter the intended value in the *Start* field. 25 | 4. Now, specify *Start* and *Stop* values for the variable parameter 26 | 5. The interval is specified in terms of photographic [Exposure Values](https://en.wikipedia.org/wiki/Exposure_value) (EV)
With a value of 1/3 EV the series is obtained by multiplying the last value of *Exposure Time* or *Analogue Gain* by 2**(1/3) to get the next value.
With a value of 1 EV, the factor is 2**(1)=2
and with 2 EV, the factor is 2**(2)=4.
1/3 EV is the typical raster value for commercial cameras when modifying either aperture, exposure time or ISO. 27 | 28 | Finally push the **Submit** button to store the specified value. 29 | This will recalculate the *Number of Shots* required for the series. 30 | 31 | To start photoshooting, go to the [Series](./PhotoSeries.md) subdialog 32 | 33 | ## Result 34 | 35 | After the series has finished, the results can be inspected on the *Exposure Series* subscreen: 36 | 37 | ![Exposure](img/PhotoSeriesExp2.jpg) 38 | 39 | Together with each photo, the screen shows a histogram and characteristic metadata: 40 | - Exp: Exposure Time in seconds 41 | - Gain: Analogue Gain 42 | - Lux: An estimation of the brightness 43 | 44 | 45 | More information can be gained from 46 | - the [Series Camera File](./PhotoSeries.md#series-camera-file) which lists the configuration and control parameters applied before shooting a photo 47 | - the [Series Log File](./PhotoSeries.md#series-log-file) which lists the metadata captured together with each photo. 48 | 49 | 50 | ## Parameter Table (1/3 EV) 51 | 52 | The following table contains systematic values for Exposure Time and Analogue Gain with 1/3 EV, corresponding roughly to commercial camera settings 53 | 54 | ![1/3EV](img/PhotoSeriesExpTab1_3.jpg) 55 | 56 | ## Parameter Taple (1 EV) 57 | 58 | The following table contains systematic values for Exposure Time and Analogue Gain with 1 EV, corresponding roughly to commercial camera settings 59 | 60 | ![1/3EV](img/PhotoSeriesExpTab1.jpg) 61 | 62 | 63 | -------------------------------------------------------------------------------- /docs/PhotoSeriesFocus.md: -------------------------------------------------------------------------------- 1 | # Photo Series of Type "Focus Stack" 2 | 3 | [![Up](img/goup.gif)](./PhotoSeries.md) 4 | 5 | 6 | A Focus Stack series iterates the Lens Position (or Focal Distance). 7 | With suitable software, such a stack can be combined to achieve a large Depth of Field (DoF). 8 | 9 | ![Focus Stack](img/PhotoSeriesFoc1.jpg) 10 | 11 | To create a focus stack, you can proceed as follows: 12 | 13 | 1. In the [Live Screen](./LiveScreen.md) use [Focus Handling](./FocusHandling.md) to determine the Focal Distance for the nearest and the furthest point of the scene. 14 | 2. After initializing a Photo Series in the [Series](./PhotoSeries.md) subscreen, open the *Photo Stack* subscreen and check *Focus Stacking Series* 15 | 3. Then enter the nearest and furthest Focal Distance as *Start* and *Stop* values and choose a suitable *Interval* 16 | 4. Push **Submit** to configure the series 17 | 5. In the [Series](./PhotoSeries.md) subscreen, start the Photo Series 18 | 19 | 20 | The result will be shown in the *Focus Stack* subdialog: 21 | 22 | ![Fochs Stack Final](img/PhotoSeriesFoc2.jpg) 23 | 24 | Together with each photo, characteristic metadata are shown: 25 | - The *Lens Position* with which the photo was taken
(reciprocal of Focal Distance) 26 | - The *Focal Distance* which was varied within the series 27 | - The *Focus FoM*, a Figure of Merit (FoM) to indicate how in-focus the frame is. A larger FocusFoM value indicates a more in-focus frame. 28 | 29 | More information can be gained from 30 | - the [Series Camera File](./PhotoSeries.md#series-camera-file) which lists the configuration and control parameters applied before shooting a photo 31 | - the [Series Log File](./PhotoSeries.md#series-log-file) which lists the metadata captured together with each photo. 32 | -------------------------------------------------------------------------------- /docs/PhotoSeriesTimelapse.md: -------------------------------------------------------------------------------- 1 | # Photo Series of Type "Timelapse" 2 | 3 | [![Up](img/goup.gif)](./PhotoSeries.md) 4 | 5 | This screen allows special configurations for Photo Series in the Timelapse domain. 6 | Of course, every normal Photo Series can be used for Timelapse purposes. However, users often require specific features like specific time slots for multi-day series or automatic exposure adjustment during sunset/sunrise phases (Autoramping / "Timelapse Holy Grail"). 7 | 8 | This page is dedicated to this kind of configuration settings. 9 | Currently, raspiCamSrv supports limiting photo shooting to configurable periods depending on sunrise and sunset. 10 | 11 | Usage of this feature requires calculation of sunrise and sunset, depending on date. 12 | The algorithm (see [Sunrise Equation](#sunrise-equation)) requires information about the geografic coordinates of the camera position. 13 | These need to be specified on the [Settings](./Settings.md) screen before a Series can be classified as "Sun-controlled". 14 | It is recommended to [store the configuration](./SettingsConfiguration.md#server-configuration-storage) in order to have these settings available after a server restart. 15 | 16 | When this screen is activated after a [new Series](./PhotoSeries.md#creation-of-a-new-series) has been created, it will show up as 17 | 18 | ![Timelapse1](./img/PhotoSeriesTL1.jpg) 19 | 20 | - The fields **Series**Name, **Interval** and **Number of Shots** refer to the same parameters as screen [Series](./PhotoSeries.md). 21 | - Activating the checkbox **Sun-controlled Series** will activate selective photo shooting in periods depending on sunrise and/or sunset. 22 | - You can specify the **Number of Days** for which the series shall be active 23 | - The fields **Sunrise** and **Sunset** will show values for the current day.
If the series will be running for several days, sunrise and sunset will be calculated individually for every day. 24 | - The system allows the definition of two periods per day during which photos will be shot with the given **Interval**:
These are named **Period 1** and **Period 2** 25 | - At least for **Period 1**, you need to specify **Start** and **End**
If only one is specified, the system reports an error and does not persist the specified data.
**Start** and **End** are specified if the **Reference** is not "Unused". 26 | - The **Reference** specifies whether "Sunrise" or "Sunset" will be used to limit the intended period. 27 | - For each **Period**s **Start** and **End**, you can specify a time **Shift** in Minutes by which the start or the end of the period will be shifted with respect to the selected **Reference**.
The **Shift** can be positive or negative. 28 | - After **Submit**, the system will calculate **Todays Values** for **Start** and **End**. 29 | - Also the time for the **Next Shot** will be shown. 30 | 31 | When submitting entries with a reasonable interval and Number of Days, the system will recalculate the required **Number of Shots** as well as the expected **End** of the Series, shown on the [Series](./PhotoSeries.md) screen. 32 | 33 | ![Timelapse2](./img/PhotoSeriesTL2.jpg) 34 | 35 | ## Example: Single Period for Daylight Photos 36 | 37 | ![Timelapse3](./img/PhotoSeriesTL3.jpg) 38 | 39 | ## Example: Two Periods around Sunrise and Sunset 40 | 41 | ![Timelapse4](./img/PhotoSeriesTL4.jpg) 42 | 43 | ## Sunrise Equation 44 | 45 | The algorithm for the sunrise/sunset equation has been taken from Wikipedia: 46 | [https://en.wikipedia.org/wiki/Sunrise_equation](https://en.wikipedia.org/wiki/Sunrise_equation) 47 | 48 | This article also publishes Python code which has been taken as is (version from August 11, 2024, 14:18) and integrated with minor technical adjustments into the RaspiCamSrv Flask server code. 49 | 50 | Comparison of the results from this algorithm with those from the "NOAA Solar Calculator" ([https://gml.noaa.gov/grad/solcalc/](https://gml.noaa.gov/grad/solcalc/)) for the time of writing at the author's location showed a deviation of -2 Minutes for sunrise and +3 Minutes for sunset. 51 | However, the NOAA Calculator does not seem to take elevation into account. -------------------------------------------------------------------------------- /docs/PhotoViewer.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Photo Viewer 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | All photos, raw photos or videos taken wit **raspiCamSrv** are stored in a camera-specific folder on the server. 6 | 7 | Currently, the folder is located within the folder where Flask expects static content 8 | (```~/home/prgraspi-cam-srv/raspiCamSrv/static/photos/camera_n``` (n=0, 1)). 9 | The full path of the folder for the active camera is shown in the [Settings](./Settings.md) screen. 10 | 11 | The current implementation of **raspiCamSrv** includes a very simple viewer which allows inspecting the available photos and videos as well as downloading and deleting selected files: 12 | 13 | ![Photos](img/Photos.jpg) 14 | 15 | On the left side, a selection of photos (.jpg placeholders for raw and video) are shown in a scroll area in reverse order with the newest one on top. 16 | 17 | The file name in the photo (or placeholder) shows the correct filename of the resource represented by the picture. 18 | 19 | A large view of the photo or a video player is presented when a specific picture has been clicked on. 20 | 21 | - You need to select the **Camera** for which photos shall be shown.
In systems with multiple cameras, photos taken with a camera are stored in a camera-specific folder. 22 | - **From** and **To** date selectors allow restricting photos to a specific range of dates
When initially starting the dialog, the current day is selected.
Internally, **From** has time 00:00:00 and **To** 23:59:59. 23 | - Button **Today** restricts the time range to the current date 24 | - Button **All** sets **From** to January 1st, 1970 and **To** to today. 25 | - On the left of each thumbnail picture, there is a **checkbox** where you can select photos or videos for download or for deletion. 26 | - Buttons **Select all** and **Deselect all** apply to all photos currently shown in the scrolling area. 27 | - With button **Delete** you can delete all selected photos
Before deletion is executed, a confirmation is required.
If a specific media (e.g. video or raw photo) incudes the media file itself, a jpg placeholder and an optional histogram file, all are deleted.
Deletion of photos also clears the [Photo Display Buffer](./Phototaking.md#photo-display). 28 | - With the **Download** button, you can download the selected files.
Also here, a confirmation is required.
If more than one file has been selected, the selected files will be zipped into a file named *raspiCamSrvMedia_YYYYMMDD_HHMMSS.zip*
If a single file is selected, it will be downloades as is.
Placeholders for raw and videos as well as histogram are not included in the download. -------------------------------------------------------------------------------- /docs/Phototaking.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Photo Taking and Video Recording 2 | 3 | [![Up](img/goup.gif)](./LiveScreen.md) 4 | 5 | The *Live* tab of **raspiCamSrv** provides functionality to take photos, raw photos and videos. 6 | 7 | In all cases, the predefined [Camara Configuration](./Configuration.md) for the specific use case is applied together with the currently activated [Camera Controls](./CameraControls.md). 8 | 9 | As long as no photo has been taken, the *Live* screen will show like below: 10 | 11 | ![Foto0](img/Foto0.jpg) 12 | 13 | Now, you can use 14 | - the **Photo** button to take a photo, 15 | where the file type can be selected in the [Settings](./Settings.md) screen. ("jpg" is recommended) 16 | - the **Raw** button to take a raw photo. 17 | Currently only the *.dng* format is supported. 18 | - the **Video** button to record a video, 19 | where for the video format you may choose between *.mp4* and *.h264* in the [Settings](./Settings.md). Recommended is *.mp4* 20 | 21 | ## Photo / Raw Photo 22 | 23 | If the *Photo*/*Raw Photo* [Configuration](./Configuration.md) is not compliant with the *Live View* configuration, the live stream will be shortly interrupted in order to allow the system to apply the [Camera Configuration](./Configuration.md) for these use cases. 24 | For more details, see [raspiCamSrv Tasks and Background Processes](./Background%20Processes.md) 25 | 26 | The photo (in the case of raw photos a placeholder photo) will be shown in the bottom area of the screen together with the Metadata. 27 | 28 | ## Video 29 | 30 | ### With active Live Stream 31 | 32 | When video recording is started, the system will first check whether the required [Camera Configuration](./Configuration.md) is compliant with the configuration of the active Live Stream. 33 | 34 | If this is the case, first a normal photo of the scene will be taken, which will be used as placeholder. This will be shown in the bottom area. 35 | 36 | ![Video1](img/Video1.jpg) 37 | 38 | The **Video** button has changed to **Stop** which must be used to stop video recording. 39 | 40 | If audio is recorded along with video (see [Settings](./Settings.md#recording-audio-along-with-video)), this will be indicated by the process indicator: 41 | 42 | ![Processindicator](img/ProcessIndicator3.jpg) 43 | 44 | ### With paused Live Stream 45 | 46 | If video recording requires exclusive camera access because of specific configuration (see [raspiCamSrv Tasks and Background Processes](./Background%20Processes.md)), the live stream will be paused and a placeholder is shown instead: 47 | 48 | 49 | ![Video1](img/Video2.jpg) 50 | 51 | ## Photo Display 52 | 53 | When a photo, raw photo or video has been taken, the bottom area will show the photo together with its Metadata or its histogram: 54 | 55 | ![Foto1](img/Foto1.jpg) 56 | 57 | The file name for the photo, raw photo or video has been generated automatically based on system date/time when the request is issued to the camera. 58 | 59 | Above the photo, some buttons are shown which allow manipulation of a display buffer: 60 | 61 | ![PhotoBuffer0](img/FotoBuffer0.jpg) 62 | 63 | - Pressing the **-** button will remove the photo from display. 64 | It will not be removed from the file system. 65 | 66 | - The active **+** button shows that the photo is not yet a member of the display buffer. 67 | Pressing this button will add it to the buffer. 68 | 69 | This is shown as: 70 | 71 | ![PhotoBuffer1](img/FotoBuffer1.jpg) 72 | 73 | The indicator (x/y) above the **+** button shows the position of the Photo within the buffer as the left number and the total number of photos in the buffer as the right number. 74 | 75 | With the larger number of photos within the buffer, navigation buttons **<** and **>** allow navigation within the buffer: 76 | 77 | ![PhotoBuffer3](img/FotoBuffer3.jpg) 78 | 79 | Additional buttons are available: 80 | 81 | - **Hide** / **Show** can be used to hide or show the bottom area with the display buffer 82 | - **Clr(x)** will clear the entire buffer. 83 | The number in brackets is the total number of elements in the buffer. 84 | - **<** will display the previous photo in the buffer 85 | - **>** will display the next photo within the buffer 86 | - **-** when applied to a member of the buffer, will remove it from the buffer 87 | 88 | ## Metadata 89 | 90 | Along with a photo, also its metadata will be shown. 91 | 92 | Metadata and photo have been captured within the same capturing request. 93 | 94 | For the metadata, tooltips on the metadata properties explain the respective parameter. 95 | 96 | **Previous** and **Next** buttons allow scrolling the list of metadata if it does not fit on the screen. 97 | 98 | ![Metadata1](img/Metadata1.jpg) 99 | 100 | ![Metadata2](img/Metadata2.jpg) 101 | 102 | ## Histogram 103 | 104 | Alternatively to the metadata, you may also switch to Histogram if usage of histograms has been activated in the [Settings](./Settings.md). 105 | 106 | ![Histogram](img/MetaHistogram.jpg) 107 | 108 | The setting whether metadata or histogram are shown, is kept and remains active also when the next photo is taken or when scrolling through the Photo Buffer. 109 | 110 | Histogram graphics are calculated on the fly when they are requested for the first time. 111 | They are stored in a "hist" subfolder under the *Path for Photos/Videos* (see [Settings](./Settings.md)) -------------------------------------------------------------------------------- /docs/ScalerCrop.md: -------------------------------------------------------------------------------- 1 | # Image Cropping and Sensor Modes 2 | 3 | [![Up](img/goup.gif)](./ZoomPan.md) 4 | 5 | 6 | ## Pixel Array Size and Sensor Modes 7 | 8 | Raspberry Pi cameras have sensors with various Pixel Array Sizes which are shown in the [Camera Properies](./Information.md#camera-properties) section of the [Info](./Information.md) screen. 9 | 10 | For example, the V3 camera (Imx708) has a PixelArraySize of 4608 x 2592 pixels. 11 | 12 | ![SensorModes](./img/Cropping_SensorModes.jpg) 13 | 14 | A camera can operate in a limited number of **Sensor Modes** (e.g. Sensor Modes 0, 1, 2 for the Imx708). 15 | 16 | Information on Sensor Modes is shown in the [Sensor Mode x](./Information.md#sensor-modes) section of the [Info](./Information.md) screen. 17 | 18 | Each Sensor Mode is characterized by (among others) 19 | - a Bit Depth 20 | - a Frame Rate 21 | - a specific field of view (Crop Limits) which either spans the entire PixelArraySize or a subarea of it. 22 | - an output size which specifies the resolution of the image obtained with this Sensor Mode. 23 | Here, an image pixel corresponds to a single sensor pixel or a group of 2x2 pixels. 24 | The output sizes for Imx708 are 25 | Sensor Mode 0: 1536 x 864 26 | Sensor Mode 1: 2304 x 1296 27 | Sensor Mode 2: 4608 x 2592 28 | 29 | ## Cropping 30 | 31 | Raspberry Pi cameras can deliver images from a subarea of the sensor. 32 | This area is specified by the [Camera Controls](./CameraControls.md) parameter [ScalerCrop](./ZoomPan.md#current-scalercrop-zoom) which can be specified in the [Zoom and Pan](./ZoomPan.md) section of the [Live](./LiveScreen.md) screen of **raspiCamSrv**. 33 | 34 | The effective ScalerCrop rectangle (ScalerCrop Zoop/Pan) is restricted by parameters which can be obtained from the ```camera_controls``` (see [Picamera2 Manual](./picamera2-manual.pdf), Appendix B) 35 | 36 | **NOTE**: All rectangles are specified by a tuple (xOffset, yOffset, width, height) 37 | 38 | - ScalerCrop Maximum 39 | This is the largest rectangle in which the effective ScalerCrop rectanglemust be completely enclosed. 40 | This rectangle is limited by the Crop Limits of the Sensor Mode. 41 | - Scaler Crop Minimum 42 | This is the smallest area which can be delivered by the camera. 43 | Only width and height are relevant and width and height of the effective ScalerCrop rectangle must not be smaller. 44 | - Scaler Crop Default 45 | This is the default ScalerCrop rectangle which will always be chosen by the camera if an effective ScalerCrop rectangle is not requested within the Camera Properties. 46 | 47 | Whereas in a standard case, ScalerCrop Maximum and ScalerCrop Default cover the entire PixelArraySize, the pictures below show the situation for two extreme cases: 48 | 49 | ![ScalerCrop Sensor Mode 0](./img/Cropping_ScalerCrop_0.jpg)   ![ScalerCrop Sensor Mode 0](./img/Cropping_ScalerCrop_2.jpg) 50 | 51 | ## Strategy 52 | 53 | The strategies by which the camera operates are not fully documented in detail. 54 | However, systematic experiments with the relevant parameters show the following bahavior: 55 | 56 | - Use the [Camera Configuration](./Configuration.md) to specify the **Stream Sizes** for different use cases. 57 | The most 'relevant' configuration seems to be the **raw** stream. 58 | A special option (*Sync Aspect Ratio*) assures consistent aspect ratios for all configurations. 59 | - Depending on the 'relevant' Stream Size, the camera will automatically choose a suitable Sensor Mode. 60 | The active Sensor Mode can be seen in the [Installed Cameras](./Information.md#camera-x) section of the [Info](./Information.md) screen for the active camera if it is currently open and started. 61 | **NOTE**: **raspiCamSrv** will normally use configurations where all 3 streams (raw, main, lores) are configured in order to allow simultaneous camera access with different intents. 62 | - From the Crop Limits of the Sensor Mode the ScalerCrop Maximum rectangle is determined. 63 | - The ScalerCrop Default is the largest rectangle, 64 | which has the aspect ratio of the 'relevant' Stream Size, 65 | and which is fully inside the Crop Limits of the active Sensor Mode, 66 | and which is horizontally and vertically centered. 67 | - Zooming and Panning allows scaling the rectangle and panning it within the area of the ScalerCrop Maximum rectangle. 68 | Zooming and Panning with **raspiCamSrv** always preserves the aspect ratio. 69 | - Finally, the effective ScalerCrop area is scaled to the *Stream Size* of the different streams 70 | 71 | Because the aspect ratio of the ScalerCrop Zoom/Pan rectangle is determined from the aspect ratio of the 'relevant' stream, the Live Stream will be distorted if the aspect ratio for the *Live View* configuration is different from that of the configuration for the 'relevant' stream. -------------------------------------------------------------------------------- /docs/SettingsAButtons.md: -------------------------------------------------------------------------------- 1 | # Settings - Action Buttons 2 | 3 | [![Up](img/goup.gif)](./Settings.md) 4 | 5 | On this screen, you can 'design' the [Console Action Buttons](./ConsoleActionButtons.md) by assigning visual attributes and [Actions](./TriggerActions.md) to Buttons arranged on a grid. 6 | 7 | ![ActionButtons](./img/Settings_AButtons.jpg) 8 | 9 | The general usage of this screen is similar to that for configuring [Versatile Buttons](./ConsoleVButtons.md), except that an [Actions](./TriggerActions.md) needs to be assigned to a button. -------------------------------------------------------------------------------- /docs/SettingsAPI.md: -------------------------------------------------------------------------------- 1 | # Settings API 2 | 3 | [![Up](img/goup.gif)](./Settings.md) 4 | 5 | In this section of the Settings screen, parameters for protection of the API through [JSON Web Tokens](https://en.wikipedia.org/wiki/JSON_Web_Token) (JWT) can be configured. 6 | 7 | **raspiCamSrv** uses the [Flask implementation of JWT](https://flask-jwt-extended.readthedocs.io/en/stable/index.html), requiring installation of the ```flask_jwt_extended``` package (see [Release Notes for 2.11](./ReleaseNotes.md#v2110)) 8 | 9 | This section will only be visible if this package is installed and if the [Geleral Parameter](./Settings.md) *Allow access through API* is checked. 10 | 11 | ![Settings API](./img/Settings_API_1.jpg) 12 | 13 | JWT requires a secret private key to sign tokens. 14 | 15 | **raspiCamSrv** will store this key in a secrets file and will not publish it in [configuration exports](./SettingsConfiguration.md#server-configuration-storage).
Therefore, in order to activate API support, the location of the secrets file needs to be specified. It is recommended using the folowing path:
```/home//.secrets/raspiCamSrv.secrets```
This file will usually also be used to store credentials of the mail server for [notification](./TriggerNotification.md) on motion detection. 16 | 17 | The following parameters need to be configured: 18 | 19 | - *JWT Secret Key File Path*:
The full path to the secrets file
The path as well as the file will be automatically created if they do not exist. 20 | - *Access Token Expiration in Minutes*
The Access Token is used for normal access to API endpoints.
For higher security, it is recommended to limit the livetime of this token.
This requires, however, that clients are able to react on an expiration error with refreshing the token.
If this is not possible, expiration can be deactivated by specifying the value 0. 21 | - *Refresh Token Expiration in Days*
The refresh token can be used to authenticate for receiving a fresh Access Token.
Both, Access Token and Refresh Token are obtained with the ```/api/login``` endpoint.
If an expiration period > 0 for the Refresh Token is specified, a new login is required if the refresh token has expired. 22 | 23 | ## API Status Information 24 | 25 | The status of API support is indicated by the colored status line. 26 | 27 | A status change will only take effect for clients if the server is restarted with the necessary configuration: 28 | 29 | 1. [Store the configuration](./SettingsConfiguration.md) 30 | 2. Make sure that the server is configured to [Start with stored Configuration](./SettingsConfiguration.md) 31 | 3. Restart the server (see [Update Procedure, step 4](./ReleaseNotes.md#update-procedure)) 32 | 33 | 34 | ### API enabled but not active 35 | 36 | ![Settings API](./img/Settings_API_2.jpg) 37 | 38 | This is the initial status before specification of the path to the secrets file. 39 | 40 | ### API configuration completed but not yet active 41 | 42 | ![Settings API](./img/Settings_API_3.jpg) 43 | 44 | This status is obtained after valid JWT data have been submitted and if the server has not yet been restarted with these data. 45 | 46 | ### API active 47 | 48 | ![Settings API](./img/Settings_API_4.jpg) 49 | 50 | This status is shown after the server has been started with valid JWT settings. 51 | 52 | ## Generation of Access Token 53 | 54 | If a client system is not able to correctly obtain valid tokens from the server, it is possible to use an Access Token which does not expire and generate it with the **raspiCamSrv** UI: 55 | 56 | ![Settings API](./img/Settings_API_5.jpg) 57 | 58 | This token can be copied into the clipboard and used as bearer token in API calls.
**raspiCamSrv** will never persist or publish this token, except once on this screen after it has been generated. -------------------------------------------------------------------------------- /docs/SettingsConfiguration.md: -------------------------------------------------------------------------------- 1 | # Settings / Server Configuration 2 | 3 | [![Up](img/goup.gif)](./Settings.md) 4 | 5 | 6 | The *Settings* screen includes a *Configuration* section with functions to control the **raspiCamSrv** configuration: 7 | 8 | ![Configuration](./img/Settings_Config.jpg) 9 | 10 | - Button *Store Configuration* generates a set of JSON files which include the entire configuration of the **raspiCamSrv** server (see [below](#configuration-storage)).
**NOTE**: This does not include [Photo Series](./PhotoSeries.md). These are persisted automatically and independently. It also does not include [Events](./TriggerActive.md). 11 | - Button *Load Stored Configuration* replaces the current configuration with the previously stored configuration.
[Photo Series](./PhotoSeries.md) and [Events](./TriggerEventViewer.md) are not affected.
**NOTE**: If you had activated [API](./SettingsAPI.md) access before, this will be deactivated when the stored configuration is loaded. You need to restart the server to activate it again. 12 | - Button *Reset Server* stops any background activity (live stream, video, photo series, motion capturing and event handling) and replaces the current configuration with the default configuration.
[Photo Series](./PhotoSeries.md) and [Events](./TriggerEventViewer.md) are not affected. Any associated resources remain unchanged. However, an active [Photo Series](./PhotoSeries.md) will be paused and needs to be continued.
**NOTE**: If you had activated [API](./SettingsAPI.md) access before, this will no longer be available when the configuration is reset.
The same applies to [Notification Settings](./TriggerNotification.md) which need to be reconfigured.
**NOTE**: If you had activated *Start Server with Stored Configuration*, this will be deactivated. Probably, you might want to store the new configuration bofore activationg this again. 13 | - *Start server with stored Configuration* controls whether a server start shall use the default configuration or the stored configuration. 14 | 15 | #### Server Configuration Storage 16 | 17 | When the configuration is stored with the *Store Configuration* button, a set of files is created/replaced in the ```raspi-cam-srv/raspiCamSrv/static/config``` folder: 18 | 19 | ![Config](./img/Settings_ConfigStore.jpg) 20 | 21 | - _loadConfigOnStart.txt
This is just an empty marker file. If the file exists, the server will initiate its configuration with configuration data stored in the other files.
Otherwise, default configuration settings will be applied. 22 | - cameraConfigs.json
This is currently not used 23 | - cameraProperties.json
This file contains the camera properties of the actice camera, which are shown in [Camera Properties](./Information.md#camera-properties).
Camera properties are always read directly from the camera. 24 | - cameras.json
This file contains the installed cameras with information shown in [Installed Cameras](./Information.md#installed-cameras)
Installed cameras are always directly queried from the camera system. 25 | - controls.json
This file includes all the camera configuration settings as shown in the upper right part of the Live screen [Camera Controls](./LiveScreen.md#top-right-quarter) 26 | - LiveViewConfig.json, photoConfig.json, rawConfig.json, videoConfig.json
contain the camera configuration settings for the different use cases as shown in the [Config screen](./Configuration.md) 27 | - rawFormats.json
contain a list of formats which can be used for raw photos.
This information is extracted from the different [Sensor Modes](./Information.md#sensor-modes) and is always directly obtained from the camera system. 28 | - serverConfig.json
This file includes configuration settings for the **raspiCamSrv** dialog system, such as information included in the [Settings](./Settings.md) dialog, or the configuration of the [Display Buffer](./LiveScreen.md#bottom-left-quarter) and some navigation details. 29 | - streamingCfg.json contains, for each camera, the [Tuning](./Tuning.md) configuration, the [Live View Configuration](./Configuration.md) settings and the [Camera Controls](./CameraControls.md) which will be used for streaming. The included Video Configuration is stored because Picamera2 always requires the *main* stream to be configured. This will not be used for streaming. 30 | - triggerConfig.json contains the configuration settings for triggered capture of videos and photos (motion capture) 31 | - tuningConfig.json contains the settings maintained in the [Tuning](./Tuning.md) dialog 32 | -------------------------------------------------------------------------------- /docs/SettingsUsers.md: -------------------------------------------------------------------------------- 1 | # Settings Users 2 | 3 | [![Up](img/goup.gif)](./Settings.md) 4 | 5 | 6 | For management of users, the *Settings* screen has an additional section *Users* which is visible only for the SuperUser: 7 | 8 | ![User Management](./img/Auth_UserManagement.jpg) 9 | 10 | The list shows all registered users with 11 | - unique user *ID* 12 | - user *Name* 13 | - *Initial*, indicating whether the user has been initially created by the SuperUser and needs to change password on first log-in. 14 | - *SuperUser*, indicating the user registered as SuperUser 15 | 16 | The SuperUser can 17 | - register new users using the *Register New User* button 18 | - remove users which have been selected in the list 19 | -------------------------------------------------------------------------------- /docs/SettingsVButtons.md: -------------------------------------------------------------------------------- 1 | # Settings - Versatile Buttons 2 | 3 | [![Up](img/goup.gif)](./Settings.md) 4 | 5 | This Settings screen allows configuration of function buttons which will be shown on the [Console](./Console.md) screen. 6 | 7 | ![vButtons](./img/SettingsVButtons.jpg) 8 | The screenshot above is an example layout. Initially, the *Button Settings* area is empty. 9 | 10 | ## Button Layout 11 | 12 | Buttons on the [Console](./Console.md) screen are arranged in an N x M grid where the *Number of Rows* and *Number of Columns* can be configured. 13 | 14 | Once non-zero values have been specified and submitted, the *Buttons Settings* area will show a list of parameters for specification of button properties. 15 | 16 | If an existing grid layout is modified by changing either the number of rows and/or the number of columns, the configured rows and columns of buttons will be preserved if the new values are larger than the old ones. Superfluous rows or columns will be removed in case that new dimensions are smaller than the old ones. 17 | 18 | The checkbox *Interactive Commandline* controls whether [Console](./Console.md) will show an interactive commandline where commands can be directly entered. 19 | 20 | **IMPORTANT**: You need to [Store Configuration](./SettingsConfiguration.md) if you want the button settings to survive a server restart! 21 | 22 | ## Button Settings 23 | 24 | - *Row*
The row in which the button will be placed. 25 | - *Col*
The column in which the button will be placed. 26 | - *Visible*
When the checkbox is activated, a button will be shown in the given grid cell, otherways the grid cell will remain empty. 27 | - *Shape*
The shape of each button can be selected from a small set of standard shapes (Rectangle, Rounded, Circular, Square).
The example layout of the above configuration is shown for the [Console](./Console.md) screen. 28 | - *Color*
The Color of each button can be selected from a small set of standard Colors (Black, Red, Green, Yellow, Blue).
The example layout of the above configuration is shown for the [Console](./Console.md) screen. 29 | - *Button Text*
Text to be shown on the button. 30 | - *Command*
Linux command to be executed on OS level.
You may use available Linux commands or run your own scripts.
It is recommended to test these commands on an OS prompt before configuring and running them out of **raspiCamSrv**
The working directory is that of the service (see [Service Configuration](../README.md#service-configuration)). 31 | - *Conf*
If the checkbox is checked, the respective button will require a confirmation before the command will be executed. 32 | 33 | Any changes for these settings need to be submitted with the button underneath the table 34 | 35 | -------------------------------------------------------------------------------- /docs/TriggerActions.md: -------------------------------------------------------------------------------- 1 | # Actions 2 | 3 | [![Up](img/goup.gif)](./Trigger.md) 4 | 5 | This screen is used to specify actions which can be started by **raspiCamSrv**, either as a reaction on a [Trigger](./TriggerTriggers.md) or manually through an [Action Button](./ConsoleActionButtons.md). 6 | 7 | ![Actions1](./img/Trigger_Actions1.jpg) 8 | 9 | **IMPORTANT**: To preserve any configurations over server restart, you need to [store the configuration and activate *Start Server with stored Configuration*](./SettingsConfiguration.md). 10 | 11 | ## Creating an Action 12 | 13 | 1. In field *Action Source*, select the source system for which the action is defined: 14 | ![Action2](./img/Trigger_Actions2.jpg) 15 | 2. This will open a list of devices defined for the chosen source system: 16 | ![Action3](./img/Trigger_Actions3.jpg) 17 | For the GPIO system, these are the **Output** devices configured on [Settings/Devices](./SettingsDevices.md)
**NOTE**: For SMTP, a device will only be shown if a mail account has been specified and verified in dialog [Notification](./TriggerNotification.md).
If this is the case, the configured *SMTP Server* will be shown as device. 18 | 3. After a device has been selected, the system will show the device type with a link to related gpiozero documentation as well as the action methods which can be executed for this device (this information is taken from the [fixed configuration for the device type](./SettingsDevices.md#device-type-configuration)): 19 | ![Action4](./img/Trigger_Actions4.jpg) 20 | 4. When the method has been chosen, the sytem will display any parameters which may be required for this method: 21 | ![Action5](./img/Trigger_Actions5.jpg) 22 | Now you need to specify values for these parameters, unless you leave the defaults, and enter a unique name for the action. 23 | In this step, the *Submit* button will be activated. 24 | 5. Pressing the *Submit* button will create the action and show it in the *Action Overview*. 25 | 26 | ### Parameters 27 | 28 | The parameters, for which values can be specified, are parameters of the method signature for the device class. 29 | Information about their type and value range, as well as about their function can be obtained from the *gpiozero* class documentation accessible through the link. 30 | 31 | **raspCamSrv** will check the data type by analyzing the datatype of the [configured template](./SettingsDevices.md#device-type-configuration). However, the allowed value range is currently not checked. You need to consult the *gpiozero* documentation. 32 | 33 | Sometimes, the 'Action Method' is in fact a property and not a callable method. In this case, **raspiCamSrv** will just assign the value to the property and ignore the parameter name. 34 | 35 | ### Control 36 | 37 | Control parameters are not part of the class interfaces but they can affect how **raspiCamSrv** processes an action method: 38 | 39 | - *duration*
With duration, you can specify the length of the time interval, during which the device will stay in the state achieved through the method, for example the 'on' state of an LED.
After this time, the system will check, whether the device object has a method off() (which is the case for LEDs and Buzzer) or a method stop() (which is the case for Motor and TonalBuzzer).
If either of these methods is found, it is applied.
In effect, the device will be in an inactive state afterwards. 40 | - *steps*
This is the number of steps in which the device shall reach the intended state within the given duration.
The intention here is that one might want a smooth rather than an abrupt movement, for example for a Servo.
**NOTE**This feature is currently not yet supported. 41 | - *burst_count*
This is a a parameter for method "take_photo". You can specify the number of photos which shall be taken as part of a photo burst in a series with a given interval. 42 | - *burst_intvl*
This is the interval you can specify for a photo burst. 43 | - *attach_photo*, *attach_video*
for an SMTP action, you can specify whether or not photos and/or videos shall be attached to the mail which have been created as part of the actions of the triggered event. 44 | 45 | ### Restrictions 46 | 47 | At a given time, only one action can be executed on a specific device type. 48 | 49 | ### Timing of Action Execution 50 | 51 | Whereas action execution is synchronous, when invoked through an [Action Button](./ConsoleActionButtons.md) (the user needs to wait until the action is completed), this is different for the case when an action is triggered by a [Trigger](./TriggerTriggers.md). 52 | 53 | In the latter case, action execution is done in an own thread which allows the action to be completed independently from the event handling thread which can treat other events in the meantime. 54 | 55 | This means that actions are always completed and not interrupted. 56 | 57 | This applies to actions with a configured duration, such as an LED which shall be 'on' for a certain time or a video with a given duration. 58 | However, it applies also to actions with an inherent time consumtion. For example the movement of a StepperMotor can consist of hundrets of steps with a waiting tyme of 1 to 4 ms after each step. This require in total several seconds to complete. 59 | 60 | If for such an action a new action is requested before the previous action is completed, it will wait until the device is no longer busy. 61 | 62 | When stopping the event handling system, **raspiCamSrv** will wait for active actions to complete. 63 | 64 | ## Activation of Actions 65 | 66 | If the event-handling thread is currently active: 67 | - The *Active* check boxes are locked. 68 | 69 | If the event-handling thread is not active: 70 | - The *Active* check boxes are active 71 | 72 | You can activate/deactivate Actions by changing the *Active* check box and submitting the change. 73 | 74 | ## Deletion of Actions 75 | 76 | You can select one or multiple actions for deletion in the *Delete* column and submit the selection. 77 | 78 | The *Delete* column will only be accessible for change if the event-handling thread is currently not active. 79 | 80 | You cannot delete an action if it is used in an [Action Button](./SettingsAButtons.md). 81 | 82 | When an action is deleted, also its reference in the [Trigger-Actions](./TriggerTriggerActions.md) will be removed. 83 | 84 | ## Changing Actions 85 | 86 | Changing of actions is currently not possible. 87 | 88 | However, you can easily create a new similar one with different parameters and deactivate or delete the old one. 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /docs/TriggerActive.md: -------------------------------------------------------------------------------- 1 | # Triggered Capture of Videos and Photos 2 | 3 | [![Up](img/goup.gif)](./Trigger.md) 4 | 5 | # Active Motion Capturing 6 | 7 | The *Start* button on the *Control* page starts the trigger capturing process. 8 | 9 | ![ActiveCapture](./img/Trigger_Active.jpg) 10 | 11 | An active capture process is indicated with red [Process Status Indicator](./UserGuide.md#process-status-indicators) 12 | 13 | The *Start* button has changed to *Stop*, which allows stopping the process. 14 | 15 | If motion capturing is currently active but operation paused because of schedule settings, this is indicated by a yellow process status indicator: 16 | 17 | ![Capturepaused](./img/ProcessIndicator8.jpg) 18 | 19 | ## Event Data 20 | 21 | Event data are stored in directory ```./prg/raspi-cam-srv/raspiCamSrv/static/events```: 22 | 23 | ![Eventstorage](./img/Trigger_Storage.jpg) 24 | 25 | Storage includes a log file as well as video and photo files. 26 | 27 | ## Parallel Activities 28 | 29 | While motion capturing is active, the live stream process will be kept active because this is used for motion detection. 30 | 31 | While motion capturing is active, you may continue working with **raspiCamSrv**. 32 | You may even take photos, videos or photo series. 33 | 34 | However, you should avoid changing camera controls or configuration because this might restart the camera. 35 | 36 | ### Dos and Don'ts 37 | 38 | #### Blocked: 39 | 40 | - Changing [Settings](./Settings.md) 41 | - Starting a [Exposure Series](./PhotoSeriesExp.md) or a [Focus Stack Series](./PhotoSeriesFocus.md) 42 | - Changing [Camera Configuration](./Configuration.md) 43 | 44 | #### Changing Zoom 45 | 46 | This can be done while trigger capturing is active. 47 | However the moment when the new zoom setting is activated will be registered as motion event. 48 | 49 | #### Changing Focus 50 | 51 | To improve the focus for camera model 3, you may change [Focus Settings](./FocusHandling.md) and [Trigger Autofocus](./FocusHandling.md#trigger-autofocus) 52 | 53 | #### Changing Camera Controls 54 | 55 | In order to change the quality of videos and photos, you may change any [Camera Controls](./CameraControls.md) while motion capturing is active. 56 | 57 | ## Log File 58 | 59 | While events are registered and videos and photos are taken, the system maintains a log file (```events/_events.log```) with antries for all events and the times when photos are captured or videos are started and stopped: 60 | 61 | ![EventLog](./img/Trigger_Logfile.jpg) 62 | 63 | The log file of the above screenshot shows examples without delayed actions as well as with configurations with 4 photos in the *Photo Burst*. 64 | 65 | ## Database 66 | 67 | Events and event actions are also stored in the SQLite3 database stored at 68 | ```./prg/raspi-cam-srv/instance/raspiCamSrv.sqlite```. 69 | 70 | The primary purpose of the database is providing fast access to event data over a longer period for the [Event Viewer](./TriggerEventViewer.md) 71 | 72 | ![TriggerDB](./img/Trigger_DB.jpg) 73 | 74 | Table *events* holds all individual events: 75 | 76 | ![DBEvents](./img/Trigger_DB_Events.jpg) 77 | 78 | Table *eventactions* holds the actions taken for each event: 79 | 80 | ![DBEventactions](./img/Trigger_DB_Eventactions.jpg) -------------------------------------------------------------------------------- /docs/TriggerCameraActions.md: -------------------------------------------------------------------------------- 1 | # Camera Actions 2 | 3 | [![Up](img/goup.gif)](./Trigger.md) 4 | 5 | 6 | ![Action](./img/Trigger_Action.jpg) 7 | 8 | This section allows specification of aspects for photos and/or videos recorded in reaction an an event: 9 | 10 | - *Video Recording Type* 11 | With *Normal*, video recording starts with the event or, if configured, after a specified dalay. 12 | With "Circular*, the system continuesly captures video in a circular buffer with a capacity of a few seconds. In case of an event, also the seconds before the event will be available in the video. 13 | Currently, only *Normal* is supported. 14 | - *Circular Buffer Size* is the number of seconds, the system shall look 'backwards' from the time of an event. 15 | - *Video Duration* specifies the length of videos captured in case of an event. 16 | If a new event is registered while video recording from the previous event is still active, this will be stopped before recording for the new event starts. 17 | - *Photo Burst - Number of Photos* allows specifying a number of photos which will be successively captured in case of an event. 18 | If video is recorded, at least one photo must be specified. 19 | - *Photo Burst Interval* is the interval after the previous photo when the system will capture a new photo if there is still motion detected. If no motion is detected after this interval, no photo will be taken. 20 | - *Action data path* is the path where pictures and logs for events will be stored. 21 | -------------------------------------------------------------------------------- /docs/TriggerEventViewer.md: -------------------------------------------------------------------------------- 1 | # Triggered Capture of Videos and Photos 2 | 3 | [![Up](img/goup.gif)](./Trigger.md) 4 | 5 | ## Calendar 6 | 7 | The calendar gives an overview on the number of events which have been registered for a specific day: 8 | 9 | ![EventCalendar](./img/Trigger_Calendar.jpg) 10 | 11 | Clicking on a red field navigates to the [Events](#events) display for this specific day. 12 | 13 | You can change the active month using the date control and navigation arrows, or return to the current month with the *Now* button. 14 | 15 | ### Download Log 16 | 17 | You can download the [Log file](./TriggerActive.md#log-file) including a timeline of all events and associated actions.
18 | Note that only those triggers and their associated actions will be included in the log, for which the [control parameter](./TriggerTriggers.md#control) *event_log* has the value "True". 19 | 20 | ### Cleanup 21 | 22 | The *Cleanup* button can be used for removing old events. 23 | This requires that the process is stopped. 24 | 25 | After pressing the button, a confirmation is required: 26 | ![CleanupConfirm](./img/Trigger_ConfirmCleanup.jpg) 27 | The *Retention Period* for cleanup, shown in this confirmation, has been specified on the [Trigger/Control](./Trigger.md) page. 28 | 29 | For all events older than the *Retention Period*, cleanup will 30 | 31 | - remove all log file entries 32 | - delete all photo and video files 33 | - delete related database entries 34 | 35 | 36 | # Events 37 | 38 | Event Details are shown in the Event Viewer for a specific day: 39 | 40 | ![Event Viewer](./img/Trigger_Events.jpg) 41 | 42 | In the top area, you may 43 | - change the active day using the date control or the arrow buttons. 44 | Single arrows shift by day, double arrows by week. 45 | In each case the starting hour is set to 00:00h. 46 | - change the start time from which on events will be shown. 47 | Here, single arrows shift by a quarter of an hour, double arrows by an hour. 48 | - You can select whether you want to see videos, photos, both or none. 49 | In case of videos, the first photo is always shown instead of the video on the left side, however clicking on the photo will open the video viewer. 50 | - whether a video or a photo is represented by the small picture can be distinguished by information on the video length. 51 | 52 | Selecting a video or photo shows it in the detail area on the right side. 53 | 54 | The Event Card for each event 55 | ![EventCard](./img/Trigger_EventCard.jpg) 56 | shows, from top to bottom: 57 | - Event Type (currently always "Motion") 58 | - Event date 59 | - Event time 60 | - Event trigger (Currently only "Motion Detection") 61 | - Event trigger algorithm 62 | [Mean Square Diff](./TriggerMotion.md) 63 | [Frame Diff.](./TriggerMotion.md#test-for-frame-differencing-algorithm) 64 | [Optical Flow](./TriggerMotion.md#test-for-optical-flow-algorithm) 65 | [BG Subtraction](./TriggerMotion.md#test-for-background-subtraction-algorithm) 66 | - Trigger parameter (see [Motion](./TriggerMotion.md) tab) 67 | msd : *Mean Square Threshold* 68 | BBox_thr : *Bounding Box Threshold* 69 | IOU_thr : *IOU Threshold* 70 | Motion_thr : *Motion Threshold* 71 | Model : *Background Subtraction Model* (1=MOG2, 2=KNN) 72 | 73 | 74 | You may use the information to fine tune the algorithm parameters on the [Motion](./TriggerMotion.md#motion-detection-configuration) tab. 75 | 76 | In case that photos have been taken together with videos, this is represented as shown below. 77 | Videos show the video length in the footer. 78 | 79 | ![EventsVodeoPhoto](./img/Trigger_Events_Photo.jpg) -------------------------------------------------------------------------------- /docs/TriggerNotification.md: -------------------------------------------------------------------------------- 1 | # Triggered Capture of Videos and Photos 2 | 3 | [![Up](img/goup.gif)](./Trigger.md) 4 | 5 | ## Notification 6 | 7 | On this tab, you specify the details required for notification on an event by e-Mail: 8 | 9 | ![TriggerNotification0](./img/Trigger_Notification0.jpg) 10 | 11 | ### Mail Server Settings 12 | 13 | - *SMTP Server* is the server address, for example "smtp.gmail.com" 14 | - *Port* is the server port to be used 15 | - *Use SSL* specifies whether or not SSL (Secure Sockets Layer) is to be used 16 | - *Server requires Authentication* must be checked if the mail server requires authentication with user and password. 17 | - *User* is the user name to be used for login to the server. This is typically identical with the e-Mail address. 18 | - *Password* is the password required for authentication 19 | 20 | ### Handling of Mail Server Credentials 21 | 22 | Credentials for authentication to the mail server are not part of the normal raspiCamSrv configuration. 23 | They ere never exported to JSON files when configuration is stored ([Settings/Configuration](./SettingsConfiguration.md)) 24 | Therefore, they can also not be imported when the server restarts. 25 | 26 | **raspiCamSrv** offers two alternatives for secure handling: 27 | 28 | #### 1. Storage in a Secrets File 29 | 30 | This is activated by checking *Store Credentials in File* and by specifying the full path of that file in *Credentials File Path*. 31 | For example, the path could be ```/home//.secrets/raspiCamSrv.secrets```. 32 | If the path and the file do not exist, they will be automatically created. 33 | Access to this file should be restricted to the user running **raspiCamSrv** as service or from the command line. 34 | 35 | The advantage of this method is, that on server restart the system can automatically load user name and password for connection to the mail server. Thus, notification will automatically be activated, provided that Triggered Capture is automatically started with server start. 36 | 37 | #### 2. Manual Entry 38 | 39 | Alternatively to storage in a secrets file, *User* and *Password* can be manually entered. 40 | **raspiCamSrv** will keep this information in memory during the server livetime. 41 | After server restart, these credentials are initally not available and, therefore, notification will not be active until the credentials have been entered once on this screen. 42 | 43 | ### Mail Settings 44 | 45 | - *From e-Mail* is the e-Mail address to be shown in the *From* field. Mail servers may replace this with the e-Mail address of the account. 46 | - *To e-Mail* is the e-Mail address of the recipient to whom the notification is to be sent. 47 | - *Subject* Is the text for the *Subject* field of the mail to be sent. 48 | - With *Notification Pause*, you can specify a pause in seconds in which no further notification mail wil be sent. 49 | A value smaller than the *Detection Pause* (see [Trigger Control](./Trigger.md#control)) will have no effect, so that every event will be notified. 50 | If the value is chosen as a multiple (N) of the *Detection Pause*, only every Nth event will be notified. 51 | - *Include Video* specifies whether or not the event video will be included in the mail. 52 | If this is selected, the mail will be sent not earlier than video recording has terminated. 53 | This is determined by *Video Duration* (see [Trigger Actions](./Trigger.md#actions)). 54 | Keep in mind that the video size should not exceed the maximum mail size allowed by the provider. 55 | - *Include Photos* specifies whether or not photos should be attached to the mail. 56 | If this is selected and a number > 1 has been specified for *Photo Burst* (see [Trigger Actions](./Trigger.md#actions)), the mail will not be sent before the last photo has been taken or the next event has been registered. 57 | 58 | ### Submitting Configuration Settings 59 | 60 | ![TriggerNotification1](./img/Trigger_Notification1.jpg) 61 | 62 | When submitting configuration entries, the system will automatically try to connect to the mail server using the specified credentials. 63 | 64 | ![TriggerNotification3](./img/Trigger_Notification3.jpg) 65 | 66 | ![TriggerNotification3a](./img/Trigger_Notification3a.jpg) 67 | 68 | If the connection test was successful, this is indicated in the message area, otherwise, an error message is shown. 69 | User and password are removed from the screen and need to be entered again, if necessary. 70 | 71 | Whether or not connection to the mail server has been verified, is allways shown in the top of the screen. 72 | 73 | ### Entering Credentials after Server Restart 74 | 75 | After the server has been restarted and credentials are not stored in a secrets file, they need to be entered once: 76 | 77 | ![TriggerNotification2](./img/Trigger_Notification2.jpg) 78 | 79 | 80 | ### Notification Errors 81 | 82 | Sending a mail may require several seconds, especially if the mail includes larger attachments. 83 | Therefore an additional thread is started for each mail to be sent, in order not to block capturing events. 84 | 85 | If an error occurs while trying to send a mail, an error status is set in the Trigger configuration settings. 86 | The error message is shown on the *Control* Tab of the *Trigger* screen: 87 | 88 | ![TriggerNotificationError](./img/Trigger_NotificationError.jpg) 89 | 90 | The message will vanish when Triggered Capture is restarted or when the server is restarted. 91 | 92 | Errors occurring in the sending process do not stop motion capturing. -------------------------------------------------------------------------------- /docs/TriggerTriggerActions.md: -------------------------------------------------------------------------------- 1 | # Trigger-Actions 2 | 3 | [![Up](img/goup.gif)](./Trigger.md) 4 | 5 | On this page, you specify which actions are invoked in case of a specific Trigger event. 6 | 7 | ![TriggerActions](./img/Trigger_TriggerActions.jpg) 8 | 9 | **IMPORTANT**: To preserve any configurations over server restart, you need to [store the configuration and activate *Start Server with stored Configuration*](./SettingsConfiguration.md) 10 | 11 | 12 | The dialog will only allow changes when the event handling thread is not active. 13 | 14 | Just activate the check box for every event you want to be triggered by a specific trigger. -------------------------------------------------------------------------------- /docs/TriggerTriggers.md: -------------------------------------------------------------------------------- 1 | # Triggers 2 | 3 | [![Up](img/goup.gif)](./Trigger.md) 4 | 5 | This page is used for spacification of triggers. 6 | Triggers are registered events occurring for the camera system or for GPIO input [devices](./SettingsDevices.md) which can be used to initiate one or multiple [actions](./TriggerActions.md). 7 | 8 | ![Trigger0](./img/Trigger_Trigger1.jpg) 9 | 10 | 11 | **IMPORTANT**: To preserve any configurations over server restart, you need to [store the configuration and activate *Start Server with stored Configuration*](./SettingsConfiguration.md) 12 | 13 | ## Creating a Trigger 14 | 15 | 1. In field *Trigger Source*, select the source system for which the trigger is defined: 16 | ![Trigger1](./img/Trigger_Trigger2.jpg) 17 | 2. This will open a list of devices defined for the chosen source system: 18 | ![Trigger1](./img/Trigger_Trigger3.jpg) 19 | for the GPIO system, these are the **Input** devices configured on [Settings/Devices](./SettingsDevices.md) 20 | 3. After a device has been selected, the system will show the device type with a link to related gpiozero documentation as well as the events which can be trapped for this device (this information is taken from the [fixed configuration for the device type](./SettingsDevices.md#device-type-configuration)): 21 | ![Trigger1](./img/Trigger_Trigger4.jpg) 22 | 4. When the event has been chosen, the sytem will display any parameters which may be required for this event: 23 | ![Trigger1](./img/Trigger_Trigger5.jpg) 24 | Now you need to specify values for these parameters, unless you leave the defaults, and enter a unique name for the trigger. 25 | In this step, the *Submit* button will be activated. 26 | 5. Pressing the *Submit* button will create the trigger and show it in the *Trigger Overview*. 27 | 28 | ### Parameters 29 | 30 | The parameters, for which values can be specified, are properties or methods of the device class. 31 | Information about their function can be obtained from the gpiozero class documentation accessible through the link. 32 | 33 | ### Control 34 | 35 | Control parameters are not part of the class functionality but they can affect how **raspiCamSrv** processes a captured event: 36 | 37 | - *bounce_time*
This is a time interval given in seconds.
After an event has been processed, other events occurring within this interval will be ignored.
This shall avoid jitter in triggered actions. For some devices (e.g. Button), bounce time can already be specified for the device and will be handled by gpiozero. 38 | - *event_log*
The value of this parameter decides whether or not a trigger and its [associated actions](./TriggerTriggerActions.md) will be treated as events and included in [event logging](./TriggerActive.md) and [event viewer](./TriggerEventViewer.md).
If **False**, events triggered by the trigger will not be logged in [event logging](./TriggerActive.md) and they will also not be visible in the [event viewer](./TriggerEventViewer.md). Instead, if camera actions are associated with the trigger, the resulting photos and videos will be visible in the normal [Photo Viewer](./PhotoViewer.md). 39 | 40 | ### Restrictions 41 | 42 | Only one active trigger can be configured for a specific device-event. 43 | 44 | If another trigger is configured for the same event, only one trigger will remain active. 45 | 46 | If you want multiple actions on a specific trigger, you will specify this in [Trigger-Actions](./TriggerTriggerActions.md). 47 | 48 | ## Activation of Triggers 49 | 50 | If the event-handling thread is currently active: 51 | - The *Active* check boxes are locked. 52 | - If this is the only trigger for the chosen device-event, the trigger will be activated. 53 | - If another trigger exists for the same device-event, the new trigger will not be activated. 54 | 55 | If the event-handling thread is not active: 56 | - The *Active* check boxes are active 57 | - If this is the only trigger for the chosen device-event, the trigger will be activated 58 | - If another trigger exists for the same device-event, this will be deactivated and the new trigger will be activated. 59 | 60 | You can activate/deactivate triggers by changing the *Active* check box and submitting the change. 61 | 62 | If you tried to activate several triggers for the same device-event, the system will leave only one of them active. 63 | 64 | ## Deletion of Triggers 65 | 66 | You can select one or multiple triggers for deletion in the *Delete* column and submit the selection. 67 | 68 | The *Delete* column will only be accessible for change if the event-handling thread is currently not active. 69 | 70 | ## Changing Triggers 71 | 72 | Changing of triggers is currently not possible. 73 | 74 | However, you can easily create a new similar one with different parameters and deactivate the old one. 75 | -------------------------------------------------------------------------------- /docs/Troubelshooting.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Troubleshooting 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | This page intends to collect information on how to deal with errors or problems which may occur while running **raspiCamSrv**. 6 | 7 | - **Password forgotten** 8 | If you have your password forgotten, there are two alternatives:
1. Somone else is Superuser:
Ask him to remove your user entry and create a new one (See [Settings / Users](./SettingsUsers.md)).
2. You are the Superuser.
You need to reset the database where user entries are stored.
You do this with with ```flask --app raspiCamSrv init-db``` (see [RaspiCamSrv Installation](../README.md#raspicamsrv-installation) Step 11).
At the next Login, you need to Register as new Superuser (see [Authorization](./Authentication.md)) 9 | 10 | - **ERROR in motionDetector: Exception in _motionThread: OpenCV(4.6.0)** 11 | This error may occur when trying to use [extended motion capturing](./TriggerMotion.md) while the 'YUV420' stream format is set for the [Live View Configuration](./Configuration.md).
It seems that OpenCV is not capable to handle images with this format. 12 | This error is typically observed on Pi3 and Pi4 where the YUV stream format is mandatory for the lores stream according to the [Picamera2 Manual](https://datasheets.raspberrypi.com/camera/picamera2-manual.pdf), ch. 4.2.
13 | As a workaround, you may try setting the "main" stream for the Live View configuration with "RGB888" Stream Format. 14 | To avoid performance issues, also a low Stream Size (e.g. 640x400) should be chosen.
15 | See [raspi-cam-srv Issue #48](https://github.com/signag/raspi-cam-srv/issues/48) 16 | 17 | - **No Connection to server although server has been started as service**. 18 | This may happen (see [raspi-cam-srv Issue #8](https://github.com/signag/raspi-cam-srv/issues/8)) if the service has been started before the network interfaces are ready. 19 | The systemd journal will indicate that the Flask server is only listening to *localhost* (127.0.0.1) 20 | In this case, more restrictive settings in the *After* clause of the [service configuration](../README.md#service-configuration) file may be required (see [systemd Network Configuration Synchronization Points](https://systemd.io/NETWORK_ONLINE/)) 21 | - **SystemError: No cameras were found on the server's device** 22 | See [raspi-cam-srv Issue #6](https://github.com/signag/raspi-cam-srv/issues/6) 23 | - **ERROR in camera_pi: Could not import SensorConfiguration from picamera2.configuration. Bypassing sensor configuration** 24 | This message may occur when running on Bullseye systems. 25 | Currently, it can be ignored because the missing *SensorConfiguration* class has currently no impact on **raspiCamSrv** functionality. 26 | *SensorConfiguration* is a class in Picamera2 which is referenced in the CameraConfiguration (see [Picamera2 Manual](https://datasheets.raspberrypi.com/camera/picamera2-manual.pdf) chapter 4.3) 27 | It includes information on the output size and bit depth of a stream. 28 | In Bullseye systems, this class is missing. 29 | Currently, raspiCamSrv does not require the *SensorConfigiuration* but it is included in the data model because Picamera2 uses it. 30 | The error occurs when trying to import the class. 31 | 32 | - **WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise** 33 | This is just a warning from the libcamera system that the tuning file should be updated. 34 | It is currently not known that there is an impact on raspiCamSrv functionality. 35 | 36 | 37 | - **ERROR V4L2 v4l2_videodevice.cpp:1906 /dev/video4[16:cap]: Failed to start streaming: Broken pipe** 38 | See [picamera2 Issue #104](https://github.com/raspberrypi/libcamera/issues/104) from Feb 1, 2024 39 | The recommended solution was to go back to kernel release 6.1.65 with ```sudo rpi-update d16727d``` 40 | - **ModuleNotFoundError: No module named 'picamera2'** 41 | See [raspi-cam-srv Issue #4](https://github.com/signag/raspi-cam-srv/issues/4) 42 | - **TypeError: memoryview: casts are restricted to C-contiguous views** 43 | See [picamera2 Issue #959](https://github.com/raspberrypi/picamera2/issues/959) 44 | 45 | ## Logging 46 | 47 | The **raspiCamSrv** server uses Python logging. 48 | 49 | Logging is initialized in module ```__init__.py```. 50 | All lines controlling the way of logging or [code generation](#generation-of-python-code-for-camera) are preceeded with a comment line, starting with 51 | ```#>>>>>``` 52 | 53 | By default, a StreamingHandler is added to all loggers which outputs log information to sys.stderr. 54 | If desired, the prepared FileHandler can be activated. 55 | 56 | The log level for all loggers is initialized with level ERROR. 57 | This can be modified for all or for specific modules. 58 | 59 | ### Flask logging 60 | 61 | Flask logging is controlled by ```app.logger``` 62 | 63 | ### Werkzeug logging 64 | 65 | Werkzeug implements WSGI, the standard Python interface between applications and servers. 66 | 67 | Werkzeug logs basic request/response information. 68 | 69 | Werkzeug logging is controlled by ```logging.getLogger("werkzeug")```. 70 | 71 | The log level is initialized in ```__init__.py``` with INFO, in order to enable informative logging during server start. 72 | 73 | After the server has been started, the log level is raised to ERROR. 74 | This is done in ```auth.py``` in function ```login_required(view)```. 75 | 76 | ### raspiCamSrv Logging 77 | 78 | Logging can be controlled individually for each module. 79 | 80 | ### libcamera logging 81 | 82 | The libcamera library is the basic C++ camera library on which Picamera2 is based. 83 | 84 | The log level is controlled through an environment variable LIBCAMERA_LOG_LEVELS. 85 | This is set in ```__init__.py``` to WARNING. 86 | Other allowed log levels are listed in the comment. 87 | 88 | For more details, see [Picamera2 manual](./picamera2-manual.pdf), chapter 8.6.2 89 | 90 | ### Picamera2 logging 91 | 92 | Picamera2 logging is initialized in ```__init__.py``` with ERROR 93 | 94 | For more details, see [Picamera2 manual](./picamera2-manual.pdf), chapter 8.6.1 95 | 96 | ## Generation of Python Code for Camera 97 | 98 | The system can generate a file with Python code including the entire interaction of **raspiCamSrv** with Picamera2. 99 | This file can then be used for debugging and error analysis. 100 | 101 | A specific logger ("pc2_prg") with with level DEBUG is used for code generation. 102 | The logger can be activated by setting 103 | ```prgLogger.setLevel(logging.DEBUG)``` 104 | in ```__init___.py``` 105 | 106 | The code file is located in 107 | ```/home//prg/raspi-cam-srv/logs``` 108 | with name 109 | ```prgLog_YYYYMMDD_hhmmss.log``` 110 | 111 | A new file will be generatet at every server start. 112 | 113 | To run the files, you neet to change the file type from ```.log``` to ```.py``` 114 | Generating the files with ```.py``` extension does not work because Flask seems to recognize these files and does strange things. 115 | 116 | All photo and video output generated by these files will be located at 117 | ```/home//prg/raspi-cam-srv/output``` 118 | with the same file names as in the original session. 119 | -------------------------------------------------------------------------------- /docs/Tuning.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Camera Tuning 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | The algorithms of Raspberry Pi cameras are affected by tuning files which are specific for each camera type and Raspberry Pi version. These files are automatically loaded when the camera system is instantiated. 6 | A set of default tuning files for all camera models are part of the Raspberry Pi OS distribution. 7 | (For details, see the [Raspberry Pi Camera Algorithm and Tuning Guide](https://datasheets.raspberrypi.com/camera/raspberry-pi-camera-guide.pdf)) 8 | 9 | With **raspiCamSrv**, you can control which files are used and you may tweak specific features within these files to optimize the camera behavior for your specific needs. 10 | 11 | This functionality can be accessed through menu *Config*, submenu *Tuning*: 12 | 13 | ![Tuning1](./img/Tuning1.jpg) 14 | 15 | The configuration provides three parameters: 16 | 17 | - *Name of Tuning File*
This is the name of the tuning file to be loaded for the active camera.
Raspberry Pi OS distributions include default tuning files with '.json' type and a name which is identical to the name of the camera model.
If you provide own tuning files, you may choose an arbitrary name. If you are using multiple camera models simultaneously, you should be able to correctly associate a file with a camera model. 18 | - *Full path to folder with tuning files*
If this is empty (None), Picamera2 will search a system-specific list of likely installation folders for the required tuning file.
raspiCamSrv supports usage of a custom folder (```/home//prg/raspi-cam-srv/raspiCamSrv/static/tuning```) which allows keeping own tuning files separate from the default ones. 19 | - *Load Tuning File*
If this checkbox is activated, raspiCamSrv will request Picamera2 to load the specified tuning file instead of the default one.
Otherwise, Picamera2 will load the default tuning file. 20 | 21 | Any changes of one of these parameters needs to be submitted with the *Submit & Apply* button. 22 | If *Load Tuning File* is checked, a restart of the live stream will be requested so that the result of the chosen tuning file can be directly seen in the [Live](./LiveScreen.md) view. 23 | 24 | ## Switching between Custom and Default Folder 25 | 26 | - Button *Custom Folder* will switch the folder for tuning files to the custom folder ```/home//prg/raspi-cam-srv/raspiCamSrv/static/tuning```
If there is already a tuning file with the specified name in this folder, it will be used.
If the tuning file does not yet exist in the custom folder, the standard tuning file will be copied to the custom folder. 27 | - Button *Default Folder* (toggled) will switch to the default folder.
This folder is system-specific, e.g. ```/usr/share/libcamera/ipa/rpi/pisp``` 28 | 29 | ![Tuning2](./img/Tuning2.jpg) 30 | 31 | ## Modification of Tuning Files 32 | 33 | Modification of tuning files with raspiCamSrv can only be done in the custom folder. 34 | 35 | If you are not directly accessing the tuning files on the Raspberry Pi, you can download a file, rename it, if desired, and modify it on the client machine. 36 | Afterwards you can upload it to the custom folder. 37 | When done, the file will be available for selection. 38 | 39 | ### Deleting a Tuning File 40 | 41 | The button *Delete Tuning File* will only be active, if 42 | 43 | - the custom folder is activated 44 | - *Load Tuning File* is unchecked 45 | - No parameter changes have beenn made after the last *Submit & Apply* 46 | 47 | This restriction avoids inadvertently deleting the wrong file if the file has been changed without submitting. 48 | 49 | ### Download Tuning File 50 | 51 | A tuning file can be downloaded from the default folder or from the custom folder. 52 | 53 | ### Uploading Tuning Files 54 | 55 | The buttons for upload will only be active if the custom folder is selected. 56 | 57 | 1. You start pushing the *Select Tuning File for Upload* button
![Tuning3](./img/Tuning3.jpg) 58 | 2. If a single file has been selected, its name will be shown on the button:
![Tuning4](./img/Tuning4.jpg) 59 | 3. If a multiple files have been selected, the number of selected files will be shown on the button:
![Tuning5](./img/Tuning5.jpg) 60 | 4. Finally, you need to the *Upload selected File* button to upload:
![Tuning6](./img/Tuning6.jpg) 61 | 62 | ## Using a different Custom Folder 63 | 64 | If you have already prepared tuning files in a specific folder on the Raspberry Pi, which is different from the Custom Folder used by raspiCamSrv, you can also refer to this folder. 65 | 66 | You first need to manually enter the *Full Path* to this folder and push *Submit & Apply*. 67 | 68 | Afterwards, the .json files in this folder will be available for selection as *Name of Tuning File* 69 | 70 | ## Tuning with Multiple Cameras 71 | 72 | Tuning files are specific for a camera and not for a camera model. 73 | 74 | If two cameras are used with a Pi5, the tuning file needs to be individually specified for each camera, also if both are the same model. 75 | 76 | To preserve the tuning configuration for a camera, it must be memorized using the *Memorize Configuration and Controls for Camera Change* in screen [Web Cam](./Webcam.md) 77 | 78 | Because of a Threading issue in Picamera2 (see Picamera2 Issue #1103 [Tuning file support not thread-safe?](https://github.com/raspberrypi/picamera2/issues/1103)), the streams from the two cameras in dialog [Web Cam](./Webcam.md) may look as if the tuning file of the first camera would have also been applied to the second one. 79 | 80 | Nevertheless, the handling in raspiCamSrv is correct. 81 | You may proof this in the following way: 82 | 83 | 1. Activate a dialog without live view, e.g. [Info](./Information.md). 84 | 2. Wait at least 10 sec. until both streaming threads have terminated (refresh the screen from time to time) 85 | 3. In another browser window, stream just one camera (endpoint video_feed or video_feed2).
You should then see the effect of the correct tuning file.
However, if you later start streaming the other camera, you may see that the tuning file for the previously started camera has been applied. 86 | -------------------------------------------------------------------------------- /docs/Webcam.md: -------------------------------------------------------------------------------- 1 | # Web Cam Settings 2 | 3 | [![Up](img/goup.gif)](./UserGuide.md) 4 | 5 | **raspiCamSrv** enables webcam functionalities with Raspberry Pi cameras. 6 | 7 | For Pi 5 with two camera ports, both cameras can be streamed simultaneously. 8 | 9 | This page shows the URLS for MJPEG streaming as well as for photo snapshots: 10 | 11 | ![Webcam](./img/Webcam2.jpg) 12 | 13 | The left side of the page always shows the active camera. 14 | If an additional camera is available, video stream and photo are shown on the right side. 15 | 16 | When switching the cameras, either with the **Switch Cameras** button on this side or by changing the camera in the [Settings](./Settings.md#switching-the-active-camera), the streams will be exchanged. 17 | The *video_feed* endpoint will always refer to the active camera, which is also shown in the title bar. 18 | The *video_feed2* endpoint will always refer to the other camera, if available. 19 | 20 | The configuration and camera stream used for video and photo capture are indicated. 21 | 22 | The links shown on the page open a new browser window. 23 | 24 | ### Buttons 25 | 26 | #### Memorize Configuration and Controls for Camera Change 27 | 28 | This button stores the current [Camera Configuration](./Configuration.md) for *Live View* and *Video* as well as the current [Controls](./CameraControls.md) settings for the active camera in a specific structure (streamingCfg) so that it can be reused for streaming in a case that the other camera has been activated. (See also [Configuring MJPEG Stream and jpeg Photo](#configuring-mjpeg-stream-and-jpeg-photo)) 29 | 30 | 31 | #### <<< Switch Cameras >>> 32 | 33 | With this button, you can switch the cameras so that the one sown on the right side will become the active camera. 34 | 35 | ## Process Status Indicators 36 | 37 | [Process Status Indicators](./UserGuide.md#process-status-indicators) show whether a background thread for streaming is active or not. 38 | This is independently done for the active camera ![StatusActiveCam](./img/ProcessIndicatorLiveActive.jpg) and for the other camera ![StatusActiveCam](./img/ProcessIndicatorLive2Active.jpg) 39 | 40 | 41 | ## Video Stream 42 | 43 | The video stream will always use the LIVE configuration. 44 | By default, this configuration uses the *lores* camera stream. 45 | The camera stream as well as its *stream size* can be configured in the [Configuration](./Configuration.md) screen. 46 | 47 | ## Photo Snapshot 48 | 49 | The photo snapshot is currently also using the LIVE configuration. 50 | 51 | ## Configuring MJPEG Stream and jpeg Photo 52 | 53 | With **raspiCamSrv**, [Camera Configuration](./Configuration.md) and [Controls](./CameraControls.md) apply always to the active camera (which camera is the active one, can be selected in the [Settings](./Settings.md)). 54 | 55 | When the Flask server starts up without preloading stored configurations, the active camera and, if available, the second camera are preconfigured with parameter defaults. 56 | 57 | The Live View Configuration as well as the Controls for both cameras are stored in a specific streaming datastructure. 58 | 59 | When [Camera Configuration](./Configuration.md) and/or [Controls](./CameraControls.md) for the active camera are modified, these settings can be memorized with the **Memorize Configuration and Controls for Camera Change**. 60 | When cameras are switched, their specific configurations and controls will be applied. 61 | 62 | In order to configure your camera setup, you can proceed as follows: 63 | 64 | 1. Select one of the cameras as active camera 65 | 2. Adjust the [Camera Configuration](./Configuration.md), 66 | for example *Transform* and/or *Sensor Mode* with *Stream Size* 67 | 3. Adjust the [Controls](./CameraControls.md), 68 | for example *focus*/*lensposition*, *zoom*, *AutoExposure* or others 69 | 4. When the setup is satisfactory, go to the *Webcam* dialog and press the **Memorize Configuration and Controls for Camera Change** button. 70 | 5. Then switch cameras with the **<<< Switch Cameras >>>** button. 71 | 6. Repeat steps 2. to 4. for the other camera 72 | 7. If you now switch cameras, each stream and photo should show in the way specifically configured for the camera. 73 | 8. Now you can go to the [Settings](./Settings.md) screen and push the **Store Configuration** button 74 | 9. If you want the entire configuration, including the streaming configuration, to be loaded when the server starts up, check the related checkbox in the [Settings](./Settings.md) screen. 75 | 76 | 77 | -------------------------------------------------------------------------------- /docs/ZoomPan.md: -------------------------------------------------------------------------------- 1 | # raspiCamSrv Zoom & Pan 2 | 3 | [![Up](img/goup.gif)](./LiveScreen.md) 4 | 5 | ![ZoomAndPan](img/Zoom.jpg) 6 | 7 | This tab allows zooming and panning the image area within the dimensions supported by the camera pixel array size and Sensor Modes. 8 | 9 | For more details, see [Image Cropping and Sensor Modes](./ScalerCrop.md) 10 | 11 | ## Current zoom factor in % 12 | 13 | This value shows the current zoom factor. 14 | It cannot be modified manually but only through the **Zoom in**, **Zoom out** or **Full** buttons. 15 | 16 | The value is given in % of the [ScalerCrop Default](./ScalerCrop.md#cropping) size. 17 | 18 | ## Zoom & pan step in % 19 | 20 | This value can be adjusted. 21 | It specifies the step size by which every click on **Zoom in** or **Zoom out** will change the *Current zoom factor*. 22 | 23 | ## Current ScalerCrop (Zoom) 24 | 25 | This rectangle, given in pixels, specifies the ScalerCrop rectangle which will be requested as part of the [Camera Controls](./CameraControls.md). 26 | 27 | The rectangle is given as tuple (x_offset, y_offset, width, height). 28 | 29 | When drawing the zoom window (see [below](#graphically-setting-the-zoom-window)), the rectangle parameters will be updated. 30 | 31 | After Submitting, the entry should be identical to the *Current ScalerCrop (Live View)*. 32 | 33 | ## Current ScalerCrop (Live View) 34 | 35 | This shows the scaler crop rectangle which is currently active for the live view. 36 | 37 | The *Current ScalerCrop (Live View)* is the base for determining offset and size of the *Autofocus Windows* when drawing rectangles on the canvas (see [Focus](./FocusHandling.md)). 38 | 39 | ## Zoom 40 | 41 | The following buttons allow zooming: 42 | - Zoom in 43 | zooms into the image (reduces the viewport), keeping the center. 44 | - Zoom out 45 | zooms out (enlarges the viewport), keeping the center. 46 | If the image had been panned before, the center will be shifted, if necessary, to keep the ScalerCrop rectangle within the [ScalerCrop Maximum](./ScalerCrop.md#cropping) area. 47 | - Full 48 | Zooms to 100% keeping the center, unless a shift is required to keep the ScalerCrop rectangle within the [ScalerCrop Maximum](./ScalerCrop.md#cropping) area. 49 | 50 | ## Pan 51 | 52 | Panning can be done with the following buttons: 53 | 54 | - Pan up / Pan down 55 | Move the ScalerCrop rectangle up/down until the upper/lower border of the [ScalerCrop Maximum](./ScalerCrop.md#cropping) rectangle is reached. 56 | - Pan left / Pan right 57 | Move the ScalerCrop rectangle left/right until the left/right border of the [ScalerCrop Maximum](./ScalerCrop.md#cropping) rectangle is reached. 58 | - Center 59 | Move the ScalerCrop rectangle to the center of the [ScalerCrop Maximum](./ScalerCrop.md#cropping) rectangle, keeping the zoom factor. 60 | - Default 61 | Set the ScalerCrop rectangle to the [ScalerCrop Default](./ScalerCrop.md#cropping) rectangle. 62 | 63 | 64 | ## Graphically setting the Zoom Window 65 | 66 | Pushing the **Draw** button will switch into graphical mode where the zoom window can be drawn on a canvas over the Live Stream area. 67 | All other buttons, except **Full** will be disabled in this mode. 68 | 69 | ![ZoomGraphically](img/Zoom_Graph.jpg) 70 | 71 | **Attention:** With Safari (e.g. on an iPad), due to the issue with onload events, the canvas will not be directly visible. It needs to trigger window resize by shortly 'pulling' down the window. 72 | 73 | While drawing a rectangle for the intended image section, the original aspect ratio will be preserved. 74 | After drawing is finished, the *Current ScalerCrop (Zoom)* will be updated with offset and dimensions of the zoom window. 75 | 76 | After pressing **Draw**, the button has changed to **Submit** which must be pressed in order to apply the ScalerCrop setting to the preview and store it for later photo or video taking. 77 | 78 | Pressing **Submit** terminates the graphic mode. 79 | 80 | When the **Full** button is pressed in the graphic mode, the dialog returns to normal mode without applying a previously drawn zoom window. 81 | -------------------------------------------------------------------------------- /docs/api/postman/raspiCamSrv.postman_collection.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/api/postman/raspiCamSrv.postman_collection.pdf -------------------------------------------------------------------------------- /docs/bp_Hotspot_Bookworm.md: -------------------------------------------------------------------------------- 1 | # Hotspot Configuration for 'Bookworm' OS 2 | 3 | [![Up](img/goup.gif)](./bp_PiZero_Standalone.md) 4 | 5 | This section describes how to configure a Raspberry Pi as hotspot if the OS is *Debian Bookworm*. 6 | 7 | In the following description, you will need to replace 8 | 9 | - `````` with the intended hotspot SSID, e.g. "RaspCamSrv01" 10 | - `````` with the passphrase to protect hotspot access 11 | 12 | The connection ID, used in [NetworkManager](https://networkmanager.dev/docs/api/latest/nmcli.html) commands is chosen as "RaspiCamSrv" 13 | 14 | ## 1. Install required packages 15 | 16 | ``` 17 | sudo apt install dnsmasq iptables 18 | ``` 19 | 20 | ## 2. Configure Hotspot 21 | 22 | ``` 23 | sudo nmcli con add type wifi ifname wlan0 con-name RaspiCamSrv autoconnection yes ssid 24 | 25 | sudo nmcli con modify RaspiCamSrv 802-11-wireless.mode ap 802-11-wireless.band bg 26 | 27 | sudo nmcli con modify RaspiCamSrv wifi-sec.key-mgmt wpa-psk 28 | 29 | sudo nmcli con modify RaspiCamSrv wifi-sec.psk "" 30 | 31 | ``` 32 | 33 | ## 3. Assign a Fixed IP Address 34 | 35 | ``` 36 | sudo nmcli con modify RaspiCamSrv ipv4.method manual ipv4.addresses 192.168.1.1/24 37 | 38 | sudo nmcli con modify RaspiCamSrv ipv4.gateway 192.168.1.1 39 | 40 | sudo nmcli con modify RaspiCamSrv ipv4.dns 192.168.1.1 41 | 42 | ``` 43 | 44 | ## 4. Activate Hotspot 45 | 46 | ``` 47 | sudo nmcli con up RaspiCamSrv 48 | ``` 49 | 50 | If your SSH session uses the Wi-Fi Adapter, connection will now be lost. 51 | 52 | If you reconnect, the ethernet adapter will be used. 53 | 54 | At this time, a TCP/IP connection through the hotspot is not yet possible. 55 | 56 | ## 5. Configure DHCP for hotspot 57 | 58 | ``` 59 | sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig 60 | 61 | sudo nano /etc/dnsmasq.conf 62 | ``` 63 | 64 | Enter the following code: 65 | 66 | ``` 67 | interface=wlan0 68 | no-dhcp-interface=eth0 69 | dhcp-range=192.168.1.100,192.168.1.200,255.255.255.0,24h 70 | dhcp-option=option:router,192.168.1.1 71 | dhcp-option=option:dns-server,192.168.1.1 72 | ``` 73 | 74 | ## 6. Check and start DHCP Server and DNS-Cache 75 | 76 | ``` 77 | dnsmasq --test -C /etc/dnsmasq.conf 78 | ``` 79 | 80 | ## 7. Enable dnsmasq for automatic start 81 | 82 | ``` 83 | sudo systemctl restart dnsmasq 84 | 85 | sudo systemctl status dnsmasq 86 | 87 | sudo systemctl enable dnsmasq 88 | ``` 89 | 90 | ## 8. Enable IP Forwarding 91 | 92 | ``` 93 | sudo nano /etc/sysctl.conf 94 | ``` 95 | 96 | Find and uncomment the following line: 97 | ``` 98 | net.ipv4.ip_forward=1 99 | ``` 100 | 101 | ## 9. Set up NAT 102 | 103 | ``` 104 | sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE 105 | 106 | sudo iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT 107 | 108 | sudo iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT 109 | 110 | ``` 111 | 112 | ## 10. Save Firewall Rules 113 | 114 | ``` 115 | sudo sh -c "iptables-save > /etc/iptables.rules" 116 | ``` 117 | 118 | ## 11. Load firewall rules on boot 119 | 120 | ``` 121 | sudo nano /etc/network/interfaces 122 | ``` 123 | 124 | Add the following line: 125 | 126 | ``` 127 | post-up iptables-restore < /etc/iptables.rules 128 | ``` 129 | 130 | ## 12. Extend hosts 131 | 132 | ``` 133 | sudo nano /etc/hosts 134 | ``` 135 | 136 | Add the following line: 137 | 138 | ``` 139 | 192.168.1.1 140 | ``` 141 | 142 | where `````` must be replaced by the host name specified during OS setup. 143 | 144 | 145 | ## 13. Reboot the system 146 | 147 | ``` 148 | sudo reboot 149 | ``` 150 | 151 | ## 14. Check processes 152 | 153 | After reconnecting with SSH 154 | 155 | ``` 156 | nmcli con show --active 157 | 158 | ip addr show wlan0 159 | ``` 160 | 161 | ## 19. Test Hotspot access 162 | 163 | - Unplug the network cable 164 | - Switch Off/On the power supply 165 | - From a mobile device, wait for the hotspot and try to connect. -------------------------------------------------------------------------------- /docs/bp_Hotspot_Bullseye.md: -------------------------------------------------------------------------------- 1 | # Hotspot Configuration for 'Bullseye' OS 2 | 3 | [![Up](img/goup.gif)](./bp_PiZero_Standalone.md) 4 | 5 | This section describes how to configure a Raspberry Pi as hotspot if the OS is *Debian Bullseye*. 6 | 7 | ## 1. Install required packages 8 | 9 | ``` 10 | sudo apt install dnsmasq hostapd iptables 11 | ``` 12 | 13 | ## 2. Configure WLAN 14 | 15 | ``` 16 | sudo nano /etc/dhcpcd.conf 17 | ``` 18 | 19 | Copy/Paste the following code: 20 | 21 | ``` 22 | interface wlan0 23 | static ip_address=192.168.1.1/24 24 | nohook wpa_supplicant 25 | ``` 26 | 27 | This will configure the Wi-Fi adapter with a static IP address 192.168.1.1 28 | 29 | ## 3. Restart DHCP 30 | 31 | ``` 32 | sudo systemctl restart dhcpcd 33 | ``` 34 | 35 | If your client is connected through Wi-Fi, it will now lose connection 36 | and you need to reconnect, which will now use the ethernet connection. 37 | 38 | ## 4. Check interfaces 39 | 40 | ``` 41 | ip l 42 | ``` 43 | 44 | Check that both, the ethernet interface (eth0) and Wi-Fi adapter (wlan0) are available. 45 | 46 | ## 5. Setup DHCP server and DNS-Cache 47 | 48 | ``` 49 | sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf_orig 50 | 51 | sudo nano /etc/dnsmasq.conf 52 | ``` 53 | 54 | Enter the following code: 55 | 56 | ``` 57 | interface=wlan0 58 | no-dhcp-interface=eth0 59 | dhcp-range=192.168.1.100,192.168.1.200,255.255.255.0,24h 60 | dhcp-option=option:dns-server,192.168.1.1 61 | ``` 62 | 63 | ## 6. Test & start DHCP server and DNS Cache 64 | 65 | ``` 66 | dnsmasq --test -C /etc/dnsmasq.conf 67 | ``` 68 | 69 | The response should be 70 | ``` 71 | dnsmasq: syntax check OK. 72 | ``` 73 | 74 | ## 7. Restart DNSMASQ and enable it for automatic start 75 | 76 | ``` 77 | sudo systemctl restart dnsmasq 78 | 79 | sudo systemctl status dnsmasq 80 | 81 | sudo systemctl enable dnsmasq 82 | ``` 83 | 84 | ## 8. Setup WLAN-AP-Host (hostapd) 85 | 86 | ``` 87 | sudo nano /etc/hostapd/hostapd.conf 88 | ``` 89 | 90 | Replace the content with the following code 91 | 92 | ``` 93 | interface=wlan0 94 | ssid= 95 | channel=1 96 | hw_mode=g 97 | ieee80211n=1 98 | ieee80211d=1 99 | country_code= 100 | wmm_enabled=1 101 | auth_algs=1 102 | wpa=2 103 | wpa_key_mgmt=WPA-PSK 104 | rsn_pairwise=CCMP 105 | wpa_passphrase= 106 | ``` 107 | 108 | where you need to replace 109 | 110 | - with the intended SSID for the hotspot (e.g.: RaspiCamSrv) 111 | - with your [A-2 ISO 3166-1 Country Code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes) 112 | - with the passphrase to secure hotspot access 113 | 114 | ## 9. Test & start WLAN-AP-Host 115 | 116 | ``` 117 | sudo hostapd -dd /etc/hostapd/hostapd.conf 118 | ``` 119 | 120 | At the end of the output you should find: 121 | 122 | ``` 123 | ... 124 | wlan0: interface state COUNTRY_UPDATE->ENABLED 125 | ... 126 | wlan0: AP-ENABLED 127 | ... 128 | 129 | ``` 130 | 131 | ## 10. Test Hotspot Access 132 | 133 | With a mobile device try to access the hotspot. 134 | 135 | This will generate log output in the SSH session. 136 | 137 | ## 11. Enable hostapd process for automatic start 138 | 139 | In the SSH session stop the active process
140 | 141 | 142 | ``` 143 | sudo systemctl unmask hostapd 144 | sudo systemctl start hostapd 145 | sudo systemctl enable hostapd 146 | ``` 147 | 148 | ## 12. Check that hostapd is active 149 | 150 | ``` 151 | sudo systemctl status hostapd 152 | ``` 153 | 154 | ## 13. Activate routing 155 | 156 | ``` 157 | sudo nano /etc/sysctl.conf 158 | ``` 159 | 160 | Find and uncomment the following line: 161 | 162 | ``` 163 | net.ipv4.ip_forward=1 164 | ``` 165 | 166 | ## 14. Activate NAT 167 | 168 | ``` 169 | sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE 170 | 171 | sudo sh -c "iptables-save > /etc/iptables.ipv4.nat" 172 | ``` 173 | 174 | ## 15. Assure NAT activation at system start 175 | 176 | ``` 177 | sudo nano /etc/rc.local 178 | ``` 179 | 180 | Before the last line with ```exit 0``` enter 181 | 182 | ``` 183 | iptables-restore < /etc/iptables.ipv4.nat 184 | ``` 185 | 186 | ## 16. Reboot the system 187 | 188 | ``` 189 | sudo reboot 190 | ``` 191 | 192 | ## 18. Check processes 193 | 194 | After reconnecting with SSH 195 | 196 | ``` 197 | sudo systemctl status hostapd 198 | 199 | ps ax | grep hostapd 200 | 201 | sudo systemctl status dnsmasq 202 | 203 | ps ax | grep dnsmasq 204 | ``` 205 | 206 | ## 19. Test Hotspot access 207 | 208 | - Unplug the network cable 209 | - Switch Off/On the power supply 210 | - From a mobile device, wait for the hotspot and try to connect. -------------------------------------------------------------------------------- /docs/bp_PiZero_Standalone.md: -------------------------------------------------------------------------------- 1 | # Setup of Raspberry Pi Zero as Standalone System 2 | 3 | [![Up](img/goup.gif)](../README.md) 4 | 5 | This section describes how to set up a Raspberry Pi **Zero W** or **Zero 2 W** as standalone system. 6 | 7 | This will allow you placing the Raspi camera anywhere, independently from an accessible Wi-Fi. 8 | 9 | It will act as hotspot to which you can connect from a mobile client to gain access to **raspiCamSrv**. 10 | 11 | The subsequent descriptions can, in principle, also be applied for other Raspberry Pi models. 12 | 13 | ## Headless Setup 14 | 15 | During the setup of such a system, the Raspberry Pi requires a cabled network connection because the Wi-Fi adapter will be configured as hotspot and is, therefore, not available for access by the configuration client. 16 | 17 | Connections to a display, keyboard and mouse are not required. 18 | 19 | ![Standalone Setup](./img/bp_PiZero_Connect.jpg) 20 | 21 | Required [cables and adapters](https://www.raspberrypi.com/products/#power-supplies-and-cables): 22 | 23 | - USB A to Ethernet adapter 24 | - Micro USB/Male to USB A/Female cable 25 | - Power supply with Micro USB plug 26 | 27 | ## 1. Install OS on microSD Card 28 | 29 | Follow the instructions for [Install using Imager](https://www.raspberrypi.com/documentation/computers/getting-started.html#raspberry-pi-imager). 30 | 31 | - **Model**
32 | Make sure to select the correct model 33 | - **Bullseye or Bookworm?**
34 | raspiCamSrv can be used with both systems.
35 | Whereas there were still some issues for early versions of Bookworm on Pi Zero systems, 36 | this is no longer the case with the current version. 37 | - **Full or lite system?**
38 | It is recommended to install the full system although the desktop environment will not be required. 39 | - **OS Customisation**
40 | Make sure to *Configure wireless LAN*, although the Wi-Fi Adapter will later not be run in client mode,
41 | however this will assure that the *Wireless LAN Country* will be set. 42 | 43 | ## 2. Power Up 44 | 45 | 1. Connect the camera (the small CSI-2 port of Pi Zero and Pi 5 require a special cable) 46 | 2. Insert the microSD card into the card slot 47 | 3. If available, encapsulate the Pi into a case 48 | 4. Connect the network USB cable through an ethernet adapter to a switch of your local network 49 | 5. Connect the power supply 50 | 51 | ## 3. Connect and upgrade 52 | 53 | The system may take some time until it is visible within the network. 54 | 55 | From a client device connect via SSH
56 | 57 | ``` 58 | ssh @ 59 | 60 | ... 61 | 62 | sudo apt update 63 | sudo apt full-upgrade 64 | ``` 65 | 66 | ## 4. Configure Hotspot 67 | 68 | The process of configuration is slightly different, depending on the cosen OS: 69 | 70 | - [Hotspot Configuration for 'Bullseye' OS](./bp_Hotspot_Bullseye.md) 71 | - [Hotspot Configuration for 'Bookworm' OS](./bp_Hotspot_Bookworm.md) 72 | 73 | ## 5. Install raspiCamSrv 74 | 75 | For installation, you will need to connect through ethernet. 76 | 77 | Then, follow the [raspiCamSrv Installation Procedure](../README.md#raspicamsrv-installation) 78 | 79 | ## 6. Configure raspiCamSrv Sercice 80 | 81 | Follow the [Service Configuration](../README.md#service-configuration) instructions 82 | 83 | ## 7. Test 84 | 85 | After rebooting, first test using the client connected with ethernet cable. 86 | 87 | If this is successfull, you can shutdown and unplug the ethernet cable 88 | 89 | After restart, connect from a mobile client to the hotspot and connect to raspiCamSrv from a browser window. 90 | -------------------------------------------------------------------------------- /docs/gpioDevices/StepperMotor.md: -------------------------------------------------------------------------------- 1 | # StepperMotor 2 | 3 | ``` 4 | class StepperMotor(*args, **kwargs) 5 | ``` 6 | 7 | extends ```gpiozero.OutputDevice``` and represents a generic stepper motor connected to a stepper motor driver. 8 | An example combination, for which this class has been developped and tested, is the stepper motor **28BYJ-48** with the motor driver **ULN2003A**. 9 | 10 | 1. Plug in the 5-cable jack of the motor into the socket of the motor driver. 11 | 2. Connect the 4 inputs on the motor driver (IN1 ... IN4) to 4 GPIO pins of the Raspberry Pi.
It is important to correctly memorize which pin is connected to which input. 12 | 3. Connect the power input of the motor driver to Raspberry Pi 5V and GND pins with the correct polarity. 13 | 14 | The following code will rotate the motor counter-clockwise (from the perspective of the motor) by 15°: 15 | ``` 16 | from raspiCamSrv.gpioDevices import StepperMotor 17 | stepper = StepperMotor(6, 13, 19, 26) 18 | stepper.rotate(-15) 19 | stepper.close() 20 | ``` 21 | 22 | ## Parameters 23 | 24 | - **in1** (*int*) - The GPIO pin that the motor drivers **IN1** pin is connected to 25 | - **in2** (*int*) - The GPIO pin that the motor drivers **IN2** pin is connected to 26 | - **in3** (*int*) - The GPIO pin that the motor drivers **IN3** pin is connected to 27 | - **in4** (*int*) - The GPIO pin that the motor drivers **IN4** pin is connected to 28 | - **mode** (*int*) The mode in which the motor is operated.
Can be ```0``` (the default) for selecting half step mode with a resolution of 8 steps per full turn or ```1``` for full step mode with 4 steps per turn. 29 | - **speed** (*float*) - The speed with which the motor is operated. The speed is controlled through waiting times between successive steps.
A value of ```0.0``` results in the lowest speed with a waiting time of 4 ms and a value of ```1.0``` (the default) results in the highest speed with a waiting time of 1ms.
Values outside of this interval will be set to the nearest interval border. 30 | - **current_angle** - (*float*) The current angle of the motor. Defaults to 0.0 31 | - **swing_from** - (*float*) left boundary angle for swinging. Defaults to -45.0 32 | - **swing_to** - (*float*) right boundary angle for swinging. Defaults to 45.0 33 | - **swing_step** - (*float*) step width for swinging. Defaults to 9.0 34 | - **swing_direction** - (*int*) current swing direction. 1 (default) clockwise, 0 counter-clockwise. 35 | - **stride_angle** - (*float*) The angle incremet for a single step after gearing.
The default value of 5.625 is the value for the **28BYJ-48** motor. 36 | - **gear_reduction** (*int*) - The inverse of the transmission ratio of the gear box.
The default value of 64 is the value of the 1/64 ratio for the **28BYJ-48** motor. 37 | 38 | ### *property* **mode** 39 | 40 | Returns or sets the mode of operation. 41 | 42 | ### *property* **speed** 43 | 44 | Returns or sets the speed. 45 | 46 | ### *property* **stride_angle** 47 | 48 | Returns the stride angle. 49 | 50 | ### *property* **gear_reduction** 51 | 52 | Returns the gear_reduction 53 | 54 | ### *property* **current_angle** 55 | 56 | Returns or sets the current angle. 57 | When the class is initiated, the angle is set to zero. 58 | Every motor movement will update the current angle. 59 | For **step**, **step_forward** and **step_backward**, the current angle will stay within (-360 <= *current_angle* <= 360). 60 | For the **rotate*** and **swing** methods, *current_angle* is not restricted to these limits, which allows tracking of multiple turns. 61 | 62 | ### *property* **value** 63 | 64 | Returns or sets the current angle. 65 | 66 | ### *property* **swing_from** 67 | 68 | Returns or sets the left boundary for swinging in degree (-360 - 0). 69 | 70 | ### *property* **swing_to** 71 | 72 | Returns or sets the right boundary for swinging in degree (0 - 360). 73 | 74 | ### *property* **swing_step** 75 | 76 | Returns or sets the step width for swinging in degree (0 - 360). 77 | 78 | ### *property* **swing_direction** 79 | 80 | Returns or sets the current swinging direction. 1=right, -1=left 81 | 82 | ### **step**(*steps=?*) 83 | 84 | Steps forward for positive and backward for negative argument by the given number of steps. 85 | Thus, the angle is changed by *steps x stride_angle*. 86 | When using this method, 87 | 88 | **Parameters**: 89 | 90 | - **steps** (*int*) Number of steps to move (positive or negative) 91 | 92 | ### **step_forward**(*steps=?*) 93 | 94 | Steps forward (clockwise rotation) by the given number of steps. 95 | Thus, the angle is increased by *steps x stride_angle* 96 | 97 | **Parameters**: 98 | 99 | - **steps** (*int*) Number of steps to move forward (positive value) 100 | 101 | ### **step_backward**(*steps=?*) 102 | 103 | Steps backward (anti-clockwise rotation) by the given number of steps. 104 | Thus, the angle is decreased by *steps x stride_angle* 105 | 106 | **Parameters**: 107 | 108 | - **steps** (*int*) Number of steps to move backward (positive palue) 109 | 110 | ### **rotate**(*angle=?*) 111 | 112 | Rotate clockwise (for positive angle) or counter-clockwise (for negative angle) by the given angle. 113 | 114 | **Parameters**: 115 | 116 | - **angle** (*float*) Angle to rotate (positive or negative) 117 | 118 | ### **rotate_right**(*angle=?*) 119 | 120 | Rotate right (clockwise from the pespective of the motor) by the given angle. 121 | 122 | **Parameters**: 123 | 124 | - **angle** (*float*) Angle to rotate (positive) 125 | 126 | ### **rotate_left**(*angle=?*) 127 | 128 | Rotate left (anti-clockwise from the pespective of the motor) by the given angle. 129 | 130 | **Parameters**: 131 | 132 | - **angle** (*float*) Angle to rotate (positive) 133 | 134 | ### **rotate_to**(*target=?*) 135 | 136 | Rotate to the given angle. 137 | 138 | **Parameters**: 139 | 140 | - **target** (*float*) Angle to rotate to 141 | 142 | ### **swing**() 143 | 144 | Do one swing step in the current *swing_direction* with the current *swing_step*. 145 | If the *current_angle* would exceed *swing_from* or *swing_to*, rotation will reverse its direction at the border. 146 | 147 | **Parameters**: 148 | 149 | - **angle** (*float*) Angle to rotate (positive) 150 | 151 | ### **close()** 152 | 153 | Shut down the device and release all associated resources (such as GPIO pins). 154 | -------------------------------------------------------------------------------- /docs/img/AFMessage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/AFMessage.jpg -------------------------------------------------------------------------------- /docs/img/AFTrigger2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/AFTrigger2.jpg -------------------------------------------------------------------------------- /docs/img/AFWindows1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/AFWindows1.jpg -------------------------------------------------------------------------------- /docs/img/AFWindows2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/AFWindows2.jpg -------------------------------------------------------------------------------- /docs/img/AFWindows3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/AFWindows3.jpg -------------------------------------------------------------------------------- /docs/img/API_Postman_collection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/API_Postman_collection.jpg -------------------------------------------------------------------------------- /docs/img/API_Postman_variables.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/API_Postman_variables.jpg -------------------------------------------------------------------------------- /docs/img/Auth_Login.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Auth_Login.jpg -------------------------------------------------------------------------------- /docs/img/Auth_Password.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Auth_Password.jpg -------------------------------------------------------------------------------- /docs/img/Auth_RegisterInitial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Auth_RegisterInitial.jpg -------------------------------------------------------------------------------- /docs/img/Auth_UserManagement.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Auth_UserManagement.jpg -------------------------------------------------------------------------------- /docs/img/Auth_UserManagement_old.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Auth_UserManagement_old.jpg -------------------------------------------------------------------------------- /docs/img/AutoExposure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/AutoExposure.jpg -------------------------------------------------------------------------------- /docs/img/CameraStreamUsage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/CameraStreamUsage.jpg -------------------------------------------------------------------------------- /docs/img/Config.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Config.jpg -------------------------------------------------------------------------------- /docs/img/Console.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Console.jpg -------------------------------------------------------------------------------- /docs/img/Console_AButtons.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Console_AButtons.jpg -------------------------------------------------------------------------------- /docs/img/Console_AButtonsDeviceBusy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Console_AButtonsDeviceBusy.jpg -------------------------------------------------------------------------------- /docs/img/Console_VButtons.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Console_VButtons.jpg -------------------------------------------------------------------------------- /docs/img/Console_VButtons_commandline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Console_VButtons_commandline.jpg -------------------------------------------------------------------------------- /docs/img/Console_VButtons_conf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Console_VButtons_conf.jpg -------------------------------------------------------------------------------- /docs/img/Cropping_ScalerCrop_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Cropping_ScalerCrop_0.jpg -------------------------------------------------------------------------------- /docs/img/Cropping_ScalerCrop_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Cropping_ScalerCrop_2.jpg -------------------------------------------------------------------------------- /docs/img/Cropping_SensorModes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Cropping_SensorModes.jpg -------------------------------------------------------------------------------- /docs/img/Exposure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Exposure.jpg -------------------------------------------------------------------------------- /docs/img/Focus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Focus.jpg -------------------------------------------------------------------------------- /docs/img/Foto0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Foto0.jpg -------------------------------------------------------------------------------- /docs/img/Foto1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Foto1.jpg -------------------------------------------------------------------------------- /docs/img/FotoBuffer0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/FotoBuffer0.jpg -------------------------------------------------------------------------------- /docs/img/FotoBuffer1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/FotoBuffer1.jpg -------------------------------------------------------------------------------- /docs/img/FotoBuffer3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/FotoBuffer3.jpg -------------------------------------------------------------------------------- /docs/img/Image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Image.jpg -------------------------------------------------------------------------------- /docs/img/Info-CamProps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Info-CamProps.jpg -------------------------------------------------------------------------------- /docs/img/Info-Cameras.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Info-Cameras.jpg -------------------------------------------------------------------------------- /docs/img/Info-StreamingClients.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Info-StreamingClients.jpg -------------------------------------------------------------------------------- /docs/img/Info_SensorMode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Info_SensorMode.jpg -------------------------------------------------------------------------------- /docs/img/Live.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Live.jpg -------------------------------------------------------------------------------- /docs/img/Live0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Live0.jpg -------------------------------------------------------------------------------- /docs/img/Live_start.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Live_start.jpg -------------------------------------------------------------------------------- /docs/img/MetaHistogram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/MetaHistogram.jpg -------------------------------------------------------------------------------- /docs/img/Metadata1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Metadata1.jpg -------------------------------------------------------------------------------- /docs/img/Metadata2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Metadata2.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeries4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeries4.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeries5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeries5.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeries6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeries6.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeries7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeries7.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeries8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeries8.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesExp1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesExp1.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesExp2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesExp2.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesExp3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesExp3.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesExpTab1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesExpTab1.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesExpTab1_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesExpTab1_3.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesFoc1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesFoc1.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesFoc2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesFoc2.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesStateChart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesStateChart.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesTL1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesTL1.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesTL2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesTL2.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesTL3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesTL3.jpg -------------------------------------------------------------------------------- /docs/img/PhotoSeriesTL4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/PhotoSeriesTL4.jpg -------------------------------------------------------------------------------- /docs/img/Photos.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Photos.jpg -------------------------------------------------------------------------------- /docs/img/Photoseries0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Photoseries0.jpg -------------------------------------------------------------------------------- /docs/img/Photoseries1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Photoseries1.jpg -------------------------------------------------------------------------------- /docs/img/Photoseries2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Photoseries2.jpg -------------------------------------------------------------------------------- /docs/img/Photoseries2b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Photoseries2b.jpg -------------------------------------------------------------------------------- /docs/img/Photoseries3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Photoseries3.jpg -------------------------------------------------------------------------------- /docs/img/Photoseries3b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Photoseries3b.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator0.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator1.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator10.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator11.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator12.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator13.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator14.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator15.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator2.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator3.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator4.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator5.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator6.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator7.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator8.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicator9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicator9.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicatorLive2Active.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicatorLive2Active.jpg -------------------------------------------------------------------------------- /docs/img/ProcessIndicatorLiveActive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/ProcessIndicatorLiveActive.jpg -------------------------------------------------------------------------------- /docs/img/RN282_img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/RN282_img1.jpg -------------------------------------------------------------------------------- /docs/img/Settings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings.jpg -------------------------------------------------------------------------------- /docs/img/SettingsVButtons.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/SettingsVButtons.jpg -------------------------------------------------------------------------------- /docs/img/Settings_AButtons.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_AButtons.jpg -------------------------------------------------------------------------------- /docs/img/Settings_API.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_API.jpg -------------------------------------------------------------------------------- /docs/img/Settings_API_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_API_1.jpg -------------------------------------------------------------------------------- /docs/img/Settings_API_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_API_2.jpg -------------------------------------------------------------------------------- /docs/img/Settings_API_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_API_3.jpg -------------------------------------------------------------------------------- /docs/img/Settings_API_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_API_4.jpg -------------------------------------------------------------------------------- /docs/img/Settings_API_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_API_5.jpg -------------------------------------------------------------------------------- /docs/img/Settings_API_a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_API_a.jpg -------------------------------------------------------------------------------- /docs/img/Settings_API_change.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_API_change.jpg -------------------------------------------------------------------------------- /docs/img/Settings_API_na.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_API_na.jpg -------------------------------------------------------------------------------- /docs/img/Settings_Auth_Streaming.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_Auth_Streaming.jpg -------------------------------------------------------------------------------- /docs/img/Settings_CamSel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_CamSel.jpg -------------------------------------------------------------------------------- /docs/img/Settings_Config.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_Config.jpg -------------------------------------------------------------------------------- /docs/img/Settings_ConfigStore.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_ConfigStore.jpg -------------------------------------------------------------------------------- /docs/img/Settings_Devices.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_Devices.jpg -------------------------------------------------------------------------------- /docs/img/Settings_Devices_Calibration.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_Devices_Calibration.jpg -------------------------------------------------------------------------------- /docs/img/Settings_Devices_Calibration_State.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_Devices_Calibration_State.jpg -------------------------------------------------------------------------------- /docs/img/Settings_full.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_full.jpg -------------------------------------------------------------------------------- /docs/img/Settings_microphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_microphone.jpg -------------------------------------------------------------------------------- /docs/img/Settings_noHistogram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_noHistogram.jpg -------------------------------------------------------------------------------- /docs/img/Settings_no_microphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Settings_no_microphone.jpg -------------------------------------------------------------------------------- /docs/img/TLSeriesStateChart.vsdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/TLSeriesStateChart.vsdx -------------------------------------------------------------------------------- /docs/img/Tooltip.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Tooltip.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Action.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Action.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Actions1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Actions1.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Actions2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Actions2.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Actions3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Actions3.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Actions4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Actions4.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Actions5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Actions5.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Active.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Active.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Calendar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Calendar.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_ConfirmCleanup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_ConfirmCleanup.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Control.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Control.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_DB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_DB.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_DB_Eventactions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_DB_Eventactions.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_DB_Events.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_DB_Events.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_EventCard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_EventCard.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Events.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Events.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Events_Photo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Events_Photo.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_LoadProfile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_LoadProfile.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Logfile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Logfile.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Motion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Motion.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Motion_Algos.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Motion_Algos.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Motion_BGSubtract_Test_l.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Motion_BGSubtract_Test_l.gif -------------------------------------------------------------------------------- /docs/img/Trigger_Motion_FrameDiff_Test_l.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Motion_FrameDiff_Test_l.gif -------------------------------------------------------------------------------- /docs/img/Trigger_Motion_OpticalFlow_Test_l.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Motion_OpticalFlow_Test_l.gif -------------------------------------------------------------------------------- /docs/img/Trigger_Notification.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Notification.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Notification0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Notification0.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Notification1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Notification1.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Notification2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Notification2.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Notification3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Notification3.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Notification3a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Notification3a.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_NotificationError.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_NotificationError.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Storage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Storage.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Trigger1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Trigger1.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Trigger2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Trigger2.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Trigger3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Trigger3.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Trigger4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Trigger4.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_Trigger5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_Trigger5.jpg -------------------------------------------------------------------------------- /docs/img/Trigger_TriggerActions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Trigger_TriggerActions.jpg -------------------------------------------------------------------------------- /docs/img/Tuning1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Tuning1.jpg -------------------------------------------------------------------------------- /docs/img/Tuning2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Tuning2.jpg -------------------------------------------------------------------------------- /docs/img/Tuning3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Tuning3.jpg -------------------------------------------------------------------------------- /docs/img/Tuning4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Tuning4.jpg -------------------------------------------------------------------------------- /docs/img/Tuning5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Tuning5.jpg -------------------------------------------------------------------------------- /docs/img/Tuning6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Tuning6.jpg -------------------------------------------------------------------------------- /docs/img/UnsavedChangesIndicator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/UnsavedChangesIndicator.jpg -------------------------------------------------------------------------------- /docs/img/Video1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Video1.jpg -------------------------------------------------------------------------------- /docs/img/Video2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Video2.jpg -------------------------------------------------------------------------------- /docs/img/Webcam1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Webcam1.jpg -------------------------------------------------------------------------------- /docs/img/Webcam2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Webcam2.jpg -------------------------------------------------------------------------------- /docs/img/Zoom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Zoom.jpg -------------------------------------------------------------------------------- /docs/img/Zoom_Graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/Zoom_Graph.jpg -------------------------------------------------------------------------------- /docs/img/bp_PiZero_Connect.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/bp_PiZero_Connect.jpg -------------------------------------------------------------------------------- /docs/img/docker_CreateContainer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/docker_CreateContainer.jpg -------------------------------------------------------------------------------- /docs/img/docker_InitDb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/docker_InitDb.jpg -------------------------------------------------------------------------------- /docs/img/docker_StartContainer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/docker_StartContainer.jpg -------------------------------------------------------------------------------- /docs/img/goup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/goup.gif -------------------------------------------------------------------------------- /docs/img/pi_zero_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/img/pi_zero_cover.jpg -------------------------------------------------------------------------------- /docs/picamera2-manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/docs/picamera2-manual.pdf -------------------------------------------------------------------------------- /raspiCamSrv/auth_su.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | from flask import ( 4 | g, 5 | redirect, 6 | url_for, 7 | ) 8 | from werkzeug.security import check_password_hash, generate_password_hash 9 | from raspiCamSrv.camCfg import CameraCfg 10 | 11 | from raspiCamSrv.db import get_db 12 | import logging 13 | 14 | logger = logging.getLogger(__name__) 15 | 16 | def superuser_required(view): 17 | @functools.wraps(view) 18 | def wrapped_view(**kwargs): 19 | logger.debug("superuser_required. g.user: %s", g.user) 20 | if g.user is None: 21 | db = get_db() 22 | nrUsers = 0 23 | try: 24 | nrUsers = db.execute("SELECT COUNT(*) from user").fetchone()[0] 25 | except db.Error as e: 26 | logger.error("Database error: %s", e) 27 | nrUsers = 0 28 | if nrUsers > 0: 29 | logger.debug("found %s users. Redirecting to login", nrUsers) 30 | return redirect(url_for("auth.login")) 31 | else: 32 | if g.user["issuperuser"] == 0: 33 | logger.debug("Logged-In user is not SuperUser. Redirecting to index") 34 | return redirect(url_for("index")) 35 | logger.debug("Allowing access") 36 | return view(**kwargs) 37 | 38 | return wrapped_view 39 | -------------------------------------------------------------------------------- /raspiCamSrv/console.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, Response, flash, g, redirect, render_template, request, url_for 2 | from werkzeug.exceptions import abort 3 | from raspiCamSrv.camera_pi import Camera 4 | from raspiCamSrv.camCfg import CameraCfg 5 | from raspiCamSrv.version import version 6 | import subprocess 7 | from subprocess import CalledProcessError 8 | from raspiCamSrv.triggerHandler import TriggerHandler 9 | 10 | 11 | from raspiCamSrv.auth import login_required 12 | import logging 13 | 14 | bp = Blueprint("console", __name__) 15 | 16 | logger = logging.getLogger(__name__) 17 | 18 | @bp.route("/console") 19 | @login_required 20 | def console(): 21 | cam = Camera().cam 22 | props = cam.camera_properties 23 | g.hostname = request.host 24 | g.version = version 25 | cfg = CameraCfg() 26 | sc = cfg.serverConfig 27 | if sc.vButtonHasCommandLine == True: 28 | if sc.vButtonCommand is None: 29 | sc.vButtonCommand = "" 30 | sc.curMenu = "console" 31 | return render_template("console/console.html", props=props, sc=sc) 32 | 33 | @bp.route("/execute//", methods=("GET", "POST")) 34 | @login_required 35 | def execute(row:None, col=None): 36 | logger.debug("In execute - row=%s, col=%s", row, col) 37 | cam = Camera().cam 38 | props = cam.camera_properties 39 | g.hostname = request.host 40 | g.version = version 41 | cfg = CameraCfg() 42 | sc = cfg.serverConfig 43 | sc.curMenu = "console" 44 | sc.vButtonCommand = None 45 | sc.vButtonArgs = None 46 | sc.vButtonReturncode = None 47 | sc.vButtonStderr = None 48 | sc.vButtonStdout = None 49 | sc.lastConsoleTab = "versbuttons" 50 | if request.method == "POST": 51 | msg = "" 52 | r = int(row) 53 | c = int(col) 54 | btn = sc.vButtons[r][c] 55 | cmd = btn.buttonExec 56 | sc.vButtonCommand = cmd 57 | args = cmd.rsplit(" ") 58 | sc.vButtonArgs = args 59 | 60 | msg = "Command successfully executed." 61 | result = None 62 | if cmd != "": 63 | try: 64 | result = subprocess.run(args, capture_output=True, text=True, check=False) 65 | except CalledProcessError as e: 66 | msg = f"Command executed with error: {e}." 67 | except Exception as e: 68 | msg = f"Command executed with error: {e}." 69 | if result: 70 | sc.vButtonReturncode = result.returncode 71 | sc.vButtonStdout = result.stdout 72 | sc.vButtonStderr = result.stderr 73 | else: 74 | msg = "No command executed" 75 | 76 | if msg != "": 77 | flash(msg) 78 | return render_template("console/console.html", props=props, sc=sc) 79 | 80 | @bp.route("/execCommandline", methods=("GET", "POST")) 81 | @login_required 82 | def execCommandline(): 83 | logger.debug("In execCommandline") 84 | cam = Camera().cam 85 | props = cam.camera_properties 86 | g.hostname = request.host 87 | g.version = version 88 | cfg = CameraCfg() 89 | sc = cfg.serverConfig 90 | if request.method == "POST": 91 | msg = "" 92 | cmd = request.form["commandline"] 93 | sc.vButtonCommand = cmd 94 | args = cmd.rsplit(" ") 95 | sc.vButtonArgs = args 96 | 97 | msg = "Command successfully executed." 98 | result = None 99 | if cmd != "": 100 | try: 101 | result = subprocess.run(args, capture_output=True, text=True, check=False) 102 | except CalledProcessError as e: 103 | msg = f"Command executed with error: {e}." 104 | except Exception as e: 105 | msg = f"Command executed with error: {e}." 106 | if result: 107 | sc.vButtonReturncode = result.returncode 108 | sc.vButtonStdout = result.stdout 109 | sc.vButtonStderr = result.stderr 110 | else: 111 | msg = "No command executed" 112 | 113 | if msg != "": 114 | flash(msg) 115 | return render_template("console/console.html", props=props, sc=sc) 116 | 117 | @bp.route("/do_action//", methods=("GET", "POST")) 118 | @login_required 119 | def do_action(row:None, col=None): 120 | logger.debug("In do_action - row=%s, col=%s", row, col) 121 | cam = Camera().cam 122 | props = cam.camera_properties 123 | g.hostname = request.host 124 | g.version = version 125 | cfg = CameraCfg() 126 | sc = cfg.serverConfig 127 | sc.curMenu = "console" 128 | sc.vButtonCommand = None 129 | sc.vButtonArgs = None 130 | sc.vButtonReturncode = None 131 | sc.vButtonStderr = None 132 | sc.vButtonStdout = None 133 | sc.lastConsoleTab = "actionbuttons" 134 | if request.method == "POST": 135 | msg = "" 136 | r = int(row) 137 | c = int(col) 138 | btn = sc.aButtons[r][c] 139 | action = btn.buttonAction 140 | 141 | msg = "Action successfully executed." 142 | result = None 143 | if action != "": 144 | msg = TriggerHandler.doAction(action) 145 | else: 146 | msg = "No Action executed" 147 | 148 | if msg != "": 149 | flash(msg) 150 | return render_template("console/console.html", props=props, sc=sc) 151 | -------------------------------------------------------------------------------- /raspiCamSrv/db.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | import click 4 | from flask import current_app, g 5 | from raspiCamSrv.camCfg import CameraCfg 6 | import logging 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | def get_db(): 11 | if "db" not in g: 12 | g.db = sqlite3.connect( 13 | current_app.config["DATABASE"], detect_types=sqlite3.PARSE_DECLTYPES 14 | ) 15 | g.db.row_factory = sqlite3.Row 16 | 17 | return g.db 18 | 19 | 20 | def close_db(e=None): 21 | db = g.pop("db", None) 22 | 23 | if db is not None: 24 | db.close() 25 | 26 | 27 | def init_db(): 28 | db = get_db() 29 | 30 | with current_app.open_resource("schema.sql") as f: 31 | db.executescript(f.read().decode("utf8")) 32 | 33 | 34 | @click.command("init-db") 35 | def init_db_command(): 36 | """Clear the existing data and create new tables.""" 37 | init_db() 38 | click.echo("Initialized the database.") 39 | 40 | 41 | def init_app(app): 42 | app.teardown_appcontext(close_db) 43 | app.cli.add_command(init_db_command) 44 | -------------------------------------------------------------------------------- /raspiCamSrv/dbx.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | import raspiCamSrv.camCfg as camCfg 4 | import logging 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | 9 | def get_dbx() -> sqlite3.Connection: 10 | """ Get database outside of application context 11 | """ 12 | database = camCfg.CameraCfg().serverConfig.database 13 | logger.debug("get_dbx - database: %s", database) 14 | db = sqlite3.connect(database, detect_types=sqlite3.PARSE_DECLTYPES) 15 | db.row_factory = sqlite3.Row 16 | return db 17 | -------------------------------------------------------------------------------- /raspiCamSrv/info.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, Response, flash, g, redirect, render_template, request, url_for 2 | from werkzeug.exceptions import abort 3 | from raspiCamSrv.camera_pi import Camera 4 | from raspiCamSrv.camCfg import CameraCfg, TuningConfig 5 | from raspiCamSrv.version import version 6 | import threading 7 | 8 | from raspiCamSrv.auth import login_required 9 | import logging 10 | 11 | bp = Blueprint("info", __name__) 12 | 13 | logger = logging.getLogger(__name__) 14 | 15 | @bp.route("/info") 16 | @login_required 17 | def main(): 18 | cam = Camera().cam 19 | props = cam.camera_properties 20 | g.hostname = request.host 21 | g.version = version 22 | cfg = CameraCfg() 23 | cs = cfg.cameras 24 | sc = cfg.serverConfig 25 | cp = cfg.cameraProperties 26 | sm = cfg.sensorModes 27 | tcs = {} 28 | for c in cs: 29 | camnum = str(c.num) 30 | if c.num == sc.activeCamera: 31 | tcs[camnum] = cfg.tuningConfig 32 | else: 33 | strc = cfg.streamingCfg 34 | if camnum in strc: 35 | cstrc = strc[camnum] 36 | tcs[camnum] = cstrc["tuningconfig"] 37 | else: 38 | tcs[camnum] = TuningConfig() 39 | c.status = Camera.cameraStatus(c.num) 40 | # Update streaming clients 41 | sc.updateStreamingClients() 42 | sc.curMenu = "info" 43 | return render_template("info/info.html", props=props, sm=sm, sc=sc, tcs=tcs, cp=cp, cs=cs, cfg=cfg) 44 | -------------------------------------------------------------------------------- /raspiCamSrv/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS user; 2 | DROP TABLE IF EXISTS config; 3 | DROP TABLE IF EXISTS events; 4 | DROP TABLE IF EXISTS eventactions; 5 | 6 | CREATE TABLE IF NOT EXISTS user ( 7 | id INTEGER PRIMARY KEY AUTOINCREMENT, 8 | username TEXT UNIQUE NOT NULL, 9 | password TEXT NOT NULL, 10 | issuperuser INTEGER DEFAULT 0 NOT NULL, 11 | isinitial INTEGER DEFAULT 1 NOT NULL 12 | ); 13 | 14 | CREATE TABLE IF NOT EXISTS config ( 15 | key TEXT NOT NULL, 16 | type TEXT NOT NULL, 17 | value TEXT NOT NULL 18 | ); 19 | 20 | CREATE TABLE IF NOT EXISTS events ( 21 | id INTEGER PRIMARY KEY AUTOINCREMENT, 22 | timestamp TEXT NOT NULL, 23 | date TEXT NOT NULL, 24 | minute TEXT NOT NULL, 25 | time TEXT NOT NULL, 26 | type TEXT NOT NULL, 27 | trigger TEXT NOT NULL, 28 | triggertype TEXT NOT NULL, 29 | triggerparam TEXT NOT NULL 30 | ); 31 | 32 | CREATE TABLE IF NOT EXISTS eventactions ( 33 | id INTEGER PRIMARY KEY AUTOINCREMENT, 34 | event TEXT NOT NULL, 35 | timestamp TEXT NOT NULL, 36 | actiontype TEXT NOT NULL, 37 | date TEXT NOT NULL, 38 | time TEXT NOT NULL, 39 | actionduration INTEGER, 40 | filename TEXT NOT NULL, 41 | fullpath TEXT NOT NULL, 42 | FOREIGN KEY(event) REFERENCES events(timestamp) 43 | ); 44 | 45 | CREATE INDEX IF NOT EXISTS events_date_idx ON events( 46 | date, 47 | minute 48 | ); 49 | 50 | CREATE INDEX IF NOT EXISTS eventactions_type_idx ON eventactions( 51 | event, 52 | actiontype 53 | ); 54 | 55 | -------------------------------------------------------------------------------- /raspiCamSrv/static/device_Buzzer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_Buzzer.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_DigitalInputDevice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_DigitalInputDevice.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_DigitalOutputDevice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_DigitalOutputDevice.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_DistanceSensor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_DistanceSensor.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_InputDevice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_InputDevice.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_LED.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_LED.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_LightSensor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_LightSensor.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_LineSensor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_LineSensor.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_Motor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_Motor.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_OutputDevice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_OutputDevice.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_RGBLED.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_RGBLED.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_RotaryEncoder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_RotaryEncoder.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_Servo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_Servo.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_StepperMotor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_StepperMotor.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_TonalBuzzer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_TonalBuzzer.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_button.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_button.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/device_motionSensor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/device_motionSensor.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/favicon.ico -------------------------------------------------------------------------------- /raspiCamSrv/static/histogramfailed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/histogramfailed.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/onlineHelp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/onlineHelp.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_active.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_active.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_active.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_audio_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_audio_active.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_audio_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_audio_inactive.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_events_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_events_active.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_events_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_events_inactive.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_events_wait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_events_wait.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_inactive.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_live2_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_live2_active.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_live2_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_live2_inactive.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_live_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_live_active.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_live_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_live_inactive.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_series_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_series_active.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_series_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_series_inactive.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_trigger_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_trigger_active.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_trigger_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_trigger_inactive.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_trigger_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_trigger_test.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_trigger_wait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_trigger_wait.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_video_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_video_active.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recording_video_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recording_video_inactive.png -------------------------------------------------------------------------------- /raspiCamSrv/static/recordingphotoseries.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recordingphotoseries.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/recordingvideo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recordingvideo.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/recordingvideo_sound.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/recordingvideo_sound.jpg -------------------------------------------------------------------------------- /raspiCamSrv/static/save_changes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/save_changes.png -------------------------------------------------------------------------------- /raspiCamSrv/static/underconstruction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/signag/raspi-cam-srv/bd431617e7b4e12eebec997ca98ec04379a9ee8b/raspiCamSrv/static/underconstruction.jpg -------------------------------------------------------------------------------- /raspiCamSrv/sun.py: -------------------------------------------------------------------------------- 1 | """ Module for calculation of sunrise / sunset 2 | 3 | Based on code from https://en.wikipedia.org/wiki/Sunrise_equation 4 | """ 5 | 6 | import logging 7 | from datetime import datetime, timedelta, timezone, tzinfo 8 | from math import acos, asin, ceil, cos, degrees, fmod, radians, sin, sqrt 9 | from time import time 10 | from zoneinfo import ZoneInfo 11 | 12 | log = logging.getLogger(__name__) 13 | 14 | class Sun(): 15 | def __init__(self, latitude: float, longitude: float, elevation: float, timezone: str): 16 | """Constructor for sun class 17 | 18 | Args: 19 | - `latitude (float)` : Latitude 20 | - `longitude (float)` : Longitude 21 | - `elevation (float)` : Elevation 22 | - `timezone (str)` : Time Zone 23 | """ 24 | self._latitude = latitude 25 | self._longitude = longitude 26 | self._elevation = elevation 27 | self._timezone = timezone 28 | 29 | def _ts2human(self, ts: float, debugtz: tzinfo) -> str: 30 | return str(datetime.fromtimestamp(ts, debugtz)) 31 | 32 | 33 | def _j2ts(self, j: float) -> float: 34 | return (j - 2440587.5) * 86400 35 | 36 | 37 | def _ts2j(self, ts: float) -> float: 38 | return ts / 86400.0 + 2440587.5 39 | 40 | 41 | def _j2human(self, j: float, debugtz: tzinfo) -> str: 42 | ts = self._j2ts(j) 43 | return f'{ts} = {self._ts2human(ts, debugtz)}' 44 | 45 | 46 | def _deg2human(self, deg: float) -> str: 47 | x = int(deg * 3600.0) 48 | num = f'∠{deg:.3f}°' 49 | rad = f'∠{radians(deg):.3f}rad' 50 | human = f'∠{x // 3600}°{x // 60 % 60}′{x % 60}″' 51 | return f'{rad} = {human} = {num}' 52 | 53 | 54 | def _calc( 55 | self, 56 | current_timestamp: float, 57 | f: float, 58 | l_w: float, 59 | elevation: float = 0.0, 60 | *, 61 | debugtz: tzinfo = None, 62 | ) -> tuple: 63 | log.debug(f'Latitude f = {self._deg2human(f)}') 64 | log.debug(f'Longitude l_w = {self._deg2human(l_w)}') 65 | log.debug(f'Now ts = {self._ts2human(current_timestamp, debugtz)}') 66 | 67 | J_date = self._ts2j(current_timestamp) 68 | log.debug(f'Julian date j_date = {J_date:.3f} days') 69 | 70 | # Julian day 71 | # TODO: ceil ? 72 | n = ceil(J_date - (2451545.0 + 0.0009) + 69.184 / 86400.0) 73 | log.debug(f'Julian day n = {n:.3f} days') 74 | 75 | # Mean solar time 76 | J_ = n + 0.0009 - l_w / 360.0 77 | log.debug(f'Mean solar time J_ = {J_:.9f} days') 78 | 79 | # Solar mean anomaly 80 | # M_degrees = 357.5291 + 0.98560028 * J_ # Same, but looks ugly 81 | M_degrees = fmod(357.5291 + 0.98560028 * J_, 360) 82 | M_radians = radians(M_degrees) 83 | log.debug(f'Solar mean anomaly M = {self._deg2human(M_degrees)}') 84 | 85 | # Equation of the center 86 | C_degrees = 1.9148 * sin(M_radians) + 0.02 * sin(2 * M_radians) + 0.0003 * sin(3 * M_radians) 87 | # The difference for final program result is few milliseconds 88 | # https://www.astrouw.edu.pl/~jskowron/pracownia/praca/sunspot_answerbook_expl/expl-4.html 89 | # e = 0.01671 90 | # C_degrees = \ 91 | # degrees(2 * e - (1 / 4) * e ** 3 + (5 / 96) * e ** 5) * sin(M_radians) \ 92 | # + degrees(5 / 4 * e ** 2 - (11 / 24) * e ** 4 + (17 / 192) * e ** 6) * sin(2 * M_radians) \ 93 | # + degrees(13 / 12 * e ** 3 - (43 / 64) * e ** 5) * sin(3 * M_radians) \ 94 | # + degrees((103 / 96) * e ** 4 - (451 / 480) * e ** 6) * sin(4 * M_radians) \ 95 | # + degrees((1097 / 960) * e ** 5) * sin(5 * M_radians) \ 96 | # + degrees((1223 / 960) * e ** 6) * sin(6 * M_radians) 97 | 98 | log.debug(f'Equation of the center C = {self._deg2human(C_degrees)}') 99 | 100 | # Ecliptic longitude 101 | # L_degrees = M_degrees + C_degrees + 180.0 + 102.9372 # Same, but looks ugly 102 | L_degrees = fmod(M_degrees + C_degrees + 180.0 + 102.9372, 360) 103 | log.debug(f'Ecliptic longitude L = {self._deg2human(L_degrees)}') 104 | 105 | Lambda_radians = radians(L_degrees) 106 | 107 | # Solar transit (julian date) 108 | J_transit = 2451545.0 + J_ + 0.0053 * sin(M_radians) - 0.0069 * sin(2 * Lambda_radians) 109 | log.debug(f'Solar transit time J_trans = {self._j2human(J_transit, debugtz)}') 110 | 111 | # Declination of the Sun 112 | sin_d = sin(Lambda_radians) * sin(radians(23.4397)) 113 | # cos_d = sqrt(1-sin_d**2) # exactly the same precision, but 1.5 times slower 114 | cos_d = cos(asin(sin_d)) 115 | 116 | # Hour angle 117 | some_cos = (sin(radians(-0.833 - 2.076 * sqrt(elevation) / 60.0)) - sin(radians(f)) * sin_d) / (cos(radians(f)) * cos_d) 118 | try: 119 | w0_radians = acos(some_cos) 120 | except ValueError: 121 | return None, None, some_cos > 0.0 122 | w0_degrees = degrees(w0_radians) # 0...180 123 | 124 | log.debug(f'Hour angle w0 = {self._deg2human(w0_degrees)}') 125 | 126 | j_rise = J_transit - w0_degrees / 360 127 | j_set = J_transit + w0_degrees / 360 128 | 129 | log.debug(f'Sunrise j_rise = {self._j2human(j_rise, debugtz)}') 130 | log.debug(f'Sunset j_set = {self._j2human(j_set, debugtz)}') 131 | log.debug(f'Day length {w0_degrees / (180 / 24):.3f} hours') 132 | 133 | return self._j2ts(j_rise), self._j2ts(j_set), None 134 | 135 | def sunTimezone(self) -> str: 136 | """## Return the timezone key used for sun calculations 137 | 138 | ### Returns: 139 | - `str`: Timezone key 140 | """ 141 | return self._timezone 142 | 143 | def sunrise_sunset(self, time: datetime) -> tuple[datetime, datetime]: 144 | """Determine sunrise and sunset for a specific date 145 | 146 | Args: 147 | - `time (datetime)`: Date for which to determine sunrise 148 | 149 | Returns: 150 | - `datetime`: time of sunrise 151 | """ 152 | timeTS = datetime.timestamp(time) 153 | sunriseTS, sunsetTS, err = self._calc( 154 | timeTS, 155 | self._latitude, 156 | self._longitude, 157 | self._elevation, 158 | debugtz=ZoneInfo(self._timezone) 159 | ) 160 | sunrise = datetime.fromtimestamp(sunriseTS, ZoneInfo(self._timezone)) 161 | sunset = datetime.fromtimestamp(sunsetTS, ZoneInfo(self._timezone)) 162 | return sunrise, sunset -------------------------------------------------------------------------------- /raspiCamSrv/templates/auth/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block header %} 4 | {% block title %}Log In{% endblock %} 5 | {% endblock %} 6 | 7 | {% block content %} 8 |

Log In

9 |
10 | 11 | 12 | 13 | 14 |

15 | 16 |
17 | {% endblock %} -------------------------------------------------------------------------------- /raspiCamSrv/templates/auth/password.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block header %} 4 | {% block title %}Change Password{% endblock %} 5 | {% endblock %} 6 | 7 | {% block content %} 8 |

Change Password

9 |
10 | 11 | 12 | 13 | 14 |

15 | 16 | 17 | 18 | 19 |

20 | 21 |
22 | {% endblock %} -------------------------------------------------------------------------------- /raspiCamSrv/templates/auth/register.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block header %} 4 | {% block title %}Register{% endblock %} 5 | {% endblock %} 6 | 7 | {% block content %} 8 |

Register

9 |
10 | 11 | 12 | 13 | 14 |

15 | 16 |
17 | {% endblock %} -------------------------------------------------------------------------------- /raspiCamSrv/version.py: -------------------------------------------------------------------------------- 1 | version="V3.5.2" -------------------------------------------------------------------------------- /raspiCamSrv/webcam.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, Response, flash, g, redirect, render_template, request, url_for 2 | from werkzeug.exceptions import abort 3 | from raspiCamSrv.camera_pi import Camera 4 | from raspiCamSrv.camCfg import CameraCfg, TuningConfig 5 | from raspiCamSrv.version import version 6 | from _thread import get_ident 7 | import copy 8 | 9 | from raspiCamSrv.auth import login_required, login_for_streaming 10 | import logging 11 | 12 | bp = Blueprint("webcam", __name__) 13 | 14 | logger = logging.getLogger(__name__) 15 | 16 | @bp.route("/webcam") 17 | @login_required 18 | def webcam(): 19 | logger.debug("In webcam") 20 | g.hostname = request.host 21 | g.version = version 22 | cfg = CameraCfg() 23 | sc = cfg.serverConfig 24 | sc.error = None 25 | sc.errorc2 = None 26 | Camera().startLiveStream() 27 | Camera().startLiveStream2() 28 | str2 = None 29 | if sc.isLiveStream2: 30 | str2 = cfg.streamingCfg[str(Camera().camNum2)] 31 | sc.curMenu = "webcam" 32 | if sc.error: 33 | msg = "Error in " + sc.errorSource + ": " + sc.error 34 | flash(msg) 35 | if sc.error2: 36 | flash(sc.error2) 37 | if sc.errorc2: 38 | msg = "Error in " + sc.errorc2Source + ": " + sc.errorc2 39 | flash(msg) 40 | if sc.errorc22: 41 | flash(sc.errorc22) 42 | return render_template("webcam/webcam.html", sc=sc, cfg=cfg, str2=str2) 43 | 44 | @bp.route("/store_streaming_config", methods=("GET", "POST")) 45 | @login_required 46 | def store_streaming_config(): 47 | logger.debug("In store_streaming_config") 48 | Camera().startLiveStream() 49 | Camera().startLiveStream2() 50 | g.hostname = request.host 51 | g.version = version 52 | cfg = CameraCfg() 53 | sc = cfg.serverConfig 54 | str2 = None 55 | if sc.isLiveStream2: 56 | str2 = cfg.streamingCfg[str(Camera().camNum2)] 57 | sc.curMenu = "webcam" 58 | if request.method == "POST": 59 | scfg = cfg.streamingCfg[str(sc.activeCamera)] 60 | scfg["tuningconfig"] = copy.deepcopy(cfg.tuningConfig) 61 | scfg["liveconfig"] = copy.deepcopy(cfg.liveViewConfig) 62 | scfg["videoconfig"] = copy.deepcopy(cfg.videoConfig) 63 | scfg["controls"] = copy.deepcopy(cfg.controls) 64 | return render_template("webcam/webcam.html", sc=sc, cfg=cfg, str2=str2) 65 | 66 | @bp.route("/switch_cameras", methods=("GET", "POST")) 67 | @login_required 68 | def switch_cameras(): 69 | logger.debug("In switch_cameras") 70 | g.hostname = request.host 71 | g.version = version 72 | cfg = CameraCfg() 73 | sc = cfg.serverConfig 74 | str2 = None 75 | if sc.isLiveStream2: 76 | str2 = cfg.streamingCfg[str(Camera().camNum2)] 77 | sc.curMenu = "webcam" 78 | if request.method == "POST": 79 | msg = None 80 | cs = cfg.cameras 81 | activeCam = sc.activeCamera 82 | newCam = activeCam 83 | for cm in cs: 84 | if cm.isUsb == False: 85 | if activeCam != cm.num: 86 | newCam = cm.num 87 | newCamInfo = "Camera " + str(cm.num) + " (" + cm.model + ")" 88 | newCamModel = cm.model 89 | break 90 | if newCam != sc.activeCamera: 91 | if sc.isTriggerRecording: 92 | msg = "Please go to 'Trigger' and stop the active process before changing the configuration" 93 | if sc.isVideoRecording == True: 94 | msg = "Please stop video recording before changing the tuning configuration" 95 | if sc.isPhotoSeriesRecording: 96 | msg = "Please go to 'Photo Series' and stop the active process before changing the tuning configuration" 97 | if not msg: 98 | sc.activeCameraInfo = newCamInfo 99 | sc.activeCameraModel = newCamModel 100 | cfg.liveViewConfig.stream_size = None 101 | cfg.photoConfig.stream_size = None 102 | cfg.rawConfig.stream_size = None 103 | cfg.videoConfig.stream_size = None 104 | sc.activeCamera = newCam 105 | strCfg = cfg.streamingCfg 106 | newCamStr = str(newCam) 107 | if newCamStr in strCfg: 108 | ncfg = strCfg[newCamStr] 109 | if "tuningconfig" in ncfg: 110 | cfg.tuningConfig = ncfg["tuningconfig"] 111 | else: 112 | cfg.tuningConfig = TuningConfig 113 | else: 114 | cfg.tuningConfig = TuningConfig 115 | Camera.switchCamera() 116 | if sc.isLiveStream2: 117 | str2 = cfg.streamingCfg[str(Camera().camNum2)] 118 | logger.debug("switch_cameras - active camera set to %s", sc.activeCamera) 119 | if msg: 120 | flash(msg) 121 | return render_template("webcam/webcam.html", sc=sc, cfg=cfg, str2=str2) 122 | 123 | @bp.route("/photo_feed") 124 | @login_for_streaming 125 | def photo_feed(): 126 | logger.debug("Thread %s: In photo_feed", get_ident()) 127 | Camera().startLiveStream() 128 | return Response(Camera().get_photoFrame(), mimetype='image/jpeg') 129 | 130 | @bp.route("/photo_feed2") 131 | @login_for_streaming 132 | def photo_feed2(): 133 | logger.debug("Thread %s: In photo_feed2", get_ident()) 134 | Camera().startLiveStream2() 135 | return Response(Camera().get_photoFrame2(), mimetype='image/jpeg') 136 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | RPi.GPIO 2 | gpiozero 3 | Flask>=3,<4 4 | numpy 5 | matplotlib 6 | flask-jwt-extended --------------------------------------------------------------------------------