Skip to content

Commit

Permalink
Конфигурация устройств вынесена в отдельные файлы
Browse files Browse the repository at this point in the history
  • Loading branch information
and7ey authored May 28, 2024
1 parent a28ef6c commit 578d005
Show file tree
Hide file tree
Showing 12 changed files with 329 additions and 80 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#### Серия Coral
<details>
<summary>AS20HPL1HRA</summary>

- Поддерживается
- Отображение текущей температуры
- Включение/выключение
Expand Down
27 changes: 27 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from __future__ import annotations

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
import asyncio
from . import api
from .const import DOMAIN
import logging
_LOGGER = logging.getLogger(__name__)
PLATFORMS: list[str] = ["climate"]

async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
haier_object = api.Haier(hass, entry.data["email"], entry.data["password"])
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = haier_object
await hass.async_add_executor_job(
haier_object.pull_data
)

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True

async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)

return unload_ok
98 changes: 66 additions & 32 deletions api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
from homeassistant.core import HomeAssistant
from homeassistant import config_entries, exceptions
from urllib.parse import urlparse, parse_qs
from . import yaml_helper

import websocket
from websocket._exceptions import WebSocketConnectionClosedException
from websocket._exceptions import WebSocketConnectionClosedException, WebSocketException
from enum import Enum



SST_CLOUD_API_URL = "https://api.sst-cloud.com/"
API_PATH = "https://evo.haieronline.ru"
API_LOGIN = "v1/users/auth/sign-in"
Expand Down Expand Up @@ -156,16 +158,20 @@ class SocketStatus(Enum):
NOT_INITIALIZED = 3





class HaierAC:
def __init__(self, device_mac: str, device_serial: str, device_title: str, haier: Haier):
self._haier = haier

self._hass:HomeAssistant = haier.hass

self._id = device_mac
self.model_name = "AC"
self._device_name = device_title

