Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
dscao authored Nov 30, 2022
1 parent 208cbd8 commit 3decaf4
Show file tree
Hide file tree
Showing 5 changed files with 476 additions and 25 deletions.
43 changes: 25 additions & 18 deletions custom_components/ikuai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

_LOGGER = logging.getLogger(__name__)

PLATFORMS: list[Platform] = [Platform.SENSOR]
PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.BUTTON, Platform.SWITCH]


async def async_setup(hass: HomeAssistant, config: Config) -> bool:
Expand Down Expand Up @@ -96,6 +96,7 @@ def __init__(self, hass, host, username, passwd, pas, update_interval_seconds):
_LOGGER.debug("%s Data will be update every %s", host, update_interval)
self._token = ""
self._token_expire_time = 0
self._allow_login = True

super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=update_interval)

Expand All @@ -106,25 +107,31 @@ async def get_access_token(self):
if time.time() < self._token_expire_time:
return self._token
else:
self._token = await self._fetcher._login_ikuai()
self._token_expire_time = time.time() + 60*60*2
return self._token
if self._allow_login == True:
self._token = await self._fetcher._login_ikuai()
if self._token == 10001:
self._allow_login = False
self._token_expire_time = time.time() + 60*60*2
return self._token
else:
return

async def _async_update_data(self):
"""Update data via DataFetcher."""
_LOGGER.debug("token_expire_time=%s", self._token_expire_time)

sess_key = await self.get_access_token()
_LOGGER.debug(sess_key)
if self._allow_login == True:

try:
async with timeout(10):
data = await self._fetcher.get_data(sess_key)
if data == 401:
self._token_expire_time = 0
return
if not data:
raise UpdateFailed("failed in getting data")
return data
except Exception as error:
raise UpdateFailed(error) from error
sess_key = await self.get_access_token()
_LOGGER.debug(sess_key)

try:
async with timeout(10):
data = await self._fetcher.get_data(sess_key)
if data == 401:
self._token_expire_time = 0
return
if not data:
raise UpdateFailed("failed in getting data")
return data
except Exception as error:
raise UpdateFailed(error) from error
175 changes: 175 additions & 0 deletions custom_components/ikuai/button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
"""IKUAI Entities"""
import logging
import time
import datetime
import json
import re
import requests
from async_timeout import timeout
from aiohttp.client_exceptions import ClientConnectorError

from homeassistant.helpers.device_registry import DeviceEntryType

from homeassistant.components.button import ButtonEntity

from .const import (
COORDINATOR,
DOMAIN,
BUTTON_TYPES,
CONF_USERNAME,
CONF_PASSWD,
CONF_PASS,
CONF_HOST,
ACTION_URL,
)

from .data_fetcher import DataFetcher

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass, config_entry, async_add_entities):
"""Add bjtoon_health_code entities from a config_entry."""

coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR]
host = config_entry.data[CONF_HOST]
username = config_entry.data[CONF_USERNAME]
passwd = config_entry.data[CONF_PASSWD]
pas = config_entry.data[CONF_PASS]

buttons = []
for button in BUTTON_TYPES:
buttons.append(IKUAIButton(hass, button, coordinator, host, username, passwd, pas))

async_add_entities(buttons, False)


class IKUAIButton(ButtonEntity):
"""Define an bjtoon_health_code entity."""

def __init__(self, hass, kind, coordinator, host, username, passwd, pas):
"""Initialize."""
super().__init__()
self.kind = kind
self.coordinator = coordinator
self._state = None
self._attr_device_info = {
"identifiers": {(DOMAIN, self.coordinator.host)},
"name": self.coordinator.data["device_name"],
"manufacturer": "iKuai",
"model": "iKuai Router",
"sw_version": self.coordinator.data["sw_version"],
}
self._attr_device_class = "restart"
self._attr_entity_registry_enabled_default = True
self._hass = hass
self._token = ""
self._token_expire_time = 0
self._allow_login = True
self._fetcher = DataFetcher(hass, host, username, passwd, pas)
self._host = host


async def get_access_token(self):
if time.time() < self._token_expire_time:
return self._token
else:
if self._allow_login == True:
self._token = await self._fetcher._login_ikuai()
if self._token == 10001:
self._allow_login = False
self._token_expire_time = time.time() + 60*60*2
return self._token
else:
return

@property
def name(self):
"""Return the name."""
return f"{BUTTON_TYPES[self.kind]['name']}"

@property
def unique_id(self):
return f"{DOMAIN}_{self.kind}_{self.coordinator.host}"

@property
def should_poll(self):
"""Return the polling requirement of the entity."""
return True

@property
def state(self):
"""Return the state."""
return self._state


@property
def device_class(self):
"""Return the unit_of_measurement."""
if BUTTON_TYPES[self.kind].get("device_class"):
return BUTTON_TYPES[self.kind]["device_class"]


def press(self) -> None:
"""Handle the button press."""

async def async_press(self) -> None:
"""Handle the button press."""
await self._ikuai_action(BUTTON_TYPES[self.kind]["action_body"])


async def async_added_to_hass(self):
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)

async def async_update(self):
"""Update Bjtoon health code entity."""
await self.coordinator.async_request_refresh()


def requestpost_json(self, url, headerstr, json_body):
responsedata = requests.post(url, headers=headerstr, json = json_body, verify=False)
if responsedata.status_code != 200:
return responsedata.status_code
json_text = responsedata.content.decode('utf-8')
resdata = json.loads(json_text)
return resdata

