コード例 #1
0
def ring(mock_ring_requests):
    """Return ring object."""
    auth = Auth("PythonRingDoorbell/0.6")
    auth.fetch_token("foo", "bar")
    ring = Ring(auth)
    ring.update_data()
    return ring
コード例 #2
0
def initialize_ring():
    cache_file = Path("token.cache")

    def token_updated(token):
        cache_file.write_text(json.dumps(token))

    def otp_callback():
        auth_code = input("2FA code: ")
        return auth_code

    if cache_file.is_file():
        auth = Auth("CamBot/1.0", json.loads(cache_file.read_text()),
                    token_updated)
    else:
        username = input("Username: "******"Password: "******"CamBot/1.0", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())

    ring = Ring(auth)
    ring.update_data()
    return ring
コード例 #3
0
def ringOperations(emailname):
    s3 = boto3.client('s3')
    getCacheFileFromBucket(BUCKET_NAME, emailname)

    if cache_file.is_file():
        cachefile = open(CACHE_FILE_NAME, "r")
        tokendata = json.loads(cachefile.read())
        cachefile.close()
        auth = Auth("MyProject/1.0", tokendata, token_updated)
        uploadCacheFileToBucket(BUCKET_NAME, CACHE_FILE_NAME, emailname)

    ring = Ring(auth)
    ring.update_data()

    devices = ring.devices()

    getLatestMotionVideo(devices)
    getFrameFromVideo()
    sourceKey = "video_frame.png"
    imagelabels = getlabels(BUCKET_NAME, sourceKey)
    imagefaces = getfaces(BUCKET_NAME, sourceKey)
    imagetext = gettext(BUCKET_NAME, sourceKey)
    addImageInfotoTable(imagelabels, imagetext, imagefaces)

    s3.delete_object(Bucket=BUCKET_NAME, Key=sourceKey)
    s3.delete_object(Bucket=BUCKET_NAME, Key="last_trigger.mp4")
コード例 #4
0
ファイル: test.py プロジェクト: tahder/python-ring-doorbell
def main():
    if cache_file.is_file():
        auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()), token_updated)
    else:
        username = input("Username: "******"Password: "******"MyProject/1.0", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())

    ring = Ring(auth)
    ring.update_data()

    devices = ring.devices()
    print(devices)

    doorbells = devices["doorbots"]
    chimes = devices["chimes"]
    stickup_cams = devices["stickup_cams"]

    print(doorbells)
    print(chimes)
    print(stickup_cams)
コード例 #5
0
def initialize_ring():
    if cache_file.is_file():
        auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()),
                    token_updated)
    else:
        auth = Auth("MyProject/1.0", None, token_updated)
        try:
            auth.fetch_token(config.ringuser, config.ringpassword)
        except MissingTokenError:
            auth.fetch_token(config.ringuser, config.ringpassword,
                             otp_callback())

    ring = Ring(auth)
    ring.update_data()
    return ring
コード例 #6
0
def main(download_only=False):
    if cache_file.is_file():
        auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()), token_updated)
    else:
        username = os.environ.get('USERNAME')
        password = os.environ.get('PASSWORD')
        auth = Auth("MyProject/1.0", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())

    ring = Ring(auth)
    ring.update_data()

    wait_for_update(ring, download_only=download_only)
コード例 #7
0
def main():
    global cache_file, token_updated, ring
    if not cache_file.is_file():
        print("Token not found", file=sys.stderr)
        exit(1)

    print("Instantiating ring api...")
    auth = Auth(user_agent="SmartThingsApi/0.1",
                token=json.loads(cache_file.read_text()),
                token_updater=token_updated)
    ring = Ring(auth)
    ring.update_data()
    print("Instantiating background job...")
    scheduler = BackgroundScheduler()
    scheduler.add_job(pingring, 'interval', hours=2)
    scheduler.start()
    print("Starting web server...")
    run()
