diff --git a/custom_components/fhem/__init__.py b/custom_components/fhem/__init__.py index b031c4a..4d8a7c4 100644 --- a/custom_components/fhem/__init__.py +++ b/custom_components/fhem/__init__.py @@ -41,9 +41,7 @@ class FhemConnection(ReconnectingClient): def register_device(self, id, d): self._devices[id].append(d) if self._writer: - self._writer.writelines([ - "displayattr .*\n".encode(), - ]) + d.refresh() async def _update_all_devices(self, state): if state == 'connected': @@ -51,6 +49,7 @@ class FhemConnection(ReconnectingClient): self.write_line("inform on") for device_list in self._devices.values(): for device in device_list: + device.refresh() await device.async_update_ha_state() async def _process_line(self, line): diff --git a/custom_components/fhem/binary_sensor.py b/custom_components/fhem/binary_sensor.py index e22d560..c9924f3 100644 --- a/custom_components/fhem/binary_sensor.py +++ b/custom_components/fhem/binary_sensor.py @@ -64,6 +64,9 @@ class FhemBinarySensor(BinarySensorDevice): def is_on(self): return self._state + def refresh(self): + pass + async def line_received(self, line): if self._type == 'motion' and line.startswith('motion'): self._available = True diff --git a/custom_components/fhem/cover.py b/custom_components/fhem/cover.py index 70137d5..cb8a667 100644 --- a/custom_components/fhem/cover.py +++ b/custom_components/fhem/cover.py @@ -58,6 +58,9 @@ class FhemCover(CoverDevice): def current_cover_position(self): return self._position + def refresh(self): + self.connection.fhem_set(self._ids[0], 'statusRequest') + @property def is_closed(self): """Return if the cover is closed.""" @@ -88,8 +91,7 @@ class FhemCover(CoverDevice): _, new_motor_state, new_position = line.split(':') new_position = new_position.strip().lower() new_motor_state = new_motor_state.strip().lower() - assert new_motor_state == 'stop' or new_motor_state == 'up' or new_motor_state == 'down', \ - 'Unknown motor state ' + new_motor_state + assert new_motor_state in ('up', 'down', 'stop', 'err'), 'Unknown motor state ' + new_motor_state if new_motor_state == 'stop': if new_position == 'on': self._position = 100 diff --git a/custom_components/fhem/light.py b/custom_components/fhem/light.py index bfaf735..c3486c2 100644 --- a/custom_components/fhem/light.py +++ b/custom_components/fhem/light.py @@ -72,6 +72,9 @@ class FhemLight(Light): else: return None + def refresh(self): + self.connection.fhem_set(self._ids[0], 'statusRequest') + async def async_turn_on(self, **kwargs): brightness = kwargs.get(ATTR_BRIGHTNESS, None) transition_time = kwargs.get(ATTR_TRANSITION, 0.5) @@ -124,6 +127,7 @@ class FhemLight(Light): pass await self.async_update_ha_state() elif line.startswith('ResndFail') or line.startswith('MISSING ACK'): + _LOGGER.warning(f"FHEM light {self.name} became unavailable: '{line}'") self._available = False await self.async_update_ha_state() else: diff --git a/custom_components/fhem/sensor.py b/custom_components/fhem/sensor.py index c31dd3c..9d5fe27 100644 --- a/custom_components/fhem/sensor.py +++ b/custom_components/fhem/sensor.py @@ -60,6 +60,9 @@ class FhemSensor(Entity): def state(self): return self._state + def refresh(self): + pass + async def line_received(self, line): if self._type == 'brightness' and line.startswith('brightness'): self._available = True @@ -69,7 +72,7 @@ class FhemSensor(Entity): elif self._type == 'power' and line.startswith('power'): self._available = True _, new_value = line.split(':') - self._state = int(new_value) + self._state = float(new_value) await self.async_update_ha_state() elif line.startswith('ResndFail') or line.startswith('MISSING ACK'): self._available = False diff --git a/custom_components/fhem/switch.py b/custom_components/fhem/switch.py index 5436be7..ef28c3b 100644 --- a/custom_components/fhem/switch.py +++ b/custom_components/fhem/switch.py @@ -53,24 +53,33 @@ class FhemSwitch(SwitchDevice): async def async_turn_on(self, **kwargs): """Turn the device on.""" + self._on = True self.connection.fhem_set(self._ids[0], 'on') async def async_turn_off(self, **kwargs): """Turn the device off.""" + self._on = False self.connection.fhem_set(self._ids[0], 'off') + def refresh(self): + self.connection.fhem_set(self._ids[0], 'statusRequest') + async def line_received(self, line): line = line.strip() if line.startswith('level:'): + self._available = True _, new_state = line.split(':') new_state = new_state.strip().lower() if new_state in ('on', '100'): self._on = True - if new_state in ('off', '0'): + elif new_state in ('off', '0'): self._on = False await self.async_update_ha_state() elif line in ('on', 'off'): + self._available = True + prev = self._on self._on = (line == 'on') + await self.async_update_ha_state() elif line.startswith('ResndFail') or line.startswith('MISSING ACK'): self._available = False await self.async_update_ha_state() diff --git a/custom_components/reconnecting_client.py b/custom_components/reconnecting_client.py index 6a4deba..ee1e168 100644 --- a/custom_components/reconnecting_client.py +++ b/custom_components/reconnecting_client.py @@ -41,14 +41,14 @@ class ReconnectingClient: self._writer.write(line.encode()) else: _LOGGER.warning(f"Skipping line '{line}'' because _writer is None") - except RuntimeError: + except RuntimeError as e: + _LOGGER.error("Writing failed " + str(e)) self._connection_task.cancel() self._connection_task = self.hass.loop.create_task(self._connection()) async def _connection(self): try: reader, writer = await asyncio.open_connection(self._host, self._port) - _LOGGER.info("Connected to {} {}:{}".format(self._connection_name, self._host, self._port)) self._connection_last_state = 'CONNECTED' self._writer = writer @@ -61,17 +61,16 @@ class ReconnectingClient: if not line: raise OSError("Disconnect") line = line.decode() - _LOGGER.debug("{} received line: {}".format(self._connection_name, line)) + _LOGGER.warning("{} received line: {}".format(self._connection_name, line)) await self._receive_line_callback(line) - except OSError: + except OSError as e: if self._connection_last_state != 'FAILED': notification_text = "{} connection to {}:{} failed".format(self._connection_name,self._host, self._port) self.hass.components.persistent_notification.async_create(notification_text, title="No connection") _LOGGER.error("Connection to {} failed {}:{}".format(self._connection_name, self._host, self._port)) await self._connection_status_changed_callback('disconnected') self._connection_last_state = 'FAILED' - self.connected = False await asyncio.sleep(self.reconnect_time) self.reconnect_time = min(2 * self.reconnect_time, self.reconnect_time_max) - self.hass.loop.create_task(self._connection()) + self._connection_task = self.hass.loop.create_task(self._connection()) diff --git a/custom_components/squeezebox_telnet/media_player.py b/custom_components/squeezebox_telnet/media_player.py index d7acdb1..d670c50 100644 --- a/custom_components/squeezebox_telnet/media_player.py +++ b/custom_components/squeezebox_telnet/media_player.py @@ -239,6 +239,8 @@ class LogitechMediaServer(ReconnectingClient): if player_id in self._players: await self._players[player_id].on_receive(cmd, data) + elif line.startswith('listen'): + pass else: _LOGGER.warning("LMS Ignoring line " + line)