From 8c159778500b35e431c558ab22fff0fbc79b32e5 Mon Sep 17 00:00:00 2001 From: Dan Howe Date: Fri, 16 Aug 2019 10:09:45 +1000 Subject: [PATCH] Initial commit --- spectur_live_view.py | 181 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 spectur_live_view.py diff --git a/spectur_live_view.py b/spectur_live_view.py new file mode 100644 index 0000000..5cf9d7a --- /dev/null +++ b/spectur_live_view.py @@ -0,0 +1,181 @@ +"""spectur_live_view + +Open an automated selenium webdriver, and download images from Live View mode. +""" + +import os +import time +import pytz +from io import BytesIO +from datetime import datetime +import requests +import numpy as np +from PIL import Image +from selenium import webdriver +from selenium.webdriver.firefox.options import Options +from selenium.common.exceptions import (NoSuchElementException, + StaleElementReferenceException, + WebDriverException) + +CAM_ID = 1 +USERNAME = '' +PASSWORD = '' +URL = 'https://camera.uwatchit.com.au/UWatchitWebV2/User/LiveView#' +OUTPUT_DIR = 'images' +TIMEZONE = 'Australia/Sydney' +WAIT_TIME = 0.1 + + +def start_session(): + """Start automated browser session. + + Returns: + selenium webdriver object + """ + # Start webdriver + options = Options() + options.headless = False + driver = webdriver.Firefox(options=options) + + return driver + + +def login(driver): + """Log into Spectur camera portal. + + Args: + driver: selenium webdriver object + + Returns: + cookies from current browser session + """ + + driver.get(URL) + + # Get login fields + usr = driver.find_element_by_id('UserName') + pss = driver.find_element_by_id('Password') + btn = driver.find_element_by_id('submitlogin') + + # Input login details + usr.send_keys(USERNAME) + pss.send_keys(PASSWORD) + btn.click() + + # Extract cookies + session = requests.Session() + for c in driver.get_cookies(): + session.cookies.set(c['name'], c['value']) + + return session.cookies + + +def return_to_live_view(driver): + """Return to live camera feed in Spectur portal. + """ + + driver.get(URL) + driver.execute_script('ChangeCam({})'.format(CAM_ID)) + + +def get_image_timestamp(driver): + """Get timestamp from image link. + + Args: + driver: selenium webdriver object + + Returns: + UNIX timestamp, in seconds + """ + + im_url = driver.find_element_by_id('camimage').get_property('src') + timestamp = int(im_url.rsplit('&', 1)[-1]) / 1000 + + return timestamp + + +def get_next_image(driver, cookies): + """Get next image. + + Args: + driver: selenium webdriver object + cookies: cookies from current browser session + """ + # Get timestamp + t_current = get_image_timestamp(driver) + + # Wait until image timestamp is updated + while t_current == get_image_timestamp(driver): + time.sleep(WAIT_TIME) + + # Get image URL + im_url = driver.find_element_by_id('camimage').get_property('src') + + # Get jpeg data, and convert to image object + page = requests.get(im_url, cookies=cookies) + im = Image.open(BytesIO(page.content)) + + # Get EXIF timestamp + datestr = im._getexif()[36867] + + # Convert to local time + t_naive = datetime.strptime(datestr, '%Y:%m:%d %H:%M:%S') + t_utc = t_naive.replace(tzinfo=pytz.utc) + t_local = t_utc.astimezone(pytz.timezone(TIMEZONE)) + + # Save image + ts = t_local.strftime + jpg_name = os.path.join(OUTPUT_DIR, ts('%Y'), ts('%Y-%m-%d'), ts('%H'), + ts('%Y-%m-%d_%H-%M-%S%z') + '.jpg') + os.makedirs(os.path.dirname(jpg_name), exist_ok=True) + im.save(jpg_name) + + # Get battery level + with open(os.path.join(OUTPUT_DIR, 'battery.txt'), 'a') as f: + battery_str = driver.find_element_by_id('battery').text + f.write('{}\t{}\n'.format(t_local.isoformat(), battery_str[:-1])) + + # Update counter + t.append(time.mktime(t_local.timetuple())) + + # Count images collected + n = len(t) + + if n > 1: + # Get frames per second + fps = 1 / np.median(np.diff(t)) + + # Count dropped frames + n_dropped = np.max([0, int(fps * (t[-1] - t[0]) - n + 1)]) + + print('{} total images: {} fps: {} dropped frames: {}'.format( + t_local.isoformat(), n, fps, n_dropped), + end='\r', + flush=True) + + +def main(): + # Start browser session + driver = start_session() + cookies = login(driver) + return_to_live_view(driver) + + while True: + try: + # Get latest image + get_next_image(driver, cookies) + except (NoSuchElementException, StaleElementReferenceException, + WebDriverException): + # Navigate to Live View + return_to_live_view(driver) + except ConnectionError: + # Attempt to re-login if server goes down + time.sleep(5) + cookies = login(driver) + + +# Create counter +t = [] + +# Open browser +main()