Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ring_doorbell/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ def from_name(name: str) -> RingCapability:
STICKUP_CAM_ELITE_KINDS = ["stickup_cam_elite", "stickup_cam_wired"]
STICKUP_CAM_WIRED_KINDS = STICKUP_CAM_ELITE_KINDS # Deprecated
STICKUP_CAM_GEN3_KINDS = ["cocoa_camera"]
OUTDOOR_CAM_PLUS_KINDS = ["cocoa_camera_v2"]
BEAM_KINDS = ["beams_ct200_transformer"]

INTERCOM_KINDS = ["intercom_handset_audio", "intercom_handset_video"]
Expand Down
27 changes: 22 additions & 5 deletions ring_doorbell/stickup_cam.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
LIGHTS_ENDPOINT,
MSG_ALLOWED_VALUES,
MSG_VOL_OUTBOUND,
OUTDOOR_CAM_PLUS_KINDS,
SIREN_DURATION_MAX,
SIREN_DURATION_MIN,
SIREN_ENDPOINT,
Expand All @@ -38,6 +39,12 @@
class RingStickUpCam(RingDoorBell):
"""Implementation for RingStickUpCam."""

def _outdoor_cam_plus_has_battery(self) -> bool:
"""Return if an Outdoor Cam Plus reports a battery."""
if "battery_present" in self._attrs.get("health", {}):
return bool(self._attrs["health"]["battery_present"])
return self.battery_life is not None

@property
def family(self) -> str:
"""Return Ring device family type."""
Expand All @@ -58,6 +65,8 @@ def model(self) -> str: # noqa: C901, PLR0911, PLR0912
return "Indoor Cam (2nd Gen)"
if self.kind in INDOOR_CAM_PTZ_KINDS:
return "Pan-Tilt Indoor Cam"
if self.kind in OUTDOOR_CAM_PLUS_KINDS:
return "Outdoor Cam Plus"
if self.kind in SPOTLIGHT_CAM_BATTERY_KINDS:
return "Spotlight Cam {}".format(
self._attrs.get("ring_cam_setup_flow", "battery").title()
Expand Down Expand Up @@ -91,11 +100,17 @@ def has_capability(self, capability: RingCapability | str) -> bool:
if capability == RingCapability.HISTORY:
return True
if capability == RingCapability.BATTERY:
return self.kind in (
SPOTLIGHT_CAM_BATTERY_KINDS
+ STICKUP_CAM_KINDS
+ STICKUP_CAM_BATTERY_KINDS
+ STICKUP_CAM_GEN3_KINDS
return (
self.kind in OUTDOOR_CAM_PLUS_KINDS
and self._outdoor_cam_plus_has_battery()
) or (
self.kind
in (
SPOTLIGHT_CAM_BATTERY_KINDS
+ STICKUP_CAM_KINDS
+ STICKUP_CAM_BATTERY_KINDS
+ STICKUP_CAM_GEN3_KINDS
)
)
if capability == RingCapability.LIGHT:
return self.kind in (
Expand All @@ -115,6 +130,7 @@ def has_capability(self, capability: RingCapability | str) -> bool:
+ INDOOR_CAM_KINDS
+ INDOOR_CAM_GEN2_KINDS
+ INDOOR_CAM_PTZ_KINDS
+ OUTDOOR_CAM_PLUS_KINDS
+ SPOTLIGHT_CAM_BATTERY_KINDS
+ SPOTLIGHT_CAM_WIRED_KINDS
+ SPOTLIGHT_CAM_PLUS_KINDS
Expand All @@ -131,6 +147,7 @@ def has_capability(self, capability: RingCapability | str) -> bool:
+ INDOOR_CAM_KINDS
+ INDOOR_CAM_GEN2_KINDS
+ INDOOR_CAM_PTZ_KINDS
+ OUTDOOR_CAM_PLUS_KINDS
+ SPOTLIGHT_CAM_BATTERY_KINDS
+ SPOTLIGHT_CAM_WIRED_KINDS
+ SPOTLIGHT_CAM_PLUS_KINDS
Expand Down
30 changes: 30 additions & 0 deletions tests/test_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,36 @@ def test_stickup_cam_attributes(ring):
assert dev.siren == 0


def test_outdoor_cam_plus_battery_attributes(ring):
dev = ring.devices()["stickup_cams"][0]
dev._attrs["kind"] = "cocoa_camera_v2"
dev._attrs["battery_life"] = 76
dev._attrs["health"] = {"battery_present": True}

assert dev.model == "Outdoor Cam Plus"
assert dev.has_capability("battery") is True
assert dev.has_capability("light") is False
assert dev.has_capability("history") is True
assert dev.has_capability("motion_detection") is True
assert dev.has_capability("siren") is True
assert dev.has_capability("video") is True


def test_outdoor_cam_plus_powered_attributes(ring):
dev = ring.devices()["stickup_cams"][0]
dev._attrs["kind"] = "cocoa_camera_v2"
dev._attrs["battery_life"] = None
dev._attrs["health"] = {"battery_present": False}

assert dev.model == "Outdoor Cam Plus"
assert dev.has_capability("battery") is False
assert dev.has_capability("light") is False
assert dev.has_capability("history") is True
assert dev.has_capability("motion_detection") is True
assert dev.has_capability("siren") is True
assert dev.has_capability("video") is True


async def test_stickup_cam_controls(ring, aioresponses_mock):
dev = ring.devices()["stickup_cams"][0]

Expand Down