Skip to content

Commit

Permalink
Merge pull request #225 from parkpow/genetec-pp-snapshot
Browse files Browse the repository at this point in the history
feat: genetec camera integration
  • Loading branch information
marcbelmont authored Jan 13, 2025
2 parents 0a8b126 + 0521c5e commit f636f5a
Show file tree
Hide file tree
Showing 6 changed files with 427 additions and 1 deletion.
19 changes: 19 additions & 0 deletions parkpow/genetec/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1

WORKDIR /app

RUN apt-get update\
&& apt-get install --no-install-recommends -y curl libgl1\
&& rm -rf /var/lib/apt/lists/*\
&& pip install --upgrade pip

# Copy python dependecies file
COPY requirements.txt .

RUN pip install -r requirements.txt

# Copy source code
COPY . /app/

ENTRYPOINT ["python3", "main.py"]
42 changes: 42 additions & 0 deletions parkpow/genetec/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Genetec Integration
Forward Genetec Events to ParkPow or Platerecognizer Snapshot

## Setup
1. Build the image
```shell
docker build --tag platerecognizer/genetec-integration .
```

2. Process Events
1. Using ParkPow
```shell
docker run --rm -t \
--net=host \
-e LOGGING=DEBUG \
platerecognizer/genetec-integration \
parkpow \
--token=pass \
--url='http://localhost:8000'
```

**token**: ParkPow token
**url**: ParkPow URL, Optional for ParkPow cloud.
2. Using Snapshot
```shell
docker run --rm -t \
--net=host \
-e LOGGING=DEBUG \
platerecognizer/genetec-integration \
snapshot \
--token=pass \
--url='http://localhost:8080'
```

**token**: Platerecognizer token, Optional for Snapshot onPremise.
**url**: Snapshot URL, Optional for Snapshot cloud.
> you should not provide both args at the same time

3. URL to use for Genetec Webhooks settings is: `http://<machine-ip>:8001/` Test using CURL:
```shell
curl -vX POST http://localhost:8002/ -d @../../snapshot-middleware/test/Genetec.txt --header "Content-Type: application/json"
```
113 changes: 113 additions & 0 deletions parkpow/genetec/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import logging
import time

import requests

lgr = logging.getLogger(__name__)

API_BASE = "https://api.platerecognizer.com"


class SnapshotApiError(Exception):
status_code = 400


class LicenseVerificationError(SnapshotApiError):
status_code = 403


class PayloadTooLargeError(SnapshotApiError):
status_code = 413


class TooManyRequestsError(SnapshotApiError):
status_code = 429


RETRY_LIMIT = 10


class Snapshot:
def __init__(self, token, sdk_url=None):
self.sdk_url = sdk_url
if token is None:
raise ValueError("A TOKEN is required if using Cloud API")
else:
self.session = requests.Session()
self.session.headers = {"Authorization": "Token " + token}

def recognition(self, data: dict):
"""
Send image b64 to Snapshot
:param data:
:return:
"""
if self.sdk_url:
api_base = self.sdk_url
else:
api_base = API_BASE

url = f"{api_base}/v1/plate-reader/"
lgr.debug(f"Url: {url}")
tries = 1
while True:
# files = dict(upload=image_b64)
response = self.session.post(url, data)
lgr.debug(f"Plate Recognition Response: {response} -----------------")
lgr.debug(response.text)
lgr.debug("End Plate Recognition Response -----------------")
if response.status_code < 200 or response.status_code > 300:
if response.status_code == 429:
time.sleep(1)
tries += 1
if tries > RETRY_LIMIT:
raise TooManyRequestsError(response.json()["detail"])
elif response.status_code == 403:
raise LicenseVerificationError(response.json()["detail"])
elif response.status_code == 413:
raise PayloadTooLargeError(response.json()["error"])
elif response.status_code == 400:
raise SnapshotApiError(response.json())
else:
response.raise_for_status()
else:
res_json = response.json()
if "error" in res_json:
raise SnapshotApiError(res_json["error"])

return res_json


class ParkPowApi:
def __init__(self, token, sdk_url=None):
if token is None:
raise ValueError("ParkPow TOKEN is required if using Cloud API")
if sdk_url:
self.api_base = sdk_url + "/api/v1/"
else:
self.api_base = "https://app.parkpow.com/api/v1/"

lgr.debug(f"Api Base: {self.api_base}")
self.session = requests.Session()
self.session.headers = {"Authorization": "Token " + token}

def log_vehicle(self, data):
endpoint = "log-vehicle/"
try:
tries = 0
while tries < 5:
response = self.session.post(self.api_base + endpoint, json=data)
lgr.debug(f"response: {response}")
if response.status_code < 200 or response.status_code > 300:
if response.status_code == 429:
tries += 1
time.sleep(1)
else:
lgr.error(response.text)
raise RuntimeError("Error logging vehicle")
else:
res_json = response.json()
return res_json
except requests.RequestException as e:
lgr.error("Error", exc_info=e)
Loading

0 comments on commit f636f5a

Please sign in to comment.