# the following values are updated below
self.model_name = "AC"
self._current_temperature = 0
self._target_temperature = 0
self._status = None
Expand All @@ -174,10 +180,17 @@ def __init__(self, device_mac: str, device_serial: str, device_title: str, haier
self._min_temperature = 7
self._max_temperature = 35
self._sw_version = None

self._disconnect_requested = False
# config values, updated below
self._config = None
self._config_current_temperature = None
self._config_mode = None
self._config_fan_mode = None
self._config_status = None
self._config_target_temperature = None
self._config_command_name = None


self._disconnect_requested = False

status_url = API_STATUS.replace("{mac}", self._id)
_LOGGER.info(f"Getting initial status of device {self._id}, url: {status_url}")
Expand All @@ -191,17 +204,32 @@ def __init__(self, device_mac: str, device_serial: str, device_title: str, haier
):
_LOGGER.debug(f"Update device {self._id} status code: {resp.status_code}")
_LOGGER.debug(resp.text)
device_info = resp.json().get("info", {})
device_model = device_info.get("model", "AC")
_LOGGER.debug(f"Device model {device_model}")
self.model_name = device_model
self._config = yaml_helper.DeviceConfig(device_model)

# read config values
self._config_current_temperature = self._config.get_id_by_name('current_temperature')
self._config_mode = self._config.get_id_by_name('mode')
self._config_fan_mode = self._config.get_id_by_name('fan_mode')
self._config_status = self._config.get_id_by_name('status')
self._config_target_temperature = self._config.get_id_by_name('target_temperature')
self._config_command_name = self._config.get_command_name()
_LOGGER.debug(f"The following values are used: current temp - {self._config_current_temperature}, mode - {self._config_mode}, fan speed - {self._config_fan_mode}, status - {self._config_status}, target temp - {self._config_target_temperature}")

attributes = resp.json().get("attributes", {})
for attr in attributes:
if attr.get('name', '') == "0": # Температура в комнате
if attr.get('name', '') == self._config_current_temperature: # Температура в комнате
self._current_temperature = int(attr.get('currentValue'))
if attr.get('name', '') == "5": # Режимы (0 - Авто, 1 - Охлаждение, 4 - Нагрев, 6 - Вентилятор, 2 - Осушение)
elif attr.get('name', '') == self._config_mode: # Режимы
self._mode = int(attr.get('currentValue'))
if attr.get('name', '') == "6": # Скорость вентилятора (0 - Авто, 1 - Охлаждение, 4 - Нагрев, 6 - Вентилятор, 2 - Осушение)
self._mode = int(attr.get('currentValue'))
if attr.get('name', '') == "21": # Включение/выключение
elif attr.get('name', '') == self._config_fan_mode: # Скорость вентилятора
self._fan_mode = int(attr.get('currentValue'))
elif attr.get('name', '') == self._config_status: # Включение/выключение
self._status = int(attr.get('currentValue'))
if attr.get('name', '') == "31": # Целевая температура
elif attr.get('name', '') == self._config_target_temperature: # Целевая температура
self._target_temperature = int(attr.get('currentValue'))
self._min_temperature = int(attr.get('range', {}).get('data', {}).get('minValue', 0))
self._max_temperature = int(attr.get('range', {}).get('data', {}).get('maxValue', 0))
Expand Down Expand Up @@ -280,19 +308,18 @@ def _handle_status_update(self, received_message: dict) -> None:
_LOGGER.debug(f"Received status update, message_id {message_id}")

for key, value in message_statuses[0]['properties'].items():
if key == "0": # Температура в комнате
if key == self._config_current_temperature: # Температура в комнате
self._current_temperature = int(value)
if key == "5": # Режимы (0 - Авто, 1 - Охлаждение, 4 - Нагрев, 6 - Вентилятор, 2 - Осушение)
self._mode = int(value)
if key == "6": # Скорость вентилятора (0 - Авто, 1 - Охлаждение, 4 - Нагрев, 6 - Вентилятор, 2 - Осушение)
self._fan_mode = int(value)
if key == "21": # Включение/выключение
if key == self._config_mode: # Режимы
self._mode = self._config.get_value_from_mappings(self._config_mode, int(value))
if key == self._config_fan_mode: # Скорость вентилятора
self._fan_mode = self._config.get_value_from_mappings(self._config_fan_mode, int(value))
if key == self._config_status: # Включение/выключение
self._status = int(value)
if key == "31": # Целевая температура
if key == self._config_target_temperature: # Целевая температура
self._target_temperature = int(value)



def _on_open(self, ws: websocket.WebSocket) -> None:
_LOGGER.debug("Websocket opened")

Expand Down Expand Up @@ -325,7 +352,11 @@ def connect(self) -> None:
]:
self._socket_status = SocketStatus.INITIALIZING
_LOGGER.info(f"Connecting to websocket ({API_WS_PATH})")
self._socket_app.run_forever()
try:
self._socket_app.run_forever()
except WebSocketException: # websocket._exceptions.WebSocketException: socket is already opened
pass

else:
_LOGGER.info(
f"Can not attempt socket connection because of current "
Expand Down Expand Up @@ -391,37 +422,38 @@ def get_fan_mode(self) -> str:
def get_status(self) -> str:
return self._status


def setTemperature(self, temp) -> None:
self._target_temperature = temp

self._send_message(json.dumps(
{
"action": "operation",
"macAddress": self._id,
"commandName": "3",
"commandName": self._config_command_name,
"commands": [
{
"commandName": "31",
"commandName": self._config_target_temperature,
"value": str(temp)
}
]
}))

def switchOn(self, hvac_mode=0) -> None: # default hvac mode is 0 - Авто
def switchOn(self, hvac_mode="auto") -> None:
hvac_mode_haier = self._config.get_haier_code_from_mappings(self._config_mode, hvac_mode)

self._send_message(json.dumps(
{
"action": "operation",
"macAddress": self._id,
"commandName": "3",
"commandName": self._config_command_name,
"commands": [
{
"commandName": "21",
"commandName": self._config_status,
"value": "1"
},
{
"commandName": "5",
"value": str(hvac_mode)
"commandName": self._config_mode,
"value": str(hvac_mode_haier)
}
]
}))
Expand All @@ -433,28 +465,30 @@ def switchOff(self) -> None:
{
"action": "operation",
"macAddress": self._id,
"commandName": "3",
"commandName": self._config_command_name,
"commands": [
{
"commandName": "21",
"commandName": self._config_status,
"value": "0"
}
]
}))
self._status = 0

