robgeerts wrote: ↑Thursday 16 June 2022 23:23 I installed this script today and it almost works, the problem is when i actived motion detection.
"last_event_type" is in my case always 'motion'...
Never 'ding'.
When i disabled motion detection, my 'last_event_type' is 'ding' and the script is working fine.
In the most ideal situation i want one domoticz switch for motion and one for ding.. how to solve if ding is never a 'last_event_type'?
Code: Select all
def check_device_has_active_alerts(device_name: str, doorbells): try: triggered_device = next((doorbell for doorbell in doorbells if doorbell.name == device_name), None) last_event_type = triggered_device.history(limit=1)[0]['kind'] newest_event_id = find_newest_recording_id(triggered_device) if "ding" in last_event_type: print(f"{ts()}: {device_name} '{last_event_type}' event was triggered (id: {newest_event_id})") notify_domoticz(device_name) except: triggered_device, last_event_type, newest_event_id = None, None, None return triggered_device, last_event_type, newest_event_id
The script is getting events from history. A ding is mostly after a motion... Since a motion last for 40-60s, this would be the last item being stored in history when the ding appears...
I've recoded the script to not look at history but take the event at that time.
Ive also changed notify domoticz to trigger different ding and motion devices

Code: Select all
import json, os
from pathlib import Path
from ring_doorbell import Ring, Auth
from oauthlib.oauth2 import MissingTokenError
import time
from datetime import datetime, timezone
import urllib.request as urllib
from threading import Thread
######### This Section Needs Edited By You - unique_api_name as well! ###########################
your_username = '***@*****.*l'
your_password = **************'
your_unique_api_name = 'PythonMonitorAPI/0.1.1'
cache_file = Path("/home/pi/domoticz/scripts/ring/cached_auth_token.json")
videopath = '/mnt/documents/ring/captures/'
poll_interval = 1.0 # interval in seconds that we poll the Ring API for new events
# Domoticz setup
domoticz_api = 'http://192.168.1.210:8080'
domoticz_idx_mapping_ding = {"Voordeur": 6711, "Back Door": 6711}
domoticz_idx_mapping_motion = {"Voordeur": 11231, "Back Door": 11231}
#################################################################################################
###### DO NOT EDIT THESE IF YOU DO NOT KNOW WHAT THEY ARE FOR ###################################
# .env overrides: 1) create your .env file with the exported VARS below (ie. export RING_USERNAME='MYUSERNAME')
# 2) source them and start this script like: $ source .env && python3 <script_name>.py
# Note: decided to handle this natively rather than use the python-dotenv package
username = os.getenv('RING_USERNAME', your_username)
password = os.getenv('RING_PASSWORD', your_password)
unique_api_name = os.getenv('RING_API_NAME', your_unique_api_name)
def authenticate():
if cache_file.is_file():
auth = Auth(unique_api_name, json.loads(cache_file.read_text()), token_updated)
else:
auth = Auth(unique_api_name, None, token_updated)
try:
auth.fetch_token(username, password)
except MissingTokenError:
auth.fetch_token(username, password, otp_callback())
auth = Ring(auth)
return auth
def authenticate_and_initialize(gadget_type: str = "doorbells"):
myring = authenticate()
myring.update_data()
devices = myring.devices()
if gadget_type is "doorbells":
doorbells = devices['doorbots']
enumerate_doorbells(doorbells)
return myring, doorbells
def ts(filename_format: bool = False, dirname_format: bool = False):
if dirname_format:
return f"{datetime.now().strftime('%Y-%m-%d')}/"
if filename_format:
return datetime.now().strftime('%H-%M-%S')
else:
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def construct_local_filename(triggered_device, device_name: str, last_event_type: str, newest_event_id: int):
filename_timestamp = triggered_device.history(limit=1, enforce_limit=True)[0]['created_at'].replace(
tzinfo=timezone.utc).astimezone(tz=None).strftime('%H-%M-%S')
local_filename = f"{videopath}{daily_directory()}{device_name.replace(' ', '')}_{last_event_type}_" \
f"{filename_timestamp}_{str(newest_event_id)[-4:]}.mp4"
return local_filename
def daily_directory():
daily_directory_path = videopath + ts(dirname_format=True)
if os.path.isdir(daily_directory_path):
return ts(dirname_format=True)
else:
os.mkdir(daily_directory_path)
print(f"{ts()}: Created new daily directory at {daily_directory_path}")
return ts(dirname_format=True)
def token_updated(token):
cache_file.write_text(json.dumps(token))
def otp_callback():
auth_code = input("2FA code: ")
return auth_code
def enumerate_doorbells(doorbells):
for doorbell in doorbells:
print(f"{ts()}: Authentication and discovery successful for {doorbell}.")
def notify_domoticz(device_name: str, this_event_type: str):
try:
if this_event_type == "ding":
idx = domoticz_idx_mapping_ding.get(device_name)
if this_event_type == "motion":
idx = domoticz_idx_mapping_motion.get(device_name)
urllib.urlopen(f'{domoticz_api}/json.htm?type=command¶m=switchlight&idx={idx}&switchcmd=On')
print(f"{ts()}: Domoticz (idx:{idx}) notified of event at {device_name}")
except:
print(f"{ts()}: Error switching to domoticz : '{domoticz_api}/json.htm?type=command¶m=switchlight&idx={idx}&switchcmd=On'.")
def main():
myring, doorbells = authenticate_and_initialize(gadget_type="doorbells")
if myring and doorbells:
print(f"{ts()}: Entering observation loop - polling interval set to {poll_interval}s\n")
while True:
myring.update_dings()
alerts = myring.active_alerts()
if alerts:
for alert in alerts:
try:
this_event_id = alert['id']
this_device_name = alert['doorbot_description']
this_event_type = alert['kind']
print(f"{ts()}: {this_device_name} '{this_event_type}' event was triggered (id: {this_event_id})")
if this_event_type in "dingmotion":
notify_domoticz(this_device_name, this_event_type)
except:
time.sleep(poll_interval)
continue
time.sleep(poll_interval)
if __name__ == "__main__":
main()