async def _ikuai_action(self, action_body):
if self._allow_login == True:
sess_key = await self.get_access_token()
header = {
'Cookie': 'Cookie: username=admin; login=1; sess_key='+sess_key,
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
'Content-Type': 'application/json;charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.40 Safari/537.36',
}

json_body = action_body

url = self._host + ACTION_URL

try:
async with timeout(10):
resdata = await self._hass.async_add_executor_job(self.requestpost_json, url, header, json_body)
except (
ClientConnectorError
) as error:
raise UpdateFailed(error)
_LOGGER.debug("Requests remaining: %s", url)
_LOGGER.debug(resdata)
if resdata == 401:
self._data = 401
return
if resdata["Result"] == 10014:
self._data = 401
return

self._state = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
_LOGGER.info("操作ikuai: %s ", json_body)
return "OK"

20 changes: 18 additions & 2 deletions custom_components/ikuai/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"unit_of_measurement": "MB/s",
},
"ikuai_wan_ip": {
"icon": "mdi:wan",
"icon": "mdi:ip-network-outline",
"label": "WAN IP",
"name": "ikuai_wan_ip",
},
Expand All @@ -90,8 +90,24 @@
"name": "ikuai_wan_uptime",
},
"ikuai_wan6_ip": {
"icon": "mdi:wan",
"icon": "mdi:ip-network",
"label": "WAN IP6",
"name": "ikuai_wan6_ip",
},
}


BUTTON_TYPES = {
"ikuai_restart": {
"label": "Ikuai重启",
"name": "ikuai_restart",
"device_class": "restart",
"action_body": {"func_name":"wan","action":"link_dhcp_reconnect","param":{"id":1}}
},
"ikuai_restart_reconnect_wan": {
"label": "ikuai重连wan网络",
"name": "ikuai_reconnect_wan",
"device_class": "restart",
"action_body": {"func_name":"wan","action":"link_dhcp_reconnect","param":{"id":1}}
},
}
52 changes: 47 additions & 5 deletions custom_components/ikuai/data_fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,12 @@ async def _login_ikuai(self):
try:
async with timeout(10):
resdata = await self._hass.async_add_executor_job(self.requestpost_cookies, url, header, json_body)
_LOGGER.debug("login_successfully for IKUAI")
_LOGGER.debug(resdata)
if isinstance(resdata, list):
_LOGGER.debug("iKuai Username or Password is wrong,please reconfig!")
return resdata.get("Result")
else:
_LOGGER.debug("login_successfully for IKUAI")
except (
ClientConnectorError
) as error:
Expand Down Expand Up @@ -133,7 +138,7 @@ async def _get_ikuai_status(self, sess_key):
ClientConnectorError
) as error:
raise UpdateFailed(error)
_LOGGER.debug("Requests remaining: %s", url)
_LOGGER.debug("Requests remaining: %s: %s", url, json_body)
_LOGGER.debug(resdata)
if resdata == 401:
self._data = 401
Expand All @@ -142,7 +147,7 @@ async def _get_ikuai_status(self, sess_key):
self._data = 401
return

self._data = {}
self._data = {}

self._data["sw_version"] = resdata["Data"]["sysstat"]["verinfo"]["verstring"]
self._data["device_name"] = resdata["Data"]["sysstat"]["hostname"]
Expand Down Expand Up @@ -193,7 +198,7 @@ async def _get_ikuai_waninfo(self, sess_key):
ClientConnectorError
) as error:
raise UpdateFailed(error)
_LOGGER.debug("Requests remaining: %s", url)
_LOGGER.debug("Requests remaining: %s: %s", url, json_body)
_LOGGER.debug(resdata)
if resdata == 401:
self._data = 401
Expand Down Expand Up @@ -237,7 +242,7 @@ async def _get_ikuai_wan6info(self, sess_key):
ClientConnectorError
) as error:
raise UpdateFailed(error)
_LOGGER.debug("Requests remaining: %s", url)
_LOGGER.debug("Requests remaining: %s: %s", url, json_body)
_LOGGER.debug(resdata)
if resdata == 401:
self._data = 401
Expand All @@ -252,6 +257,42 @@ async def _get_ikuai_wan6info(self, sess_key):
self._data["ikuai_wan6_ip"] = ""
return

async def _get_ikuai_mac_control(self, sess_key):
header = {
'Cookie': 'Cookie: username=admin; login=1; sess_key='+sess_key,
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
'Content-Type': 'application/json;charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.40 Safari/537.36',
}

json_body = {"func_name":"acl_mac","action":"show","param":{"TYPE":"total,data","limit":"0,100","ORDER_BY":"","ORDER":""}}


url = self._host + ACTION_URL

try:
async with timeout(10):
resdata = await self._hass.async_add_executor_job(self.requestpost_json, url, header, json_body)
except (
ClientConnectorError
) as error:
raise UpdateFailed(error)
_LOGGER.debug("Requests remaining: %s: %s", url, json_body)
_LOGGER.debug(resdata)
if resdata == 401:
self._data = 401
return
if resdata["Result"] == 10014:
self._data = 401
return
if resdata["Data"].get("data"):
self._data["mac_control"] = resdata["Data"].get("data")
else:
self._data["mac_control"] = ""
return


async def get_data(self, sess_key):
threads = [
Expand All @@ -262,6 +303,7 @@ async def get_data(self, sess_key):
threads = [
self._get_ikuai_waninfo(sess_key),
self._get_ikuai_wan6info(sess_key),
self._get_ikuai_mac_control(sess_key),
]
await asyncio.wait(threads)
_LOGGER.debug(self._data)
Expand Down
Loading

0 comments on commit 3decaf4

Please sign in to comment.