mirror of
https://github.com/andvikt/mega_hacs.git
synced 2025-12-13 18:14:28 +05:00
- fix http error
This commit is contained in:
@@ -13,40 +13,42 @@ from homeassistant.core import HomeAssistant
|
|||||||
from .const import EVENT_BINARY_SENSOR, DOMAIN, CONF_RESPONSE_TEMPLATE
|
from .const import EVENT_BINARY_SENSOR, DOMAIN, CONF_RESPONSE_TEMPLATE
|
||||||
from .tools import make_ints
|
from .tools import make_ints
|
||||||
from . import hub as h
|
from . import hub as h
|
||||||
_LOGGER = logging.getLogger(__name__).getChild('http')
|
|
||||||
|
_LOGGER = logging.getLogger(__name__).getChild("http")
|
||||||
|
|
||||||
|
|
||||||
def is_ext(data: typing.Dict[str, typing.Any]):
|
def is_ext(data: typing.Dict[str, typing.Any]):
|
||||||
for x in data:
|
for x in data:
|
||||||
if x.startswith('ext'):
|
if x.startswith("ext"):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class MegaView(HomeAssistantView):
|
class MegaView(HomeAssistantView):
|
||||||
|
url = "/mega"
|
||||||
url = '/mega'
|
name = "mega"
|
||||||
name = 'mega'
|
|
||||||
requires_auth = False
|
requires_auth = False
|
||||||
|
|
||||||
def __init__(self, cfg: dict):
|
def __init__(self, cfg: dict):
|
||||||
self._try = 0
|
self._try = 0
|
||||||
self.protected = True
|
self.protected = True
|
||||||
self.allowed_hosts = {'::1', '127.0.0.1'}
|
self.allowed_hosts = {"::1", "127.0.0.1"}
|
||||||
self.notified_attempts = defaultdict(lambda : False)
|
self.notified_attempts = defaultdict(lambda: False)
|
||||||
self.callbacks = defaultdict(lambda: defaultdict(list))
|
self.callbacks = defaultdict(lambda: defaultdict(list))
|
||||||
self.templates: typing.Dict[str, typing.Dict[str, Template]] = {
|
self.templates: typing.Dict[str, typing.Dict[str, Template]] = {
|
||||||
mid: {
|
mid: {
|
||||||
pt: cfg[mid][pt][CONF_RESPONSE_TEMPLATE]
|
pt: cfg[mid][pt][CONF_RESPONSE_TEMPLATE]
|
||||||
for pt in cfg[mid]
|
for pt in cfg[mid]
|
||||||
if isinstance(pt, int) and CONF_RESPONSE_TEMPLATE in cfg[mid][pt]
|
if isinstance(pt, int) and CONF_RESPONSE_TEMPLATE in cfg[mid][pt]
|
||||||
} for mid in cfg if isinstance(cfg[mid], dict)
|
}
|
||||||
|
for mid in cfg
|
||||||
|
if isinstance(cfg[mid], dict)
|
||||||
}
|
}
|
||||||
_LOGGER.debug('templates: %s', self.templates)
|
_LOGGER.debug("templates: %s", self.templates)
|
||||||
self.hubs = {}
|
self.hubs = {}
|
||||||
|
|
||||||
async def get(self, request: Request) -> Response:
|
async def get(self, request: Request) -> Response:
|
||||||
_LOGGER.debug('request from %s %s', request.remote, request.headers)
|
_LOGGER.debug("request from %s %s", request.remote, request.headers)
|
||||||
hass: HomeAssistant = request.app['hass']
|
hass: HomeAssistant = request.app["hass"]
|
||||||
if self.protected:
|
if self.protected:
|
||||||
auth = False
|
auth = False
|
||||||
for x in self.allowed_hosts:
|
for x in self.allowed_hosts:
|
||||||
@@ -54,33 +56,39 @@ class MegaView(HomeAssistantView):
|
|||||||
auth = True
|
auth = True
|
||||||
break
|
break
|
||||||
if not auth:
|
if not auth:
|
||||||
msg = f"Non-authorised request from {request.remote} to `/mega`. "\
|
msg = (
|
||||||
f"If you want to accept requests from this host "\
|
f"Non-authorised request from {request.remote} to `/mega`. "
|
||||||
f"please add it to allowed hosts in `mega` UI-configuration"
|
f"If you want to accept requests from this host "
|
||||||
|
f"please add it to allowed hosts in `mega` UI-configuration"
|
||||||
|
)
|
||||||
if not self.notified_attempts[request.remote]:
|
if not self.notified_attempts[request.remote]:
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
'persistent_notification',
|
"persistent_notification",
|
||||||
'create',
|
"create",
|
||||||
{
|
{
|
||||||
"notification_id": request.remote,
|
"notification_id": request.remote,
|
||||||
"title": "Non-authorised request",
|
"title": "Non-authorised request",
|
||||||
"message": msg
|
"message": msg,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
_LOGGER.warning(msg)
|
_LOGGER.warning(msg)
|
||||||
return Response(status=401)
|
return Response(status=401)
|
||||||
|
|
||||||
remote = request.headers.get('X-Real-IP', request.remote)
|
remote = request.headers.get("X-Real-IP", request.remote)
|
||||||
hub: 'h.MegaD' = self.hubs.get(remote)
|
hub: "h.MegaD" = self.hubs.get(remote)
|
||||||
if hub is None and 'mdid' in request.query:
|
if hub is None and "mdid" in request.query:
|
||||||
hub = self.hubs.get(request.query['mdid'])
|
hub = self.hubs.get(request.query["mdid"])
|
||||||
if hub is None:
|
if hub is None:
|
||||||
_LOGGER.warning(f'can not find mdid={request.query["mdid"]} in {list(self.hubs)}')
|
_LOGGER.warning(
|
||||||
if hub is None and request.remote in ['::1', '127.0.0.1']:
|
f'can not find mdid={request.query["mdid"]} in {list(self.hubs)}'
|
||||||
|
)
|
||||||
|
if hub is None and request.remote in ["::1", "127.0.0.1"]:
|
||||||
try:
|
try:
|
||||||
hub = list(self.hubs.values())[0]
|
hub = list(self.hubs.values())[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
_LOGGER.warning(f'can not find mdid={request.query["mdid"]} in {list(self.hubs)}')
|
_LOGGER.warning(
|
||||||
|
f'can not find mdid={request.query["mdid"]} in {list(self.hubs)}'
|
||||||
|
)
|
||||||
return Response(status=400)
|
return Response(status=400)
|
||||||
elif hub is None:
|
elif hub is None:
|
||||||
return Response(status=400)
|
return Response(status=400)
|
||||||
@@ -91,17 +99,17 @@ class MegaView(HomeAssistantView):
|
|||||||
)
|
)
|
||||||
_LOGGER.debug(f"Request: %s from '%s'", data, request.remote)
|
_LOGGER.debug(f"Request: %s from '%s'", data, request.remote)
|
||||||
make_ints(data)
|
make_ints(data)
|
||||||
if data.get('st') == '1':
|
if data.get("st") == "1":
|
||||||
hass.async_create_task(self.later_restore(hub))
|
hass.async_create_task(self.later_restore(hub))
|
||||||
return Response(status=200)
|
return Response(status=200)
|
||||||
port = data.get('pt')
|
port = data.get("pt")
|
||||||
data = data.copy()
|
data = data.copy()
|
||||||
update_all = True
|
update_all = True
|
||||||
if 'v' in data:
|
if "v" in data:
|
||||||
update_all = False
|
update_all = False
|
||||||
data['value'] = data.pop('v')
|
data["value"] = data.pop("v")
|
||||||
data['mega_id'] = hub.id
|
data["mega_id"] = hub.id
|
||||||
ret = 'd' if hub.force_d else ''
|
ret = "d" if hub.force_d else ""
|
||||||
if port is not None:
|
if port is not None:
|
||||||
if is_ext(data):
|
if is_ext(data):
|
||||||
# ret = '' # пока ответ всегда пустой, неясно какая будет реакция на непустой ответ
|
# ret = '' # пока ответ всегда пустой, неясно какая будет реакция на непустой ответ
|
||||||
@@ -110,49 +118,70 @@ class MegaView(HomeAssistantView):
|
|||||||
else:
|
else:
|
||||||
pt_orig = hub.ext_in.get(port, hub.ext_in.get(str(port)))
|
pt_orig = hub.ext_in.get(port, hub.ext_in.get(str(port)))
|
||||||
if pt_orig is None:
|
if pt_orig is None:
|
||||||
hub.lg.warning(f'can not find extender for int port {port}, '
|
hub.lg.warning(
|
||||||
f'have ext_int: {hub.ext_in}, ext: {hub.extenders}')
|
f"can not find extender for int port {port}, "
|
||||||
|
f"have ext_int: {hub.ext_in}, ext: {hub.extenders}"
|
||||||
|
)
|
||||||
return Response(status=200)
|
return Response(status=200)
|
||||||
for e, v in data.items():
|
for e, v in data.items():
|
||||||
_data = data.copy()
|
_data = data.copy()
|
||||||
if e.startswith('ext'):
|
if e.startswith("ext"):
|
||||||
idx = e[3:]
|
idx = e[3:]
|
||||||
pt = f'{pt_orig}e{idx}' if not hub.new_naming else f'{int(pt_orig):02d}e{int(idx):02d}'
|
pt = (
|
||||||
_data['pt_orig'] = pt_orig
|
f"{pt_orig}e{idx}"
|
||||||
_data['value'] = 'ON' if v == '1' else 'OFF'
|
if not hub.new_naming
|
||||||
_data['m'] = 1 if _data[e] == '0' else 0 # имитация поведения обычного входа, чтобы события обрабатывались аналогично
|
else f"{int(pt_orig):02d}e{int(idx):02d}"
|
||||||
|
)
|
||||||
|
_data["pt_orig"] = pt_orig
|
||||||
|
_data["value"] = "ON" if v == "1" else "OFF"
|
||||||
|
_data["m"] = (
|
||||||
|
1 if _data[e] == "0" else 0
|
||||||
|
) # имитация поведения обычного входа, чтобы события обрабатывались аналогично
|
||||||
hub.values[pt] = _data
|
hub.values[pt] = _data
|
||||||
for cb in self.callbacks[hub.id][pt]:
|
for cb in self.callbacks[hub.id][pt]:
|
||||||
cb(_data)
|
cb(_data)
|
||||||
act = hub.ext_act.get(pt)
|
act = hub.ext_act.get(pt)
|
||||||
hub.lg.debug(f'act on port {pt}: {act}, all acts are: {hub.ext_act}')
|
hub.lg.debug(
|
||||||
template: Template = self.templates.get(hub.id, {}).get(port, hub.def_response)
|
f"act on port {pt}: {act}, all acts are: {hub.ext_act}"
|
||||||
|
)
|
||||||
|
template: Template = self.templates.get(hub.id, {}).get(
|
||||||
|
port, hub.def_response
|
||||||
|
)
|
||||||
if template is not None:
|
if template is not None:
|
||||||
template.hass = hass
|
template.hass = hass
|
||||||
ret = template.async_render(_data)
|
ret = template.async_render(_data)
|
||||||
hub.lg.debug(f'response={ret}, template={template}')
|
hub.lg.debug(f"response={ret}, template={template}")
|
||||||
if ret == 'd' and act:
|
if ret == "d" and act:
|
||||||
await hub.request(cmd=act.replace(':3', f':{v}'))
|
await hub.request(cmd=act.replace(":3", f":{v}"))
|
||||||
ret = 'd' if hub.force_d else ''
|
ret = "d" if hub.force_d else ""
|
||||||
else:
|
else:
|
||||||
# elif port in hub.binary_sensors:
|
# elif port in hub.binary_sensors:
|
||||||
hub.values[port] = data
|
hub.values[port] = data
|
||||||
for cb in self.callbacks[hub.id][port]:
|
for cb in self.callbacks[hub.id][port]:
|
||||||
cb(data)
|
cb(data)
|
||||||
template: Template = self.templates.get(hub.id, {}).get(port, hub.def_response)
|
template: Template = self.templates.get(hub.id, {}).get(
|
||||||
|
port, hub.def_response
|
||||||
|
)
|
||||||
if template is not None:
|
if template is not None:
|
||||||
template.hass = hass
|
template.hass = hass
|
||||||
ret = template.async_render(data)
|
ret = template.async_render(data)
|
||||||
if hub.update_all and update_all:
|
if hub.update_all and update_all:
|
||||||
asyncio.create_task(self.later_update(hub))
|
asyncio.create_task(self.later_update(hub))
|
||||||
_LOGGER.debug('response %s', ret)
|
_LOGGER.debug("response %s", ret)
|
||||||
Response(body='' if hub.fake_response else ret, content_type='text/plain')
|
Response(body="" if hub.fake_response else ret, content_type="text/plain")
|
||||||
|
|
||||||
if hub.fake_response and 'value' not in data and 'pt' in data and port in hub.binary_sensors:
|
if (
|
||||||
if 'd' in ret:
|
hub.fake_response
|
||||||
|
and "value" not in data
|
||||||
|
and "pt" in data
|
||||||
|
and port in hub.binary_sensors
|
||||||
|
):
|
||||||
|
if "d" in ret:
|
||||||
await hub.request(pt=port, cmd=ret)
|
await hub.request(pt=port, cmd=ret)
|
||||||
else:
|
else:
|
||||||
await hub.request(cmd=ret)
|
await hub.request(cmd=ret)
|
||||||
|
if not isinstance(ret, str):
|
||||||
|
return ""
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
async def later_restore(self, hub):
|
async def later_restore(self, hub):
|
||||||
@@ -169,5 +198,5 @@ class MegaView(HomeAssistantView):
|
|||||||
|
|
||||||
async def later_update(self, hub):
|
async def later_update(self, hub):
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
_LOGGER.debug('force update')
|
_LOGGER.debug("force update")
|
||||||
await hub.updater.async_refresh()
|
await hub.updater.async_refresh()
|
||||||
Reference in New Issue
Block a user