Ring Video Doorbell

Begonnen von blueberry63, 23 August 2017, 11:06:28

Vorheriges Thema - Nächstes Thema

Seppel

Zitat von: Screambear am 17 Februar 2020, 13:12:27
Moin, hast du auch mal klingeln probiert?
Hallo,
ja, hab ich. Brachte leider keinen Erfolg. Inzwischen habe ich auch einen Authentifizierungsfehler, wenn ich die ring.py manuell starte. Ich werde dann immer aufgefordert, den neuen Loginversuch durch die Eingabe eines sechsstelligen Codes zu bestätigen. Ob das hiermit zusammenhängt? https://www.bbc.com/news/technology-51555450 Laut diesem Bericht soll Amazon von nun an die Zwei-Faktor-Authentifizierung vorschreiben.

Viele Grüße
Sebastian

Screambear

Dieses Problem habe ich seit dem 18.02. Auch. Sehr merkwürdig.

Weiß jemand Rat?

nhetzke

N'Abend zusammen. Ich denke es hat mit der erforderlichen 2 Faktoren Authentifizierung zu tun, die nun in Ring aktiviert wurde.
Hier mal ein Link zu einem Beispiel wie es gehen sollte, bei mir jedoch (hoffentlich nur leider) noch nicht.

https://github.com/tchellomello/python-ring-doorbell/blob/master/test.py
Entwickler, Projekt und Qualitätsmanager
RasPi1b & FHEM & HM-CFG-USB

Seppel

Zitat von: nhetzke am 25 Februar 2020, 21:44:04
Hier mal ein Link zu einem Beispiel wie es gehen sollte, bei mir jedoch (hoffentlich nur leider) noch nicht.

https://github.com/tchellomello/python-ring-doorbell/blob/master/test.py
Vielleicht steh ich ja komplett auf dem Schlauch, aber wie soll das auch funktionieren? Ring will doch bei jedem Login zusätzlich den per SMS geschickten sechsstelligen Code eingegeben haben. Wo soll ich den denn eintippen?

bluemevo

Es ist eine Mail, die verschickt wird. Die test.py ist darauf ausgelegt, das mach dem Start User, PW und verify eingegeben werden. Dann wird ein Token erstellt, der 30 Tage gültig sein soll, mit dem sich das Script solange einloggen kann.

Btw hat jemand eine Idee wie ich den Bug zur Stickup Cam in der Version 0.6.0 fixen kann? Für die 2FA brauchen wir zwingend die Version 0.6.0

nhetzke

Ja es kommt darauf an, ob man in der App die 2FA aktiviert hat oder nicht. Ohne Aktivierung bekommt man eine eMail, mit Aktivierung eine SMS mit dem entsprechendem Code.
Entwickler, Projekt und Qualitätsmanager
RasPi1b & FHEM & HM-CFG-USB

Seppel

OK, ich habe testweise die test.py ausgeführt und alles eingegeben, daraufhin wurde das Token generiert und im selben Ordner abgelegt. Ich habe aber keine Ahnung, was ich nun damit machen soll. Leider verstehe ich insgesamt viel zu wenig von dieser Materie, um selbstständig zum Ziel zu kommen. Eine Schritt-für-Schritt-Anleitung wäre super...

speed

Ich bin genauso weit wie Seppel,
wie geht es den jetzt weiter ?

nhetzke

Ich hab mir das mal angeschaut.
So wie es aussieht muss lediglich der Token bei der Anmeldung mitgegeben werden. Es scheint so, dass einmalig ein manueller mehr Aufwand existiert um die 2FA Nummer zu hinterlegen. Ist diese da, kann der Token genutzt und ggf. erneuert werden.
Entwickler, Projekt und Qualitätsmanager
RasPi1b & FHEM & HM-CFG-USB

Seppel

Sorry. Eventuell habe ich ein Brett vor dem Kopf, aber ich weiß wirklich nicht, wie das geht. Wie gebe ich dieses Token mit? Muss dafür die ring.py angepasst werden? Müssen weitere Dateien kopiert werden?

speed

Würde mich auch interessieren .

nhetzke

