mirror of
				https://github.com/python-kasa/python-kasa.git
				synced 2025-10-31 20:51:54 +00:00 
			
		
		
		
	 44c561b04d
			
		
	
	44c561b04d
	
	
		
			
	
		
	
	
		
			Some checks failed
		
		
	
	CI / Perform linting checks (3.13) (push) Has been cancelled
				
			CodeQL checks / Analyze (python) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.11) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.12) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.13) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.11) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.12) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.13) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.11) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.12) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.13) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.11) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.12) (push) Has been cancelled
				
			CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.13) (push) Has been cancelled
				
			Co-authored-by: Teemu R. <tpr@iki.fi>
		
			
				
	
	
		
			217 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """Implementation of alarm module."""
 | |
| 
 | |
| from __future__ import annotations
 | |
| 
 | |
| from typing import Annotated
 | |
| 
 | |
| from ...feature import Feature
 | |
| from ...interfaces import Alarm as AlarmInterface
 | |
| from ...module import FeatureAttribute
 | |
| from ...smart.smartmodule import allow_update_after
 | |
| from ..smartcammodule import SmartCamModule
 | |
| 
 | |
| DURATION_MIN = 0
 | |
| DURATION_MAX = 6000
 | |
| 
 | |
| VOLUME_MIN = 0
 | |
| VOLUME_MAX = 10
 | |
| 
 | |
| 
 | |
| class Alarm(SmartCamModule, AlarmInterface):
 | |
|     """Implementation of alarm module."""
 | |
| 
 | |
|     REQUIRED_COMPONENT = "siren"
 | |
|     QUERY_GETTER_NAME = "getSirenStatus"
 | |
|     QUERY_MODULE_NAME = "siren"
 | |
| 
 | |
|     def query(self) -> dict:
 | |
|         """Query to execute during the update cycle."""
 | |
|         q = super().query()
 | |
|         q["getSirenConfig"] = {self.QUERY_MODULE_NAME: {}}
 | |
|         q["getSirenTypeList"] = {self.QUERY_MODULE_NAME: {}}
 | |
| 
 | |
|         return q
 | |
| 
 | |
|     def _initialize_features(self) -> None:
 | |
|         """Initialize features."""
 | |
|         device = self._device
 | |
|         self._add_feature(
 | |
|             Feature(
 | |
|                 device,
 | |
|                 id="alarm",
 | |
|                 name="Alarm",
 | |
|                 container=self,
 | |
|                 attribute_getter="active",
 | |
|                 icon="mdi:bell",
 | |
|                 category=Feature.Category.Debug,
 | |
|                 type=Feature.Type.BinarySensor,
 | |
|             )
 | |
|         )
 | |
|         self._add_feature(
 | |
|             Feature(
 | |
|                 device,
 | |
|                 id="alarm_sound",
 | |
|                 name="Alarm sound",
 | |
|                 container=self,
 | |
|                 attribute_getter="alarm_sound",
 | |
|                 attribute_setter="set_alarm_sound",
 | |
|                 category=Feature.Category.Config,
 | |
|                 type=Feature.Type.Choice,
 | |
|                 choices_getter="alarm_sounds",
 | |
|             )
 | |
|         )
 | |
|         self._add_feature(
 | |
|             Feature(
 | |
|                 device,
 | |
|                 id="alarm_volume",
 | |
|                 name="Alarm volume",
 | |
|                 container=self,
 | |
|                 attribute_getter="alarm_volume",
 | |
|                 attribute_setter="set_alarm_volume",
 | |
|                 category=Feature.Category.Config,
 | |
|                 type=Feature.Type.Number,
 | |
|                 range_getter=lambda: (VOLUME_MIN, VOLUME_MAX),
 | |
|             )
 | |
|         )
 | |
|         self._add_feature(
 | |
|             Feature(
 | |
|                 device,
 | |
|                 id="alarm_duration",
 | |
|                 name="Alarm duration",
 | |
|                 container=self,
 | |
|                 attribute_getter="alarm_duration",
 | |
|                 attribute_setter="set_alarm_duration",
 | |
|                 category=Feature.Category.Config,
 | |
|                 type=Feature.Type.Number,
 | |
|                 range_getter=lambda: (DURATION_MIN, DURATION_MAX),
 | |
|             )
 | |
|         )
 | |
|         self._add_feature(
 | |
|             Feature(
 | |
|                 device,
 | |
|                 id="test_alarm",
 | |
|                 name="Test alarm",
 | |
|                 container=self,
 | |
|                 attribute_setter="play",
 | |
|                 type=Feature.Type.Action,
 | |
|             )
 | |
|         )
 | |
