diff --git a/custom_components/ds_air/__init__.py b/custom_components/ds_air/__init__.py index b6f6fbd..b335381 100644 --- a/custom_components/ds_air/__init__.py +++ b/custom_components/ds_air/__init__.py @@ -13,6 +13,7 @@ from .const import CONF_GW, DEFAULT_GW, DEFAULT_HOST, DEFAULT_PORT, DOMAIN from .ds_air_service import Config, Service + _LOGGER = logging.getLogger(__name__) PLATFORMS = [ @@ -30,15 +31,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: _LOGGER.debug(f"{host}:{port} {gw} {scan_interval}") - # hass.data[DOMAIN][CONF_HOST] = host - # hass.data[DOMAIN][CONF_PORT] = port - # hass.data[DOMAIN][CONF_GW] = gw - # hass.data[DOMAIN][CONF_SCAN_INTERVAL] = scan_interval - config = Config() config.is_c611 = gw == DEFAULT_GW - await hass.async_add_executor_job(Service.init, host, port, scan_interval, config) + service = Service() + hass.data[DOMAIN][entry.entry_id] = service + await hass.async_add_executor_job(service.init, host, port, scan_interval, config) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) entry.async_on_unload(entry.add_update_listener(update_listener)) @@ -47,12 +45,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" - if Service.state_change_listener is not None: - Service.state_change_listener() + service: Service = hass.data[DOMAIN]["service"] + + if service.state_change_listener is not None: + service.state_change_listener() + unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) - Service.destroy() + if not unload_ok: + return False + + service.destroy() - return unload_ok + return True async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: diff --git a/custom_components/ds_air/climate.py b/custom_components/ds_air/climate.py index 71f7f1f..0a8172d 100644 --- a/custom_components/ds_air/climate.py +++ b/custom_components/ds_air/climate.py @@ -46,7 +46,7 @@ get_fan_direction_name, get_mode_name, ) -from .ds_air_service import AirCon, AirConStatus, Config, EnumControl, display, Service +from .ds_air_service import AirCon, AirConStatus, EnumControl, display, Service _SUPPORT_FLAGS = ( @@ -74,10 +74,10 @@ async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up the climate devices.""" - + service: Service = hass.data[DOMAIN][entry.entry_id] climates = [] - for aircon in Service.get_aircons(): - climates.append(DsAir(aircon)) + for aircon in service.get_aircons(): + climates.append(DsAir(service, aircon)) async_add_entities(climates) link = entry.options.get("link") sensor_temp_map: dict[str, list[DsAir]] = {} @@ -107,7 +107,7 @@ async def listener(event: Event): remove_listener = async_track_state_change_event( hass, list(sensor_temp_map.keys()) + list(sensor_humi_map.keys()), listener ) - Service.state_change_listener = remove_listener + service.state_change_listener = remove_listener class DsAir(ClimateEntity): @@ -133,18 +133,19 @@ class DsAir(ClimateEntity): _enable_turn_on_off_backwards_compatibility: bool = False # used in 2024.2~2024.12 - def __init__(self, aircon: AirCon): + def __init__(self, service: Service, aircon: AirCon): _log("create aircon:") _log(str(aircon.__dict__)) _log(str(aircon.status.__dict__)) """Initialize the climate device.""" + self.service = service self._device_info = aircon self._attr_unique_id = aircon.unique_id self.linked_temp_entity_id: str | None = None self.linked_humi_entity_id: str | None = None self._link_cur_temp = False - Service.register_status_hook(aircon, self._status_change_hook) + service.register_status_hook(aircon, self._status_change_hook) self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, self.unique_id)}, @@ -314,7 +315,7 @@ def set_temperature(self, **kwargs) -> None: new_status = AirConStatus() status.setted_temp = round(temperate * 10.0) new_status.setted_temp = round(temperate * 10.0) - Service.control(self._device_info, new_status) + self.service.control(self._device_info, new_status) self.schedule_update_ha_state() def set_humidity(self, humidity: int) -> None: @@ -327,7 +328,7 @@ def set_humidity(self, humidity: int) -> None: new_status = AirConStatus() status.humidity = EnumControl.Humidity(humidity) new_status.humidity = EnumControl.Humidity(humidity) - Service.control(self._device_info, new_status) + self.service.control(self._device_info, new_status) self.schedule_update_ha_state() def set_fan_mode(self, fan_mode: str) -> None: @@ -340,7 +341,7 @@ def set_fan_mode(self, fan_mode: str) -> None: new_status = AirConStatus() status.air_flow = get_air_flow_enum(fan_mode) new_status.air_flow = get_air_flow_enum(fan_mode) - Service.control(self._device_info, new_status) + self.service.control(self._device_info, new_status) self.schedule_update_ha_state() def set_hvac_mode(self, hvac_mode: HVACMode) -> None: @@ -351,7 +352,7 @@ def set_hvac_mode(self, hvac_mode: HVACMode) -> None: if hvac_mode == HVACMode.OFF: status.switch = EnumControl.Switch.OFF new_status.switch = EnumControl.Switch.OFF - Service.control(self._device_info, new_status) + self.service.control(self._device_info, new_status) else: status.switch = EnumControl.Switch.ON new_status.switch = EnumControl.Switch.ON @@ -382,7 +383,7 @@ def set_hvac_mode(self, hvac_mode: HVACMode) -> None: mode = m.SLEEP status.mode = mode new_status.mode = mode - Service.control(self._device_info, new_status) + self.service.control(self._device_info, new_status) self.schedule_update_ha_state() def set_swing_mode(self, swing_mode: str) -> None: @@ -394,7 +395,7 @@ def set_swing_mode(self, swing_mode: str) -> None: new_status.fan_direction1 = self._device_info.status.fan_direction1 status.fan_direction2 = get_fan_direction_enum(swing_mode) new_status.fan_direction2 = get_fan_direction_enum(swing_mode) - Service.control(self._device_info, new_status) + self.service.control(self._device_info, new_status) self.schedule_update_ha_state() def set_preset_mode(self, preset_mode: str) -> None: @@ -418,7 +419,7 @@ def set_preset_mode(self, preset_mode: str) -> None: mode = m.RELAX status.mode = mode new_status.mode = mode - Service.control(self._device_info, new_status) + self.service.control(self._device_info, new_status) self.schedule_update_ha_state() @property diff --git a/custom_components/ds_air/config_flow.py b/custom_components/ds_air/config_flow.py index 1d3cb30..da27f8d 100644 --- a/custom_components/ds_air/config_flow.py +++ b/custom_components/ds_air/config_flow.py @@ -23,7 +23,6 @@ from homeassistant.data_entry_flow import FlowResult from .const import CONF_GW, DEFAULT_GW, DEFAULT_HOST, DEFAULT_PORT, DOMAIN, GW_LIST -from .ds_air_service import Service _LOGGER = logging.getLogger(__name__) @@ -43,30 +42,27 @@ def __init__(self): async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: - if self._async_current_entries(): - return self.async_abort(reason="single_instance_allowed") - errors = {} if user_input is not None: self.user_input.update(user_input) if not user_input.get(CONF_SENSORS) or user_input.get("temp") is not None: return self.async_create_entry(title="金制空气", data=self.user_input) - else: - return self.async_show_form( - step_id="user", - data_schema=vol.Schema( - { - vol.Required("temp", default=True): bool, - vol.Required("humidity", default=True): bool, - vol.Required("pm25", default=True): bool, - vol.Required("co2", default=True): bool, - vol.Required("tvoc", default=True): bool, - vol.Required("voc", default=False): bool, - vol.Required("hcho", default=False): bool, - } - ), - errors=errors, - ) + + return self.async_show_form( + step_id="user", + data_schema=vol.Schema( + { + vol.Required("temp", default=True): bool, + vol.Required("humidity", default=True): bool, + vol.Required("pm25", default=True): bool, + vol.Required("co2", default=True): bool, + vol.Required("tvoc", default=True): bool, + vol.Required("voc", default=False): bool, + vol.Required("hcho", default=False): bool, + } + ), + errors=errors, + ) return self.async_show_form( step_id="user", @@ -84,7 +80,7 @@ async def async_step_user( @staticmethod @callback - def async_get_options_flow(config_entry: ConfigEntry) -> DsAirOptionsFlowHandler: + def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow: """Options callback for DS-AIR.""" return DsAirOptionsFlowHandler(config_entry) @@ -96,10 +92,10 @@ def __init__(self, config_entry: ConfigEntry) -> None: """Initialize options flow.""" self.config_entry = config_entry self._config_data = [] - self._climates = list(map(lambda state: state.alias, Service.get_aircons())) - self._sensors_temp = {} - self._sensors_humi = {} - self._len = len(self._climates) + self._climates: list[str] = [] # set in async_step_init + self._len: int = 0 # set in async_step_init + self._sensors_temp: dict[str, str] = {} + self._sensors_humi: dict[str, str] = {} self._cur = -1 self.user_input = {} @@ -107,6 +103,10 @@ async def async_step_init( self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Manage the options.""" + service = self.hass.data[DOMAIN][self.config_entry.entry_id] + self._climates = list(map(lambda state: state.alias, service.get_aircons())) + self._len = len(self._climates) + sensors = self.hass.states.async_all("sensor") self._sensors_temp = { None: "None", diff --git a/custom_components/ds_air/ds_air_service/decoder.py b/custom_components/ds_air/ds_air_service/decoder.py index 7e0f33c..2436ba3 100644 --- a/custom_components/ds_air/ds_air_service/decoder.py +++ b/custom_components/ds_air/ds_air_service/decoder.py @@ -1,5 +1,7 @@ +from __future__ import annotations + import struct -import typing +from typing import TYPE_CHECKING from .base_bean import BaseBean from .config import Config @@ -34,6 +36,9 @@ Sensor2InfoParam, ) +if TYPE_CHECKING: + from .service import Service + def decoder(b: bytes, config: Config): if b[0] != 2: @@ -187,7 +192,7 @@ def __init__(self, cmd_id: int, targe: EnumDevice, cmd_type: EnumCmdType): def load_bytes(self, b: bytes, config: Config) -> None: """do nothing""" - def do(self) -> None: + def do(self, service: Service) -> None: """do nothing""" @@ -216,7 +221,7 @@ def __init__(self, cmd_id: int, target: EnumDevice): self._mode = 0 self._room_id = 0 self._sensor_type = 0 - self._sensors: typing.List[Sensor] = [] + self._sensors: list[Sensor] = [] def load_bytes(self, b: bytes, config: Config) -> None: data = Decode(b) @@ -302,10 +307,8 @@ def load_bytes(self, b: bytes, config: Config) -> None: self._sensors.append(sensor) count = count - 1 - def do(self) -> None: - from .service import Service - - Service.set_sensors_status(self._sensors) + def do(self, service: Service) -> None: + service.set_sensors_status(self._sensors) @property def count(self): @@ -460,9 +463,9 @@ class GetRoomInfoResult(BaseResult): def __init__(self, cmd_id: int, target: EnumDevice): BaseResult.__init__(self, cmd_id, target, EnumCmdType.SYS_GET_ROOM_INFO) self._count: int = 0 - self._hds: typing.List[HD] = [] - self._sensors: typing.List[Sensor] = [] - self._rooms: typing.List[Room] = [] + self._hds: list[HD] = [] + self._sensors: list[Sensor] = [] + self._rooms: list[Room] = [] def load_bytes(self, b: bytes, config: Config) -> None: ver_flag = 1 @@ -527,17 +530,15 @@ def load_bytes(self, b: bytes, config: Config) -> None: dev.alias = room.alias self.rooms.append(room) - def do(self) -> None: - from .service import Service - - Service.set_rooms(self.rooms) - Service.send_msg(AirConRecommendedIndoorTempParam()) - Service.set_sensors(self.sensors) + def do(self, service: Service) -> None: + service.set_rooms(self.rooms) + service.send_msg(AirConRecommendedIndoorTempParam()) + service.set_sensors(self.sensors) aircons = [] new_aircons = [] bathrooms = [] - for room in Service.get_rooms(): + for room in service.get_rooms(): if room.air_con is not None: room.air_con.alias = room.alias if room.air_con.new_air_con: @@ -550,15 +551,15 @@ def do(self) -> None: p = AirConCapabilityQueryParam() p.aircons = aircons p.target = EnumDevice.AIRCON - Service.send_msg(p) + service.send_msg(p) p = AirConCapabilityQueryParam() p.aircons = new_aircons p.target = EnumDevice.NEWAIRCON - Service.send_msg(p) + service.send_msg(p) p = AirConCapabilityQueryParam() p.aircons = bathrooms p.target = EnumDevice.BATHROOM - Service.send_msg(p) + service.send_msg(p) @property def count(self): @@ -604,13 +605,12 @@ def load_bytes(self, b: bytes, config: Config) -> None: d = Decode(b) self._time = d.read_utf(14) - def do(self) -> None: + def do(self, service: Service) -> None: p = GetRoomInfoParam() p.room_ids.append(0xFFFF) - from .service import Service - Service.send_msg(p) - Service.send_msg(Sensor2InfoParam()) + service.send_msg(p) + service.send_msg(Sensor2InfoParam()) class GetGWInfoResult(BaseResult): @@ -621,7 +621,7 @@ def __init__(self, cmd_id: int, target: EnumDevice): def load_bytes(self, b: bytes, config: Config) -> None: """todo""" - def do(self) -> None: + def do(self, service: Service) -> None: """todo""" @@ -670,10 +670,8 @@ def load_bytes(self, b: bytes, config: Config) -> None: status.fan_direction1 = EnumControl.FanDirection(direction & 0xF) status.fan_direction2 = EnumControl.FanDirection((direction >> 4) & 0xF) - def do(self) -> None: - from .service import Service - - Service.update_aircon(self.target, self._room, self._unit, status=self._status) + def do(self, service: Service) -> None: + service.update_aircon(self.target, self._room, self._unit, status=self._status) class AirConQueryStatusResult(BaseResult): @@ -745,9 +743,7 @@ def load_bytes(self, b: bytes, config: Config) -> None: if flag >> 7 & 1: self.breathe = EnumControl.Breathe(d.read1()) - def do(self) -> None: - from .service import Service - + def do(self, service: Service) -> None: status = AirConStatus( self.current_temp, self.setted_temp, @@ -759,7 +755,7 @@ def do(self) -> None: self.humidity, self.mode, ) - Service.set_aircon_status(self.target, self.room, self.unit, status) + service.set_aircon_status(self.target, self.room, self.unit, status) class AirConRecommendedIndoorTempResult(BaseResult): @@ -787,7 +783,7 @@ def outdoor_temp(self): class AirConCapabilityQueryResult(BaseResult): def __init__(self, cmd_id: int, target: EnumDevice): BaseResult.__init__(self, cmd_id, target, EnumCmdType.AIR_CAPABILITY_QUERY) - self._air_cons: typing.List[AirCon] = [] + self._air_cons: list[AirCon] = [] def load_bytes(self, b: bytes, config: Config) -> None: d = Decode(b) @@ -837,13 +833,11 @@ def load_bytes(self, b: bytes, config: Config) -> None: d.read1() self._air_cons.append(aircon) - def do(self) -> None: - from .service import Service - - if Service.is_ready(): + def do(self, service: Service) -> None: + if service.is_ready(): if len(self._air_cons): for i in self._air_cons: - Service.update_aircon( + service.update_aircon( get_device_by_aircon(i), i.room_id, i.unit_id, aircon=i ) else: @@ -851,10 +845,8 @@ def do(self) -> None: p = AirConQueryStatusParam() p.target = self.target p.device = i - from .service import Service - - Service.send_msg(p) - Service.set_device(self.target, self._air_cons) + service.send_msg(p) + service.set_device(self.target, self._air_cons) @property def aircons(self): diff --git a/custom_components/ds_air/ds_air_service/service.py b/custom_components/ds_air/ds_air_service/service.py index 331bf3f..98970aa 100644 --- a/custom_components/ds_air/ds_air_service/service.py +++ b/custom_components/ds_air/ds_air_service/service.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import logging import socket import time @@ -28,7 +30,7 @@ def _log(s: str): class SocketClient: - def __init__(self, host: str, port: int, config: Config): + def __init__(self, host: str, port: int, service: Service, config: Config): self._host = host self._port = port self._config = config @@ -37,7 +39,7 @@ def __init__(self, host: str, port: int, config: Config): while not self.do_connect(): time.sleep(3) self._ready = True - self._recv_thread = RecvThread(self) + self._recv_thread = RecvThread(self, service) self._recv_thread.start() def destroy(self): @@ -99,9 +101,10 @@ def recv(self) -> (list[BaseResult], bytes): class RecvThread(Thread): - def __init__(self, sock: SocketClient): + def __init__(self, sock: SocketClient, service: Service): super().__init__() self._sock = sock + self._service = service self._locker = Lock() self._running = True @@ -117,15 +120,16 @@ def run(self) -> None: self._locker.acquire() try: if i is not None: - i.do() + i.do(self._service) except Exception as e: _log(e) self._locker.release() class HeartBeatThread(Thread): - def __init__(self): + def __init__(self, service: Service): super().__init__() + self.service = service self._running = True def terminate(self): @@ -136,175 +140,160 @@ def run(self) -> None: time.sleep(30) cnt = 0 while self._running: - Service.send_msg(HeartbeatParam()) + self.service.send_msg(HeartbeatParam()) cnt += 1 - if cnt == Service.get_scan_interval(): + if cnt == self.service.get_scan_interval(): _log("poll_status") cnt = 0 - Service.poll_status() + self.service.poll_status() time.sleep(60) class Service: - _socket_client: SocketClient = None - _rooms: list[Room] = None - _aircons: list[AirCon] = None - _new_aircons: list[AirCon] = None - _bathrooms: list[AirCon] = None - _ready: bool = False - _none_stat_dev_cnt: int = 0 - _status_hook: list[(AirCon, Callable)] = [] - _sensor_hook: list[(str, Callable)] = [] - _heartbeat_thread = None - _sensors: list[Sensor] = [] - _scan_interval: int = 5 - - state_change_listener: Callable[[], None] | None = None - - @staticmethod - def init(host: str, port: int, scan_interval: int, config: Config): - if Service._ready: + def __init__(self): + self._socket_client: SocketClient = None + self._rooms: list[Room] = None + self._aircons: list[AirCon] = None + self._new_aircons: list[AirCon] = None + self._bathrooms: list[AirCon] = None + self._ready: bool = False + self._none_stat_dev_cnt: int = 0 + self._status_hook: list[(AirCon, Callable)] = [] + self._sensor_hook: list[(str, Callable)] = [] + self._heartbeat_thread = None + self._sensors: list[Sensor] = [] + self._scan_interval: int = 5 + self.state_change_listener: Callable[[], None] | None = None + + def init(self, host: str, port: int, scan_interval: int, config: Config) -> None: + if self._ready: return - Service._scan_interval = scan_interval - Service._socket_client = SocketClient(host, port, config) - Service._socket_client.send(HandShakeParam()) - Service._heartbeat_thread = HeartBeatThread() - Service._heartbeat_thread.start() + self._scan_interval = scan_interval + self._socket_client = SocketClient(host, port, self, config) + self._socket_client.send(HandShakeParam()) + self._heartbeat_thread = HeartBeatThread(self) + self._heartbeat_thread.start() while ( - Service._rooms is None - or Service._aircons is None - or Service._new_aircons is None - or Service._bathrooms is None + self._rooms is None + or self._aircons is None + or self._new_aircons is None + or self._bathrooms is None ): time.sleep(1) - for i in Service._aircons: - for j in Service._rooms: + for i in self._aircons: + for j in self._rooms: if i.room_id == j.id: i.alias = j.alias if i.unit_id: i.alias += str(i.unit_id) - for i in Service._new_aircons: - for j in Service._rooms: + for i in self._new_aircons: + for j in self._rooms: if i.room_id == j.id: i.alias = j.alias if i.unit_id: i.alias += str(i.unit_id) - for i in Service._bathrooms: - for j in Service._rooms: + for i in self._bathrooms: + for j in self._rooms: if i.room_id == j.id: i.alias = j.alias if i.unit_id: i.alias += str(i.unit_id) - Service._ready = True - - @staticmethod - def destroy(): - if Service._ready: - Service._heartbeat_thread.terminate() - Service._socket_client.destroy() - Service._socket_client = None - Service._rooms = None - Service._aircons = None - Service._new_aircons = None - Service._bathrooms = None - Service._none_stat_dev_cnt = 0 - Service._status_hook = [] - Service._sensor_hook = [] - Service._heartbeat_thread = None - Service._sensors = [] - Service._ready = False - - @staticmethod - def get_aircons() -> list[AirCon]: + self._ready = True + + def destroy(self) -> None: + if self._ready: + self._heartbeat_thread.terminate() + self._socket_client.destroy() + self._socket_client = None + self._rooms = None + self._aircons = None + self._new_aircons = None + self._bathrooms = None + self._none_stat_dev_cnt = 0 + self._status_hook = [] + self._sensor_hook = [] + self._heartbeat_thread = None + self._sensors = [] + self._ready = False + + def get_aircons(self) -> list[AirCon]: aircons = [] - if Service._new_aircons is not None: - aircons += Service._new_aircons - if Service._aircons is not None: - aircons += Service._aircons - if Service._bathrooms is not None: - aircons += Service._bathrooms + if self._new_aircons is not None: + aircons += self._new_aircons + if self._aircons is not None: + aircons += self._aircons + if self._bathrooms is not None: + aircons += self._bathrooms return aircons - @staticmethod - def control(aircon: AirCon, status: AirConStatus): + def control(self, aircon: AirCon, status: AirConStatus): p = AirConControlParam(aircon, status) - Service.send_msg(p) + self.send_msg(p) - @staticmethod - def register_status_hook(device: AirCon, hook: Callable): - Service._status_hook.append((device, hook)) + def register_status_hook(self, device: AirCon, hook: Callable): + self._status_hook.append((device, hook)) - @staticmethod - def register_sensor_hook(unique_id: str, hook: Callable): - Service._sensor_hook.append((unique_id, hook)) + def register_sensor_hook(self, unique_id: str, hook: Callable): + self._sensor_hook.append((unique_id, hook)) # ----split line---- above for component, below for inner call - @staticmethod - def is_ready() -> bool: - return Service._ready + def is_ready(self) -> bool: + return self._ready - @staticmethod - def send_msg(p: Param): + def send_msg(self, p: Param): """send msg to climate gateway""" - Service._socket_client.send(p) + self._socket_client.send(p) - @staticmethod - def get_rooms(): - return Service._rooms + def get_rooms(self): + return self._rooms - @staticmethod - def set_rooms(v: list[Room]): - Service._rooms = v + def set_rooms(self, v: list[Room]): + self._rooms = v - @staticmethod - def get_sensors(): - return Service._sensors + def get_sensors(self): + return self._sensors - @staticmethod - def set_sensors(sensors): - Service._sensors = sensors + def set_sensors(self, sensors): + self._sensors = sensors - @staticmethod - def set_device(t: EnumDevice, v: list[AirCon]): - Service._none_stat_dev_cnt += len(v) + def set_device(self, t: EnumDevice, v: list[AirCon]): + self._none_stat_dev_cnt += len(v) if t == EnumDevice.AIRCON: - Service._aircons = v + self._aircons = v elif t == EnumDevice.NEWAIRCON: - Service._new_aircons = v + self._new_aircons = v else: - Service._bathrooms = v + self._bathrooms = v - @staticmethod def set_aircon_status( - target: EnumDevice, room: int, unit: int, status: AirConStatus + self, target: EnumDevice, room: int, unit: int, status: AirConStatus ): - if Service._ready: - Service.update_aircon(target, room, unit, status=status) + if self._ready: + self.update_aircon(target, room, unit, status=status) else: li = [] if target == EnumDevice.AIRCON: - li = Service._aircons + li = self._aircons elif target == EnumDevice.NEWAIRCON: - li = Service._new_aircons + li = self._new_aircons elif target == EnumDevice.BATHROOM: - li = Service._bathrooms + li = self._bathrooms for i in li: if i.unit_id == unit and i.room_id == room: i.status = status - Service._none_stat_dev_cnt -= 1 + self._none_stat_dev_cnt -= 1 break - @staticmethod - def set_sensors_status(sensors: list[Sensor]): + def set_sensors_status(self, sensors: list[Sensor]): for new_sensor in sensors: - for sensor in Service._sensors: + for sensor in self._sensors: if sensor.unique_id == new_sensor.unique_id: for attr in STATUS_ATTR: setattr(sensor, attr, getattr(new_sensor, attr)) break - for item in Service._sensor_hook: + for item in self._sensor_hook: unique_id, func = item if new_sensor.unique_id == unique_id: try: @@ -312,19 +301,17 @@ def set_sensors_status(sensors: list[Sensor]): except Exception as e: _log(str(e)) - @staticmethod - def poll_status(): - for i in Service._new_aircons: + def poll_status(self): + for i in self._new_aircons: p = AirConQueryStatusParam() p.target = EnumDevice.NEWAIRCON p.device = i - Service.send_msg(p) + self.send_msg(p) p = Sensor2InfoParam() - Service.send_msg(p) + self.send_msg(p) - @staticmethod - def update_aircon(target: EnumDevice, room: int, unit: int, **kwargs): - li = Service._status_hook + def update_aircon(self, target: EnumDevice, room: int, unit: int, **kwargs): + li = self._status_hook for item in li: i, func = item if ( @@ -338,6 +325,5 @@ def update_aircon(target: EnumDevice, room: int, unit: int, **kwargs): _log("hook error!!") _log(str(e)) - @staticmethod - def get_scan_interval(): - return Service._scan_interval + def get_scan_interval(self): + return self._scan_interval diff --git a/custom_components/ds_air/sensor.py b/custom_components/ds_air/sensor.py index 2d8d26a..5e9fada 100644 --- a/custom_components/ds_air/sensor.py +++ b/custom_components/ds_air/sensor.py @@ -17,11 +17,12 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ): """Perform the setup for Daikin devices.""" + service: Service = hass.data[DOMAIN][config_entry.entry_id] entities = [] - for device in Service.get_sensors(): + for device in service.get_sensors(): for key in SENSOR_DESCRIPTORS: if config_entry.data.get(key): - entities.append(DsSensor(device, SENSOR_DESCRIPTORS.get(key))) + entities.append(DsSensor(service, device, SENSOR_DESCRIPTORS.get(key))) async_add_entities(entities) @@ -32,7 +33,9 @@ class DsSensor(SensorEntity): _attr_should_poll: bool = False - def __init__(self, device: Sensor, description: DsSensorEntityDescription): + def __init__( + self, service: Service, device: Sensor, description: DsSensorEntityDescription + ): """Initialize the Daikin Sensor.""" self.entity_description = description self._data_key: str = description.key @@ -47,7 +50,7 @@ def __init__(self, device: Sensor, description: DsSensorEntityDescription): self.entity_id = f"sensor.daikin_{device.mac}_{self._data_key}" self._parse_data(device) - Service.register_sensor_hook(device.unique_id, self._handle_sensor_hook) + service.register_sensor_hook(device.unique_id, self._handle_sensor_hook) def _parse_data(self, device: Sensor) -> None: """Parse data sent by gateway."""