def setFanMode(self, fan_mode) -> None:
fan_mode_haier = self._config.get_haier_code_from_mappings(self._config_fan_mode, fan_mode)

self._fan_mode = fan_mode

self._send_message(json.dumps(
{
"action": "operation",
"macAddress": self._id,
"commandName": "3",
"commandName": self._config_command_name,
"commands": [
{
"commandName": "6",
"value": str(fan_mode)
"commandName": self._config_fan_mode,
"value": str(fan_mode_haier)
}
]
}))
56 changes: 10 additions & 46 deletions climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,52 +72,26 @@ def turn_off(self):
@property
def hvac_mode(self) -> str:
"""Return hvac operation ie. heat, cool mode."""

if self._module.get_status == 1:
# (0 - Авто, 1 - Охлаждение, 4 - Нагрев, 6 - Вентилятор, 2 - Осушение)
if self._module.get_mode == 0:
return HVACMode.AUTO
if self._module.get_mode == 1:
return HVACMode.COOL
if self._module.get_mode == 2:
return HVACMode.DRY
if self._module.get_mode == 4:
return HVACMode.HEAT
if self._module.get_mode == 6:
return HVACMode.FAN_ONLY
return self._module.get_mode
return HVACMode.OFF

def set_hvac_mode(self, hvac_mode: str) -> None:
"""Set new target hvac mode."""
_LOGGER.debug(f"set_hvac_mode {hvac_mode}")
_LOGGER.debug(f"Setting HVAC mode to {hvac_mode}")
if hvac_mode == HVACMode.OFF:
self._module.switchOff()
else:
if hvac_mode == HVACMode.AUTO:
hvac_mode_int = 0
elif hvac_mode == HVACMode.COOL:
hvac_mode_int = 1
elif hvac_mode == HVACMode.DRY:
hvac_mode_int = 2
elif hvac_mode == HVACMode.HEAT:
hvac_mode_int = 4
elif hvac_mode == HVACMode.FAN_ONLY:
hvac_mode_int = 6

self._module.switchOn(hvac_mode_int)
self._module.switchOn(hvac_mode)

def set_fan_mode(self, fan_mode):
# FAN_AUTO - 5, FAN_LOW - 3, FAN_MEDIUM - 2, FAN_HIGH - 1
if fan_mode == FAN_HIGH:
fan_mode_int = 1
if fan_mode == FAN_MEDIUM:
fan_mode_int = 2
if fan_mode == FAN_LOW:
fan_mode_int = 3
if fan_mode == FAN_AUTO:
fan_mode_int = 5
"""Set new target fan mode."""
_LOGGER.debug(f"Setting fan mode to {fan_mode}")
self._module.setFanMode(fan_mode)

self._module.setFanMode(fan_mode_int)
@property
def fan_mode(self) -> str:
return self._module.get_fan_mode


def update(self) -> None:
Expand All @@ -144,17 +118,7 @@ def current_temperature(self) -> float:
def target_temperature(self) -> float:
return self._module.get_target_temperature

@property
def fan_mode(self) -> str:
# FAN_AUTO - 5, FAN_LOW - 3, FAN_MEDIUM - 2, FAN_HIGH - 1
if self._module.get_fan_mode == 1:
return FAN_HIGH
if self._module.get_fan_mode == 2:
return FAN_MEDIUM
if self._module.get_fan_mode == 3:
return FAN_LOW
if self._module.get_fan_mode == 5:
return FAN_AUTO


@property
def device_info(self):
Expand Down
Loading

0 comments on commit 578d005

Please sign in to comment.