コード例 #8
0
def main():
    if cache_file.is_file():
        auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()),
                    token_updated)
    else:
        username = input("Username: "******"Password: "******"MyProject/1.0", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())

    ring = Ring(auth)
    ring.update_data()

    devices = ring.devices()
    print(devices)

    doorbells = devices["doorbots"]
    chimes = devices["chimes"]
    stickup_cams = devices["stickup_cams"]

    print(doorbells)
    #print(chimes)
    #print(stickup_cams)
    x = 0
    y = 0
    limit = 100
    doorbell = devices['doorbots'][0]
    typelist = {
        "motion",
        "ding",
    }
    for rt in typelist:
        print(rt)
        for i in doorbell.history(limit=limit, kind=rt):
            print(i['id'])
            doorbell.recording_download(
                doorbell.history(limit=limit, kind=rt)[x]['id'],
                filename=str(i['created_at'].strftime("%m-%d-%Y-%H-%M-%S")) +
                '.mp4',
                override=True)
            x += 1
コード例 #9
0
def main():
    if cache_file.is_file():
        print("Token has already been set up, loading...")
        auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()),
                    token_updated)
    else:
        username = my_email
        print(
            "This is the first time setting up, getting the token set up now..."
        )
        password = getpass.getpass("Password: "******"MyProject/1.0", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())

    ring = Ring(auth)
    ring.update_data()
コード例 #10
0
def main():
    # initialize logger for debugging
    initialize_logger()

    if cache_file.is_file():
        auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()),
                    token_updated)
    else:
        # initialize ring account username and password
        username = config('user')
        password = config('pw')

        # use the Authenticator of the ring_doorbell API
        # tries to fetch token for authentication
        # requests user input for the code if necessary
        auth = Auth("MyProject/1.0", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())

    threshold = input(
        "Enter the percentage where-in you want to get reminders: ")
    # loop for checking battery life
    while True:
        ring = Ring(auth)
        ring.update_data()

        # filter the Ring Devices
        devices = ring.devices()
        front_door = devices['authorized_doorbots']

        battery_life = front_door[0].battery_life
        logging.info(f'The current battery life is {battery_life}')
        # if battery is less than threshold, send the e-mail
        if (battery_life <= int(threshold)):
            logging.info("Sending the email")
            send_email(battery_life)

        # loop sleeps for 6 hours 21600
        sleep(3600)
コード例 #11
0
def main():
    if cache_file.is_file():
        auth = Auth(
            "HomeAssistant/0.105.0dev0",
            json.loads(cache_file.read_text()),
            token_updated,
        )
    else:
        username = input("Username: "******"Password: "******"Hello {ring.session['profile']['first_name']}")
    print()
    pprint(ring.devices_data)
コード例 #12
0
class DoorbellManager(object):
    def __init__(self):
        if cache_file.is_file():
            auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()),
                        token_updated)
        else:
            username = input("Username: "******"Password: "******"MyProject/1.0", None, token_updated)
            try:
                auth.fetch_token(username, password)
            except MissingTokenError:
                auth.fetch_token(username, password, otp_callback())
        self.ring = Ring(auth)
        self.ring.update_data()

    def get_doorbell(self):
        devices = self.ring.devices()
        bell = devices["doorbots"][0]
        return bell

    def get_dings(self) -> DoorbellEvent:
        bell = self.get_doorbell()
        events = bell.history(limit=15, kind="ding")
        dings = list()
        for event in events:
            ding = DoorbellEvent(event)
            # ding.print()
            dings.append(ding)
        dings = sorted(dings, key=lambda ding: ding.timesince)
        return dings

    def get_last_ding(self) -> DoorbellEvent:
        dings = self.get_dings()
        if len(dings) > 0:
            ding = dings[0]
            return ding
        return None
コード例 #13
0
def main():
    if cache_file.is_file():
        auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()),
                    token_updated)
    else:
        username = input("Username: "******"Password: "******"MyProject/1.0", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())

    ring = Ring(auth)
    ring.update_data()

    devices = ring.devices()
    pprint(devices)

    # play with the API to figure out which camera you want
    deck = devices['doorbots'][0]
    download(deck)
    print('\nDONE.')
