Skip to content

Commit

Permalink
Merge pull request #288 from sdb9696/update_cli
Browse files Browse the repository at this point in the history
Fix and update cli
  • Loading branch information
sdb9696 committed Sep 27, 2023
2 parents 60f8bf8 + 0762762 commit 7ecc7bd
Show file tree
Hide file tree
Showing 10 changed files with 421 additions and 264 deletions.
19 changes: 17 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ Python Ring Door Bell
:alt: Py Versions
:target: https://pypi.python.org/pypi/ring-doorbell

*Looking for maintainers*


Python Ring Door Bell is a library written for Python 3.8+
that exposes the Ring.com devices as Python objects.

There is also a command line interface that is work in progress. `Contributors welcome <https://python-ring-doorbell.readthedocs.io/contributing.html>`_.

*Currently Ring.com does not provide an official API. The results of this project are merely from reverse engineering.*

Documentation: `http://python-ring-doorbell.readthedocs.io/ <http://python-ring-doorbell.readthedocs.io/>`_
Expand All @@ -46,6 +46,21 @@ Installation
git+https://github.com/tchellomello/python-ring-doorbell@master
Using the CLI
-------------

The CLI is work in progress and at the moment only displays your device info and video info.

1. Show your devices::
$ ring-doorbell

#. Either count or download your vidoes or both::

$ ring-doorbell videos --count --download-all

#. Run ``ring-doorbell --help`` or ``ring-doorbell videos --help`` for full options

Initializing your Ring object
-----------------------------

Expand Down
48 changes: 47 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ sphinx = { version = "^7", optional = true }
sphinx_rtd_theme = { version = "^1", optional = true }
sphinxcontrib-programoutput = { version = "^0", optional = true }
docutils = { version = ">=0.17", optional = true }
########################

asyncclick = "^8.1.3.4"
anyio = "^4.0.0" # see https://github.com/python-trio/asyncclick/issues/18

[tool.poetry.group.dev.dependencies]
flake8 = "*"
Expand Down
166 changes: 20 additions & 146 deletions ring_doorbell/__init__.py
Original file line number Diff line number Diff line change
@@ -1,146 +1,20 @@
# coding: utf-8
# vim:sw=4:ts=4:et:
"""Python Ring Doorbell wrapper."""
import logging
from time import time

from .const import (
API_URI,
DEVICES_ENDPOINT,
NEW_SESSION_ENDPOINT,
DINGS_ENDPOINT,
POST_DATA,
GROUPS_ENDPOINT,
)
from .auth import Auth # noqa
from .doorbot import RingDoorBell
from .chime import RingChime
from .stickup_cam import RingStickUpCam
from .group import RingLightGroup


_LOGGER = logging.getLogger(__name__)


TYPES = {
"stickup_cams": RingStickUpCam,
"chimes": RingChime,
"doorbots": RingDoorBell,
"authorized_doorbots": lambda ring, description: RingDoorBell(
ring, description, shared=True
),
}


# pylint: disable=useless-object-inheritance
class Ring(object):
"""A Python Abstraction object to Ring Door Bell."""

def __init__(self, auth):
"""Initialize the Ring object."""
self.auth = auth
self.session = None
self.devices_data = None
self.chime_health_data = None
self.doorbell_health_data = None
self.dings_data = None
self.groups_data = None

def update_data(self):
"""Update all data."""
if self.session is None:
self.create_session()

self.update_devices()

self.update_dings()

self.update_groups()

def create_session(self):
"""Create a new Ring session."""
session_post_data = POST_DATA
session_post_data["device[hardware_id]"] = self.auth.get_hardware_id()

self.session = self.query(
NEW_SESSION_ENDPOINT,
method="POST",
data=session_post_data,
).json()

def update_devices(self):
"""Update device data."""
data = self.query(DEVICES_ENDPOINT).json()

# Index data by device ID.
self.devices_data = {
device_type: {obj["id"]: obj for obj in devices}
for device_type, devices in data.items()
}

def update_dings(self):
"""Update dings data."""
self.dings_data = self.query(DINGS_ENDPOINT).json()

def update_groups(self):
"""Update groups data."""
# Get all locations
locations = set()
for devices in self.devices_data.values():
for dev in devices.values():
if "location_id" in dev:
locations.add(dev["location_id"])

# Query for groups
self.groups_data = {}
locations.discard(None)
for location in locations:
data = self.query(GROUPS_ENDPOINT.format(location)).json()
if data["device_groups"] is not None:
for group in data["device_groups"]:
self.groups_data[group["device_group_id"]] = group

def query(
self, url, method="GET", extra_params=None, data=None, json=None, timeout=None
):
"""Query data from Ring API."""
return self.auth.query(
API_URI + url,
method=method,
extra_params=extra_params,
data=data,
json=json,
timeout=timeout,
)

def devices(self):
"""Get all devices."""
devices = {}

for dev_type, convertor in TYPES.items():
devices[dev_type] = [
convertor(self, obj["id"])
for obj in self.devices_data.get(dev_type, {}).values()
]

return devices

def groups(self):
"""Get all groups."""
groups = {}

for group_id in self.groups_data:
groups[group_id] = RingLightGroup(self, group_id)

return groups

def active_alerts(self):
"""Get active alerts."""
alerts = []
for alert in self.dings_data:
expires_at = alert.get("now") + alert.get("expires_in")

if time() < expires_at:
alerts.append(alert)

return alerts
"""Python Package for interacting with Ring devices."""
from importlib.metadata import version

__version__ = version("ring_doorbell")

from ring_doorbell.ring import Ring
from ring_doorbell.auth import Auth
from ring_doorbell.chime import RingChime
from ring_doorbell.stickup_cam import RingStickUpCam
from ring_doorbell.group import RingLightGroup
from ring_doorbell.doorbot import RingDoorBell

__all__ = [
"Ring",
"Auth",
"RingChime",
"RingStickUpCam",
"RingLightGroup",
"RingDoorBell",
]

0 comments on commit 7ecc7bd

Please sign in to comment.