Skip to content

Commit

Permalink
feat: implemented native authentication with pwa using auth0 API
Browse files Browse the repository at this point in the history
Merge pull request #343 from vickywane/auth/auth0-pwa
  • Loading branch information
Ivelin Ivanov authored Jun 8, 2021
2 parents 50b5766 + bccf6d8 commit d82d998
Show file tree
Hide file tree
Showing 15 changed files with 424 additions and 130 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ _mdwriter.cson
**/ambianic_edge.egg-info/
ambianic-debug2.sh
config.yaml.local
premium.yaml
/.ropeproject
tmp*.jpg
src/Ambianic.egg-info/**
/docs/dist
config.yaml
/docs/dist
2 changes: 1 addition & 1 deletion ambianic-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ docker run -it --rm \
$USB_ARG \
ambianic/ambianic-edge:dev /workspace/src/run-dev.sh
# on Mac, --net=host doesnt work as expected
# --net=host \
# --net=host \
4 changes: 3 additions & 1 deletion build/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
pytest-httpserver==1.0.0
absl-py>=0.7.1
appdirs>=1.4.3
asn1crypto>=0.24.0
astor>=0.8.0
asttokens>=1.1.13
asttokens>=1.1.13
beautifulsoup4>=4.7.1
blinker>=1.4
certifi>=2018.8.24
Expand All @@ -23,6 +24,7 @@ itsdangerous>=0.24
Jinja2>=2.10.1
numpy>=1.16.2
oauthlib>=2.1.0
httpretty==1.0.5
Pillow>=5.4.1
pyOpenSSL>=19.0.0
PyYAML>=5.1.2
Expand Down
98 changes: 98 additions & 0 deletions dev/dev-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
######################################
# Ambianic main configuration file #
######################################
version: '2020.12.11'

# path to the data directory
data_dir: ./data

# Set logging level to one of DEBUG, INFO, WARNING, ERROR
logging:
file: ./data/ambianic-log.txt
level: INFO
# set a less noisy log level for the console output
# console_level: WARNING

# Store notifications provider configuration
# see https://github.com/caronc/apprise#popular-notification-services for syntax examples
# notifications:
# catch_all_email:
# include_attachments: true
# providers:
# - mailto://userid:[email protected]
# alert_fall:
# providers:
# - mailto://userid:[email protected]
# - json://hostname/a/path/to/post/to

# Pipeline event timeline configuration
timeline:
event_log: ./data/timeline-event-log.yaml

# Cameras and other input data sources
# Using Home Assistant conventions to ease upcoming integration
sources:

# # direct support for raspberry picamera
# picamera:
# uri: picamera
# type: video
# live: true
#
# # local video device integration example
# webcam:
# uri: /dev/video0
# type: video
# live: true

recorded_cam_feed:
uri: file:///workspace/tests/pipeline/avsource/test2-cam-person1.mkv
type: video
# live: true

ai_models:
image_detection:
model:
tflite: ai_models/mobilenet_ssd_v2_coco_quant_postprocess.tflite
edgetpu: ai_models/mobilenet_ssd_v2_coco_quant_postprocess_edgetpu.tflite
labels: ai_models/coco_labels.txt
face_detection:
model:
tflite: ai_models/mobilenet_ssd_v2_face_quant_postprocess.tflite
edgetpu: ai_models/mobilenet_ssd_v2_face_quant_postprocess_edgetpu.tflite
labels: ai_models/coco_labels.txt
top_k: 2
fall_detection:
model:
tflite: ai_models/posenet_mobilenet_v1_100_257x257_multi_kpt_stripped.tflite
edgetpu: ai_models/posenet_mobilenet_v1_075_721_1281_quant_decoder_edgetpu.tflite
labels: ai_models/pose_labels.txt

# A named pipeline defines an ordered sequence of operations
# such as reading from a data source, AI model inference, saving samples and others.
pipelines:
# Pipeline names could be descriptive, e.g. front_door_watch or entry_room_watch.
area_watch:
- source: recorded_cam_feed
- detect_objects: # run ai inference on the input data
ai_model: image_detection
confidence_threshold: 0.6
# Watch for any of the labels listed below. The labels must be from the model trained label set.
# If no labels are listed, then watch for all model trained labels.
label_filter:
- person
- car
- save_detections: # save samples from the inference results
positive_interval: 300 # how often (in seconds) to save samples with ANY results above the confidence threshold
idle_interval: 6000 # how often (in seconds) to save samples with NO results above the confidence threshold
- detect_falls: # look for falls
ai_model: fall_detection
confidence_threshold: 0.6
- save_detections: # save samples from the inference results
positive_interval: 10
idle_interval: 600000
# notify: # notify a thirdy party service
# providers:
# - alert_fall


11 changes: 9 additions & 2 deletions src/ambianic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
from dynaconf.utils.boxing import DynaBox
from typing import Union
import importlib_metadata as metadata
from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("-c", "--config", help="Specify config YAML file location")

args, unknown = parser.parse_known_args()

DEFAULT_WORK_DIR: str = '/workspace'
DEFAULT_DATA_DIR: str = './data'

DEFAULT_CONFIG_FILE: str = 'config.yaml'
DEFAULT_CONFIG_FILE: str = args.config or 'config.yaml'
DEFAULT_SECRETS_FILE: str = 'secrets.yaml'

__CONFIG_FILE: str = None
Expand All @@ -25,7 +31,8 @@ def get_secrets_file() -> str:
return os.path.join(get_work_dir(), DEFAULT_SECRETS_FILE)


def __merge_secrets(config: Union[Dynaconf, DynaBox], src_config: Dynaconf = None):
def __merge_secrets(config: Union[Dynaconf, DynaBox],
src_config: Dynaconf = None):
if src_config is None:
src_config = config
for key, val in config.items():
Expand Down
94 changes: 69 additions & 25 deletions src/ambianic/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,52 @@
import apprise
import os
import ambianic
import pkg_resources
import yaml
from requests import post

log = logging.getLogger(__name__)

UI_BASEURL = "https://ui.ambianic.ai"


def sendCloudNotification(data):
# r+ flag causes a permission error
try:
premiumFile = pkg_resources.resource_filename(
"ambianic.webapp", "premium.yaml")

with open(premiumFile, "r") as file:
configFile = yaml.safe_load(file)

userId = configFile['credentials']["USER_AUTH0_ID"]
endpoint = configFile['credentials']["NOTIFICATION_ENDPOINT"]
if (userId):
return post(
url='{0}/notification'.format(endpoint),
json={
'userId': userId,
'notification': {
'title': 'Ambianic.ai New {0} event'.format(
data['label']),
'message': 'New {0} detected with a {1} confidence level'.format(
data['label'],
data['confidence']),
}})

except FileNotFoundError as err:
log.warning("Error locating file: {}".format(err))

except Exception as error:
log.warning("Error sending email: {}".format(str(error)))


class Notification:
def __init__(self, event:str = "detection", data:dict = {}, providers:list = ["all"]):
def __init__(
self,
event: str = "detection",
data: dict = {},
providers: list = ["all"]):
self.event: str = event
self.providers: list = providers
self.title: str = None
Expand All @@ -36,17 +75,16 @@ def __init__(self, config: dict = None):
for provider in providers:
if not self.apobj.add(provider, tag=name):
log.warning(
"Failed to add notification provider: %s=%s"
% (name, provider)
"Failed to add notification provider: %s=%s"
% (name, provider)
)

def send(self, notification: Notification):

templates = self.config.get("templates", {})

title = notification.title
if title is None:
title = templates.get("title", "[Ambianic.ai] New ${event} event" )
title = templates.get("title", "[Ambianic.ai] New ${event} event")

message = notification.message
if message is None:
Expand All @@ -63,9 +101,14 @@ def send(self, notification: Notification):

template_args = {
"event_type": notification.event,
"event": notification.data.get("label", notification.event),
"event_details_url": "%s/%s" % (UI_BASEURL, notification.data.get("id", ""))
}
"event": notification.data.get(
"label",
notification.event),
"event_details_url": "%s/%s" %
(UI_BASEURL,
notification.data.get(
"id",
""))}
template_args = {**template_args, **notification.data}

for key, value in template_args.items():
Expand All @@ -76,22 +119,23 @@ def send(self, notification: Notification):

for provider in notification.providers:
cfg = self.config.get(provider, None)
if cfg is None:
log.warning("Skip unknown provider %s" % provider)
continue

include_attachments = cfg.get("include_attachments", False)
ok = self.apobj.notify(
message,
title=title,
tag=provider,
attach=attachments if include_attachments else [],
)
if ok:
log.debug(
"Sent notification for %s to %s" %
(notification.event, provider)

if cfg:
include_attachments = cfg.get("include_attachments", False)
ok = self.apobj.notify(
message,
title=title,
tag=provider,
attach=attachments if include_attachments else [],
)
if ok:
log.debug(
"Sent notification for %s to %s" %
(notification.event, provider)
)
else:
log.warning("Error sending notification for %s to %s" %
(notification.event, provider))
else:
log.warning("Error sending notification for %s to %s" %
(notification.event, provider))
log.warning("Skip unknown provider %s" % provider)
continue
31 changes: 20 additions & 11 deletions src/ambianic/pipeline/store.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"""Pipeline sample storage elements."""
import logging
import datetime
import pathlib
import json
import uuid
import datetime
from typing import Iterable
import numpy as np
from ambianic import DEFAULT_DATA_DIR
from ambianic.pipeline import PipeElement
from ambianic.notification import Notification, NotificationHandler
from ambianic.notification import Notification, NotificationHandler, sendCloudNotification

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -66,11 +66,13 @@ def __init__(self,
ii = idle_interval
self._idle_interval = datetime.timedelta(seconds=ii)
self._time_latest_saved_idle = self._time_latest_saved_detection

# setup notification handler
self.notification = None
self.notification_config = notify
if self.notification_config is not None and self.notification_config.get("providers"):

if self.notification_config is not None and self.notification_config.get(
"providers"):
self.notification = NotificationHandler()

def _save_sample(self,
Expand All @@ -79,7 +81,6 @@ def _save_sample(self,
thumbnail=None,
inference_result=None,
inference_meta=None):

time_prefix = inf_time.strftime("%Y%m%d-%H%M%S.%f%z-{suffix}.{fext}")
image_file = time_prefix.format(suffix='image', fext='jpg')
image_path = self._output_directory / image_file
Expand All @@ -101,6 +102,7 @@ def _save_sample(self,
'inference_result': inference_result,
'inference_meta': inference_meta
}

image.save(image_path)
thumbnail.save(thumbnail_path)
# save samples to local disk
Expand Down Expand Up @@ -139,7 +141,7 @@ def process_sample(self, **sample) -> Iterable[dict]:
# let's save it if its been longer than
# the user specified positive_interval
if now - self._time_latest_saved_detection >= \
self._positive_interval:
self._positive_interval:
self._save_sample(inf_time=now,
image=image,
thumbnail=thumbnail,
Expand All @@ -151,7 +153,7 @@ def process_sample(self, **sample) -> Iterable[dict]:
# let's save a sample if its been longer than
# the user specified idle_interval
if now - self._time_latest_saved_idle >= \
self._idle_interval:
self._idle_interval:
self._save_sample(inf_time=now,
image=image,
thumbnail=thumbnail,
Expand All @@ -171,18 +173,25 @@ def process_sample(self, **sample) -> Iterable[dict]:
yield processed_sample

def notify(self, save_json: dict):
if self.notification is None:
return
log.debug("Sending notification(s)..")
# TODO extract inference data
if save_json['inference_result'] is None:
return

for inference_result in save_json['inference_result']:
data = {
'id': save_json['id'],
'label': inference_result['label'],
'confidence': inference_result['confidence'],
'datetime': save_json['datetime'],
}
notification = Notification(data=data, providers=self.notification_config["providers"])

sendCloudNotification(data=data)

if self.notification is None:
return

notification = Notification(
data=data, providers=self.notification_config["providers"])
self.notification.send(notification)


Expand Down
Loading

0 comments on commit d82d998

Please sign in to comment.