Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Михаил Шутов committed Jan 25, 2024
2 parents c929090 + f855846 commit 9138b57
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 21 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@
![pydantic version](https://img.shields.io/badge/pydantic-ha-yellowgreen?style=plastic&logo=fastapi)
![aiohttp version](https://img.shields.io/badge/aiohttp-ha-yellowgreen?style=plastic)
![Home Assistant](https://img.shields.io/badge/HomeAssistant-latest-yellowgreen?style=plastic&logo=homeassistant)


[![Donate](https://img.shields.io/badge/donate-Tinkoff-FFDD2D.svg)](https://www.tinkoff.ru/rm/shutov.mikhail19/wUyu873109)

## Описание
Компонент для управления устройствами [ZONT](https://zont-online.ru/) из Home Assistant.

Для входа в ваш аккаунт потребуется токен. Токен можно получить [здесь](https://lk.zont-online.ru/widget-api/v2).
Для входа в ваш аккаунт потребуется токен. Его можно получить из Home Assistant.
При добавлении устройства нажмите галочку "Получить токен". При каждом получении токена
создаётся новый. Что бы их не плодить на аккаунте ZONT, запишите полученный токен.
Как удалить токен описано [здесь](https://lk.zont-online.ru/widget-api/v2).

После авторизации в Home Assistant (далее НА) добавляются все устройства аккаунта.

Expand Down
118 changes: 103 additions & 15 deletions custom_components/zont_ha/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import base64
import logging
import re
from http import HTTPStatus
Expand All @@ -6,20 +7,49 @@

from homeassistant import config_entries
from homeassistant.core import HomeAssistant
from .const import DOMAIN
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN, URL_GET_TOKEN
from .core.exceptions import RequestAPIZONTError, InvalidMail
from .core.models_zont import ErrorZont, TokenZont
from .core.zont import Zont

_LOGGER = logging.getLogger(__name__)


async def validate_auth(hass: HomeAssistant, mail: str, token: str) -> None:
async def get_token(
hass: HomeAssistant, mail: str, login: str, password: str
) -> str:
session = async_get_clientsession(hass)
encoded = f'{login}:{password}'.encode("utf-8")
basic = base64.b64encode(encoded).decode()
headers = {
'Authorization': f'Basic {basic}',
'X-ZONT-Client': mail,
'Content-Type': 'application/json'
}
response = await session.post(
url=URL_GET_TOKEN,
json={'client_name': 'Home Assistant'},
headers=headers
)
text = await response.text()
status_code = response.status
if status_code != HTTPStatus.OK:
error = ErrorZont.parse_raw(text)
hass.data['error'] = error.error_ui
raise RequestAPIZONTError(error)
data = TokenZont.parse_raw(text)
return data.token


async def validate_auth_token(
hass: HomeAssistant, mail: str, token: str
) -> None:
"""Валидация токена zont"""

zont = Zont(hass, mail, token)

result = await zont.get_update()
_LOGGER.debug(f'validate_auth: {result}')
if result != HTTPStatus.OK:
hass.data['error'] = zont.error
raise RequestAPIZONTError
Expand All @@ -37,37 +67,95 @@ def validate_mail(mail: str) -> None:


class ZontConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
VERSION = 1
VERSION = 2
data: dict = None

async def async_step_user(self, user_input=None):
errors: dict[str, str] = {}
if user_input is not None:
try:
_LOGGER.debug(user_input)
validate_mail(user_input['mail'])
await validate_auth(
if not errors:
self.data = user_input
if user_input.get('get_token', False):
return await self.async_step_auth_pswd()
else:
return await self.async_step_auth_token()
except InvalidMail:
_LOGGER.error(f"{user_input['mail']} - неверный формат")
errors['base'] = 'invalid_mail'
except Exception as e:
_LOGGER.error(f'Что-то пошло не так, неизвестная ошибка. {e}')
errors["base"] = "unknown"
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(schema="name"): str,
vol.Required(schema="mail"): str,
vol.Optional(schema="get_token"): bool
}
),
errors=errors
)

async def async_step_auth_pswd(self, user_input=None):
errors: dict[str, str] = {}
if user_input is not None:
try:
token = await get_token(
self.hass,
self.data['mail'],
user_input['login'],
user_input['password']
)
if not errors:
self.data['token'] = token
return await self.async_step_auth_token()
except RequestAPIZONTError:
_LOGGER.error(self.hass.data['error'])
errors['base'] = 'invalid_auth'
except Exception as e:
_LOGGER.error(f'Что-то пошло не так, неизвестная ошибка. {e}')
errors["base"] = "unknown"
return self.async_show_form(
step_id="auth_pswd",
data_schema=vol.Schema(
{
vol.Required("login"): str,
vol.Required("password"): str
}
),
errors=errors
)

async def async_step_auth_token(self, user_input=None):
errors: dict[str, str] = {}
if user_input is not None:
try:
await validate_auth_token(
self.hass,
user_input['mail'], user_input['token']
self.data['mail'],
user_input['token']
)
if not errors:
self.data.update(user_input)
return self.async_create_entry(
title=user_input['name'], data=user_input
title=self.data['name'], data=self.data
)
except InvalidMail:
_LOGGER.error(f"{user_input['mail']} - неверный формат")
errors['base'] = 'invalid_mail'
except RequestAPIZONTError:
_LOGGER.error(self.hass.data['error'])
errors['base'] = 'invalid_auth'
except Exception as e:
_LOGGER.error(f'Что-то пошло не так, неизвестная ошибка. {e}')
errors["base"] = "unknown"
return self.async_show_form(
step_id="user",
step_id="auth_token",
data_schema=vol.Schema(
{
vol.Required("name"): str,
vol.Required("mail"): str,
vol.Required("token"): str
vol.Required(
schema="token", default=self.data.get('token', None)
): str
}
),
errors=errors
Expand Down
4 changes: 2 additions & 2 deletions custom_components/zont_ha/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
DOMAIN = 'zont_ha'
MANUFACTURER = 'MicroLine'

ZONT_API_URL = "https://lk.zont-online.ru/api/widget/v2/"
ZONT_API_URL = 'https://lk.zont-online.ru/api/widget/v2/'

URL_SEND_COMMAND_ZONT_OLD = "https://lk.zont-online.ru/api/send_z3k_command"
URL_SEND_COMMAND_ZONT_OLD = 'https://lk.zont-online.ru/api/send_z3k_command'

URL_GET_DEVICES = 'https://lk.zont-online.ru/api/widget/v2/get_devices'
URL_SET_TARGET_TEMP = 'https://lk.zont-online.ru/api/widget/v2/set_target_temp'
Expand Down
8 changes: 8 additions & 0 deletions custom_components/zont_ha/core/models_zont.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ class AccountZont(BaseModel):
ok: bool


class TokenZont(BaseModel):
"""Клас ответа получения токена"""

token: str
token_id: str
ok: bool


class ErrorZont(BaseModel):
"""Клас ответа об ошибке"""

Expand Down
2 changes: 1 addition & 1 deletion custom_components/zont_ha/core/zont.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def __init__(self, hass: HomeAssistantType, mail: str, token: str):
}
self.mail = mail
self.session = async_get_clientsession(hass)
_LOGGER.warning(f'Создан объект Zont')
_LOGGER.debug(f'Создан объект Zont')

async def get_update(self):
"""Получаем обновление данных объекта Zont"""
Expand Down
2 changes: 1 addition & 1 deletion custom_components/zont_ha/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "hub",
"dependencies": ["http", "zeroconf"],
"requirements": [],
"version": "0.1.5"
"version": "0.2.0"
}
15 changes: 14 additions & 1 deletion custom_components/zont_ha/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,20 @@
"data": {
"name": "Название",
"mail": "mail",
"token": "токен аккаунта"
"get_token": "Получить токен"
}
},
"auth_pswd": {
"title": "Получить токен",
"data": {
"login": "Логин",
"password": "Пароль"
}
},
"auth_token": {
"title": "Авторизация в ZONT",
"data": {
"token": "Токен"
}
}
}
Expand Down

0 comments on commit 9138b57

Please sign in to comment.