Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix async track state change deprecation #8

Merged
merged 2 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 51 additions & 19 deletions custom_components/smartir/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@
PRECISION_HALVES,
PRECISION_WHOLE,
)
from homeassistant.core import Event, EventStateChangedData, callback
from homeassistant.core import HomeAssistant, Event, EventStateChangedData, callback
from homeassistant.helpers.event import async_track_state_change_event
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType
from .controller import get_controller

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -90,9 +91,44 @@ async def async_setup_platform(
device_data = json.load(j)
_LOGGER.debug(f"{device_json_path} file loaded")
except Exception:
_LOGGER.error("The device Json file is invalid")
_LOGGER.error(
"The device JSON file '%s' is not valid json!", device_json_filename
)
return

if not isinstance(device_data, dict):
_LOGGER.error("Invalid device code file '%s.", device_json_filename)
return

for key in [
"manufacturer",
"supportedModels",
"supportedController",
"commandsEncoding",
"minTemperature",
"maxTemperature",
"precision",
"operationModes",
"fanModes",
]:
if not (key in device_data and device_data[key]):
_LOGGER.error(
"Invalid device JSON file '%s, missing or not defined '%s'!",
device_json_filename,
key,
)
return

if not (
"commands" in device_data
and isinstance(device_data["commands"], dict)
and len(device_data["commands"])
):
_LOGGER.error(
"Invalid device JSON file '%s, missing 'commands'!", device_json_filename
)
return

async_add_entities([SmartIRClimate(hass, config, device_data)])


Expand Down Expand Up @@ -238,6 +274,8 @@ def max_temp(self):
@property
def target_temperature(self):
"""Return the temperature we try to reach."""
if self._hvac_mode == STATE_UNKNOWN:
return STATE_UNKNOWN
return self._target_temperature

@property
Expand Down Expand Up @@ -268,6 +306,8 @@ def fan_modes(self):
@property
def fan_mode(self):
"""Return the fan setting."""
if self._hvac_mode == STATE_UNKNOWN:
return STATE_UNKNOWN
return self._fan_mode

@property
Expand All @@ -278,6 +318,8 @@ def swing_modes(self):
@property
def swing_mode(self):
"""Return the current swing mode."""
if self._hvac_mode == STATE_UNKNOWN:
return STATE_UNKNOWN
return self._swing_mode

@property
Expand All @@ -298,6 +340,8 @@ def supported_features(self):
@property
def hvac_action(self) -> HVACAction | None:
"""Return the current running hvac operation if supported."""
if self._hvac_mode == STATE_UNKNOWN:
return STATE_UNKNOWN
return self._hvac_action

@property
Expand Down Expand Up @@ -379,47 +423,35 @@ async def send_command(self, hvac_mode, fan_mode, swing_mode, temperature):
if hvac_mode == HVACMode.OFF:
if (
self._last_on_operation == HVACMode.COOL
and isinstance(self._commands, dict)
and "off_cool" in self._commands.keys()
):
await self._controller.send(self._commands["off_cool"])
elif (
self._last_on_operation == HVACMode.HEAT
and isinstance(self._commands, dict)
and "off_heat" in self._commands.keys()
):
await self._controller.send(self._commands["off_heat"])
elif (
self._last_on_operation == HVACMode.FAN_ONLY
and isinstance(self._commands, dict)
and "off_fan" in self._commands.keys()
):
await self._controller.send(self._commands["off_fan"])
elif (
isinstance(self._commands, dict)
and "off" in self._commands.keys()
):
elif "off" in self._commands.keys():
await self._controller.send(self._commands["off"])
else:
_LOGGER.error(
"Missing device IR code for any of off/off_cool/off_heat/off_fan operation mode."
)
return
else:
if not (
isinstance(self._commands, dict)
and "on" in self._commands.keys()
):
if not "on" in self._commands.keys():
"""if on code is not present, the on bit can be still set in the all operation/fan codes"""
pass
else:
await self._controller.send(self._commands["on"])
await asyncio.sleep(self._delay)

if not (
isinstance(self._commands, dict)
and hvac_mode in self._commands.keys()
):
if not hvac_mode in self._commands.keys():
_LOGGER.error(
"Missing device IR code for %s operation mode.", hvac_mode
)
Expand Down Expand Up @@ -541,8 +573,8 @@ async def _async_power_sensor_changed(
and self._last_on_operation is not None
):
self._hvac_mode = self._last_on_operation
elif len(self._operation_modes) > 1:
self._hvac_mode = self._operation_modes[1]
else:
self._hvac_mode = STATE_UNKNOWN
await self._async_update_hvac_action()
elif new_state.state == STATE_OFF:
self._on_by_remote = False
Expand Down
82 changes: 68 additions & 14 deletions custom_components/smartir/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
ATTR_OSCILLATING,
)
from homeassistant.const import CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN
from homeassistant.core import Event, EventStateChangedData
from homeassistant.core import HomeAssistant, Event, EventStateChangedData
from homeassistant.helpers.event import async_track_state_change_event
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType
from homeassistant.util.percentage import (
ordered_list_item_to_percentage,
percentage_to_ordered_list_item,
Expand All @@ -36,9 +37,12 @@
CONF_CONTROLLER_DATA = "controller_data"
CONF_DELAY = "delay"
CONF_POWER_SENSOR = "power_sensor"
CONF_POWER_SENSOR_RESTORE_STATE = "power_sensor_restore_state"

SPEED_OFF = "off"

SUPPORT_FLAGS = SUPPORT_SET_SPEED

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Optional(CONF_UNIQUE_ID): cv.string,
Expand All @@ -47,6 +51,7 @@
vol.Required(CONF_CONTROLLER_DATA): cv.string,
vol.Optional(CONF_DELAY, default=DEFAULT_DELAY): cv.string,
vol.Optional(CONF_POWER_SENSOR): cv.entity_id,
vol.Optional(CONF_POWER_SENSOR_RESTORE_STATE, default=False): cv.boolean,
}
)