N'Abend zusammen. Hier mal ein Beispiel wie ich mir das gedacht hatte. Leider habe ich aber aktuell das Problem, dass das ganze bei mir nicht klappt, da ich eine Fehlermeldung bekomme: " AttributeError: 'Ring' object has no attribute 'stickup_cams'"
Ansonsten hier mein Codeschnipsel:

from ring_doorbell import Ring, Auth
import time
import fhem
import logging
import threading
import thread
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

from thread import start_new_thread, allocate_lock
from oauthlib.oauth2 import MissingTokenError
from pathlib import Path
import json


# CONFIG
ring_user = 'eMail'
ring_pass = 'PASSWORD'
fhem_ip   = '127.0.0.1'
fhem_port = 7072 # Telnet Port
log_level = logging.DEBUG
fhem_path = '/opt/fhem/www/ring/' # for video downloads
POLLS     = 2 # Poll every x seconds
cache_file_name = "test_token.cache"
cache_file = Path("test_token.cache")

# LOGGING
logger = logging.getLogger('ring_doorbell.doorbot')
logger.setLevel(log_level)

# create file handler which logs even debug messages
fh = logging.FileHandler('ring.log')
fh.setLevel(logging.DEBUG)

# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
fh.setFormatter(formatter)

# add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)

logger = logging.getLogger('fhem_ring')
logger.setLevel(log_level)
logger.addHandler(ch)
logger.addHandler(fh)

def token_updated(token):
file = open(cache_file_name, "w")
file.write(json.dumps(token))
file.close()

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

# Connecting to RING.com

if cache_file.is_file():
file = open(cache_file_name, "r")
auth = Auth("MyProject/1.0", json.loads(file.read()), token_updated)
file.close()
else:
auth = Auth("MyProject/1.0", None, token_updated)
try:
auth.fetch_token(ring_user, ring_pass)
except MissingTokenError:
auth.fetch_token(ring_user, ring_pass, otp_callback())

myring = Ring(auth)
myring.update_data()

#myring = Ring(ring_user, ring_pass)

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)

def askFhemForAttr(dev, attr, default):
    logger.debug("ask fhem for attribute "+attr+" from device "+dev+" (default: "+default+")")
    fh.send_cmd('{AttrVal("'+dev+'","'+attr+'","'+default+'")}')
    data = fh.sock.recv(32000)
    return data

def setRing(str, dev):
    sendFhem('set Ring_' + dev.name.replace(" ","") + ' ' + str)

def attrRing(str, dev):
    sendFhem('attr Ring_' + dev.name.replace(" ","") + ' ' + str)

def srRing(str, dev):
    sendFhem('setreading Ring_' + dev.name.replace(" ","") + ' ' + str)

num_threads = 0
thread_started = False
lock = allocate_lock()

def getDeviceInfo(dev):
    dev.update()
    logger.info("Updating device data for device '"+dev.name+"' in FHEM...")
    srRing('account ' + str(dev.account_id), dev)
    srRing('address ' + (dev.address), dev)
    srRing('family ' + str(dev.family), dev)
    srRing('id ' + str(dev.id), dev)
    srRing('name ' + str(dev.name), dev)
    srRing('timezone ' + str(dev.timezone), dev)
    srRing('doorbellType ' + str(dev.existing_doorbell_type), dev)
    srRing('battery ' + str(dev.battery_life), dev)
    srRing('ringVolume ' + str(dev.volume), dev)
    srRing('connectionStatus ' + str(dev.connection_status), dev)
    srRing('WifiName ' + str(dev.wifi_name), dev)
    srRing('WifiRSSI ' + str(dev.wifi_signal_strength), dev)


def pollDevices():
    logger.info("Polling for events.")
    global devs

    i=0
    while 1:
        for k, poll_device in devs.items():
            logger.debug("Polling for events with '" + poll_device.name + "'.")
            if poll_device.check_alerts() and poll_device.alert:
                dev = devs[poll_device.alert.get('doorbot_id')]
                logger.info("Alert detected at '" + dev.name + "'.")
                logger.debug("Alert detected at '" + dev.name + "' via '" + poll_device.name + "'.")
                alertDevice(dev,poll_device.alert)
            time.sleep(POLLS)
        i+=1
        if i>600:
            break

