Skip to content

Commit 409d2f1

Browse files
committed
updated remote component
1 parent acd162a commit 409d2f1

File tree

1 file changed

+91
-27
lines changed

1 file changed

+91
-27
lines changed

custom_components/jvcprojector/remote.py

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from homeassistant import util
55
import asyncio
66
from typing import Final
7+
from jvc_projector import JVCCommunicationError as comm_error
8+
import datetime
79

810
JVC_RETRIES: Final = "max_retries"
911

@@ -19,7 +21,7 @@
1921
_LOGGER = logging.getLogger(__name__)
2022

2123

22-
def setup_platform(hass, config, add_entities, discovery_info=None):
24+
def setup_platform(hass, config, add_entities, discovery_info=None) -> None:
2325
"""Set up the remote."""
2426
if config.get(CONF_HOST) is not None:
2527
host = config.get(CONF_HOST)
@@ -39,41 +41,59 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
3941
class JVCRemote(remote.RemoteEntity):
4042
"""Home assistant JVC remote representation"""
4143

42-
def __init__(self, name, host, password, port, delay, timeout, retries):
44+
def __init__(
45+
self,
46+
name: str | None,
47+
host: str,
48+
password: str | None,
49+
port: int | None,
50+
delay: int | None,
51+
timeout: float | None,
52+
retries: int | None,
53+
) -> None:
4354
"""Initialize the Remote."""
4455
from jvc_projector import JVCProjector
45-
from jvc_projector import JVCPoweredOffError
4656

4757
self._name = name or DEVICE_DEFAULT_NAME
4858
self._host = host
4959
self._password = password
50-
self._last_command_sent = None
60+
61+
self._last_commands_sent = None
5162
self._jvc = JVCProjector(host, password, port, delay, timeout, retries)
52-
self._state = None
53-
self._power_state = "N/A"
63+
self._power_state = self._jvc.power_state()
64+
self._state = True if self._power_state == "lamp_on" else False
65+
self._signal_state = (
66+
"unknown" if not self._state else self._jvc.command("signal")
67+
)
68+
self._input_state = "unknown" if not self._state else self._jvc.command("input")
69+
self._lamp_state = "unknown" if not self._state else self._jvc.command("lamp")
70+
self._picture_mode_state = (
71+
"unknown" if not self._state else self._jvc.command("picture_mode")
72+
)
73+
self._last_commands_response = None
5474
self.state_lock = asyncio.Lock()
5575

5676
@property
57-
def should_poll(self):
77+
def should_poll(self) -> bool:
5878
# poll the device so we know if it was state changed
5979
# via an external method, like the physical remote
6080
return True
6181

6282
@property
63-
def name(self):
83+
def name(self) -> str:
6484
"""Return the name of the device if any."""
6585
return self._name
6686

6787
async def async_update(self):
6888
await self.async_update_state()
6989

7090
@property
71-
def is_on(self):
91+
def is_on(self) -> bool:
7292
"""Return true if remote is on."""
7393
return self._state
7494

7595
@property
76-
def extra_state_attributes(self):
96+
def extra_state_attributes(self) -> dict:
7797
"""Return device state attributes."""
7898

7999
if self._power_state in ["lamp_on", "reserved"]:
@@ -82,51 +102,72 @@ def extra_state_attributes(self):
82102
self._state = False
83103

84104
return {
85-
"last_command_sent": self._last_command_sent
86-
if self._last_command_sent is not None
87-
else "N/A",
105+
"last_commands_sent": self._last_commands_sent,
106+
"last_commands_response": self._last_commands_response,
88107
"power_state": self._power_state,
108+
"signal_state": self._signal_state,
109+
"input_state": self._input_state,
110+
"lamp_state": self._lamp_state,
111+
"picture_mode": self._picture_mode_state,
89112
}
90113

91-
async def async_turn_on(self, **kwargs):
114+
async def async_turn_on(self, **kwargs) -> None:
92115
"""Turn the remote on."""
116+
if self._state:
117+
return
93118
await self.async_send_command("power-on")
94119
self._state = True
95120

96-
async def async_turn_off(self, **kwargs):
121+
async def async_turn_off(self, **kwargs) -> None:
97122
"""Turn the remote off."""
123+
if not self._state:
124+
return
98125
await self.async_send_command("power-off")
99126
self._state = False
100127

101-
async def async_send_command(self, command, **kwargs):
128+
async def async_send_command(self, command, delay_secs=0, **kwargs) -> None:
102129
"""Send a command to a device."""
103130

104131
async with self.state_lock:
105132
if type(command) != list:
106133
command = [command]
107134

135+
self._last_commands_sent = []
136+
self._last_commands_response = []
137+
108138
for com in command:
109139
_LOGGER.info(f"sending command: {com}")
110140
try:
111-
command_sent = await self.hass.async_add_executor_job(
141+
resp = await self.hass.async_add_executor_job(
112142
self._jvc.command, (com)
113143
)
114-
except JVCPoweredOffError as e:
144+
if resp is None:
145+
resp = "success"
146+
self._last_commands_sent.append(com)
147+
self._last_commands_response.append(resp)
148+
except comm_error as e:
115149
# The projector is powered off
116-
command_sent = False
117-
_LOGGER.error(f"Failed to send command, projector is powered off")
150+
_LOGGER.warning(
151+
f"Failed to send command, could not communicate with projector: {repr(e)}\nThis could happen if the command only works when the projector is on but the current state is off, or the timeout setting is too low"
152+
)
153+
self._last_commands_sent.append(com)
154+
self._last_commands_response.append("failed")
118155
except Exception as e:
119156
# when an error occured during sending, command execution probably failed
120-
command_sent = False
157+
_LOGGER.error(f"Unknown error, abort sending commands")
158+
self._last_commands_sent = ["unknown"]
159+
self._last_commands_response = ["failed"]
121160
raise e
122161

123-
if not command_sent:
124-
self._last_command_sent = "N/A"
125-
continue
126-
else:
127-
self._last_command_sent = com
162+
self.async_write_ha_state()
163+
delta = (
164+
datetime.datetime.now() - self._jvc.last_command_time
165+
).total_seconds()
166+
if delay_secs >= delta:
167+
_LOGGER.debug(f"waiting {delay_secs} seconds before next command")
168+
await asyncio.sleep(delay_secs - delta)
128169

129-
async def async_update_state(self):
170+
async def async_update_state(self) -> None:
130171
""" "Update the state with the Power Status (if available)"""
131172

132173
# do nothing until lock is released
@@ -137,6 +178,29 @@ async def async_update_state(self):
137178
self._power_state = await self.hass.async_add_executor_job(
138179
self._jvc.power_state
139180
)
181+
182+
if self._power_state != "lamp_on":
183+
(
184+
self._input_state,
185+
self._signal_state,
186+
self._picture_mode_state,
187+
self._lamp_state,
188+
) = ("unknown", "unknown", "unknown", "unknown")
189+
return
190+
191+
self._input_state = await self.hass.async_add_executor_job(
192+
self._jvc.command, ("input")
193+
)
194+
self._signal_state = await self.hass.async_add_executor_job(
195+
self._jvc.command, ("signal")
196+
)
197+
self._picture_mode_state = await self.hass.async_add_executor_job(
198+
self._jvc.command, ("picture_mode")
199+
)
200+
self._lamp_state = await self.hass.async_add_executor_job(
201+
self._jvc.command, ("lamp")
202+
)
203+
140204
except Exception as e:
141205
self._power_state = "unknown"
142206
raise e

0 commit comments

Comments
 (0)