コード例 #14
0
def main():
    if cache_file.is_file():
        token = json.loads(cache_file.read_text())
        auth = Auth("Ringer/1.0", token, token_updated)
        print(f"Token expires at {expires_at_to_datetime(token['expires_at'])}")
    else:
        username = input("Username: "******"Password: "******"Ringer/1.0", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())

    ring = Ring(auth)
    ring.update_data()

    devices = ring.devices()
    pprint(devices)

    doorbell = devices['doorbots'][0]
    history = doorbell.history(limit=100, kind='motion')
    id = history[0]['id']
    doorbell.recording_download(
        id,
        filename=f'doorbell_motion_{id}.mp4',
        override=True)

    cams = devices['stickup_cams']
    for cam in cams:
        history = cam.history(limit=100, kind='motion')
        id = history[0]['id']
        cam.recording_download(
            id,
            filename=f'cam_motion_{id}.mp4',
            override=True)
コード例 #15
0
ファイル: huebell.py プロジェクト: SenAnan/huebell
# First time need to press the button on the Bridge and connect (within 30 seconds)
# b.connect()

lights = []
hue_lights = b.lights

print("[Hue] Connected")

# Sign in to Ring
RING_USERNAME = data['RING_USER']
RING_PASSWORD = data['RING_PASS']
auth = Auth("huebell/v1")
auth.fetch_token(RING_USERNAME, RING_PASSWORD)
ring = Ring(auth)
ring.update_data()
print("[Ring] Connected")

# Load doorbell
devices = ring.devices()
doorbell = devices['doorbots'][0]


def flash_lights():
    # Get current status of all lights
    for l in hue_lights:
        light = {
            'name': l.name,
            'light': l,
            'status': b.get_light(l.name, 'on'),
            'bright': b.get_light(l.name, 'bri')
コード例 #16
0
def py_ring():
    get_access_token()
    ring = Ring(get_access_token.auth)
    ring.update_data()
    devices = ring.devices()
    get_doorbell_cam_motion2(devices)
    sys.exit(0)
    while True:
        if os.path.isdir('Recordings'):
            None
        else:
            os.mkdir('Recordings')
        print(u"{}[2J{}[;H".format(chr(27), chr(27)))

        get_access_token()
        print(u"{}[2J{}[;H".format(chr(27), chr(27)))
        print('   --- PyRing Main Menu ---   \n')
        print(style.GREEN('[01]') + style.RESET(' Ring devices.'))
        print(style.GREEN('[02]') + style.RESET(' Ring devices status.'))
        print(style.GREEN('[03]') + style.RESET(' Ring light control.'))
        print(style.GREEN('[04]') + style.RESET(' Ring motion alerts.'))
        print(
            style.GREEN('[05]') +
            style.RESET(' Download Ring latest motion video.'))
        print(style.GREEN('[06]') + style.RESET(' Download a month of video.'))
        print(style.GREEN('[99]') + style.RESET(' Exit PyRing.'))

        try:
            option = input(
                style.YELLOW('\n[+]') +
                style.RESET(' Choose your option [Eg: 01]: '))
        except KeyboardInterrupt:
            print(u"{}[2J{}[;H".format(chr(27), chr(27)))
            print(style.RED('\n[!]') + style.RESET(' Error: User exit.'))
            print(
                style.GREEN('[+]') +
                style.RESET(' Thank you for using PyRing.'))
            print(style.GREEN('[+]') + style.RESET(' Author: Pr0xy07'))
            print(
                style.GREEN('[+]') + style.RESET(
                    ' If you need any help, contact: [email protected]'))
            sys.exit(0)
        try:
            ring = Ring(get_access_token.auth)
            ring.update_data()
            devices = ring.devices()
        except:
            print(u"{}[2J{}[;H".format(chr(27), chr(27)))
            print(style.RED('\n[!]') + style.RESET(' Error: User exit.'))
            print(
                style.GREEN('[+]') +
                style.RESET(' Thank you for using PyRing.'))
            print(style.GREEN('[+]') + style.RESET(' Author: Pr0xy07'))
            print(
                style.GREEN('[+]') + style.RESET(
                    ' If you need any help, contact: [email protected]'))
            sys.exit(0)

        if option == "01":
            print(u"{}[2J{}[;H".format(chr(27), chr(27)))
            get_devices(devices)
        elif option == "02":
            print(u"{}[2J{}[;H".format(chr(27), chr(27)))
            get_status(devices)
        elif option == "03":
            light_control(devices)
        elif option == "04":
            get_alerts(devices)
        elif option == "05":
            get_motions(devices)
        elif option == "06":
            get_doorbell_cam_motion2(devices)
        elif option == "99":
            print(u"{}[2J{}[;H".format(chr(27), chr(27)))
            print(
                style.GREEN('\n[+]') +
                style.RESET(' Thank you for using PyRing.'))
            print(style.GREEN('[+]') + style.RESET(' Author: Pr0xy07'))
            print(
                style.GREEN('[+]') + style.RESET(
                    ' If you need any help, contact: [email protected]'))
            break
コード例 #17
0

if cache_file.is_file():
    auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()),
                token_updated)
else:
    username = input("Username: "******"Password: "******"MyProject/1.0", None, token_updated)
    try:
        auth.fetch_token(username, password)
    except MissingTokenError:
        auth.fetch_token(username, password, otp_callback())

myring = Ring(auth)
myring.update_data()

fh = fhem.Fhem(fhem_ip, fhem_port)


def sendFhem(str):
    logger.debug("sending: " + str)
    global fh
    fh.send_cmd(str)


def askFhemForReading(dev, reading):
    logger.debug("ask fhem for reading " + reading + " from device " + dev)
    return fh.get_dev_reading(dev, reading)

コード例 #18
0
def main():

    parser = argparse.ArgumentParser(
        description="Ring Doorbell",
        epilog="https://github.com/tchellomello/python-ring-doorbell",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument(
        "-u", "--username", dest="username", type=str, help="username for Ring account"
    )

    parser.add_argument(
        "-p", "--password", type=str, dest="password", help="username for Ring account"
    )

    parser.add_argument(
        "--count",
        action="store_true",
        default=False,
        help="count the number of videos on your Ring account",
    )

    parser.add_argument(
        "--download-all",
        action="store_true",
        default=False,
        help="download all videos on your Ring account",
    )

    args = parser.parse_args()
    _header()

    # connect to Ring account
    if cache_file.is_file():
        auth = Auth("RingCLI/0.6", json.loads(cache_file.read_text()), token_updated)
    else:
        if not args.username:
            args.username = input("Username: "******"Password: "******"RingCLI/0.6", None, token_updated)
        try:
            auth.fetch_token(args.username, args.password)
        except MissingTokenError:
            auth.fetch_token(args.username, args.password, input("2FA Code: "))

    ring = Ring(auth)
    ring.update_data()
    devices = ring.devices()
    doorbell = devices["doorbots"][0]

    _bar()

    if args.count:
        print(
            "\tCounting videos linked on your Ring account.\n"
            + "\tThis may take some time....\n"
        )

        events = []
        counter = 0
        history = doorbell.history(limit=100)
        while len(history) > 0:
            events += history
            counter += len(history)
            history = doorbell.history(older_than=history[-1]["id"])

        motion = len([m["kind"] for m in events if m["kind"] == "motion"])
        ding = len([m["kind"] for m in events if m["kind"] == "ding"])
        on_demand = len([m["kind"] for m in events if m["kind"] == "on_demand"])

        print("\tTotal videos: {}".format(counter))
        print("\tDing triggered: {}".format(ding))
        print("\tMotion triggered: {}".format(motion))
        print("\tOn-Demand triggered: {}".format(on_demand))

        # already have all events in memory
        if args.download_all:
            counter = 0
            print(
                "\tDownloading all videos linked on your Ring account.\n"
                + "\tThis may take some time....\n"
            )

            for event in events:
                counter += 1
                filename = _format_filename(event)
                print("\t{}/{} Downloading {}".format(counter, len(events), filename))

                doorbell.recording_download(
                    event["id"], filename=filename, override=False
                )

    if args.download_all and not args.count:
        print(
            "\tDownloading all videos linked on your Ring account.\n"
            + "\tThis may take some time....\n"
        )
        history = doorbell.history(limit=100)

        while len(history) > 0:
            print(
                "\tProcessing and downloading the next" + " videos".format(len(history))
            )

            counter = 0
            for event in history:
                counter += 1
                filename = _format_filename(event)
                print("\t{}/{} Downloading {}".format(counter, len(history), filename))

                doorbell.recording_download(
                    event["id"], filename=filename, override=False
                )

            history = doorbell.history(limit=100, older_than=history[-1]["id"])
コード例 #19
0
def main():
    if cache_file.is_file():
        auth = Auth("MyProject/1.0d", json.loads(cache_file.read_text()),
                    token_updated)
    else:
        # Comment or Un the following to be prompted or use what we have already set
        #        username = input("Username: "******"Password: "******"MyProjectShared/1.0d", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())
    myring = Ring(auth)
    myring.update_data()  #;print(How To Print All Data)
    devices = myring.devices()  #;print(devices)
    doorbells = devices["doorbots"]
    print(doorbells)
    stickup_cams = devices["stickup_cams"]  #;print(stickup_cams)
    chimes = devices["chimes"]  #;print(chimes)
    #    print( "myring.is_connected" ), # Not valid after python2.7
    #    print( "myring.is_connected", end = '' )
    #    print( myring.is_connected ) # True
    ## Would be nice to esplicitly test that we got connefcted,
    #    p = subprocess.Popen(["sleep", "1"], stdout=subprocess.PIPE); output, err = p.communicate()#; print(output.rstrip(os.linesep)) # Sleep for BreakAbility
    #    p = subprocess.Popen(["sleep", "1"], stdout=subprocess.PIPE); output, err = p.communicate()#; print(output.rstrip(os.linesep)) # Sleep for BreakAbility
    for acamera in list(stickup_cams + doorbells):
        # limit on dev.account_id = 12345678 and print the Account ID: when connecting?
        #    for event in acamera.history(limit=QueueDepth, older_than=6753104150123456789): # ['created_at'] #,'id'] # Older than example
        for event in acamera.history(
                limit=QueueDepth,
                older_than=OlderThan):  # ['created_at'] #,'id']
            #        filename='%s-%s-%s' % (acamera.name.replace(" ","_"), event['created_at'].astimezone(timezone('US/Pacific')).strftime("%Y%m%d.%H%M%S"), event['id']) # from pytz import timezone
            # TODO: ... ... Need a new Ignore: state for cameras that match "-Driveway-" for the neighbors cam.
            # #Or filter on the Account ID: 12345678
            camname = '%s' % acamera.name.replace(
                " ", "_")  # Sanitize Cam Names, of Spaces at least... ...
            cliptime = '%s' % event['created_at'].astimezone(
                timezone(MyTimeZone)).strftime("%Y%m%d.%H%M%S")
            clipyear = '%s' % event['created_at'].astimezone(
                timezone(MyTimeZone)).strftime("%Y")
            clipmonth = '%s' % event['created_at'].astimezone(
                timezone(MyTimeZone)).strftime("%m")
            clipday = '%s' % event['created_at'].astimezone(
                timezone(MyTimeZone)).strftime("%d")
            clipid = '%s' % event['id']
            foldername = BaseDir + "/" + clipyear + "/" + clipmonth + "/" + clipday
            p = subprocess.Popen(["mkdir", "-pv", foldername],
                                 stdout=subprocess.PIPE)
            output, err = p.communicate()
            #	        print(output.rstrip(os.linesep)) # print the result of creating the container folder YYYY/MM/DD # Prints an empty line if dir already exists
            filename = cliptime + "-" + camname + "-" + clipid
            #print(filename)
            filepath = foldername + "/" + filename + ".mp4"
            print(bcolors.OKBLUE + "Fetchin " + filepath + bcolors.ENDC,
                  end='')
            sys.stdout.flush()  # import sys # Force partial line to be printed
            print(
                "\r", end=''
            )  # Carrage return back to top of line for the results to be rewritten
            if not os.path.exists(
                    filepath):  # import os # Test that file does not exist yet
                ## Would like to esplicitly watch for a ^C BREAK from the parent, sometimes that gets ignored and can not abort.
                if acamera.recording_download(event['id'], filename=filepath):
                    print(bcolors.OKGREEN + "Success" + bcolors.ENDC +
                          bcolors.BOLD,
                          end='')
                    #	                subprocess.call(["ls", "-lh", filepath]) # import subprocess #
                    #	                print(subprocess.call(["ls", "-lh", filepath])) # import subprocess # Prints ls output and then "Success 0"(Return Code)?
                    p = subprocess.Popen(["ls", "-lh", filepath],
                                         stdout=subprocess.PIPE)
                    output, err = p.communicate()
                    #	                print("*** Running ls -l command ***\n")
                    #	                print(output), # Does a new line even though we used a comma, otherwise does two new lines, must have a \n within the output
                    #                    print(output.rstrip(os.linesep))
                    # This inline comment no longer works from py2.7 to py3.6 # similar to perl chomp to cleanup /r/n
                    #	                df=os.system("df -h / | grep /") # Not working right?
                    #	                print(df) # when attempting .rstrip(os.linesep) get error AttributeError: 'int' object has no attribute 'rstrip'
                    print(bcolors.UNDERLINE + bcolors.OKGREEN + "#" +
                          bcolors.ENDC)
#                    print(acamera.recording_url(event['id'])) # Could print this into a filename.lnk instead to keep a shareable link? DEBUG
                else:  # acamera.recording_download failed
                    print(bcolors.FAIL + "Failed-" + bcolors.ENDC)
                    print(acamera.recording_url(event['id']))
            else:  # os.path.exists so skip
                print(bcolors.WARNING + "Skipped" + bcolors.ENDC)
コード例 #20
0
ファイル: core.py プロジェクト: ring-face/ringface-connector
def getRing():
    auth = getAuth()
    ring = Ring(auth)
    ring.update_data()
    return ring
コード例 #21
0
ファイル: main.py プロジェクト: craig-rueda/ring-slack
def main():
    configure_logger()
    register_stack_dump()

    global slack
    slack = Slacker(SLACK_API_KEY)

    global worker_thread
    worker_thread = Thread(target=worker_loop, name="Worker Thread")
    worker_thread.daemon = True
    worker_thread.start()

    global s3_client
    s3_client = boto3.client(
        's3',
        aws_access_key_id=AWS_ACCESS_KEY,
        aws_secret_access_key=AWS_SECREY_KEY,
    )

    logger.info("Connecting to Ring API")
    if cache_file.is_file():
        auth = Auth("MyProject/1.0", loads(cache_file.read_text()), token_updated)
    else:
        username = RING_USERNAME
        password = RING_PASSWORD
        auth = Auth("MyProject/1.0", None, token_updated)
        try:
            auth.fetch_token(username, password)
        except MissingTokenError:
            auth.fetch_token(username, password, otp_callback())

    ring = Ring(auth)
    ring.update_data()
    logger.info("Connected to Ring API")

    devices = ring.devices()
    logger.info("Found devices {}".format(devices))

    video_devices = devices["doorbots"] + devices["stickup_cams"]
    logger.info("Watching for events on devices {}".format(video_devices))

    # Init event ids
    for device in video_devices:
        device.latest_id = get_latest_recording(device)["id"]
        logger.info("Found latest event id {} for device {}".format(
            device.latest_id, device))

    # Loop for ever, checking to see if a new video becomes available
    try:
        while True:
            time.sleep(HIST_POLL_TIMEOUT_SECS)

            for device in video_devices:
                event = get_latest_recording(device)
                new_id = event["id"]

                if new_id != device.latest_id:
                    logger.info("Detected a new event for device {}".format(device))
                    device.latest_id = new_id
                    enqueue_event(event, device)

    except KeyboardInterrupt:
        exit(0)