Expand Down Expand Up @@ -77,9 +82,40 @@ async def async_setup_platform(
device_data = json.load(j)
_LOGGER.debug(f"{device_json_path} file loaded")
except Exception:
_LOGGER.error("The device JSON file is invalid")
_LOGGER.error(
"The device JSON file '%s' is not valid json!", device_json_filename
)
return

if not isinstance(device_data, dict):
_LOGGER.error("Invalid device JSON file '%s.", device_json_filename)
return

for key in [
"manufacturer",
"supportedModels",
"supportedController",
"commandsEncoding",
"speed",
]:
if not (key in device_data and device_data[key]):
_LOGGER.error(
"Invalid device JSON file '%s, missing or not defined '%s'!",
device_json_filename,
key,
)
return

if not (
"commands" in device_data
and isinstance(device_data["commands"], dict)
and len(device_data["commands"])
):
_LOGGER.error(
"Invalid device JSON file '%s, missing 'commands'!", device_json_filename
)
return

async_add_entities([SmartIRFan(hass, config, device_data)])


Expand All @@ -92,6 +128,7 @@ def __init__(self, hass, config, device_data):
self._controller_data = config.get(CONF_CONTROLLER_DATA)
self._delay = config.get(CONF_DELAY)
self._power_sensor = config.get(CONF_POWER_SENSOR)
self._power_sensor_restore_state = config.get(CONF_POWER_SENSOR_RESTORE_STATE)

self._manufacturer = device_data["manufacturer"]
self._supported_models = device_data["supportedModels"]
Expand All @@ -101,13 +138,13 @@ def __init__(self, hass, config, device_data):
self._commands = device_data["commands"]

self._speed = SPEED_OFF
self._direction = None
self._current_direction = None
self._last_on_speed = None
self._oscillating = None
self._support_flags = SUPPORT_SET_SPEED
self._support_flags = SUPPORT_FLAGS

if DIRECTION_REVERSE in self._commands and DIRECTION_FORWARD in self._commands:
self._direction = DIRECTION_REVERSE
self._current_direction = DIRECTION_REVERSE
self._support_flags = self._support_flags | SUPPORT_DIRECTION
if "oscillate" in self._commands:
self._oscillating = False
Expand Down Expand Up @@ -138,10 +175,16 @@ async def async_added_to_hass(self):
# If _direction has a value the direction controls appears
# in UI even if SUPPORT_DIRECTION is not provided in the flags
if (
"direction" in last_state.attributes
"current_direction" in last_state.attributes
and self._support_flags & SUPPORT_DIRECTION
):
self._direction = last_state.attributes["direction"]
self._current_direction = last_state.attributes["current_direction"]

if (
"oscillating" in last_state.attributes
and self._support_flags & SUPPORT_OSCILLATE
):
self._oscillating = last_state.attributes["oscillating"]

if "last_on_speed" in last_state.attributes:
self._last_on_speed = last_state.attributes["last_on_speed"]
Expand All @@ -164,13 +207,15 @@ def name(self):
@property
def state(self):
"""Return the current state."""
if self._on_by_remote or self._speed != SPEED_OFF:
if self._speed != SPEED_OFF:
return STATE_ON
return SPEED_OFF

@property
def percentage(self):
"""Return speed percentage of the fan."""
if self._speed == STATE_UNKNOWN:
return STATE_UNKNOWN
if self._speed == SPEED_OFF:
return 0

Expand All @@ -184,12 +229,16 @@ def speed_count(self):
@property
def oscillating(self):
"""Return the oscillation state."""
if self._speed == STATE_UNKNOWN:
return STATE_UNKNOWN
return self._oscillating

@property
def current_direction(self):
"""Return the direction state."""
return self._direction
if self._speed == STATE_UNKNOWN:
return STATE_UNKNOWN
return self._current_direction

@property
def last_on_speed(self):
Expand Down Expand Up @@ -235,7 +284,7 @@ async def async_oscillate(self, oscillating: bool) -> None:

async def async_set_direction(self, direction: str):
"""Set the direction of the fan"""
self._direction = direction
self._current_direction = direction

if not self._speed.lower() == SPEED_OFF:
await self.send_command()
Expand All @@ -261,7 +310,7 @@ async def send_command(self):
async with self._temp_lock:
self._on_by_remote = False
speed = self._speed
direction = self._direction or "default"
direction = self._current_direction or "default"
oscillating = self._oscillating

if speed.lower() == SPEED_OFF:
Expand Down Expand Up @@ -290,10 +339,15 @@ async def _async_power_sensor_changed(

if new_state.state == STATE_ON and self._speed == SPEED_OFF:
self._on_by_remote = True
self._speed = None
if (
self._power_sensor_restore_state == True
and self._last_on_speed is not None
):
self._speed = self._last_on_speed
else:
self._speed = STATE_UNKNOWN
self.async_write_ha_state()

if new_state.state == STATE_OFF:
elif new_state.state == STATE_OFF:
self._on_by_remote = False
if self._speed != SPEED_OFF:
self._speed = SPEED_OFF
Expand Down
Loading
Loading