8000 Add pan tilt camera module (#1261) · python-kasa/python-kasa@95a0ef8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 95a0ef8

Browse files
sdb9696rytilahti
andcommitted
Add pan tilt camera module (#1261)
Add ptz controls for smartcameras. --------- Co-authored-by: Teemu R. <tpr@iki.fi>
1 parent 0f4de45 commit 95a0ef8

File tree

3 files changed

+112
-1
lines changed

3 files changed

+112
-1
lines changed

kasa/smartcamera/modules/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .childdevice import ChildDevice
66
from .device import DeviceModule
77
from .led import Led
8+
from .pantilt import PanTilt
89
from .time import Time
910

1011
__all__ = [
@@ -13,5 +14,6 @@
1314
"ChildDevice",
1415
"DeviceModule",
1516
"Led",
17+
"PanTilt",
1618
"Time",
1719
]

kasa/smartcamera/modules/pantilt.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""Implementation of time module."""
2+
3+
from __future__ import annotations
4+
5+
from ...feature import Feature
6+
from ..smartcameramodule import SmartCameraModule
7+
8+
DEFAULT_PAN_STEP = 30
9+
DEFAULT_TILT_STEP = 10
10+
11+
12+
class PanTilt(SmartCameraModule):
13+
"""Implementation of device_local_time."""
14+
15+
REQUIRED_COMPONENT = "ptz"
16+
_pan_step = DEFAULT_PAN_STEP
17+
_tilt_step = DEFAULT_TILT_STEP
18+
19+
def _initialize_features(self) -> None:
20+
"""Initialize features after the initial update."""
21+
22+
async def set_pan_step(value: int) -> None:
23+
self._pan_step = value
24+
25+
async def set_tilt_step(value: int) -> None:
26+
self._tilt_step = value
27+
28+
self._add_feature(
29+
Feature(
30+
self._device,
31+
"pan_right",
32+
"Pan right",
33+
container=self,
34+
attribute_setter=lambda: self.pan(self._pan_step * -1),
35+
type=Feature.Type.Action,
36+
)
37+
)
38+
self._add_feature(
39+
Feature(
40+
self._device,
41+
"pan_left",
42+
"Pan left",
43+
container=self,
44+
attribute_setter=lambda: self.pan(self._pan_step),
45+
type=Feature.Type.Action,
46+
)
47+
)
48+
self._add_feature(
49+
Feature(
50+
self._device,
51+
"pan_step",
52+
"Pan step",
53+
container=self,
54+
attribute_getter="_pan_step",
55+
attribute_setter=set_pan_step,
56+
type=Feature.Type.Number,
57+
)
58+
)
59+
self._add_feature(
60+
Feature(
61+
self._device,
62+
"tilt_up",
63+
"Tilt up",
64+
container=self,
65+
attribute_setter=lambda: self.tilt(self._tilt_step),
66+
type=Feature.Type.Action,
67+
)
68+
)
69+
self._add_feature(
70+
Feature(
71+
self._device,
72+
"tilt_down",
73+
"Tilt down",
74+
container=self,
75+
attribute_setter=lambda: self.tilt(self._tilt_step * -1),
76+
type=Feature.Type.Action,
77+
)
78+
)
79+
self._add_feature(
80+
Feature(
81+
self._device,
82+
"tilt_step",
83+
"Tilt step",
84+
container=self,
85+
attribute_getter="_tilt_step",
86+
attribute_setter=set_tilt_step,
87+
type=Feature.Type.Number,
88+
)
89+
)
90+
91+
def query(self) -> dict:
92+
"""Query to execute during the update cycle."""
93+
return {}
94+
95+
async def pan(self, pan: int) -> dict:
96+
"""Pan horizontally."""
97+
return await self.move(pan=pan, tilt=0)
98+
99+
async def tilt(self, tilt: int) -> dict:
100+
"""Tilt vertically."""
101+
return await self.move(pan=0, tilt=tilt)
102+
103+
async def move(self, *, pan: int, tilt: int) -> dict:
104+
"""Pan and tilt camera."""
105+
return await self._device._raw_query(
106+
{"do": {"motor": {"move": {"x_coord": str(pan), "y_coord": str(tilt)}}}}
107+
)

tests/test_feature.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,14 @@ async def test_precision_hint(dummy_feature, precision_hint):
160160

161161
async def test_feature_setters(dev: Device, mocker: MockerFixture):
162162
"""Test that all feature setters query something."""
163+
# setters that do not call set on the device itself.
164+
internal_setters = {"pan_step", "tilt_step"}
163165

164166
async def _test_feature(feat, query_mock):
165167
if feat.attribute_setter is None:
166168
return
167169

168-
expecting_call = True
170+
expecting_call = feat.id not in internal_setters
169171

170172
if feat.type == Feature.Type.Number:
171173
await feat.set_value(feat.minimum_value)

0 commit comments

Comments
 (0)
0