Add pan tilt camera module (#1261)

Add ptz controls for smartcameras.

---------

Co-authored-by: Teemu R. <tpr@iki.fi>
This commit is contained in:
Steven B. 2024-11-19 10:11:51 +00:00 committed by GitHub
parent a01247d48f
commit 5b5a148f9a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 112 additions and 1 deletions

View File

@ -5,6 +5,7 @@ from .camera import Camera
from .childdevice import ChildDevice from .childdevice import ChildDevice
from .device import DeviceModule from .device import DeviceModule
from .led import Led from .led import Led
from .pantilt import PanTilt
from .time import Time from .time import Time
__all__ = [ __all__ = [
@ -13,5 +14,6 @@ __all__ = [
"ChildDevice", "ChildDevice",
"DeviceModule", "DeviceModule",
"Led", "Led",
"PanTilt",
"Time", "Time",
] ]

View File

@ -0,0 +1,107 @@
"""Implementation of time module."""
from __future__ import annotations
from ...feature import Feature
from ..smartcameramodule import SmartCameraModule
DEFAULT_PAN_STEP = 30
DEFAULT_TILT_STEP = 10
class PanTilt(SmartCameraModule):
"""Implementation of device_local_time."""
REQUIRED_COMPONENT = "ptz"
_pan_step = DEFAULT_PAN_STEP
_tilt_step = DEFAULT_TILT_STEP
def _initialize_features(self) -> None:
"""Initialize features after the initial update."""
async def set_pan_step(value: int) -> None:
self._pan_step = value
async def set_tilt_step(value: int) -> None:
self._tilt_step = value
self._add_feature(
Feature(
self._device,
"pan_right",
"Pan right",
container=self,
attribute_setter=lambda: self.pan(self._pan_step * -1),
type=Feature.Type.Action,
)
)
self._add_feature(
Feature(
self._device,
"pan_left",
"Pan left",
container=self,
attribute_setter=lambda: self.pan(self._pan_step),
type=Feature.Type.Action,
)
)
self._add_feature(
Feature(
self._device,
"pan_step",
"Pan step",
container=self,
attribute_getter="_pan_step",
attribute_setter=set_pan_step,
type=Feature.Type.Number,
)
)
self._add_feature(
Feature(
self._device,
"tilt_up",
"Tilt up",
container=self,
attribute_setter=lambda: self.tilt(self._tilt_step),
type=Feature.Type.Action,
)
)
self._add_feature(
Feature(
self._device,
"tilt_down",
"Tilt down",
container=self,
attribute_setter=lambda: self.tilt(self._tilt_step * -1),
type=Feature.Type.Action,
)
)
self._add_feature(
Feature(
self._device,
"tilt_step",
"Tilt step",
container=self,
attribute_getter="_tilt_step",
attribute_setter=set_tilt_step,
type=Feature.Type.Number,
)
)
def query(self) -> dict:
"""Query to execute during the update cycle."""
return {}
async def pan(self, pan: int) -> dict:
"""Pan horizontally."""
return await self.move(pan=pan, tilt=0)
async def tilt(self, tilt: int) -> dict:
"""Tilt vertically."""
return await self.move(pan=0, tilt=tilt)
async def move(self, *, pan: int, tilt: int) -> dict:
"""Pan and tilt camera."""
return await self._device._raw_query(
{"do": {"motor": {"move": {"x_coord": str(pan), "y_coord": str(tilt)}}}}
)

View File

@ -160,12 +160,14 @@ async def test_precision_hint(dummy_feature, precision_hint):
async def test_feature_setters(dev: Device, mocker: MockerFixture): async def test_feature_setters(dev: Device, mocker: MockerFixture):
"""Test that all feature setters query something.""" """Test that all feature setters query something."""
# setters that do not call set on the device itself.
internal_setters = {"pan_step", "tilt_step"}
async def _test_feature(feat, query_mock): async def _test_feature(feat, query_mock):
if feat.attribute_setter is None: if feat.attribute_setter is None:
return return
expecting_call = True expecting_call = feat.id not in internal_setters
if feat.type == Feature.Type.Number: if feat.type == Feature.Type.Number:
await feat.set_value(feat.minimum_value) await feat.set_value(feat.minimum_value)