Skip to content

Commit

Permalink
исправлена структура папок
Browse files Browse the repository at this point in the history
  • Loading branch information
and7ey authored Jun 4, 2024
1 parent 06f88ef commit c865c46
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 90 deletions.
9 changes: 9 additions & 0 deletions custom_components/haier_evo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,23 @@

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.loader import async_get_integration
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:
integration = await async_get_integration(hass, DOMAIN)
_LOGGER.debug(f'Integration version: {integration.version}')

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(
Expand Down
126 changes: 84 additions & 42 deletions custom_components/haier_evo/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 @@ -115,21 +117,24 @@ def pull_data(self):
and "application/json" in resp.headers.get("content-type")
and resp.json().get("data", {}).get("presentation", {}).get("layout", {}).get('scrollContainer', [])
):
_LOGGER.debug(resp.text)
containers = resp.json().get("data", {}).get("presentation", {}).get("layout", {}).get('scrollContainer', [])
for item in containers:
if item.get("contractName", "") == "deviceList":
state_data = item.get("state", {})
state_json = json.loads(state_data)
# haierevo://device?deviceId=12:34:56:78:90:68&type=AC&serialNum=AAC0M1E0000000000000&uitype=AC_BASE
device_title = state_json.get('items', [{}])[0].get('title', '') # only one device is supported
device_link = state_json.get('items', [{}])[0].get('action', {}).get('link', '')
parsed_link = urlparse(device_link)
query_params = parse_qs(parsed_link.query)
device_mac = query_params.get('deviceId', [''])[0]
device_mac = device_mac.replace('%3A', ':')
device_serial = query_params.get('serialNum', [''])[0]
_LOGGER.debug(f"Received device successfully, device title {device_title}, device mac {device_mac}, device serial {device_serial}")
self.devices.append(HaierAC(device_mac, device_serial, device_title, self))
devices = state_json.get('items', [{}])
for d in devices:
# haierevo://device?deviceId=12:34:56:78:90:68&type=AC&serialNum=AAC0M1E0000000000000&uitype=AC_BASE
device_title = d.get('title', '') # only one device is supported
device_link = d.get('action', {}).get('link', '')
parsed_link = urlparse(device_link)
query_params = parse_qs(parsed_link.query)
device_mac = query_params.get('deviceId', [''])[0]
device_mac = device_mac.replace('%3A', ':')
device_serial = query_params.get('serialNum', [''])[0]
_LOGGER.debug(f"Received device successfully, device title {device_title}, device mac {device_mac}, device serial {device_serial}")
self.devices.append(HaierAC(device_mac, device_serial, device_title, self))
break

else:
Expand All @@ -155,16 +160,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 @@ -173,11 +182,20 @@ 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
# 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.debug(f"Getting initial status of device {self._id}, url: {status_url}")
_LOGGER.info(f"Getting initial status of device {self._id}, url: {status_url}")
resp = requests.get(
status_url,
headers={"X-Auth-token": self._haier._token}
Expand All @@ -187,17 +205,33 @@ def __init__(self, device_mac: str, device_serial: str, device_title: str, haier
and resp.json().get("attributes", {})
):
_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 @@ -248,8 +282,10 @@ def _on_message(self, ws: websocket.WebSocket, message: str) -> None:
self._handle_status_update(message_dict)
elif message_type == "command_response":
pass
elif message_type == "info":
pass
else:
_LOGGER.error(f"Got unknown message of type: {message_type}")
_LOGGER.debug(f"Got unknown message of type: {message_type}")



Expand All @@ -274,19 +310,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 @@ -319,7 +354,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 @@ -385,37 +424,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 @@ -427,28 +467,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 custom_components/haier_evo/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.warning(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 c865c46

Please sign in to comment.