diff --git a/EagleEyev3/__init__.py b/EagleEyev3/__init__.py deleted file mode 100644 index eb3f694..0000000 --- a/EagleEyev3/__init__.py +++ /dev/null @@ -1,569 +0,0 @@ -import json -import logging -import requests -from .settings import * - -from datetime import datetime, timedelta -from pytz import timezone - - -logging.basicConfig(level=logging.INFO) - - - -class EagleEyev3(): - """ - Class representing the EagleEyev3 client. - """ - - def __init__(self): - """ - Initializes the EagleEyev3 client object. - """ - self.client_id = None - self.client_secret = None - self.access_token = None - self.refresh_token = None - self.redirect_uri = None - - self._load_vars_from_settings() - - self.user_base_url = None - self.current_user = None - self.users = [] - self.bridges = [] - self.cameras = [] - self.switches = [] - self.users = [] - self.accounts = [] - self.user_tz_obj = None - - self.lazy_login = True - - if self.lazy_login: - try: - self._load_access_token() - except FileNotFoundError as e: - logging.warn("self.lazy_login is set to {self.lazy_login} but could not find .lazy_login file to load") - - def _load_vars_from_settings(self): - """ - Load variables from the settings module. - """ - self.client_id = settings.client_id - self.client_secret = settings.client_secret - self.server_protocol = settings.server_protocol - self.server_host = settings.server_host - self.server_port = settings.server_port - self.server_path = settings.server_path - - # Combine server_protocol, server_host, and server_port to make the redirect_uri - # Note: Please see the note in settings.py about trailing slashes and modify this line if needed - - self.redirect_uri = f"{self.server_protocol}://{self.server_host}:{self.server_port}/{self.server_path}" - - - def _save_access_token(self): - with open(".lazy_login", "w") as json_file: - json.dump({ - 'access_token': self.access_token, - 'refresh_token': self.refresh_token, - 'current_user': self.current_user - }, json_file) - - def _load_access_token(self): - with open(".lazy_login", "r") as json_file: - saved = json.load(json_file) - if 'access_token' in saved: - self.access_token = saved['access_token'] - if 'refresh_token' in saved: - self.refresh_token = saved['refresh_token'] - - self.get_base_url(cascade=True) - - - def time_now(self): - return datetime.now(tz=self.user_tz_obj).isoformat(timespec='milliseconds') - - - def time_before(self, ts=None, hours=6): - if ts == None: - ts = datetime.now(tz=self.user_tz_obj) - - if type(ts) == str: - ts = datetime.fromisoformat(ts) - - return (ts - timedelta(hours=hours)).isoformat(timespec='milliseconds') - - - - def login_tokens(self, code=None, cascade=True): - """ - Obtains login tokens using the authorization code. - - Args: - code (str): The authorization code. - cascade (bool): Indicates whether to cascade and get the base URL and current user information. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, data, and current user information. - """ - baseUrl = "https://auth.eagleeyenetworks.com/oauth2/token" - pathUrl = f"?grant_type=authorization_code&scope=vms.all&code={code}&redirect_uri={self.redirect_uri}" # Note the trailing slash, make sure it matches the whitelist - url = baseUrl + pathUrl - - # Send a POST request to obtain login tokens - response = requests.post(url, auth=(self.client_id, self.client_secret)) - response_json = response.json() - - logging.info(f"{response.status_code} in login_tokens") - - if response.status_code == 200: - success = True - self.access_token = response_json['access_token'] - self.refresh_token = response_json['refresh_token'] - - if self.lazy_login: - self._save_access_token() - - if cascade: - self.get_base_url() - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json, - 'current_user': self.current_user - } - - def logout(self): - """ - Revokes token. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = "https://auth.eagleeyenetworks.com/oauth2/revoke" - - payload = { - "token": self.access_token, - "token_type_hint": "access_token" - } - - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json", - "Content-type": "application/json" - } - - # Send a POST request to obtain the base URL - response = requests.post(url, json=payload, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in logout") - - if response.status_code == 200: - success = True - else: - success = False - logging.info(f"call to logout: {response_json}") - - self.access_token = None - self.refresh_token = None - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - def get_base_url(self, cascade=True): - """ - Obtains the base URL for the user. - - Args: - cascade (bool): Indicates whether to cascade and get the current user information. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = "https://api.eagleeyenetworks.com/api/v3.0/clientSettings" - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json" - } - - # Send a GET request to obtain the base URL - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in get_base_url") - - if response.status_code == 200: - success = True - if 'httpsBaseUrl' in response_json and 'hostname' in response_json['httpsBaseUrl']: - self.user_base_url = response_json['httpsBaseUrl']['hostname'] - if cascade: - self.get_current_user() - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - def get_current_user(self): - """ - Obtains the information of the current user. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = f"https://{self.user_base_url}/api/v3.0/users/self?include=timeZone" - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json" - } - - # Send a GET request to obtain the current user information - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in get_current_user") - - if response.status_code == 200: - success = True - self.current_user = response_json - self.user_tz_obj = timezone(response_json['timeZone']['timeZone']) - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - def get_list_of_users(self): - """ - Obtains the list of users. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = f"https://{self.user_base_url}/api/v3.0/users?include=timeZone" - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json" - } - - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in get_list_of_users") - - if response.status_code == 200: - success = True - self.users = [i for i in response_json['results']] - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - def get_list_of_cameras(self): - """ - Obtains the list of cameras. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = f"https://{self.user_base_url}/api/v3.0/cameras?include=status" - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json" - } - - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in get_list_of_cameras") - - if response.status_code == 200: - success = True - self.cameras = [ - Camera(id=i['id'],\ - name=i['name'],\ - status=i['status'],\ - account_id=i['accountId'],\ - bridge_id=i['bridgeId'],\ - user_base_url=self.user_base_url,\ - een_instance=self) - for i in response_json['results']] - for camera in self.cameras: - camera.user_base_url = self.user_base_url - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - def get_list_of_bridges(self): - """ - Obtains the list of bridges. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = f"https://{self.user_base_url}/api/v3.0/bridges" - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json" - } - - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in get_list_of_bridges") - - if response.status_code == 200: - success = True - self.bridges = [i for i in response_json['results']] - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - def get_list_of_switches(self): - """ - Obtains the list of switches. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = f"https://{self.user_base_url}/api/v3.0/switches" - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json" - } - - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in get_list_of_switches") - - if response.status_code == 200: - success = True - self.switches = [i for i in response_json['results']] - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - def get_list_of_available_devices(self, deviceType__in="camera"): - """ - Obtains the list of available devices. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = f"https://{self.user_base_url}/api/v3.0/availableDevices?deviceType__in={deviceType__in}" - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json" - } - - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in get_list_of_available_devices") - - if response.status_code == 200: - success = True - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - def get_list_of_multi_cameras(self): - """ - Obtains the list of multi-cameras. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = f"https://{self.user_base_url}/api/v3.0/multiCameras" - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json" - } - - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in get_list_of_multi_cameras") - - if response.status_code == 200: - success = True - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - def get_list_of_feeds(self): - """ - Obtains the list of feeds. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - url = f"https://{self.user_base_url}/api/v3.0/feeds" - headers = { - "Authorization": f"Bearer {self.access_token}", - "Accept": "application/json" - } - - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.info(f"{response.status_code} in get_list_of_feeds") - - if response.status_code == 200: - success = True - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } - - - - - -class Device(): - - def __init__(self, id=None, name=None, status=None, account_id=None, user_base_url=None, een_instance=None): - - self.id = id - self.name = name - self.status = status - self.account_id = account_id - self.user_base_url = user_base_url, - self.een_instance = een_instance - - def get_id(self): - return self.id - - def get_status(self): - return self.status['connectionStatus'] - - def is_online(self): - return self.status['connectionStatus'] == "online" - - def is_offline(self): - return self.status['connectionStatus'] == "deviceOffline" or self.status['connectionStatus'] == "bridgeOffline" - - def __repr__(self): - if self.is_online(): - online = '✅' - elif self.is_offline(): - online = '❌' - else: - online = '?' - return f"{online} [{self.id}] - {self.name}" - - - -class Camera(Device): - - def __init__(self, id=None, name=None, status=None, account_id=None, bridge_id=None, user_base_url=None, een_instance=None): - super().__init__(id=id, name=name, status=status, account_id=account_id, user_base_url=user_base_url, een_instance=een_instance) - self.bridge_id = bridge_id - self.previews = [] - self.videos = [] - self.events = { - 'status': [], - 'motion': [] - } - - - def get_list_of_events(self, start_timestamp=None, end_timestamp=None): - """ - Obtains the list of events. - - Returns: - dict: Dictionary containing the success status, response HTTP status code, and data. - """ - - if start_timestamp == None or end_timestamp == None: - return { - "success": False, - "response_http_status": None, - "data": { 'msg': 'get_list_of_events called without required args, needs start_timestamp, end_timestamp' } - } - - url = f"https://{self.user_base_url}/api/v3.0/events?pageSize=100&include=een.deviceCloudStatusUpdate.v1&startTimestamp__gte={start_timestamp}&endTimestamp__lte={end_timestamp}&actor=camera%3A{self.id}&type__in=een.deviceCloudStatusUpdateEvent.v1" - - headers = { - "Authorization": f"Bearer {self.een_instance.access_token}", - "Accept": "application/json" - } - - response = requests.get(url, headers=headers) - response_json = response.json() - - logging.debug(f"{response.status_code} returned from {url} with {headers} and {response.text}") - logging.info(f"{response.status_code} in get_list_of_events") - - if response.status_code == 200: - success = True - # filter events by type - [self.events['status'].append(i) for i in response.json()['results'] if i['type'] == 'een.deviceCloudStatusUpdateEvent.v1'] - [self.events['motion'].append(i) for i in response.json()['results'] if i['type'] == 'een.motionDetectionEvent.v1'] - - # remove duplicates - seen = set() - self.events['status'] = [event for event in self.events['status'] if event['endTimestamp'] and event['id'] not in seen and not seen.add(event['id'])] - seen = set() - self.events['motion'] = [event for event in self.events['motion'] if event['id'] not in seen and not seen.add(event['id'])] - - # sort by event startTimestamp descending - self.events['status'] = sorted(self.events['status'], key=lambda x: x['startTimestamp'], reverse=True) - self.events['motion'] = sorted(self.events['motion'], key=lambda x: x['startTimestamp'], reverse=True) - else: - success = False - - return { - "success": success, - "response_http_status": response.status_code, - "data": response_json - } diff --git a/EagleEyev3/settings.py b/EagleEyev3/settings.py deleted file mode 100644 index 7a35d6d..0000000 --- a/EagleEyev3/settings.py +++ /dev/null @@ -1,14 +0,0 @@ - -# Set up your application and get client id/secrete first -# https://developerv3.eagleeyenetworks.com/page/my-application -client_id = "" -client_secret = "" - -# you will need to add approved redirect_uris in your application -# this examples assumes you've added http://127.0.0.1:3333/login_callback -# change the following variables if you did something different -# Note: do not use localhost for server_host, use 127.0.0.1 instead -server_protocol = "http" -server_host = "127.0.0.1" -server_port = "3333" -server_path = "login_callback" diff --git a/Playground.ipynb b/Playground.ipynb deleted file mode 100644 index 6a73ad1..0000000 --- a/Playground.ipynb +++ /dev/null @@ -1,459 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d4582341", - "metadata": {}, - "source": [ - "# EagleEyev3 Playground\n", - "\n", - "To make this playground work, it is easier to read the `access_token` off the filesystem but you can always run the example server `python server.py` to go thorugh the Oauth2 flow. By default it will save the `access_token` into a file named `.lazy_login`. The module looks for that file and tries reading t" - ] - }, - { - "cell_type": "markdown", - "id": "8355d241", - "metadata": {}, - "source": [ - "## Import Module" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "1394471a", - "metadata": {}, - "outputs": [], - "source": [ - "from EagleEyev3 import EagleEyev3" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "486a2537", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:root:200 in get_base_url\n", - "INFO:root:200 in get_current_user\n" - ] - } - ], - "source": [ - "een = EagleEyev3()" - ] - }, - { - "cell_type": "markdown", - "id": "51b8b66e", - "metadata": {}, - "source": [ - "## Adjust Log Level" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "06d91db2", - "metadata": {}, - "outputs": [], - "source": [ - "import logging\n", - "logger = logging.getLogger()\n", - "#logger.setLevel('DEBUG')\n", - "#logger.setLevel('INFO')\n", - "logger.setLevel('WARN')\n", - "#logger.setLevel('ERROR')\n", - "#logger.setLevel('CRITICAL')" - ] - }, - { - "cell_type": "markdown", - "id": "0311109c-869c-4190-97c1-a6e717a8eeba", - "metadata": {}, - "source": [ - "## Who am I" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "e14e2be5-a5f9-4b8c-ae60-76c61cb61b8b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'Mark Cotton - mcotton@mcottondesign.com'" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "f\"{een.current_user['firstName']} {een.current_user['lastName']} - {een.current_user['email']}\"" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "4ef47ae2-a010-4b7e-87f6-3dbf0a047e16", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'eyJraWQiOiI2ODYxYjBjYS0wZjI2LTExZWQtODYxZC0wMjQyYWMxMjAwMDIiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJjYWZlZGVmMiIsImF1ZCI6InZtcy5hcGkiLCJpc3MiOiJ2bXMuYXV0aC52MSIsInZtc19hY2NvdW50IjoiMDAwMjgyMDEiLCJleHAiOjE2ODkzNzA1MTIsImlhdCI6MTY4ODc2NTcxMiwianRpIjoiYTM1Nzk3MmRmNzdiNTAwYTQ3NjBlNGY1MGYwNjNhMjUiLCJjbGllbnRfaWQiOiIzMmRhYzMzMDY0OWI0ODI3OWY5Y2FjYzJiNmY1N2FlNSIsInZtc19jbHVzdGVyIjoiYzAxMiJ9.EEmCaFqduOV5_cQ-VejeBXGbKLj1yHrxGkcMgqPUN1jYY0wR9bO7rkEwQh59Dj-1fr8pKsbrUr6DPDLfkaSIRlxpjdlsEBdzAmoZUpzPUfL9QzJu0C04OJU0gcBh7fwur7L2fMVthaZ6OKfThdM29qzRH5RR9gSAJGeNe08n4IvFVvuL80yvczgOiQwSzkg4PuHpbImDa44U7-qC8CrRvQ_TqsX6ziNzw-XmxZxXEwtZxkAOFDFaIsA8V4ezbQ_TSY6EElCnyyKLLI46-KIsGevx8dxa2NrhPFvC725dMhg-OPaCEF62sOlTrlHVBcv_e9MBk1VZLoDLStkSvU7Dxg'" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "een.access_token" - ] - }, - { - "cell_type": "markdown", - "id": "a22ff6c2", - "metadata": {}, - "source": [ - "## Get Cameras" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "bb457850", - "metadata": {}, - "outputs": [], - "source": [ - "ret = een.get_list_of_cameras()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "c43f1db1", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[✅ [1001423e] - ATM & Wine,\n", - " ✅ [100d8666] - Cash Register,\n", - " ✅ [10012735] - Fuel Dock,\n", - " ✅ [1002584c] - Safe]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[i for i in een.cameras if i.is_online()]" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "f4c6fe67", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[? [10090759] - Benny Camera,\n", - " ? [1003e10b] - Driveway,\n", - " ? [100ba388] - Front Door,\n", - " ? [100b7b3b] - Max Camera,\n", - " ? [1009ae55] - Office]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[i for i in een.cameras if not i.is_online()]" - ] - }, - { - "cell_type": "markdown", - "id": "8c140aaf-766f-4255-94ef-199d17cbc7a6", - "metadata": {}, - "source": [ - "## Getting list of Events" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "74e78ee1-33b8-4a88-9d23-cd6281603a5b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-07-07T16:41:31.990-05:00 2023-07-07T10:41:31.990-05:00\n" - ] - } - ], - "source": [ - "print(een.time_now(), een.time_before())" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "c84c30dd-4b7c-415b-8e6f-e77de70d1924", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "for i in range(0,4):\n", - " ts = een.time_now()\n", - "\n", - " for cam in een.cameras:\n", - " blah = cam.get_list_of_events(end_timestamp=een.time_before(ts=ts, hours=(6*i)), \\\n", - " start_timestamp=een.time_before(ts=ts, hours=(6*(i+1))) )" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "13809cc7-9ec2-4e15-9495-e64feaecca6d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "18" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(een.cameras[2].events['status'])" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "67d4f79b-2b43-4bdb-9068-28ac9d8d921c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(een.cameras[0].events['motion'])" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "8be8d503-b46d-4ba7-884e-2c21c3987129", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ATM & Wine - 2023-07-07T18:49:29.664+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-07T18:48:51.444+00:00 - error \n", - "ATM & Wine - 2023-07-07T16:22:04.146+00:00 - online \n", - "ATM & Wine - 2023-07-07T16:21:41.960+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-07T16:18:16.383+00:00 - error \n", - "ATM & Wine - 2023-07-07T16:16:31.511+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-07T16:15:57.174+00:00 - error \n", - "ATM & Wine - 2023-07-07T15:44:21.759+00:00 - online \n", - "ATM & Wine - 2023-07-07T15:41:31.997+00:00 - online \n", - "ATM & Wine - 2023-07-07T12:46:47.672+00:00 - bridgeOffline \n", - "ATM & Wine - 2023-07-07T11:24:46.454+00:00 - online \n", - "ATM & Wine - 2023-07-07T11:22:37.461+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-07T11:21:59.127+00:00 - error \n", - "ATM & Wine - 2023-07-07T09:44:24.462+00:00 - online \n", - "ATM & Wine - 2023-07-07T09:41:33.395+00:00 - online \n", - "ATM & Wine - 2023-07-07T06:00:38.322+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-07T06:00:00.175+00:00 - error \n", - "ATM & Wine - 2023-07-07T04:07:20.003+00:00 - online \n", - "ATM & Wine - 2023-07-07T04:05:21.238+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-07T04:04:42.160+00:00 - error \n", - "ATM & Wine - 2023-07-07T03:44:26.904+00:00 - online \n", - "ATM & Wine - 2023-07-07T03:41:56.630+00:00 - online \n", - "ATM & Wine - 2023-07-07T01:48:05.792+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-07T01:47:35.155+00:00 - error \n", - "ATM & Wine - 2023-07-06T23:19:05.335+00:00 - online \n", - "ATM & Wine - 2023-07-06T23:16:58.926+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T23:16:28.421+00:00 - error \n", - "ATM & Wine - 2023-07-06T23:10:32.790+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T21:44:28.864+00:00 - online \n", - "ATM & Wine - 2023-07-06T21:41:57.860+00:00 - online \n", - "ATM & Wine - 2023-07-06T20:08:47.208+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T20:08:16.933+00:00 - error \n", - "ATM & Wine - 2023-07-06T20:03:05.801+00:00 - online \n", - "ATM & Wine - 2023-07-06T20:02:43.659+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T20:01:41.457+00:00 - error \n", - "ATM & Wine - 2023-07-06T19:59:57.405+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T19:59:24.184+00:00 - error \n", - "ATM & Wine - 2023-07-06T19:31:55.867+00:00 - online \n", - "ATM & Wine - 2023-07-06T19:29:46.708+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T19:29:16.013+00:00 - error \n", - "ATM & Wine - 2023-07-06T18:24:27.389+00:00 - online \n", - "ATM & Wine - 2023-07-06T18:22:22.328+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T18:21:52.102+00:00 - error \n", - "ATM & Wine - 2023-07-06T15:52:12.759+00:00 - online \n", - "ATM & Wine - 2023-07-06T15:50:09.509+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T15:49:39.152+00:00 - error \n", - "ATM & Wine - 2023-07-06T15:41:58.888+00:00 - online \n", - "ATM & Wine - 2023-07-06T15:11:05.317+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T15:10:35.056+00:00 - error \n", - "ATM & Wine - 2023-07-06T14:59:51.787+00:00 - online \n", - "ATM & Wine - 2023-07-06T14:58:55.970+00:00 - bridgeOffline \n", - "ATM & Wine - 2023-07-06T14:58:40.967+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T12:58:36.884+00:00 - online \n", - "ATM & Wine - 2023-07-06T12:56:38.478+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T12:56:07.792+00:00 - error \n", - "ATM & Wine - 2023-07-06T12:49:42.742+00:00 - online \n", - "ATM & Wine - 2023-07-06T12:47:32.312+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T12:47:01.925+00:00 - error \n", - "ATM & Wine - 2023-07-06T11:40:03.505+00:00 - online \n", - "ATM & Wine - 2023-07-06T11:38:03.703+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T11:37:23.038+00:00 - error \n", - "ATM & Wine - 2023-07-06T11:31:52.611+00:00 - online \n", - "ATM & Wine - 2023-07-06T11:29:42.541+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T11:29:08.199+00:00 - error \n", - "ATM & Wine - 2023-07-06T09:42:01.013+00:00 - online \n", - "ATM & Wine - 2023-07-06T09:38:38.302+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T09:38:07.937+00:00 - error \n", - "ATM & Wine - 2023-07-06T08:31:02.432+00:00 - online \n", - "ATM & Wine - 2023-07-06T08:28:53.086+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T08:28:22.667+00:00 - error \n", - "ATM & Wine - 2023-07-06T04:07:10.931+00:00 - online \n", - "ATM & Wine - 2023-07-06T04:05:11.397+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T04:04:38.124+00:00 - error \n", - "ATM & Wine - 2023-07-06T03:43:19.799+00:00 - online \n", - "ATM & Wine - 2023-07-06T02:15:51.335+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-06T02:15:19.584+00:00 - error \n", - "ATM & Wine - 2023-07-05T21:43:39.111+00:00 - online \n", - "ATM & Wine - 2023-07-05T18:35:23.024+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-05T18:34:44.881+00:00 - error \n", - "ATM & Wine - 2023-07-05T17:13:14.356+00:00 - online \n", - "ATM & Wine - 2023-07-05T17:11:09.341+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-05T17:10:29.222+00:00 - error \n", - "ATM & Wine - 2023-07-05T15:43:44.544+00:00 - online \n", - "ATM & Wine - 2023-07-05T15:33:04.629+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-05T15:32:34.148+00:00 - error \n", - "ATM & Wine - 2023-07-05T15:13:36.151+00:00 - online \n", - "ATM & Wine - 2023-07-05T15:11:33.954+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-05T15:10:54.632+00:00 - error \n", - "ATM & Wine - 2023-07-05T14:24:50.082+00:00 - online \n", - "ATM & Wine - 2023-07-05T14:22:50.393+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-05T14:22:12.040+00:00 - error \n", - "ATM & Wine - 2023-07-05T14:02:42.746+00:00 - online \n", - "ATM & Wine - 2023-07-05T14:00:34.085+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-05T13:59:55.709+00:00 - error \n", - "ATM & Wine - 2023-07-05T10:43:54.157+00:00 - online \n", - "ATM & Wine - 2023-07-05T10:41:56.025+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-05T10:41:23.556+00:00 - error \n", - "ATM & Wine - 2023-07-05T10:10:27.404+00:00 - online \n", - "ATM & Wine - 2023-07-05T10:08:19.943+00:00 - deviceOffline \n", - "ATM & Wine - 2023-07-05T10:07:50.455+00:00 - error \n", - "ATM & Wine - 2023-07-05T09:44:11.782+00:00 - online \n", - "Cash Register - 2023-07-07T20:02:49.237+00:00 - bridgeOffline \n", - "Cash Register - 2023-07-07T20:02:31.354+00:00 - deviceOffline \n", - "Cash Register - 2023-07-07T16:01:54.202+00:00 - online \n", - "Cash Register - 2023-07-07T16:01:52.891+00:00 - bridgeOffline \n", - "Cash Register - 2023-07-07T15:44:21.759+00:00 - online \n", - "Cash Register - 2023-07-07T15:41:31.997+00:00 - online \n", - "Cash Register - 2023-07-06T23:01:59.550+00:00 - bridgeOffline \n", - "Cash Register - 2023-07-06T21:44:28.864+00:00 - online \n", - "Cash Register - 2023-07-06T21:41:57.860+00:00 - online \n", - "Cash Register - 2023-07-06T14:58:55.385+00:00 - bridgeOffline \n", - "Cash Register - 2023-07-06T14:58:40.382+00:00 - deviceOffline \n", - "Cash Register - 2023-07-06T10:01:40.245+00:00 - online \n", - "Cash Register - 2023-07-06T10:01:39.158+00:00 - bridgeOffline \n", - "Cash Register - 2023-07-06T09:42:01.013+00:00 - online \n", - "Cash Register - 2023-07-05T20:06:43.349+00:00 - bridgeOffline \n", - "Cash Register - 2023-07-05T18:01:54.584+00:00 - online \n", - "Cash Register - 2023-07-05T18:01:53.582+00:00 - bridgeOffline \n", - "Cash Register - 2023-07-05T15:43:44.544+00:00 - online \n", - "Safe - 2023-07-06T14:58:55.537+00:00 - bridgeOffline \n", - "Safe - 2023-07-06T14:58:40.535+00:00 - deviceOffline \n", - "Safe - 2023-07-06T09:42:01.013+00:00 - online \n", - "Safe - 2023-07-06T07:27:05.695+00:00 - bridgeOffline \n", - "Safe - 2023-07-06T03:43:19.799+00:00 - online \n", - "Safe - 2023-07-06T02:05:12.252+00:00 - bridgeOffline \n", - "Safe - 2023-07-05T21:43:39.111+00:00 - online \n" - ] - } - ], - "source": [ - "for cam in een.cameras:\n", - " for i in cam.events['status']:\n", - " print(f\"{cam.name} - {i['startTimestamp']} - {i['data'][0]['newStatus']['connectionStatus']} \")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1cebbb4e-4c4e-4ab0-9627-251eb812b2f1", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d8a69185-54cc-4c74-9c9b-a807e601be83", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/app.py b/app.py deleted file mode 100644 index 1406ebe..0000000 --- a/app.py +++ /dev/null @@ -1,85 +0,0 @@ - -import json, requests -from flask import Flask, request, session, render_template, redirect, url_for -from flask_session import Session - -import logging -logger = logging.getLogger() - -#logger.setLevel('DEBUG') -logger.setLevel('INFO') -#logger.setLevel('WARN') -#logger.setLevel('ERROR') -#logger.setLevel('CRITICAL') - -from EagleEyev3 import EagleEyev3 - - -app = Flask(__name__) - -SESSION_TYPE = 'filesystem' -app.config.from_object(__name__) -Session(app) - -@app.route('/') -def index(): - - if 'een' in session: - een = session['een'] - else: - een = EagleEyev3() - session['een'] = een - - # using current_user as a proxy for an established valid session - if een.access_token == None: - base_url = "https://auth.eagleeyenetworks.com/oauth2/authorize" - path_url = f"?client_id={een.client_id}&response_type=code&scope=vms.all&redirect_uri={een.redirect_uri}" - return redirect(f"{base_url}{path_url}") - - # call this to check if session is actually valid - check = een.get_current_user() - if 'success' not in check or check['success'] == False: - base_url = "https://auth.eagleeyenetworks.com/oauth2/authorize" - path_url = f"?client_id={een.client_id}&response_type=code&scope=vms.all&redirect_uri={een.redirect_uri}" - return redirect(f"{base_url}{path_url}") - else: - logging.info(f"{check['success']} - check get_current_user") - - - values = { - "current_user": een.current_user - } - - return render_template('index.html', template_values=values) - - -@app.route('/login_callback') -def login_callback(): - # This is getting the ?code= querystring value from the HTTP request. - code = request.args.get('code') - - if 'een' in session: - een = session['een'] - else: - een = EagleEyev3() - - - if (code): - # use the include code parameter to complete login process - oauth_object = een.login_tokens(code) - - - return redirect(url_for('index')) - - -@app.route('/logout') -def logout(): - if 'een' in session: - een = session['een'] - een.logout() - - return redirect(url_for('index')) - - -if __name__ == '__main__': - app.run(host=een.server_host, port=een.server_port) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 93adf52..0000000 --- a/requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -pytz==2023.3 -requests==2.29.0 -blinker==1.6.2 -certifi==2023.5.7 -charset-normalizer==3.1.0 -click==8.1.3 -Flask==2.3.2 -idna==3.4 -itsdangerous==2.1.2 -Jinja2==3.1.2 -MarkupSafe==2.1.3 -pytz==2023.3 -requests==2.29.0 -urllib3==1.26.16 -Werkzeug==2.3.6 diff --git a/templates/base.html b/templates/base.html deleted file mode 100644 index 2c1fe4c..0000000 --- a/templates/base.html +++ /dev/null @@ -1,131 +0,0 @@ - -{% if "X-PJAX" not in request.headers %} - - -
- - - - - - - {% block title %} -