def findHistoryItem(historyArry,id):
    ret = None
    for singleItem in historyArry:
        if (singleItem['id']==id):
            ret = singleItem
            break
    return ret

def waitForVideoDownload(alertID,alertKind,ringDev):
    videoIsReadyForDownload = None
    counti = 1
    while (videoIsReadyForDownload is None):
        logger.debug(str(counti) + ". Try to find history and video in history data list")
        logger.debug("  historyID:"+str(alertID))
        try:
            singleHistoryItem = findHistoryItem(ringDev.history(limit=10,kind=alertKind),alertID)
            if singleHistoryItem and singleHistoryItem['id'] == alertID :
                logger.debug("History item found!")
                if singleHistoryItem['recording']['status'] == 'ready':
                    logger.debug("Video is now ready to downloading")
                    videoIsReadyForDownload = True
        except Exception as inst:
            logger.debug("Repeating...")
        time.sleep(1)
        counti+=1
        if (counti>240):
            logger.debug("Stop trying to find history and video data")
            break

    if (alertKind == 'ding') and videoIsReadyForDownload:
        logger.debug("Start downloading new ding video now")
        ringDev.recording_download(alertID, filename=fhem_path + 'last_ding_video.mp4',override=True)
        srRing('lastDingVideo ' + fhem_path + 'last_ding_video.mp4', ringDev)

    elif (alertKind == 'motion') and videoIsReadyForDownload:
        logger.debug("Start downloading new motion video now")
        ringDev.recording_download(alertID, filename=fhem_path + 'last_motion_video.mp4',override=True)
        srRing('lastMotionVideo ' + fhem_path + 'last_motion_video.mp4', ringDev)

    if videoIsReadyForDownload:
        srRing('lastCaptureURL ' + str(ringDev.recording_url(ringDev.last_recording_id)), ringDev)


def alertDevice(dev,alert):
    srRing('lastAlertDeviceID ' + str(dev.id), dev)
    srRing('lastAlertDeviceAccountID ' + str(dev.account_id), dev)
    srRing('lastAlertDeviceName ' + str(dev.name), dev)
    srRing('lastAlertSipTo ' + str(alert.get('sip_to')), dev)
    srRing('lastAlertSipToken ' + str(alert.get('sip_token')), dev)

    lastAlertID = alert.get('id')
    lastAlertKind = alert.get('kind')
    logger.debug("lastAlertID:"+str(lastAlertID))
    logger.debug("lastAlertKind:"+str(lastAlertKind))

    if (lastAlertKind == 'ding'):
        logger.debug("Signalling ring to FHEM")
        setRing('ring', dev)
        srRing('lastAlertType ring', dev)
    elif (lastAlertKind == 'motion'):
        logger.debug("Signalling motion to FHEM")
        srRing('lastAlertType motion', dev)
        setRing('motion', dev)
    thread.start_new_thread(waitForVideoDownload,(lastAlertID,lastAlertKind,dev))


       
# GATHERING DEVICES
devs = dict()
poll_device = None
tmp = list(myring.stickup_cams + myring.doorbells)
for t in tmp:
    devs[t.account_id] = t
    # all alerts can be recognized on all devices
    poll_device = t # take one device for polling

logger.info("Found " + str(len(devs)) + " devices.")

# START POLLING DEVICES
count = 1
while count<6:  # try 5 times
    try:
        while 1:
            for k, d in devs.items(): getDeviceInfo(d)
            pollDevices()

    except Exception as inst:
        logger.error("Unexpected error:" + str(inst))
        logger.error("Exception occured. Retrying...")
        time.sleep(5)
        if count == 5:
            raise

        count += 1


Idee ist einmal manuell starten, den 2FA Token bekommen, hier oben eintragen und dann laufen lassen.
Entwickler, Projekt und Qualitätsmanager
RasPi1b & FHEM & HM-CFG-USB

bluemevo


nhetzke

Moin,

Ja das hab ich schon hinbekommen. Es wurde allerdings mit einem der letzten checkins noch mehr geändert, so dass das alerting nicht mehr funktioniert. Alles bisschen doof gerade.
Entwickler, Projekt und Qualitätsmanager
RasPi1b & FHEM & HM-CFG-USB

bluemevo

Wie hast du das denn gelöst?