Prechádzať zdrojové kódy

add roadmap + add support for a/v mute and freeze

Noah Vogt 1 mesiac pred
rodič
commit
ccb04a3425

+ 10 - 1
README.md

@@ -44,9 +44,18 @@ media_player:
     encoding: "utf-16"        # encoding for communication (optional, default is utf-8)
     password: "secret%123"    # password to establish connection (optional)
     timeout: 1.5              # timeout to establish connection in seconds (optional, default is 4 sec)
-    sources:
+    sources:                  # mapping of the raw source to appriorate names
       "31": "Smart TV"
       "32": "Camera HDMI Out"
       "11": "Laptop"
 ```
 If you omit the sources block, the integration will show raw codes like 31, 32, etc., and add new ones to the dropdown as you switch to them on the device.
+
+
+## Roadmap
+
+Possible changes in future releases:
+
+- if the sources yaml block was omitted, give the user all options the projector reports support for
+- add the option to only poll for a subset of data
+- support the full pjlink2 spec

+ 6 - 1
custom_components/pjlink2/const.py

@@ -1,4 +1,5 @@
 """Provides the constants needed for component."""
+
 from enum import StrEnum
 
 DOMAIN = "pjlink2"
@@ -15,9 +16,13 @@ ATTR_PROJECTOR_NAME = "projector_name"
 ATTR_RESOLUTION_X = "x_resolution"
 ATTR_RESOLUTION_Y = "y_resolution"
 ATTR_LAMP_HOURS = "lamp_hours"
+ATTR_AV_MUTE = "av_mute"
+ATTR_FREEZE = "freeze"
+
 
 class ProjectorState(StrEnum):
     OFF = "off"
     ON = "on"
     COOLING = "cooling"
-    WARMING = "warming"
+    WARMING = "warming"
+

+ 39 - 0
custom_components/pjlink2/media_player.py

@@ -34,6 +34,7 @@ from homeassistant.const import (
 from homeassistant.core import HomeAssistant as HomeAssistantType
 
 import homeassistant.helpers.config_validation as cv
+from homeassistant.helpers import entity_platform
 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
 
 import voluptuous as vol
@@ -51,6 +52,8 @@ from .const import (
     ATTR_RESOLUTION_X,
     ATTR_RESOLUTION_Y,
     ATTR_LAMP_HOURS,
+    ATTR_AV_MUTE,
+    ATTR_FREEZE,
     ProjectorState,
 )
 
@@ -86,6 +89,15 @@ async def async_setup_platform(
     devices = [PJLink2MediaPlayer(pjl, name, sources)]
     async_add_entities(devices, update_before_add=False)
 
+    platform = entity_platform.async_get_current_platform()
+    platform.async_register_entity_service(
+        "freeze",
+        {
+            vol.Required("freeze"): cv.boolean,
+        },
+        "async_freeze",
+    )
+
 
 class PJLink2MediaPlayer(MediaPlayerEntity):
 
@@ -93,6 +105,7 @@ class PJLink2MediaPlayer(MediaPlayerEntity):
         MediaPlayerEntityFeature.TURN_ON
         | MediaPlayerEntityFeature.TURN_OFF
         | MediaPlayerEntityFeature.SELECT_SOURCE
+        | MediaPlayerEntityFeature.MUTE_VOLUME
     )
 
     def __init__(self, pjl, name, sources):
@@ -158,6 +171,18 @@ class PJLink2MediaPlayer(MediaPlayerEntity):
     def extra_state_attributes(self) -> dict[str, Any]:
         return self.attrs
 
+    @property
+    def is_volume_muted(self) -> bool | None:
+        return self.attrs.get(ATTR_AV_MUTE)
+
+    async def async_mute_volume(self, mute: bool) -> None:
+        await self._projector.mute.both(mute)
+        self.attrs[ATTR_AV_MUTE] = mute
+
+    async def async_freeze(self, freeze: bool) -> None:
+        await self._projector.freeze.set(freeze)
+        self.attrs[ATTR_FREEZE] = freeze
+
     async def async_turn_on(self) -> None:
         await Power(self._projector).set(Power.ON)
         self._state = MediaPlayerState.ON
@@ -240,9 +265,23 @@ class PJLink2MediaPlayer(MediaPlayerEntity):
                     self.attrs.pop(ATTR_RESOLUTION_X, None)
                     self.attrs.pop(ATTR_RESOLUTION_Y, None)
 
+                try:
+                    mute_status = await self._projector.mute.status()
+                    # status() returns (video_muted, audio_muted)
+                    self.attrs[ATTR_AV_MUTE] = mute_status[0] or mute_status[1]
+                except Exception:
+                    pass
+
+                try:
+                    self.attrs[ATTR_FREEZE] = await self._projector.freeze.get()
+                except Exception:
+                    pass
+
             elif pwr == Power.State.OFF:
                 self.attrs.pop(ATTR_RESOLUTION_X, None)
                 self.attrs.pop(ATTR_RESOLUTION_Y, None)
+                self.attrs.pop(ATTR_AV_MUTE, None)
+                self.attrs.pop(ATTR_FREEZE, None)
                 self._current_source = None
 
             self._connectionErrorLogged = False

+ 14 - 0
custom_components/pjlink2/services.yaml

@@ -0,0 +1,14 @@
+freeze:
+  name: Freeze
+  description: Freeze the current image on the projector.
+  target:
+    entity:
+      integration: pjlink2
+      domain: media_player
+  fields:
+    freeze:
+      name: Freeze
+      description: True to freeze, False to unfreeze.
+      required: true
+      selector:
+        boolean: