mirror of
https://github.com/tomaae/homeassistant-mikrotik_router.git
synced 2025-07-24 12:34:31 +02:00
Allow integration to run with limited access rights #235
This commit is contained in:
parent
ac789a81c2
commit
58f931ad8e
3 changed files with 110 additions and 4 deletions
|
@ -174,9 +174,9 @@ Use integration master branch instead of latest release to keep up with RouterOS
|
||||||
|
|
||||||
## Setup integration
|
## Setup integration
|
||||||
1. Create user for homeassistant on your mikrotik router with following permissions:
|
1. Create user for homeassistant on your mikrotik router with following permissions:
|
||||||
* read, write, api, test, policy
|
* read, write, api, reboot, policy
|
||||||
2. If you want to be able to execute scripts on your mikrotik router from HA, script needs to have only following policies:
|
2. If you want to be able to execute scripts on your mikrotik router from HA, script needs to have only following policies:
|
||||||
* read, write, test
|
* read, write
|
||||||
or check "Don't Require Permissions" option
|
or check "Don't Require Permissions" option
|
||||||
3. Setup this integration for your Mikrotik device in Home Assistant via `Configuration -> Integrations -> Add -> Mikrotik Router`.
|
3. Setup this integration for your Mikrotik device in Home Assistant via `Configuration -> Integrations -> Add -> Mikrotik Router`.
|
||||||
You can add this integration several times for different devices.
|
You can add this integration several times for different devices.
|
||||||
|
|
|
@ -106,6 +106,7 @@ class MikrotikControllerData:
|
||||||
self.host = config_entry.data[CONF_HOST]
|
self.host = config_entry.data[CONF_HOST]
|
||||||
|
|
||||||
self.data = {
|
self.data = {
|
||||||
|
"access": {},
|
||||||
"routerboard": {},
|
"routerboard": {},
|
||||||
"resource": {},
|
"resource": {},
|
||||||
"health": {},
|
"health": {},
|
||||||
|
@ -181,7 +182,7 @@ class MikrotikControllerData:
|
||||||
self.major_fw_version = 0
|
self.major_fw_version = 0
|
||||||
|
|
||||||
self.async_mac_lookup = AsyncMacLookup()
|
self.async_mac_lookup = AsyncMacLookup()
|
||||||
# self.async_mac_lookup.update_vendors()
|
self.accessrights_reported = False
|
||||||
|
|
||||||
async def async_init(self):
|
async def async_init(self):
|
||||||
self.listeners.append(
|
self.listeners.append(
|
||||||
|
@ -491,7 +492,10 @@ class MikrotikControllerData:
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
|
|
||||||
await self.hass.async_add_executor_job(self.get_firmware_update)
|
await self.hass.async_add_executor_job(self.get_access)
|
||||||
|
|
||||||
|
if self.api.connected():
|
||||||
|
await self.hass.async_add_executor_job(self.get_firmware_update)
|
||||||
|
|
||||||
if self.api.connected():
|
if self.api.connected():
|
||||||
await self.hass.async_add_executor_job(self.get_system_resource)
|
await self.hass.async_add_executor_job(self.get_system_resource)
|
||||||
|
@ -685,6 +689,48 @@ class MikrotikControllerData:
|
||||||
async_dispatcher_send(self.hass, self.signal_update)
|
async_dispatcher_send(self.hass, self.signal_update)
|
||||||
self.lock.release()
|
self.lock.release()
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# get_access
|
||||||
|
# ---------------------------
|
||||||
|
def get_access(self):
|
||||||
|
"""Get access rights from Mikrotik"""
|
||||||
|
tmp_user = parse_api(
|
||||||
|
data={},
|
||||||
|
source=self.api.query("/user"),
|
||||||
|
key="name",
|
||||||
|
vals=[
|
||||||
|
{"name": "name"},
|
||||||
|
{"name": "group"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
tmp_group = parse_api(
|
||||||
|
data={},
|
||||||
|
source=self.api.query("/user/group"),
|
||||||
|
key="name",
|
||||||
|
vals=[
|
||||||
|
{"name": "name"},
|
||||||
|
{"name": "policy"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.data["access"] = tmp_group[
|
||||||
|
tmp_user[self.config_entry.data[CONF_USERNAME]]["group"]
|
||||||
|
]["policy"].split(",")
|
||||||
|
|
||||||
|
if not self.accessrights_reported:
|
||||||
|
self.accessrights_reported = True
|
||||||
|
if (
|
||||||
|
"write" not in self.data["access"]
|
||||||
|
or "policy" not in self.data["access"]
|
||||||
|
or "reboot" not in self.data["access"]
|
||||||
|
):
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Mikrotik %s user %s does not have sufficient access rights. Integration functionality will be limited.",
|
||||||
|
self.host,
|
||||||
|
self.config_entry.data[CONF_USERNAME],
|
||||||
|
)
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
# get_interface
|
# get_interface
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
@ -1330,11 +1376,26 @@ class MikrotikControllerData:
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
"write" not in self.data["access"]
|
||||||
|
or "policy" not in self.data["access"]
|
||||||
|
or "reboot" not in self.data["access"]
|
||||||
|
):
|
||||||
|
self.data["routerboard"].pop("current-firmware")
|
||||||
|
self.data["routerboard"].pop("upgrade-firmware")
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
# get_system_health
|
# get_system_health
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
def get_system_health(self):
|
def get_system_health(self):
|
||||||
"""Get routerboard data from Mikrotik"""
|
"""Get routerboard data from Mikrotik"""
|
||||||
|
if (
|
||||||
|
"write" not in self.data["access"]
|
||||||
|
or "policy" not in self.data["access"]
|
||||||
|
or "reboot" not in self.data["access"]
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
if 0 < self.major_fw_version < 7:
|
if 0 < self.major_fw_version < 7:
|
||||||
self.data["health"] = parse_api(
|
self.data["health"] = parse_api(
|
||||||
data=self.data["health"],
|
data=self.data["health"],
|
||||||
|
@ -1467,6 +1528,9 @@ class MikrotikControllerData:
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
def get_firmware_update(self):
|
def get_firmware_update(self):
|
||||||
"""Check for firmware update on Mikrotik"""
|
"""Check for firmware update on Mikrotik"""
|
||||||
|
if "write" not in self.data["access"] or "policy" not in self.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
self.execute("/system/package/update", "check-for-updates", None, None)
|
self.execute("/system/package/update", "check-for-updates", None, None)
|
||||||
self.data["fw-update"] = parse_api(
|
self.data["fw-update"] = parse_api(
|
||||||
data=self.data["fw-update"],
|
data=self.data["fw-update"],
|
||||||
|
|
|
@ -70,6 +70,9 @@ class MikrotikSwitch(MikrotikEntity, SwitchEntity, RestoreEntity):
|
||||||
|
|
||||||
async def async_turn_on(self) -> None:
|
async def async_turn_on(self) -> None:
|
||||||
"""Turn on the switch."""
|
"""Turn on the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = self.entity_description.data_reference
|
param = self.entity_description.data_reference
|
||||||
value = self._data[self.entity_description.data_reference]
|
value = self._data[self.entity_description.data_reference]
|
||||||
|
@ -79,6 +82,9 @@ class MikrotikSwitch(MikrotikEntity, SwitchEntity, RestoreEntity):
|
||||||
|
|
||||||
async def async_turn_off(self) -> None:
|
async def async_turn_off(self) -> None:
|
||||||
"""Turn off the switch."""
|
"""Turn off the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = self.entity_description.data_reference
|
param = self.entity_description.data_reference
|
||||||
value = self._data[self.entity_description.data_reference]
|
value = self._data[self.entity_description.data_reference]
|
||||||
|
@ -125,6 +131,9 @@ class MikrotikPortSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_on(self) -> Optional[str]:
|
async def async_turn_on(self) -> Optional[str]:
|
||||||
"""Turn on the switch."""
|
"""Turn on the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = self.entity_description.data_reference
|
param = self.entity_description.data_reference
|
||||||
if self._data["about"] == "managed by CAPsMAN":
|
if self._data["about"] == "managed by CAPsMAN":
|
||||||
|
@ -144,6 +153,9 @@ class MikrotikPortSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_off(self) -> Optional[str]:
|
async def async_turn_off(self) -> Optional[str]:
|
||||||
"""Turn off the switch."""
|
"""Turn off the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = self.entity_description.data_reference
|
param = self.entity_description.data_reference
|
||||||
if self._data["about"] == "managed by CAPsMAN":
|
if self._data["about"] == "managed by CAPsMAN":
|
||||||
|
@ -170,6 +182,9 @@ class MikrotikNATSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_on(self) -> None:
|
async def async_turn_on(self) -> None:
|
||||||
"""Turn on the switch."""
|
"""Turn on the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = ".id"
|
param = ".id"
|
||||||
value = None
|
value = None
|
||||||
|
@ -187,6 +202,9 @@ class MikrotikNATSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_off(self) -> None:
|
async def async_turn_off(self) -> None:
|
||||||
"""Turn off the switch."""
|
"""Turn off the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = ".id"
|
param = ".id"
|
||||||
value = None
|
value = None
|
||||||
|
@ -211,6 +229,9 @@ class MikrotikMangleSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_on(self) -> None:
|
async def async_turn_on(self) -> None:
|
||||||
"""Turn on the switch."""
|
"""Turn on the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = ".id"
|
param = ".id"
|
||||||
value = None
|
value = None
|
||||||
|
@ -229,6 +250,9 @@ class MikrotikMangleSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_off(self) -> None:
|
async def async_turn_off(self) -> None:
|
||||||
"""Turn off the switch."""
|
"""Turn off the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = ".id"
|
param = ".id"
|
||||||
value = None
|
value = None
|
||||||
|
@ -254,6 +278,9 @@ class MikrotikFilterSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_on(self) -> None:
|
async def async_turn_on(self) -> None:
|
||||||
"""Turn on the switch."""
|
"""Turn on the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = ".id"
|
param = ".id"
|
||||||
value = None
|
value = None
|
||||||
|
@ -271,6 +298,9 @@ class MikrotikFilterSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_off(self) -> None:
|
async def async_turn_off(self) -> None:
|
||||||
"""Turn off the switch."""
|
"""Turn off the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = ".id"
|
param = ".id"
|
||||||
value = None
|
value = None
|
||||||
|
@ -295,6 +325,9 @@ class MikrotikQueueSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_on(self) -> None:
|
async def async_turn_on(self) -> None:
|
||||||
"""Turn on the switch."""
|
"""Turn on the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = ".id"
|
param = ".id"
|
||||||
value = None
|
value = None
|
||||||
|
@ -308,6 +341,9 @@ class MikrotikQueueSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_off(self) -> None:
|
async def async_turn_off(self) -> None:
|
||||||
"""Turn off the switch."""
|
"""Turn off the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = ".id"
|
param = ".id"
|
||||||
value = None
|
value = None
|
||||||
|
@ -328,6 +364,9 @@ class MikrotikKidcontrolPauseSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_on(self) -> None:
|
async def async_turn_on(self) -> None:
|
||||||
"""Turn on the switch."""
|
"""Turn on the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = self.entity_description.data_reference
|
param = self.entity_description.data_reference
|
||||||
value = self._data[self.entity_description.data_reference]
|
value = self._data[self.entity_description.data_reference]
|
||||||
|
@ -337,6 +376,9 @@ class MikrotikKidcontrolPauseSwitch(MikrotikSwitch):
|
||||||
|
|
||||||
async def async_turn_off(self) -> None:
|
async def async_turn_off(self) -> None:
|
||||||
"""Turn off the switch."""
|
"""Turn off the switch."""
|
||||||
|
if "write" not in self._ctrl.data["access"]:
|
||||||
|
return
|
||||||
|
|
||||||
path = self.entity_description.data_switch_path
|
path = self.entity_description.data_switch_path
|
||||||
param = self.entity_description.data_reference
|
param = self.entity_description.data_reference
|
||||||
value = self._data[self.entity_description.data_reference]
|
value = self._data[self.entity_description.data_reference]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue