kennedyshead / aioasuswrt Goto Github PK
View Code? Open in Web Editor NEWLicense: MIT License
License: MIT License
Currently while running the asuswrt integration using Home Assistants a lot of Timeout errors and IncompleteRead exceptions are happening. A pull request has been opened on home-assistant/core that partially fixes this.
My feeling is that the underlying issue in the library is not nicely handling a persistent connection in one AsusWrt instance (at least for the TelnetConnection). Currently there is a race issue if two commands are happening (which probably causes the IncompleteRead exceptions). While the Timeouts are probably due to the router not being able to quickly handle consecutive logins.
My proposed solution would be to do simply try to write a command (assuming self._writer is not None
), and capture the relevant exceptions if a logout has happened. I'm currently running a test with increasing delays to see what exceptions is actually raised.
I am running the latest home assistant (0.84.6) and the sensors are always returning 0 with my RT-N66U running merlin 380.70
I have done some investigation and home assistant is correctly calling async_update()
(https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/sensor/asuswrt.py#L51) in sensors/asuswrt.py
Looking into the implementation of async_get_packets_total
, it seems to be failing at this line in this library: https://github.com/kennedyshead/aioasuswrt/blob/master/aioasuswrt/asuswrt.py#L194
Essentially _IP_LINK_CMD
is defined as ip -rc 1024 -s link
Running that on the router yields:
admin@RT-N66U:/tmp/home/root# ip -rc 1024 -s link
Option "-rc" is unknown, try "ip -help".
ip -s link
does work, I assume returning the result in bits rather than bytes.
A potential fix could be to convert to bytes in python rather than the shell command (there's a lot of math already happening in python already, so it's not really making the solution less elegant I think).
If this sounds sensible to you, I can supply a PR with this fix.
On the RT-AC86U, the debug script displays this:
DEBUG:asyncio:Using selector: SelectSelector
DEBUG:__main__:wl
C:\Users\Maciek\AppData\Local\Programs\hass\lib\site-packages\asyncssh\crypto\ec.py:176: CryptographyDeprecationWarning: encode_point has been deprecated on EllipticCurvePublicNumbers and will be removed in a future version. Please use EllipticCurvePublicKey.public_bytes to obtain both compressed and uncompressed point encoding.
return pub.encode_point()
C:\Users\Maciek\AppData\Local\Programs\hass\lib\site-packages\asyncssh\crypto\ec.py:182: CryptographyDeprecationWarning: Support for unsafe construction of public numbers from encoded data will be removed in a future version. Please use EllipticCurvePublicKey.from_encoded_point
self._priv_key.curve, peer_public).public_key(backend)
C:\Users\Maciek\AppData\Local\Programs\hass\lib\site-packages\asyncssh\crypto\ec.py:144: CryptographyDeprecationWarning: Support for unsafe construction of public numbers from encoded data will be removed in a future version. Please use EllipticCurvePublicKey.from_encoded_point
public_value)
DEBUG:__main__:['assoclist xx:xx:xx:xx:C0:9D', 'assoclist xx:xx:xx:xx:6F:0B', 'assoclist xx:xx:xx:xx:91:84', 'assoclist xx:xx:xx:xx:95:EF', 'assoclist xx:xx:xx:xx:97:61', 'assoclist xx:xx:xx:xx:7C:81', 'assoclist xx:xx:xx:xx:24:75', 'assoclist xx:xx:xx:xx:26:04', 'assoclist xx:xx:xx:xx:89:00', 'assoclist xx:xx:xx:xx:91:EA', 'assoclist xx:xx:xx:xx:0C:FA', 'assoclist xx:xx:xx:xx:20:26', 'assoclist xx:xx:xx:xx:07:FC', 'assoclist xx:xx:xx:xx:53:24', 'assoclist xx:xx:xx:xx:D8:0D', 'assoclist xx:xx:xx:xx:9D:59', 'assoclist xx:xx:xx:xx:BA:34', 'assoclist xx:xx:xx:xx:98:B6', '']
DEBUG:__main__:{'xx:xx:xx:xx:C0:9D': Device(mac='xx:xx:xx:xx:C0:9D', ip=None, name=None), 'xx:xx:xx:xx:6F:0B': Device(mac='xx:xx:xx:xx:6F:0B', ip=None, name=None), 'xx:xx:xx:xx:91:84': Device(mac='xx:xx:xx:xx:91:84', ip=None, name=None), 'xx:xx:xx:xx:95:EF': Device(mac='xx:xx:xx:xx:95:EF', ip=None, name=None), 'xx:xx:xx:xx:97:61': Device(mac='xx:xx:xx:xx:97:61', ip=None, name=None), 'xx:xx:xx:xx:7C:81': Device(mac='xx:xx:xx:xx:7C:81', ip=None, name=None), 'xx:xx:xx:xx:24:75': Device(mac='xx:xx:xx:xx:24:75', ip=None, name=None), 'xx:xx:xx:xx:26:04': Device(mac='xx:xx:xx:xx:26:04', ip=None, name=None), 'xx:xx:xx:xx:89:00': Device(mac='xx:xx:xx:xx:89:00', ip=None, name=None), 'xx:xx:xx:xx:91:EA': Device(mac='xx:xx:xx:xx:91:EA', ip=None, name=None), 'xx:xx:xx:xx:0C:FA': Device(mac='xx:xx:xx:xx:0C:FA', ip=None, name=None), 'xx:xx:xx:xx:20:26': Device(mac='xx:xx:xx:xx:20:26', ip=None, name=None), 'xx:xx:xx:xx:07:FC': Device(mac='xx:xx:xx:xx:07:FC', ip=None, name=None), 'xx:xx:xx:xx:53:24': Device(mac='xx:xx:xx:xx:53:24', ip=None, name=None), 'xx:xx:xx:xx:D8:0D': Device(mac='xx:xx:xx:xx:D8:0D', ip=None, name=None), 'xx:xx:xx:xx:9D:59': Device(mac='xx:xx:xx:xx:9D:59', ip=None, name=None), 'xx:xx:xx:xx:BA:34': Device(mac='xx:xx:xx:xx:BA:34', ip=None, name=None), 'xx:xx:xx:xx:98:B6': Device(mac='xx:xx:xx:xx:98:B6', ip=None, name=None)}
DEBUG:__main__:arp
DEBUG:__main__:['? (192.168.2.200) at xx:xx:xx:xx:6e:5a [ether] on br0', '? (192.168.2.90) at xx:xx:xx:xx:6f:0b [ether] on br0', '? (192.168.2.249) at xx:xx:xx:xx:b6:aa [ether] on br0', '? (192.168.2.110) at xx:xx:xx:xx:95:ef [ether] on br0', '? (192.168.2.240) at xx:xx:xx:xx:89:00 [ether] on br0', '? (192.168.2.40) at xx:xx:xx:xx:56:f4 [ether] on br0', '? (192.168.2.150) at xx:xx:xx:xx:d8:0d [ether] on br0', '? (192.168.2.47) at <incomplete> on br0', '? (192.168.2.115) at xx:xx:xx:xx:9d:59 [ether] on br0', '? (192.168.2.80) at <incomplete> on br0', '? (192.168.2.100) at xx:xx:xx:xx:c0:9d [ether] on br0', '? (192.168.2.3) at xx:xx:xx:xx:07:0d [ether] on br0', '? (192.168.2.246) at xx:xx:xx:xx:91:ea [ether] on br0', '? (192.168.2.220) at xx:xx:xx:xx:97:61 [ether] on br0', '? (192.168.2.170) at xx:xx:xx:xx:ba:34 [ether] on br0', '? (192.168.2.254) at xx:xx:xx:xx:07:fc [ether] on br0', '? (192.168.2.2) at xx:xx:xx:xx:b9:9e [ether] on br0', '? (192.168.2.60) at xx:xx:xx:xx:fe:c4 [ether] on br0', '? (192.168.2.245) at xx:xx:xx:xx:24:75 [ether] on br0', '? (192.168.2.210) at <incomplete> on br0', '? (192.168.1.6) at <incomplete> on eth0', '? (192.168.2.10) at xx:xx:xx:xx:e3:bd [ether] on br0', '? (192.168.2.253) at xx:xx:xx:xx:0c:fa [ether] on br0', '? (192.168.2.160) at xx:xx:xx:xx:91:84 [ether] on br0', '? (192.168.2.121) at <incomplete> on br0', '? (192.168.2.244) at <incomplete> on br0', '? (192.168.2.50) at xx:xx:xx:xx:1e:fb [ether] on br0', '? (192.168.2.243) at xx:xx:xx:xx:7c:81 [ether] on br0', '? (192.168.2.120) at xx:xx:xx:xx:98:b6 [ether] on br0', '? (192.168.2.140) at <incomplete> on br0', '? (192.168.2.30) at xx:xx:xx:xx:8f:78 [ether] on br0', '? (192.168.2.189) at <incomplete> on br0', '? (192.168.2.251) at xx:xx:xx:xx:af:c6 [ether] on br0', '? (192.168.1.1) at xx:xx:xx:xx:77:56 [ether] on eth0', '? (192.168.2.174) at <incomplete> on br0', '? (192.168.2.242) at <incomplete> on br0', '? (192.168.2.130) at xx:xx:xx:xx:53:24 [ether] on br0', '? (192.168.2.250) at xx:xx:xx:xx:20:26 [ether] on br0', '? (192.168.2.20) at xx:xx:xx:xx:9b:3c [ether] on br0', '? (192.168.2.56) at <incomplete> on br0', '? (192.168.2.241) at xx:xx:xx:xx:26:04 [ether] on br0', '']
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.47) at <incomplete> on br0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.80) at <incomplete> on br0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.210) at <incomplete> on br0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.1.6) at <incomplete> on eth0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.121) at <incomplete> on br0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.244) at <incomplete> on br0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.140) at <incomplete> on br0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.189) at <incomplete> on br0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.174) at <incomplete> on br0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.242) at <incomplete> on br0
DEBUG:aioasuswrt.asuswrt:Could not parse row: ? (192.168.2.56) at <incomplete> on br0
DEBUG:__main__:{'xx:xx:xx:xx:C0:9D': Device(mac='xx:xx:xx:xx:C0:9D', ip='192.168.2.100', name=None), 'xx:xx:xx:xx:6F:0B': Device(mac='xx:xx:xx:xx:6F:0B', ip='192.168.2.90', name=None), 'xx:xx:xx:xx:91:84': Device(mac='xx:xx:xx:xx:91:84', ip='192.168.2.160', name=None), 'xx:xx:xx:xx:95:EF': Device(mac='xx:xx:xx:xx:95:EF', ip='192.168.2.110', name=None), 'xx:xx:xx:xx:97:61': Device(mac='xx:xx:xx:xx:97:61', ip='192.168.2.220', name=None), 'xx:xx:xx:xx:7C:81': Device(mac='xx:xx:xx:xx:7C:81', ip='192.168.2.243', name=None), 'xx:xx:xx:xx:24:75': Device(mac='xx:xx:xx:xx:24:75', ip='192.168.2.245', name=None), 'xx:xx:xx:xx:26:04': Device(mac='xx:xx:xx:xx:26:04', ip='192.168.2.241', name=None), 'xx:xx:xx:xx:89:00': Device(mac='xx:xx:xx:xx:89:00', ip='192.168.2.240', name=None), 'xx:xx:xx:xx:91:EA': Device(mac='xx:xx:xx:xx:91:EA', ip='192.168.2.246', name=None), 'xx:xx:xx:xx:0C:FA': Device(mac='xx:xx:xx:xx:0C:FA', ip='192.168.2.253', name=None), 'xx:xx:xx:xx:20:26': Device(mac='xx:xx:xx:xx:20:26', ip='192.168.2.250', name=None), 'xx:xx:xx:xx:07:FC': Device(mac='xx:xx:xx:xx:07:FC', ip='192.168.2.254', name=None), 'xx:xx:xx:xx:53:24': Device(mac='xx:xx:xx:xx:53:24', ip='192.168.2.130', name=None), 'xx:xx:xx:xx:D8:0D': Device(mac='xx:xx:xx:xx:D8:0D', ip='192.168.2.150', name=None), 'xx:xx:xx:xx:9D:59': Device(mac='xx:xx:xx:xx:9D:59', ip='192.168.2.115', name=None), 'xx:xx:xx:xx:BA:34': Device(mac='xx:xx:xx:xx:BA:34', ip='192.168.2.170', name=None), 'xx:xx:xx:xx:98:B6': Device(mac='xx:xx:xx:xx:98:B6', ip='192.168.2.120', name=None), 'xx:xx:xx:xx:6E:5A': Device(mac='xx:xx:xx:xx:6E:5A', ip='192.168.2.200', name=None), 'xx:xx:xx:xx:B6:AA': Device(mac='xx:xx:xx:xx:B6:AA', ip='192.168.2.249', name=None), 'xx:xx:xx:xx:56:F4': Device(mac='xx:xx:xx:xx:56:F4', ip='192.168.2.40', name=None), 'xx:xx:xx:xx:07:0D': Device(mac='xx:xx:xx:xx:07:0D', ip='192.168.2.3', name=None), 'xx:xx:xx:xx:B9:9E': Device(mac='xx:xx:xx:xx:B9:9E', ip='192.168.2.2', name=None), 'xx:xx:xx:xx:FE:C4': Device(mac='xx:xx:xx:xx:FE:C4', ip='192.168.2.60', name=None), 'xx:xx:xx:xx:E3:BD': Device(mac='xx:xx:xx:xx:E3:BD', ip='192.168.2.10', name=None), 'xx:xx:xx:xx:1E:FB': Device(mac='xx:xx:xx:xx:1E:FB', ip='192.168.2.50', name=None), 'xx:xx:xx:xx:8F:78': Device(mac='xx:xx:xx:xx:8F:78', ip='192.168.2.30', name=None), 'xx:xx:xx:xx:AF:C6': Device(mac='xx:xx:xx:xx:AF:C6', ip='192.168.2.251', name=None), 'xx:xx:xx:xx:77:56': Device(mac='xx:xx:xx:xx:77:56', ip='192.168.1.1', name=None), 'xx:xx:xx:xx:9B:3C': Device(mac='xx:xx:xx:xx:9B:3C', ip='192.168.2.20', name=None)}
DEBUG:__main__:neigh
DEBUG:__main__:['192.168.2.200 dev br0 lladdr xx:xx:xx:xx:6e:5a STALE', '192.168.2.90 dev br0 lladdr xx:xx:xx:xx:6f:0b STALE', '192.168.2.249 dev br0 lladdr xx:xx:xx:xx:b6:aa STALE', '192.168.2.110 dev br0 lladdr xx:xx:xx:xx:95:ef REACHABLE', '192.168.2.240 dev br0 lladdr xx:xx:xx:xx:89:00 REACHABLE', '192.168.2.40 dev br0 lladdr xx:xx:xx:xx:56:f4 STALE', '192.168.2.150 dev br0 lladdr xx:xx:xx:xx:d8:0d REACHABLE', '192.168.2.47 dev br0 FAILED', '192.168.2.115 dev br0 lladdr xx:xx:xx:xx:9d:59 STALE', '192.168.2.80 dev br0 FAILED', '192.168.2.100 dev br0 lladdr xx:xx:xx:xx:c0:9d STALE', '192.168.2.3 dev br0 lladdr xx:xx:xx:xx:07:0d STALE', '192.168.2.246 dev br0 lladdr xx:xx:xx:xx:91:ea STALE', '192.168.2.220 dev br0 lladdr xx:xx:xx:xx:97:61 REACHABLE', '192.168.2.170 dev br0 lladdr xx:xx:xx:xx:ba:34 STALE', '192.168.2.254 dev br0 lladdr xx:xx:xx:xx:07:fc STALE', '192.168.2.2 dev br0 lladdr xx:xx:xx:xx:b9:9e STALE', '192.168.2.60 dev br0 lladdr xx:xx:xx:xx:fe:c4 STALE', '192.168.2.245 dev br0 lladdr xx:xx:xx:xx:24:75 STALE', '192.168.2.210 dev br0 FAILED', '192.168.1.6 dev eth0 FAILED', '192.168.2.10 dev br0 lladdr xx:xx:xx:xx:e3:bd STALE', '192.168.2.253 dev br0 lladdr xx:xx:xx:xx:0c:fa REACHABLE', '192.168.2.160 dev br0 lladdr xx:xx:xx:xx:91:84 STALE', '192.168.2.121 dev br0 FAILED', '192.168.2.244 dev br0 FAILED', '192.168.2.50 dev br0 lladdr xx:xx:xx:xx:1e:fb STALE', '192.168.2.243 dev br0 lladdr xx:xx:xx:xx:7c:81 STALE', '192.168.2.120 dev br0 lladdr xx:xx:xx:xx:98:b6 REACHABLE', '192.168.2.140 dev br0 FAILED', '192.168.2.30 dev br0 lladdr xx:xx:xx:xx:8f:78 REACHABLE', '192.168.2.189 dev br0 FAILED', '192.168.2.251 dev br0 lladdr xx:xx:xx:xx:af:c6 STALE', '192.168.1.1 dev eth0 lladdr xx:xx:xx:xx:77:56 DELAY', '192.168.2.174 dev br0 FAILED', '192.168.2.242 dev br0 FAILED', '192.168.2.130 dev br0 lladdr xx:xx:xx:xx:53:24 STALE', '192.168.2.250 dev br0 lladdr xx:xx:xx:xx:20:26 REACHABLE', '192.168.2.20 dev br0 lladdr xx:xx:xx:xx:9b:3c STALE', '192.168.2.56 dev br0 FAILED', '192.168.2.241 dev br0 lladdr xx:xx:xx:xx:26:04 STALE', '']
DEBUG:__main__:{'xx:xx:xx:xx:C0:9D': Device(mac='xx:xx:xx:xx:C0:9D', ip='192.168.2.100', name=None), 'xx:xx:xx:xx:6F:0B': Device(mac='xx:xx:xx:xx:6F:0B', ip='192.168.2.90', name=None), 'xx:xx:xx:xx:91:84': Device(mac='xx:xx:xx:xx:91:84', ip='192.168.2.160', name=None), 'xx:xx:xx:xx:95:EF': Device(mac='xx:xx:xx:xx:95:EF', ip='192.168.2.110', name=None), 'xx:xx:xx:xx:97:61': Device(mac='xx:xx:xx:xx:97:61', ip='192.168.2.220', name=None), 'xx:xx:xx:xx:7C:81': Device(mac='xx:xx:xx:xx:7C:81', ip='192.168.2.243', name=None), 'xx:xx:xx:xx:24:75': Device(mac='xx:xx:xx:xx:24:75', ip='192.168.2.245', name=None), 'xx:xx:xx:xx:26:04': Device(mac='xx:xx:xx:xx:26:04', ip='192.168.2.241', name=None), 'xx:xx:xx:xx:89:00': Device(mac='xx:xx:xx:xx:89:00', ip='192.168.2.240', name=None), 'xx:xx:xx:xx:91:EA': Device(mac='xx:xx:xx:xx:91:EA', ip='192.168.2.246', name=None), 'xx:xx:xx:xx:0C:FA': Device(mac='xx:xx:xx:xx:0C:FA', ip='192.168.2.253', name=None), 'xx:xx:xx:xx:20:26': Device(mac='xx:xx:xx:xx:20:26', ip='192.168.2.250', name=None), 'xx:xx:xx:xx:07:FC': Device(mac='xx:xx:xx:xx:07:FC', ip='192.168.2.254', name=None), 'xx:xx:xx:xx:53:24': Device(mac='xx:xx:xx:xx:53:24', ip='192.168.2.130', name=None), 'xx:xx:xx:xx:D8:0D': Device(mac='xx:xx:xx:xx:D8:0D', ip='192.168.2.150', name=None), 'xx:xx:xx:xx:9D:59': Device(mac='xx:xx:xx:xx:9D:59', ip='192.168.2.115', name=None), 'xx:xx:xx:xx:BA:34': Device(mac='xx:xx:xx:xx:BA:34', ip='192.168.2.170', name=None), 'xx:xx:xx:xx:98:B6': Device(mac='xx:xx:xx:xx:98:B6', ip='192.168.2.120', name=None), 'xx:xx:xx:xx:6E:5A': Device(mac='xx:xx:xx:xx:6E:5A', ip='192.168.2.200', name=None), 'xx:xx:xx:xx:B6:AA': Device(mac='xx:xx:xx:xx:B6:AA', ip='192.168.2.249', name=None), 'xx:xx:xx:xx:56:F4': Device(mac='xx:xx:xx:xx:56:F4', ip='192.168.2.40', name=None), 'xx:xx:xx:xx:07:0D': Device(mac='xx:xx:xx:xx:07:0D', ip='192.168.2.3', name=None), 'xx:xx:xx:xx:B9:9E': Device(mac='xx:xx:xx:xx:B9:9E', ip='192.168.2.2', name=None), 'xx:xx:xx:xx:FE:C4': Device(mac='xx:xx:xx:xx:FE:C4', ip='192.168.2.60', name=None), 'xx:xx:xx:xx:E3:BD': Device(mac='xx:xx:xx:xx:E3:BD', ip='192.168.2.10', name=None), 'xx:xx:xx:xx:1E:FB': Device(mac='xx:xx:xx:xx:1E:FB', ip='192.168.2.50', name=None), 'xx:xx:xx:xx:8F:78': Device(mac='xx:xx:xx:xx:8F:78', ip='192.168.2.30', name=None), 'xx:xx:xx:xx:AF:C6': Device(mac='xx:xx:xx:xx:AF:C6', ip='192.168.2.251', name=None), 'xx:xx:xx:xx:77:56': Device(mac='xx:xx:xx:xx:77:56', ip='192.168.1.1', name=None), 'xx:xx:xx:xx:9B:3C': Device(mac='xx:xx:xx:xx:9B:3C', ip='192.168.2.20', name=None)}
DEBUG:__main__:leases
DEBUG:__main__:['81300 xx:xx:xx:xx:8f:78 192.168.2.30 stacjonarny xx:xx:xx:xx:20:8f:78', '66229 xx:xx:xx:xx:af:c6 192.168.2.251 yeelight-color-v2-bulb *', '66229 xx:xx:xx:xx:b6:aa 192.168.2.249 yeelight-color-bulb-1 *', '43335 xx:xx:xx:xx:b9:9e 192.168.2.2 switch *', '58399 xx:xx:xx:xx:07:0d 192.168.2.3 fingbox xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:4d:25:e0', '50062 xx:xx:xx:xx:56:f4 192.168.2.40 denon xx:xx:xx:xx:45:56:f4', '47420 xx:xx:xx:xx:95:ef 192.168.2.110 harmony xx:xx:xx:xx:fb:95:ef', '53562 xx:xx:xx:xx:26:04 192.168.2.241 shelly2-5b2604 *', '81300 xx:xx:xx:xx:6f:0b 192.168.2.90 migateway *', '45714 xx:xx:xx:xx:20:26 192.168.2.250 yeelight-color-bulb-2 *', '49516 xx:xx:xx:xx:89:00 192.168.2.240 shelly1-328900 *', '46045 xx:xx:xx:xx:0c:fa 192.168.2.253 yeelight-lightstrip-1 *', '45617 xx:xx:xx:xx:07:fc 192.168.2.254 yeelight-lightstrip-2 *', '79862 xx:xx:xx:xx:97:61 192.168.2.220 mihumidifier *', '69946 xx:xx:xx:xx:1e:fb 192.168.2.50 playstation xx:xx:xx:xx:5f:1e:fb', '56383 xx:xx:xx:xx:24:75 192.168.2.245 sonoff-s26-182475 *', '67469 xx:xx:xx:xx:91:ea 192.168.2.246 wemos-d1-mini-1c91ea *', '76330 xx:xx:xx:xx:c0:9d 192.168.2.100 brother xx:xx:xx:xx:33:c0:9d', '47210 xx:xx:xx:xx:98:b6 192.168.2.120 androidtv xx:xx:xx:xx:95:98:b6', '50243 xx:xx:xx:xx:53:24 192.168.2.130 dafang xx:xx:xx:xx:e5:53:24', '56136 xx:xx:xx:xx:7c:81 192.168.2.243 sonoff-basic-067c81 *', '48747 xx:xx:xx:xx:e3:bd 192.168.2.10 synology xx:xx:xx:xx:0a:e3:bd', '56122 xx:xx:xx:xx:9b:3c 192.168.2.20 raspberry xx:xx:xx:xx:28:9b:3c', '61531 xx:xx:xx:xx:83:e1 192.168.2.140 oneplus xx:xx:xx:xx:31:83:e1', '52998 xx:xx:xx:xx:ba:34 192.168.2.170 ipad xx:xx:xx:xx:df:ba:34', '68120 xx:xx:xx:xx:9d:59 192.168.2.115 iPad-Edyta xx:xx:xx:xx:4b:9d:59', '78620 xx:xx:xx:xx:d8:0d 192.168.2.150 iphone xx:xx:xx:xx:e7:d8:0d', '61788 xx:xx:xx:xx:91:84 192.168.2.160 lumia xx:xx:xx:xx:8c:91:84', '']
DEBUG:__main__:{'xx:xx:xx:xx:C0:9D': Device(mac='xx:xx:xx:xx:C0:9D', ip='192.168.2.100', name='brother'), 'xx:xx:xx:xx:6F:0B': Device(mac='xx:xx:xx:xx:6F:0B', ip='192.168.2.90', name='migateway'), 'xx:xx:xx:xx:91:84': Device(mac='xx:xx:xx:xx:91:84', ip='192.168.2.160', name='lumia'), 'xx:xx:xx:xx:95:EF': Device(mac='xx:xx:xx:xx:95:EF', ip='192.168.2.110', name='harmony'), 'xx:xx:xx:xx:97:61': Device(mac='xx:xx:xx:xx:97:61', ip='192.168.2.220', name='mihumidifier'), 'xx:xx:xx:xx:7C:81': Device(mac='xx:xx:xx:xx:7C:81', ip='192.168.2.243', name='sonoff-basic-067c81'), 'xx:xx:xx:xx:24:75': Device(mac='xx:xx:xx:xx:24:75', ip='192.168.2.245', name='sonoff-s26-182475'), 'xx:xx:xx:xx:26:04': Device(mac='xx:xx:xx:xx:26:04', ip='192.168.2.241', name='shelly2-5b2604'), 'xx:xx:xx:xx:89:00': Device(mac='xx:xx:xx:xx:89:00', ip='192.168.2.240', name='shelly1-328900'), 'xx:xx:xx:xx:91:EA': Device(mac='xx:xx:xx:xx:91:EA', ip='192.168.2.246', name='wemos-d1-mini-1c91ea'), 'xx:xx:xx:xx:0C:FA': Device(mac='xx:xx:xx:xx:0C:FA', ip='192.168.2.253', name='yeelight-lightstrip-1'), 'xx:xx:xx:xx:20:26': Device(mac='xx:xx:xx:xx:20:26', ip='192.168.2.250', name='yeelight-color-bulb-2'), 'xx:xx:xx:xx:07:FC': Device(mac='xx:xx:xx:xx:07:FC', ip='192.168.2.254', name='yeelight-lightstrip-2'), 'xx:xx:xx:xx:53:24': Device(mac='xx:xx:xx:xx:53:24', ip='192.168.2.130', name='dafang'), 'xx:xx:xx:xx:D8:0D': Device(mac='xx:xx:xx:xx:D8:0D', ip='192.168.2.150', name='iphone'), 'xx:xx:xx:xx:9D:59': Device(mac='xx:xx:xx:xx:9D:59', ip='192.168.2.115', name='iPad-Edyta'), 'xx:xx:xx:xx:BA:34': Device(mac='xx:xx:xx:xx:BA:34', ip='192.168.2.170', name='ipad'), 'xx:xx:xx:xx:98:B6': Device(mac='xx:xx:xx:xx:98:B6', ip='192.168.2.120', name='androidtv'), 'xx:xx:xx:xx:6E:5A': Device(mac='xx:xx:xx:xx:6E:5A', ip='192.168.2.200', name=None), 'xx:xx:xx:xx:B6:AA': Device(mac='xx:xx:xx:xx:B6:AA', ip='192.168.2.249', name='yeelight-color-bulb-1'), 'xx:xx:xx:xx:56:F4': Device(mac='xx:xx:xx:xx:56:F4', ip='192.168.2.40', name='denon'), 'xx:xx:xx:xx:07:0D': Device(mac='xx:xx:xx:xx:07:0D', ip='192.168.2.3', name='fingbox'), 'xx:xx:xx:xx:B9:9E': Device(mac='xx:xx:xx:xx:B9:9E', ip='192.168.2.2', name='switch'), 'xx:xx:xx:xx:FE:C4': Device(mac='xx:xx:xx:xx:FE:C4', ip='192.168.2.60', name=None), 'xx:xx:xx:xx:E3:BD': Device(mac='xx:xx:xx:xx:E3:BD', ip='192.168.2.10', name='synology'), 'xx:xx:xx:xx:1E:FB': Device(mac='xx:xx:xx:xx:1E:FB', ip='192.168.2.50', name='playstation'), 'xx:xx:xx:xx:8F:78': Device(mac='xx:xx:xx:xx:8F:78', ip='192.168.2.30', name='stacjonarny'), 'xx:xx:xx:xx:AF:C6': Device(mac='xx:xx:xx:xx:AF:C6', ip='192.168.2.251', name='yeelight-color-v2-bulb'), 'xx:xx:xx:xx:77:56': Device(mac='xx:xx:xx:xx:77:56', ip='192.168.1.1', name=None), 'xx:xx:xx:xx:9B:3C': Device(mac='xx:xx:xx:xx:9B:3C', ip='192.168.2.20', name='raspberry')}
Devices xx:xx:xx:xx:FE:C4
, xx:xx:xx:xx:0c:fa
or xx:xx:xx:xx:20:26
are on the list from script but they are offline (physically disconnected from the network). This gives a false positive state of these devices in the Home Assistant. These devices have a static IP address from DHCP.
Python 3.7.2/aioasuswrt==1.1.21
With commit d62c74d the cache isn't created by async_get_packets_total. It doubles the number of queries when doing async_get_packets_total/async_get_current_transfer_rates in succession.
Hi,
I just noticed that the function async_get_connected_devices shows disconnected devices as present, even if they're not. This is probably due to using the dnsmasq.leases file, which keeps the device record till the dns lease is expired.
I noticed there is a file /tmp/clientlist.json that basically shows the same information, but shows disconnected devices much quicker. In that file it also shows the clients separated by wifi "2G", "5G" and "wired_mac", which could also be used in async_get_wl to avoid the loops and multiple calls.
Is there any reason why that file has not been used for this cases?
From my tests, that file was kept updated even when no client was connected to the web admin of the router (Unless I missed out something).
To properly test this just via console/command line for different devices it would be nice if there would be just a small set of synchronous functions exposed in the __init__
that one can play with.
Hi, I've tested with an Asus AC87U with merlin firmware version 384.13_10.
import asyncio
import logging
import sys
from aioasuswrt.asuswrt import AsusWrt
component = AsusWrt('192.168.1.1', 22, username='USER', password='PASS')
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logger = logging.getLogger(__name__)
async def print_data():
logger.debug(await component.connection.async_connect())
loop = asyncio.get_event_loop()
loop.run_until_complete(print_data())
loop.close()
DEBUG:asyncio:Using selector: EpollSelector
Traceback (most recent call last):
File "asus.py", line 18, in <module>
loop.run_until_complete(print_data())
File "/usr/local/lib/python3.7/asyncio/base_events.py", line 587, in run_until_complete
return future.result()
File "asus.py", line 14, in print_data
logger.debug(await component.connection.async_connect())
File "/usr/local/lib/python3.7/site-packages/aioasuswrt/connection.py", line 75, in async_connect
self._client = await asyncssh.connect(self._host, **kwargs)
File "/usr/local/lib/python3.7/site-packages/asyncssh/connection.py", line 5696, in connect
conn_factory, 'Opening SSH connection to')
File "/usr/local/lib/python3.7/site-packages/asyncssh/connection.py", line 175, in _connect
await conn.wait_established()
File "/usr/local/lib/python3.7/site-packages/asyncssh/connection.py", line 1927, in wait_established
await self._waiter
File "/usr/local/lib/python3.7/asyncio/selector_events.py", line 814, in _read_ready__data_received
data = self._sock.recv(self.max_size)
ConnectionResetError: [Errno 104] Connection reset by peer
Thanks
Got sent here, with my issue, due to integration using this?!
I got the following in my log, on every boot of HA:
Logger: homeassistant.config_entries
Source: components/asuswrt/router.py:426
First occurred: 5. juni 2021, 19:01:03 (1 occurrences)
Last logged: 5. juni 2021, 19:01:03
Error setting up entry 192.168.0.1 for asuswrt
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/config_entries.py", line 293, in async_setup
result = await component.async_setup_entry(hass, self) # type: ignore
File "/usr/src/homeassistant/homeassistant/components/asuswrt/init.py", line 123, in async_setup_entry
await router.setup()
File "/usr/src/homeassistant/homeassistant/components/asuswrt/router.py", line 230, in setup
model = await _get_nvram_info(self._api, "MODEL")
File "/usr/src/homeassistant/homeassistant/components/asuswrt/router.py", line 426, in _get_nvram_info
info = await api.async_get_nvram(info_type)
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 275, in async_get_nvram
lines = await self.connection.async_run_command(_NVRAM_CMD)
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/connection.py", line 140, in async_run_command
return [line.decode("utf-8") for line in data]
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/connection.py", line 140, in
return [line.decode("utf-8") for line in data]
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb in position 4: invalid start byte
Tell me if you need more then this log, and I will find.
The router is anyways a RT-N66W, and is not updated for the last months, and there isn't any available updates for it.
Anyway, this issue started with HA 2021.6.
Hi,
I've been using the asuswrt integration on homeassistant, but the logging has been overflowing with a ValueError exception:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 278, in async_update_ha_state
await self.async_device_update()
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 469, in async_device_update
await self.async_update() # type: ignore
File "/usr/src/homeassistant/homeassistant/components/asuswrt/sensor.py", line 90, in async_update
await super().async_update()
File "/usr/src/homeassistant/homeassistant/components/asuswrt/sensor.py", line 68, in async_update
self._rates = await self._api.async_get_bytes_total()
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 336, in async_get_bytes_total
rx = await self.async_get_rx()
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 344, in async_get_rx
return float(data[0]) if data[0] != '' else None
ValueError: could not convert string to float: '/net/eth2/statistics/rx_bytes\r'
The issue is present on the master version. I've been interfacing with an Asus RT-AC51U, firmware version '3.0.0.4.380_8591'. As this router does not support ssh (at least I cannot find it in the configuration) I've been interfacing with telnet which is supported.
I can reproduce the issue easily using this script:
#!/usr/bin/env python3
import asyncio
import logging
import sys
from aioasuswrt.asuswrt import AsusWrt
component = AsusWrt('192.168.2.1', 23, username='admin', password='....', interface='eth2', use_telnet=True)
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logger = logging.getLogger(__name__)
async def print_data():
logger.debug("get_rx_stuff")
logger.debug(await component.async_get_rx())
loop = asyncio.get_event_loop()
loop.run_until_complete(print_data())
loop.close()
The main issue is (as expected) in the async_run_command
of the TelnetConnection
class. I've added logging to the method to see what happens:
DEBUG:__main__:get_rx_stuff
The input is: (cat /sys/class/net/eth2/statistics/rx_bytes)
The send command is: (b'PATH=$PATH:/bin:/usr/sbin:/sbin && cat /sys/class/net/eth2/statistics/rx_bytes\n')
The data before splitting: b' PATH=$PATH:/bin:/usr/sbin:/sbin && cat /sys/class\r\r\n/net/eth2/statistics/rx_bytes\r\n81115610\r\nadmin@RT-AC51U:/tmp/home/root#'
The data after splitting: [b'/net/eth2/statistics/rx_bytes\r', b'81115610\r']
[b'/net/eth2/statistics/rx_bytes\r', b'81115610\r']
My expectation is that the main cause of problems is the \r\r\n
(especially the \n
) causing an extra unexpected split. My best guess is that this is added by someone due to a character limit of 50 per line (as it seems to happen exactly after 50 characters, if I counted correctly).
I've not had any inspiration on how to fix the split to give the correct output, especially as I'm unsure of the exact results of all the different functions calling this method.
For the rx (and probably tx) methods specifically this problem might be easily fixed in the calling method, eg. by replacing lines 344 and 350
return float(data[0]) if data[0] != '' else None
with
return float(data[-1]) if data[-1] != '' else None
Although I'm unsure whether this will cause problems for the ssh version.
I asked the question on the asyncssh github about this and Ron recommended adding
asyncssh.set_log_level('WARNING')
into the code.
I've inserted this into aioasuswrt.connection code and tried this on my installation at home and it's reduced the 'spamming' to just asuswrt checking devices text which is perfect.
Could this be included in the next release?
Thank you
Saw this https://github.com/vrachieru/asuswrt-api
Any reason why it can’t be used over telnet/ssh?
To obtain the data, the following command can be issued:
killall -USR2 rstats # This asks rstats to create a JS file at `/var/spool/rstats-history.js`
Afterwards, the file at /var/spool/rstats-history.js
can be read. Example contents:
daily_history = [
[0x790418,0x8f9bea0,0x90b8374],[0x790419,0x16c6f68,0x32d5ca9],[0x79041a,0x1435521,0x17f6c63],[0x79041b,0x8c97980,0xa1a4b10],[0x79041c,0x15c8771,0x150b02c],[0x79041d,0x3a6c971,0x7c0bf19],[0x79041e,0xd20a7c,0x861438],[0x79041f,0xf88093,0x1382069],[0x790501,0xc68ff6f,0xbabb5c5],[0x790502,0x1e0102b,0xfe4535],[0x790503,0x232246b,0x2a3a73b],[0x790504,0x1012b81c,0x103627bc],[0x790505,0xbf7317d,0xe576fdb],[0x790506,0x849a390,0x7b82ecc],[0x790507,0x91bb84b,0x879d320],[0x790508,0x91f9a53,0xcad3723],[0x790509,0xf4e0808,0x199dfe29],[0x79050a,0x5e40a39,0x5641d04]];
monthly_history = [
[0x790400,0x1b40d89d,0x22a23b79],[0x790500,0x5c3c2610,0x69bc8e0e]];
(The web interface deletes this file after reading it)
The data is in the format [date, rx, tx]
where:
date
is in 0xYYMMDD
, where YY
is years since 1900, MM
is month starting from zero, and DD
is the date of the month
0x790418
is 2021-05-24rx
is bytes rxed for the day in KBtx
is bytes txed for the day in KBInstead, the statistics file at /var/lib/misc/rstats-history.gz
can be read directly:
/ 1024
)GPL_RT_AC1200GPlus_300438252272 / ... / release / src / router / rstats / rstats.c
Most probably newest asus routers simply do not have a 'wl' command at all.
Even your 1.1.9 patch does not work (actually on this router it even breaks nvram, because on my router it is in /bin/nvram not /usr/sbin/nvram.
Another thing is that your script does not scan guest networks for clients (which might hand there).
So here is line for all these fixes:
for dev in nvram get wl1_vifs && nvram get wl0_vifs && nvram get wl_ifnames
; do wlanconfig $dev list | awk 'FNR > 1 {print substr($1
, 0, 18)}'; done
I have an AC-RT88U. Running HomeAssistant 0.82 (though I think this may have been happening from before). I perpetually see my devices as set to "home" state, even when they are disconnected. I just checked one device that's not connected, SSH'd to router, did 'ip neigh' and did not see it there.
I notice there is a flurry of activity today on this; is this a KI and is just waiting for a new HA release? Anything else I can do to be of help debugging?
Hello @kennedyshead ,
TL;DR: Do not expect to measure the Internet traffic when looking at eth0
of a Broadcom based Asuswrt device.
This is maybe more a clarification than a bug. I am using the ASUSWRT integration for Home Assistant and the bandwidth monitoring shows a strange behaviour when checking my gateway: Upload and download rates are all the time almost identical. Which is kind of weird, when you are downloading a file at say 200MBit/s and upload also show a rate of about 200MBit/s - which can't be, as my upload is limited to 30MBit/s.
So I started digging and checked the plugin, as well as aioasuswrt
:
eth0
of the router, which is the interface connected to the Internet (WAN).The strange behaviour is reproducable, also based on the low-level kernel statistics of the interface. But the traffic monitor feature of Asuswrt displays a reasonable graph for Internet traffic when doing a download (download rate >> upload rate). So I checked how the traffic monitor gets its numbers.
Basically it is similar to the implementation in aioasuswrt
: read the total of bytes every 'x' seconds and divide the difference by 'x', but with a twist for Broadcom based routers: when doing the delta, first a difference is computed like eth0
minus vlan1
(for both TX and RX bytes).
See the function netdev_calc()
in release/src/router/shared/misc.c
- search for // special handle for non-tag wan of broadcom solution
.
The implementation looks like this: If in NVRAM switch_wantag
is set to none
(and there is an interface vlan1
- see bcmvlan_models(model, modelvlan)
), the special handling is activated. eth0
will become the WIRED
connection, while the difference will become the INTERNET
connection.
You can see the network traffic information the Traffic Monitor page gets by e.g. using the developer tools of Firefox. Look for calls to update.cgi
and check the returned JSON data:
netdev = {
'WIRED':{rx:0x694fd5a0,tx:0x38930af4}
,'INTERNET':{rx:0x5f4b4b20,tx:0x156603d5}
,'BRIDGE':{rx:0x5712764,tx:0x6545be3c}
,'WIRELESS0':{rx:0x0,tx:0x0}
,'WIRELESS1':{rx:0x0,tx:0x0}
}
So the bottom line is: if you want to measure your Internet throughput, you need to use figures from INTERNET
, not WIRED
(eth0
). //
Unfortunately this metric is not available via aioasuswrt
, as you can only give an existing interface for monitoring. A new approach would be needed. I quickly whipped up a short script to illustrate the solution (which produces sensible values for me):
#!/usr/bin/env python3
import asyncio
import logging
import re
import sys
from aioasuswrt.asuswrt import AsusWrt
from aioasuswrt.helpers import convert_size
component = AsusWrt("gateway", 22, username='admin', ssh_key='~/.ssh/gateway_rsa')
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logger = logging.getLogger(__name__)
async def print_data():
# sampling interval
dtime = 5
prevrx = None
prevtx = None
while True:
eth0rx = eth0tx = 0
vlanrx = vlantx = 0
# based on the built-in Traffic Monitor code of AsusWrt
# see - ej_netdev() in release/src/router/httpd/web.c
# - netdev_calc() in release/src/router/shared/misc.c
# search for '// special handle for non-tag wan of broadcom solution'
# BONUS: gets a *consistent* snapshot of the transferred bytes across all interfaces
netdev = await component.connection.async_run_command("cat /proc/net/dev")
# skip the first two header lines, process each interface
for line in netdev[2:]:
parts = re.split('[\s:]+', line.strip())
# NOTES:
# * assuming eth0 always comes before vlan1 in dev file
# * counted bytes wrap around at 0xFFFFFFFF
if (parts[0] == "eth0"):
eth0rx = int(parts[1]) # received bytes
eth0tx = int(parts[9]) # transmitted bytes
elif (parts[0] == "vlan1"):
vlanrx = int(parts[1]) # received bytes
vlantx = int(parts[9]) # transmitted bytes
def handle32bitwrap(v):
return v if v > 0 else v + 0xFFFFFFFF
# the true amount of Internet related data equals eth0 - vlan1
inetrx = handle32bitwrap(eth0rx - vlanrx)
inettx = handle32bitwrap(eth0tx - vlantx)
if prevrx is None or prevtx is None:
rx = tx = 0
else:
rx = int(handle32bitwrap(inetrx - prevrx)/dtime)
tx = int(handle32bitwrap(inettx - prevtx)/dtime)
prevrx = inetrx
prevtx = inettx
logger.debug("DL: {}/s UL: {}/s".format(convert_size(rx), convert_size(tx)))
await asyncio.sleep(dtime)
loop = asyncio.get_event_loop()
loop.run_until_complete(print_data())
loop.close()
Hope this helps if anybody comes across this phenomenon. Perhaps it would be great to have some kind of virtual interface like inet
which could be passed to aioasuswrt
which would trigger the special handling on readout?
Anyway, thanks for your work & Cheers,
tempura
Updating device list from asuswrt took longer than the scheduled scan interval 0:00:12
Need to restart Home Assistant for it to start working again.
I've enabled logs now and I'll let you know the outcome.
On the previous version (old non-async code on Home Assistant) I had to disconnect and reconnect the session when this happened, guess it still happens the same and the plugin doesn't figure out it lost the connection to the router
I own a RT-AC68P. After a recent firmware upgrade I noticed the shell environment had changed and many of the commands were failing because it could not find them in the path. I modified my local version to use the full path name for the commands and this fixed the issue. If you want, I can do a PR to fix them in the master branch or you can fix them on the next release. It doesn't hurt to have the full path names (hopefully they are the same on most Asus routers) and hopefully will prevent other people from having the same issue when they update their router firmware.
Recent changes force stat collection from asuswrt a mandatory .
I really have no use for the all those stats, I am just in for the device tracker.
Is there any way to avoid all those data collections?
It's a burden for the router. It produces tons of [asyncssh] logs. I am forced to disable Asuswrt components for the time being.
Question from a noob in this area. From what I understand Home Assistant uses aioasuswrt to pull data from asus devices. I have a RT-N66U where I use telnet to pull data from router.
The problem I have now is the router end up with ~400 telnet connections after a while and stops wotking.
Feb 17 20:00:37 disk_monitor: Got SIGALRM...
Feb 17 20:11:49 kernel: SKIPPED false Type 6 Radar Detection. min_pw=24 pw_delta=0 pri=60119 fm_min=0 fm_max=0 nconsecq_pulses=1. Time from last detection = 1894, = 31min 34sec. Detected pulse index: 4
Feb 17 20:28:44 telnetd[332]: vfork: Cannot allocate memory
Feb 17 20:29:05 telnetd[332]: vfork: Cannot allocate memory
From router:
N66U:/tmp# netstat -t| grep telnet|wc -l
with a result of 386.
I do have an option in the router gui to "close telnet sessions with a value between 10-99" turning that on will do some hourekeeping and everythings works again.
So my question is, where and who will close the session?
Cheers
Fredrik
Error visible in logs (multiple instances). I have not notice impact on "end user".
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/asuswrt/router.py", line 252, in update_all
await self.update_devices()
File "/usr/src/homeassistant/homeassistant/components/asuswrt/router.py", line 259, in update_devices
wrt_devices = await self._api.async_get_connected_devices()
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 353, in async_get_connected_devices
dev = await self.async_get_arp()
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 325, in async_get_arp
lines = await self.connection.async_run_command(_ARP_CMD)
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/connection.py", line 34, in async_run_command
await self.async_connect()
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/connection.py", line 77, in async_connect
self._client = await asyncssh.connect(self._host, **kwargs)
File "/usr/local/lib/python3.8/site-packages/asyncssh/connection.py", line 6460, in connect
return await _connect(options.host, options.port, loop, options.tunnel,
File "/usr/local/lib/python3.8/site-packages/asyncssh/connection.py", line 223, in _connect
await conn.wait_established()
File "/usr/local/lib/python3.8/site-packages/asyncssh/connection.py", line 2107, in wait_established
await self._waiter
asyncssh.misc.ConnectionLost: Connection lost
2021-04-08 11:08:17 ERROR (MainThread) [aioasuswrt.connection] Host timeout.
2021-04-08 11:08:17 ERROR (MainThread) [homeassistant.components.asuswrt.router] Unexpected error fetching sensors_bytes data: list index out of range
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 173, in _async_refresh
self.data = await self._async_update_data()
File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 143, in _async_update_data
return await self.update_method()
File "/usr/src/homeassistant/homeassistant/components/asuswrt/router.py", line 81, in _get_bytes
datas = await self._api.async_get_bytes_total()
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 380, in async_get_bytes_total
rx = await self.async_get_rx()
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 389, in async_get_rx
return float(data[0]) if data[0] != "" else None
IndexError: list index out of range
I'm getting the following error occasionally on my router. I'm guessing that data is occasionally coming back as completely empty in some form, but since I'm not sure what is triggering that response it's difficult to test.
Maybe worth adding ahead of the existing return:
if not data return None
2020-11-30 23:54:58 ERROR (MainThread) [homeassistant.helpers.entity] Update for sensor.asuswrt_upload_speed fails
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 278, in async_update_ha_state
await self.async_device_update()
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 482, in async_device_update
await task
File "/usr/src/homeassistant/homeassistant/components/asuswrt/sensor.py", line 136, in async_update
await super().async_update()
File "/usr/src/homeassistant/homeassistant/components/asuswrt/sensor.py", line 69, in async_update
self._speed = await self._api.async_get_current_transfer_rates()
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 401, in async_get_current_transfer_rates
data = await self.async_get_bytes_total(use_cache)
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 380, in async_get_bytes_total
rx = await self.async_get_rx()
File "/usr/local/lib/python3.8/site-packages/aioasuswrt/asuswrt.py", line 389, in async_get_rx
return float(data[0]) if data[0] != "" else None
IndexError: list index out of range
It would be great if an method would be added to get the uptime of the router
Issue discovered when debugging home-assistant/core#103230 and should have been solved by #68 long time ago
aioasuswrt
does not always close SSH connections, making remote system solely responsible for freeing up resources, which is a bad assumption, especially on AsusWRT routers, where "Idle Timeout" setting for SSH server applies only to interactive sessions, not to SSH connections with all channels closed (dropbear
is always started without -I
so it never times out). This behaviour quite often makes high-end routers with 1GB of memory crash in less than a week.
Points to solve:
SshConnection.async_connect()
should check if a connection exists before creating a new one, so it can be closed if needed; this code may be called when a connection object exists, but some error was handled and reconnect is needed
entire SshConnection.async_connect()
should be guarded by some form of lock, for example asyncio.Lock()
so it's Coroutine-Safe; otherwise bad timing of await
can create and overwrite multiple connections we no longer have access to, yet they still consume resources on a server
018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=70] Requesting new SSH session
2018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=70] Command: arp -n
2018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=70] Received exit status 0
2018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=70] Received channel close
2018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=70] Channel closed
2018-11-11 15:27:09 DEBUG (MainThread) [aioasuswrt.asuswrt] Could not parse row: ? (172.16.10.142) at 00:18:DD:04:E2:FA [ether] on br0
2018-11-11 15:27:09 DEBUG (MainThread) [aioasuswrt.asuswrt] Could not parse row: ? (172.16.10.1) at 00:08:A2:0D:54:B8 [ether] on br0
2018-11-11 15:27:09 DEBUG (MainThread) [aioasuswrt.asuswrt] Could not parse row: ? (172.16.10.125) at 60:01:94:41:C4:21 [ether] on br0
2018-11-11 15:27:09 DEBUG (MainThread) [aioasuswrt.asuswrt] Could not parse row: ? (172.16.10.61) at 00:09:B0:A1:51:3C [ether] on br0
2018-11-11 15:27:09 DEBUG (MainThread) [aioasuswrt.asuswrt] Could not parse row: ? (172.16.10.2) at 00:25:90:12:2D:90 [ether] on br0
2018-11-11 15:27:09 DEBUG (MainThread) [aioasuswrt.asuswrt] Could not parse row:
2018-11-11 15:27:09 DEBUG (MainThread) [asyncssh] [conn=0, chan=71] Set write buffer limits: low-water=16384, high-water=65536
2018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=71] Requesting new SSH session
2018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=71] Command: ip neigh
2018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=71] Received exit status 0
2018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=71] Received channel close
2018-11-11 15:27:09 INFO (MainThread) [asyncssh] [conn=0, chan=71] Channel closed
I tried adding the row to the ARP_DATA tests, but its not failing, so I'm confused whats going on.
This is Home Assistant 0.82.0 which should have the new version in it.
Hi
Thanks for providing this library , used by the Home assistant asuswrt integration.
I have several ASUS RTN-66u's devices configured as AP's.
The firmware on them is a Merlin LTS fork (based on the Merlin 374 version where power settings where still unlocked).
Although the integration can connect the AP's, the information provided by this library doesn't make any sense.
I would like to see these figures based on the list of devices connected via the WiFi (when in AP mode).
Best Eric
I have the ASUS RT-N56U router with Padavan's firmware. The firmware uses the network intervace name "eth3" for WAN.
This is a problem because aioasuswrt assumes that WAN will be "eth0" to obtain upload and download bandwidth statistics. For example:
cat /sys/class/net/eth0/statistics/rx_bytes
Could you please consider adding a config variable so that the interface name can be changed? The variable could be passed in from Home Assistant. For example:
asuswrt:
...
interface: "eth3"
Hi! This comes from this conversation: home-assistant/core#67469
My setup is a TUG-AX5400 + RT-AC57U_V3, and devices connected to this last one are not seen by the library. I've been doing my own research (not skilled in python, but I can manage a linux system) through SSH and everything seems there.
Can you help me? and, even better, can I do something to help you to help me? :)
Thank you!
When adding python 3.8 to the test workflow it does not pass, there is an error when asserting so afaik there is at this moment no support for python 3.8
using the testscript from #1 with python3 I get no results. The commands fail.
DEBUG:asyncio:Using selector: EpollSelector
DEBUG:__main__:wl
INFO:asyncssh:Opening SSH connection to 192.168.1.3, port 22
INFO:asyncssh:[conn=0] Connection to 192.168.1.3, port 22 succeeded
INFO:asyncssh:[conn=0] Local address: 192.168.1.11, port 41448
DEBUG:asyncssh:[conn=0] Requesting key exchange
DEBUG:asyncssh:[conn=0] Received key exchange request
DEBUG:asyncssh:[conn=0] Beginning key exchange
DEBUG:asyncssh:[conn=0] Completed key exchange
INFO:asyncssh:[conn=0] Beginning auth for user admin
DEBUG:asyncssh:[conn=0] Trying password auth
INFO:asyncssh:[conn=0] Auth for user admin succeeded
DEBUG:asyncssh:[conn=0, chan=0] Set write buffer limits: low-water=16384, high-water=65536
INFO:asyncssh:[conn=0, chan=0] Requesting new SSH session
INFO:asyncssh:[conn=0, chan=0] Command: for dev in `nvram get wl_ifnames`; do wl -i $dev assoclist; done
INFO:asyncssh:[conn=0, chan=0] Received exit status 127
INFO:asyncssh:[conn=0, chan=0] Received channel close
INFO:asyncssh:[conn=0, chan=0] Channel closed
DEBUG:__main__:['']
DEBUG:asyncssh:[conn=0, chan=1] Set write buffer limits: low-water=16384, high-water=65536
INFO:asyncssh:[conn=0, chan=1] Requesting new SSH session
INFO:asyncssh:[conn=0, chan=1] Command: for dev in `nvram get wl_ifnames`; do wl -i $dev assoclist; done
INFO:asyncssh:[conn=0, chan=1] Received exit status 127
INFO:asyncssh:[conn=0, chan=1] Received channel close
INFO:asyncssh:[conn=0, chan=1] Channel closed
DEBUG:__main__:{}
DEBUG:__main__:arp
DEBUG:asyncssh:[conn=0, chan=2] Set write buffer limits: low-water=16384, high-water=65536
INFO:asyncssh:[conn=0, chan=2] Requesting new SSH session
INFO:asyncssh:[conn=0, chan=2] Command: arp -n
INFO:asyncssh:[conn=0, chan=2] Received exit status 127
INFO:asyncssh:[conn=0, chan=2] Received channel close
INFO:asyncssh:[conn=0, chan=2] Channel closed
DEBUG:__main__:['']
DEBUG:asyncssh:[conn=0, chan=3] Set write buffer limits: low-water=16384, high-water=65536
INFO:asyncssh:[conn=0, chan=3] Requesting new SSH session
INFO:asyncssh:[conn=0, chan=3] Command: arp -n
INFO:asyncssh:[conn=0, chan=3] Received exit status 127
INFO:asyncssh:[conn=0, chan=3] Received channel close
INFO:asyncssh:[conn=0, chan=3] Channel closed
DEBUG:__main__:{}
DEBUG:__main__:neigh
DEBUG:asyncssh:[conn=0, chan=4] Set write buffer limits: low-water=16384, high-water=65536
INFO:asyncssh:[conn=0, chan=4] Requesting new SSH session
INFO:asyncssh:[conn=0, chan=4] Command: ip neigh
INFO:asyncssh:[conn=0, chan=4] Received exit status 127
INFO:asyncssh:[conn=0, chan=4] Received channel close
INFO:asyncssh:[conn=0, chan=4] Channel closed
DEBUG:__main__:['']
DEBUG:asyncssh:[conn=0, chan=5] Set write buffer limits: low-water=16384, high-water=65536
INFO:asyncssh:[conn=0, chan=5] Requesting new SSH session
INFO:asyncssh:[conn=0, chan=5] Command: ip neigh
INFO:asyncssh:[conn=0, chan=5] Received exit status 127
INFO:asyncssh:[conn=0, chan=5] Received channel close
INFO:asyncssh:[conn=0, chan=5] Channel closed
DEBUG:__main__:{}
DEBUG:__main__:leases
DEBUG:asyncssh:[conn=0, chan=6] Set write buffer limits: low-water=16384, high-water=65536
INFO:asyncssh:[conn=0, chan=6] Requesting new SSH session
INFO:asyncssh:[conn=0, chan=6] Command: cat /var/lib/misc/dnsmasq.leases
INFO:asyncssh:[conn=0, chan=6] Received exit status 1
INFO:asyncssh:[conn=0, chan=6] Received channel close
INFO:asyncssh:[conn=0, chan=6] Channel closed
DEBUG:__main__:['']
DEBUG:asyncssh:[conn=0, chan=7] Set write buffer limits: low-water=16384, high-water=65536
INFO:asyncssh:[conn=0, chan=7] Requesting new SSH session
INFO:asyncssh:[conn=0, chan=7] Command: cat /var/lib/misc/dnsmasq.leases
INFO:asyncssh:[conn=0, chan=7] Received exit status 1
INFO:asyncssh:[conn=0, chan=7] Received channel close
INFO:asyncssh:[conn=0, chan=7] Channel closed
DEBUG:__main__:{}
Output for the single commands:
admin@(none):/tmp/home/root# for dev in `nvram get wl_ifnames`; do wl -i $dev assoclist; done
-sh: wl: not found
-sh: wl: not found
admin@(none):/tmp/home/root# dev in `nvram get wl_ifnames`; do wl -i $dev assoclist; done
-sh: dev: not found
-sh: wl: not found
admin@(none):/tmp/home/root# arp -n
? (192.168.1.1) at 84:16:xx:xx:xx:xx [ether] on br0
? (192.168.1.11) at 30:5a:xx:xx:xx:xx [ether] on br0
? (192.168.1.4) at b8:27:xx:xx:xx:xx [ether] on br0
admin@(none):/tmp/home/root# ip neigh
192.168.1.11 dev br0 lladdr 30:5a:xx:xx:xx:xx REACHABLE
192.168.1.4 dev br0 lladdr b8:27:xx:xx:xx:xx REACHABLE
admin@(none):/tmp/home/root# cat /var/lib/misc/dnsmasq.leases
cat: can't open '/var/lib/misc/dnsmasq.leases': No such file or directory
The test script somehow doesn't work while the commands do.
Trying to setup the ASUSWRT integration using SSH to authenticate, I am running into the below error:
`Logger: homeassistant.components.asuswrt.config_flow
Source: components/asuswrt/config_flow.py:155
Integration: ASUSWRT (documentation, issues)
First occurred: 7:30:30 PM (4 occurrences)
Last logged: 8:09:00 PM
Unknown error connecting with AsusWrt router at 192.168.50.1
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/asuswrt/config_flow.py", line 155, in _async_check_connection
await api.connection.async_connect()
File "/usr/local/lib/python3.10/site-packages/aioasuswrt/connection.py", line 78, in async_connect
self._client = await asyncssh.connect(self._host, **kwargs)
File "/usr/local/lib/python3.10/site-packages/asyncssh/connection.py", line 8037, in connect
new_options = cast(SSHClientConnectionOptions, await _run_in_executor(
File "/usr/local/lib/python3.10/site-packages/asyncssh/connection.py", line 515, in _run_in_executor
return await loop.run_in_executor(
File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/local/lib/python3.10/site-packages/asyncssh/connection.py", line 6423, in init
super().init(options=options, last_config=last_config, **kwargs)
File "/usr/local/lib/python3.10/site-packages/asyncssh/misc.py", line 350, in init
self.prepare(**self.kwargs)
File "/usr/local/lib/python3.10/site-packages/asyncssh/connection.py", line 7282, in prepare
load_keypairs(cast(KeyPairListArg, client_keys), passphrase,
File "/usr/local/lib/python3.10/site-packages/asyncssh/public_key.py", line 3470, in load_keypairs
read_private_key_and_certs(key_to_load, passphrase)
File "/usr/local/lib/python3.10/site-packages/asyncssh/public_key.py", line 3284, in read_private_key_and_certs
key, cert = import_private_key_and_certs(read_file(filename), passphrase)
File "/usr/local/lib/python3.10/site-packages/asyncssh/public_key.py", line 3157, in import_private_key_and_certs
key, end = _decode_private(data, passphrase)
File "/usr/local/lib/python3.10/site-packages/asyncssh/public_key.py", line 2761, in _decode_private
key = _decode_pem_private(pem_name, headers, data, passphrase)
File "/usr/local/lib/python3.10/site-packages/asyncssh/public_key.py", line 2672, in _decode_pem_private
return _decode_openssh_private(data, passphrase)
File "/usr/local/lib/python3.10/site-packages/asyncssh/public_key.py", line 2509, in _decode_openssh_private
raise KeyImportError('Passphrase must be specified to import '
asyncssh.public_key.KeyImportError: Passphrase must be specified to import encrypted private keys`
Note that the same SSH connection is working fine when connecting from my macOs terminal - SSH config as below
Host router
HostName 192.168.50.1
User admin
Port 1025
IdentityFile ~/.ssh/id_rsa
Sometimes I get this error:
2022-11-03 08:09:15.693 ERROR (MainThread) [homeassistant.components.asuswrt.router] Unexpected error fetching sensors_rates data: '<' not supported between instances of 'NoneType' and 'float'
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 205, in _async_refresh
self.data = await self._async_update_data()
File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 164, in _async_update_data
return await self.update_method()
File "/usr/src/homeassistant/homeassistant/components/asuswrt/router.py", line 105, in _get_rates
rates = await self._api.async_get_current_transfer_rates()
File "/usr/local/lib/python3.10/site-packages/aioasuswrt/asuswrt.py", line 491, in async_get_current_transfer_rates
if data[0] < self._rx_latest:
TypeError: '<' not supported between instances of 'NoneType' and 'float'
aioasuswrt==1.4.0
device: RT-AC86U with Merlin FW 386.7_2
Looks like asyncssh needs to be updated to a newer version due to errors in home assistant logs on startup.
A combination of changes in 1.2.3 and 0.107 breaks homeassistant.
More info:
[(https://github.com/home-assistant/core/pull/32941)]
Hi, This suggestion may be a bit off-topic but just wanted to share with out and ask what you think.
Background:
On my earlier Asus WRT I had Asuswrt-Merlin. That included busybox which supported adding new Linux users to WRT. This way I was able to make user which did not have root privileges. I used that user for aioasuswrt. This way no need to store root password in the system where I run aioasuswrt.
Idea:
Since the router got broken and I purchased new one. I would like to keep the stock FW in there. I'm wondering if it would be possible to add user using commands in stock FW just by editing files, /etc/password etc. to create another user with limited privileges which could be used for aioasuswrt.
Request:
If you think the idea is feasible and you know how to do it, could you provide instructions how to add new user with limited privileges.
Thanks
With #61 merged it would be nice to get a new release.
Thanks.
configuration.yaml
asuswrt:
host: 192.168.1.1
username: admin
ssh_key: /config/ssh/asuswrt-rsa-key
protocol: ssh
port: 22
interface: br0
sensors:
- upload
- download
- upload_speed
- download_speed
Logger: homeassistant.setup
Source: components/asuswrt/__init__.py:81
First occurred: 下午9:06:48 (1 occurrences)
Last logged: 下午9:06:48
Error during setup of component asuswrt
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/setup.py", line 171, in _async_setup_component
hass, processed_config
File "/usr/src/homeassistant/homeassistant/components/asuswrt/__init__.py", line 81, in async_setup
dnsmasq=conf[CONF_DNSMASQ],
TypeError: __init__() got an unexpected keyword argument 'interface'
That's it
PLZ help me ..... thx!!!
With #6 I'd like a new release rolled out so it can be bumped in home assistant. (Maybe even one more pr for hacktober)
Lemme know if you want help configuring or automating releases.
Is there a specified release cycle, or a plan for creating a new release? I'm waiting for the fixes of #52 to be included in the home assistant installation. (So both a new release, and an update of the core/home-assistant repo would be necessary).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.