|         self._add_feature(
 | |
|             Feature(
 | |
|                 device,
 | |
|                 id="stop_alarm",
 | |
|                 name="Stop alarm",
 | |
|                 container=self,
 | |
|                 attribute_setter="stop",
 | |
|                 type=Feature.Type.Action,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|     @property
 | |
|     def alarm_sound(self) -> Annotated[str, FeatureAttribute()]:
 | |
|         """Return current alarm sound."""
 | |
|         return self.data["getSirenConfig"]["siren_type"]
 | |
| 
 | |
|     @allow_update_after
 | |
|     async def set_alarm_sound(self, sound: str) -> Annotated[dict, FeatureAttribute()]:
 | |
|         """Set alarm sound.
 | |
| 
 | |
|         See *alarm_sounds* for list of available sounds.
 | |
|         """
 | |
|         config = self._validate_and_get_config(sound=sound)
 | |
|         return await self.call("setSirenConfig", {"siren": config})
 | |
| 
 | |
|     @property
 | |
|     def alarm_sounds(self) -> list[str]:
 | |
|         """Return list of available alarm sounds."""
 | |
|         return self.data["getSirenTypeList"]["siren_type_list"]
 | |
| 
 | |
|     @property
 | |
|     def alarm_volume(self) -> Annotated[int, FeatureAttribute()]:
 | |
|         """Return alarm volume.
 | |
| 
 | |
|         Unlike duration the device expects/returns a string for volume.
 | |
|         """
 | |
|         return int(self.data["getSirenConfig"]["volume"])
 | |
| 
 | |
|     @allow_update_after
 | |
|     async def set_alarm_volume(
 | |
|         self, volume: int
 | |
|     ) -> Annotated[dict, FeatureAttribute()]:
 | |
|         """Set alarm volume."""
 | |
|         config = self._validate_and_get_config(volume=volume)
 | |
|         return await self.call("setSirenConfig", {"siren": config})
 | |
| 
 | |
|     @property
 | |
|     def alarm_duration(self) -> Annotated[int, FeatureAttribute()]:
 | |
|         """Return alarm duration."""
 | |
|         return self.data["getSirenConfig"]["duration"]
 | |
| 
 | |
|     @allow_update_after
 | |
|     async def set_alarm_duration(
 | |
|         self, duration: int
 | |
|     ) -> Annotated[dict, FeatureAttribute()]:
 | |
|         """Set alarm volume."""
 | |
|         config = self._validate_and_get_config(duration=duration)
 | |
|         return await self.call("setSirenConfig", {"siren": config})
 | |
| 
 | |
|     @property
 | |
|     def active(self) -> bool:
 | |
|         """Return true if alarm is active."""
 | |
|         return self.data["getSirenStatus"]["status"] != "off"
 | |
| 
 | |
|     async def play(
 | |
|         self,
 | |
|         *,
 | |
|         duration: int | None = None,
 | |
|         volume: int | None = None,
 | |
|         sound: str | None = None,
 | |
|     ) -> dict:
 | |
|         """Play alarm.
 | |
| 
 | |
|         The optional *duration*, *volume*, and *sound* to override the device settings.
 | |
|         *duration* is in seconds.
 | |
|         See *alarm_sounds* for the list of sounds available for the device.
 | |
|         """
 | |
|         if config := self._validate_and_get_config(
 | |
|             duration=duration, volume=volume, sound=sound
 | |
|         ):
 | |
|             await self.call("setSirenConfig", {"siren": config})
 | |
| 
 | |
|         return await self.call("setSirenStatus", {"siren": {"status": "on"}})
 | |
| 
 | |
|     async def stop(self) -> dict:
 | |
|         """Stop alarm."""
 | |
|         return await self.call("setSirenStatus", {"siren": {"status": "off"}})
 | |
| 
 | |
|     def _validate_and_get_config(
 | |
|         self,
 | |
|         *,
 | |
|         duration: int | None = None,
 | |
|         volume: int | None = None,
 | |
|         sound: str | None = None,
 | |
|     ) -> dict:
 | |
|         if sound and sound not in self.alarm_sounds:
 | |
|             raise ValueError(
 | |
|                 f"sound must be one of {', '.join(self.alarm_sounds)}: {sound}"
 | |
|             )
 | |
| 
 | |
|         if duration is not None and (
 | |
|             duration < DURATION_MIN or duration > DURATION_MAX
 | |
|         ):
 | |
|             msg = f"duration must be between {DURATION_MIN} and {DURATION_MAX}"
 | |
|             raise ValueError(msg)
 | |
| 
 | |
|         if volume is not None and (volume < VOLUME_MIN or volume > VOLUME_MAX):
 | |
|             raise ValueError(f"volume must be between {VOLUME_MIN} and {VOLUME_MAX}")
 | |
| 
 | |
|         config: dict[str, str | int] = {}
 | |
|         if sound:
 | |
|             config["siren_type"] = sound
 | |
|         if duration is not None:
 | |
|             config["duration"] = duration
 | |
|         if volume is not None:
 | |
|             config["volume"] = str(volume)
 | |
| 
 | |
|         return config
 |