Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add telnet_password for ShellE1 and ShellMGW2 #1454

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ Only for Xiaomi Multimode Gateway 1:
- **Host** - gateway IP-address, should be fixed on your Wi-Fi router
- **Token** - gateway Mi Home token, changed only when you add gateway to Mi Home app
- **Key** - gateway secret key, [read more](https://github.com/AlexxIT/Blog/issues/13)
- **Telnet Password** - gateway(`Aqara_Hub_E1` or `Mijia_Hub_V2`) telnet password. Password will setup while adding integration(keep field empty if you don't want setup password), or you need change both integration config and password in telnet(`passwd` or `chpasswd`) later.
- **Add statistic sensors** - [read more](#statistics-table)
- **Debug logs** - enable different levels of logging ([read more](#debug-mode))

Expand Down
3 changes: 3 additions & 0 deletions custom_components/xiaomi_gateway3/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ async def async_step_user(self, user_input: dict = None):
vol.Required("host", default=device["localip"]): str,
vol.Required("token", default=device["token"]): str,
vol.Optional("key"): str,
vol.Optional("telnet_password"): str,
}
),
)
Expand Down Expand Up @@ -121,6 +122,7 @@ async def async_step_token(self, user_input: dict = None):
vol.Required("host"): str,
vol.Required("token"): str,
vol.Optional("key"): str,
vol.Optional("telnet_password"): str,
},
user_input,
)
Expand Down Expand Up @@ -189,6 +191,7 @@ async def async_step_user(self, user_input: dict = None):
vol.Required("host"): str,
vol.Required("token"): str,
vol.Optional("key"): str,
vol.Optional("telnet_password"): str,
vol.Optional("stats"): vol.In(
{
False: "Disabled", # for backward compatibility
Expand Down
17 changes: 8 additions & 9 deletions custom_components/xiaomi_gateway3/core/core_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ async def check_port(host: str, port: int) -> bool:
s.close()


async def gateway_info(host: str, token: str = None, key: str = None) -> dict | None:
async def gateway_info(host: str, token: str = None, key: str = None, telnet_password: str = None) -> dict | None:
# Strategy:
# 1. Check open telnet and return host, did, token, key
# 2. Try to enable telnet using host, token and (optionaly) key
# 3. Check open telnet again
# 4. Return error
try:
async with Session(host) as sh:
async with Session(host, telnet_password = telnet_password) as sh:
info = await sh.get_miio_info()
info["host"] = host
return info
Expand All @@ -41,24 +41,23 @@ async def gateway_info(host: str, token: str = None, key: str = None) -> dict |
return None

# try to enable telnet and return miio info
result = await enable_telnet(host, token, key)
result = await enable_telnet(host, token, key, telnet_password)

# waiting for telnet to start
await asyncio.sleep(1)

# call with empty token so only telnet will check
if info := await gateway_info(host):
if info := await gateway_info(host, telnet_password = telnet_password):
return info

# result ok, but telnet can't be opened
return {"error": "wrong_telnet" if result == "ok" else result}


# universal command for open telnet on all models
TELNET_CMD = "passwd -d $USER; riu_w 101e 53 3012 || echo enable > /sys/class/tty/tty/enable; telnetd"
TELNET_CMD = 'echo "$USER:%s" | chpasswd; riu_w 101e 53 3012 || echo enable > /sys/class/tty/tty/enable; telnetd;'


async def enable_telnet(host: str, token: str, key: str = None) -> str:
async def enable_telnet(host: str, token: str, key: str = None, telnet_password: str = None) -> str:
# Strategy:
# 1. Get miio info
miio = AsyncMiIO(host, token)
Expand Down Expand Up @@ -92,11 +91,11 @@ async def enable_telnet(host: str, token: str, key: str = None) -> str:
if method == "enable_telnet_service":
params = None
elif method == "set_ip_info":
params = {"ssid": '""', "pswd": "1; " + TELNET_CMD}
params = {"ssid": '""', "pswd": "1; " + TELNET_CMD % (telnet_password or "")}
elif method == "system_command":
params = {
"password": miio_password(miio.device_id, miio_info["mac"], key),
"command": TELNET_CMD,
"command": TELNET_CMD % (telnet_password or ""),
}
else:
raise NotImplementedError(method)
Expand Down
2 changes: 1 addition & 1 deletion custom_components/xiaomi_gateway3/core/gate/openmiio.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def openmiio_on_timer(self, ts: float):

async def openmiio_restart(self):
try:
async with Session(self.host) as sh:
async with Session(self.host, telnet_password = self.options["telnet_password"]) as sh:
if await sh.only_one():
await self.openmiio_prepare_gateway(sh)
except Exception as e:
Expand Down
4 changes: 2 additions & 2 deletions custom_components/xiaomi_gateway3/core/gate/silabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ async def silabs_process_unknown(self, uid: str):
async def silabs_process_join(self, data: dict):
self.debug("silabs_process_join", data=data)
try:
async with Session(self.host) as sh:
async with Session(self.host, telnet_password = self.options["telnet_password"]) as sh:
# check if model should be prevented from unpairing
if self.force_pair or not data["model"].startswith(("lumi.", "ikea.")):
self.force_pair = False
Expand Down Expand Up @@ -287,7 +287,7 @@ async def silabs_process_neighbors(self, device: XDevice, data: dict):

async def silabs_restart(self):
try:
async with Session(self.host) as sh:
async with Session(self.host, telnet_password = self.options["telnet_password"]) as sh:
# names for all supported gateway models
await sh.exec("killall Lumi_Z3GatewayHost_MQTT mZ3GatewayHost_MQTT")
except Exception as e:
Expand Down
6 changes: 3 additions & 3 deletions custom_components/xiaomi_gateway3/core/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async def enable_telnet(self) -> bool:
return False
try:
resp = await core_utils.enable_telnet(
self.host, token, self.options.get("key")
self.host, token, self.options.get("key"), self.options.get("telnet_password")
)
self.debug("enable_telnet", data=resp)
return resp == "ok"
Expand All @@ -73,7 +73,7 @@ async def enable_telnet(self) -> bool:

async def prepare_gateway(self) -> bool:
try:
async with Session(self.host) as sh:
async with Session(self.host, telnet_password = self.options["telnet_password"]) as sh:
if not await sh.only_one():
self.debug("Connection from a second Hass detected")
return False
Expand Down Expand Up @@ -167,7 +167,7 @@ async def send(self, device: XDevice, data: dict):
async def telnet_command(self, cmd: str) -> bool | None:
self.debug("telnet_command", data=cmd)
try:
async with Session(self.host) as sh:
async with Session(self.host, telnet_password = self.options["telnet_password"]) as sh:
if cmd == "run_ftp":
await sh.run_ftp()
return True
Expand Down
3 changes: 2 additions & 1 deletion custom_components/xiaomi_gateway3/core/shell/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@


class ShellBase:
def __init__(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
def __init__(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter, telnet_password: str = None):
self.reader = reader
self.writer = writer
self.telnet_password = telnet_password

async def close(self):
if not self.writer:
Expand Down
9 changes: 5 additions & 4 deletions custom_components/xiaomi_gateway3/core/shell/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
class Session:
reader: asyncio.StreamReader
writer: asyncio.StreamWriter
telnet_password: str

def __init__(self, host: str, port=23):
def __init__(self, host: str, port=23, telnet_password: str = None):
self.telnet_password = telnet_password
self.coro = asyncio.open_connection(host, port, limit=1_000_000)

async def __aenter__(self):
Expand All @@ -29,13 +31,12 @@ async def close(self):
async def login(self) -> ShellMGW | ShellE1 | ShellMGW2:
coro = self.reader.readuntil(b"login: ")
resp: bytes = await asyncio.wait_for(coro, 3)

if b"rlxlinux" in resp:
shell = ShellMGW(self.reader, self.writer)
elif b"Aqara-Hub-E1" in resp or b"Aqara_Hub_E1" in resp:
shell = ShellE1(self.reader, self.writer)
shell = ShellE1(self.reader, self.writer, telnet_password = self.telnet_password)
elif b"Mijia_Hub_V2" in resp:
shell = ShellMGW2(self.reader, self.writer)
shell = ShellMGW2(self.reader, self.writer, telnet_password = self.telnet_password)
else:
raise Exception(f"Unknown response: {resp}")

Expand Down
4 changes: 3 additions & 1 deletion custom_components/xiaomi_gateway3/core/shell/shell_e1.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ class ShellE1(ShellBase):
async def login(self):
self.writer.write(b"root\n")
await asyncio.sleep(0.1)
self.writer.write(b"\n") # empty password
if self.telnet_password:
self.writer.write(str.encode(self.telnet_password))
self.writer.write(b"\n")

coro = self.reader.readuntil(b" # ")
await asyncio.wait_for(coro, timeout=3)
Expand Down
3 changes: 2 additions & 1 deletion custom_components/xiaomi_gateway3/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"data": {
"host": "Host",
"token": "Token",
"key": "Key"
"key": "Key",
"telnet_password": "Telnet Password"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion custom_components/xiaomi_gateway3/translations/zh-Hans.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"data": {
"host": "网关IP",
"token": "Token",
"key": "Key"
"key": "Key",
"telnet_password": "Telnet密码"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion custom_components/xiaomi_gateway3/translations/zh-Hant.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"data": {
"host": "網關IP",
"token": "Token",
"key": "Key"
"key": "Key",
"telnet_password": "Telnet密碼"
}
}
}
Expand Down
Loading