Skip to content

tailucas/snapshot-processor

Repository files navigation

Contributors Forks Stargazers Issues MIT License

About The Project

Overview

Note 1: See my write-up on Home Security Automation which provides an architectural overview of how this project works with others in my collection.

Note 2: While I use the word Automation in these projects, there is no integration with sensible frameworks like openHAB or Home Assistant... not yet at least. The goal behind this project was a learning opportunity by employing some specific technologies and opinion on design. The parts you'll most likely find useful are touch-points with third-party libraries like Flask, ZeroMQ and RabbitMQ, because seamless behavior comes after much trial and error.

This project supports fetching image snapshots from Foscam IP cameras and forwards this data to companion projects using a RabbitMQ exchange. Most IP cameras will have varying degrees of "documented" methods to fetch image data on-demand. My use of Foscam is really based on the hardware that I currently use (at the time of writing, some of their web sites appear broken 🤷).

Additional features include:

  • a self-managed local cache of snapshot images which are asynchronously uploaded to CloudStorage instances which currently includes Google Drive.
  • periodic management of Google Driver folders by organizing non-starred images into year-month-day folders.
  • a local FTP server to support FTP-based IP camera image push using FTP basic-auth.
  • object detection using AWS Rekognition with metadata-flags for human detection.

This application extends my own boilerplate application hosted in docker hub and takes its own git submodule dependency on my own package.

There are also a few branches of this project, made for various platforms, one of which was to support the Jetson Nano developer kit. This branch includes logic to control the PWM fan to run when detection is being done. The results weren't perfect so if you do intend to fork this branch, your mileage may vary. The main branch of this project works with AWS Rekognition and I've found it to be fast, rather accurate and returns useful metadata for person detection. The current logic makes use of the DetectLabels feature and carries associated pricing.

Package Structure

The diagrams below show both the class inheritance structure. Here is the relationship between this project and my pylib submodule. For brevity, not everything is included such as the cloud storage management classes, but those are mostly self-contained. These are the non-obvious relationships.

classes

  • Snapshot receives trigger messages and fetches image data from cameras and forwards this to ObjectDetector which delegates to the chosen detection mechanism to identify features in the images. Both of these are descendants of ZMQRelay for inter-thread message passing. You can see this flow illustrated in the diagram below.
  • The main application thread contains an instance of ZMQListener which receives messages from the configured exchange and forwards them to Snapshot. After object detection, outgoing messages are sent via RabbitMQRelay.

See the diagram below for an example about how ZeroMQ is used as a message relay between threads.

comms

  • ZMQListener is responsible for receiving RabbitMQ messages from the network and then forwards these through a chain of ZMQRelay instances out the way back to the RabbitMQ publisher.

(back to top)

Built With

Technologies that help make this project useful:

1Password AWS Docker Google Drive RabbitMQ Poetry Python Sentry ZeroMQ

Also:

(back to top)

Getting Started

Here is some detail about the intended use of this package.

Prerequisites

Beyond the Python dependencies defined in the Poetry configuration, the project carries hardcoded dependencies on Sentry and 1Password in order to function.

Installation

  • 🛑 This project uses 1Password Secrets Automation to store both application key-value pairs as well as runtime secrets. It is assumed that the connect server containers are already running on your environment. If you do not want to use this, then you'll need to fork this package and make the changes as appropriate. It's actually very easy to set up, but note that 1Password is a paid product with a free-tier for secrets automation.

  • 🚧 If a Google authorization token is not present on the local file system, pydrive will initiate an oauth workflow which needs to be followed at least once in order to interact with Google Drive. During this flow, a URL will be logged that needs to be followed by the authorizing user at which point the client will store the token and it will be backed up regularly. As long as the token is backed up, it will remain valid until the authorization is revoked.

Here is an example of how this looks for my application and the generation of the docker-compose.yml relies on this step. Your secrets automation vault must contain an entry called ENV.snapshot-processor with these keys:

Variable Description Example
APP_NAME Application name used in logging and metrics snapshot-processor
AWS_ALT_REGION AWS region (used for dual-region) eu-west-1
AWS_CONFIG_FILE AWS client configuration file /home/app/.aws/config
AWS_DEFAULT_REGION AWS region us-east-1
CRONITOR_MONITOR_KEY Cronitor configuration key project specific
DEVICE_NAME Used for container host name. snapshot-processor
FTP_CREATE_DIRS IP-camera upload directories snapshots/cam1,snapshots/cam2
FTP_PASS FTP basic-auth password project specific
FTP_SERVER_ADDRESS IP address of FTP server host that runs container project specific
FTP_UPLOAD_DIR Upload directory within the FTP root uploads/snapshots
FTP_USER FTP basic-auth user project specific
GOOGLE_DRIVE_FOLDER Google Drive folder name project specific
HC_PING_URL Healthchecks URL project specific
INPUT_X_LOCATION Device location project specific
INPUT_X_TYPE Device type Camera
OBJECT_DETECTION_ENABLED Detect objects in snapshots true
OP_CONNECT_HOST 1Password connect server URL network specific
OP_CONNECT_TOKEN 1Password connect server token project specific
OP_VAULT 1Password vault project specific
OUTPUT_X_LOCATION Device location project specific
OUTPUT_X_TYPE Device type Camera
RABBITMQ_DEVICE_TOPIC Publication topic for this project snapshot
RABBITMQ_EXCHANGE Name of RabbitMQ exchange home_automation
RABBITMQ_SERVER_ADDRESS IP address of RabbitMQ exchange network specific
USER Process user app

With these configured, you are now able to build the application. Any variables referenced in the application configuration will be automatically replaced.

In addition to this, additional runtime configuration is used by the application, and also need to be contained within the secrets vault. With these configured, you are now able to run the application.

  1. Clone the repo
    git clone https://github.com/tailucas/snapshot-processor.git
  2. Verify that the git submodule is present.
    git submodule init
    git submodule update
  3. Make the Docker runtime user and set directory permissions. ✋ Be sure to first review the Makefile contents for assumptions around user IDs for Docker.
    make user
  4. Now generate the docker-compose.yml:
    make setup
  5. And generate the Docker image:
    make build
  6. If successful and the local environment is running the 1Password connect containers, run the application. For foreground:
    make run
    For background:
    make rund

(back to top)

Usage

Running the application will:

  • Start the RabbitMQ client.
  • Start a watchdog file system observer to detect FTP uploads.
  • Start a Google Drive client to store snapshots with date-folder archive function.
  • Start the main application loop Snapshot which waits for trigger events.

(back to top)

License

Distributed under the MIT License. See LICENSE for more information.

(back to top)

Acknowledgments

(back to top)

Hits